diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..6c36a7f --- /dev/null +++ b/Android.mk @@ -0,0 +1,4 @@ +ifneq ($(AUDIO_USE_STUB_HAL), true) + include $(call all-subdir-makefiles) +endif + diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md index 82a5fc6..19f7fb8 100644 --- a/CODE-OF-CONDUCT.md +++ b/CODE-OF-CONDUCT.md @@ -60,7 +60,7 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -[GitHub.CoC](mailto:github.coc@qti.qualcomm.com?subject=GitHub%20Qualcomm%20Code%20of%20Conduct%20Report). +[GitHub.QuIC.CoC](mailto:GitHub.QuIC.CoC@qti.qualcomm.com?subject=GitHub%20QuIC%20Code%20of%20Conduct%20Report). All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 345bf9c..5b0d449 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to +## Contributing to AudioReach Graph Service Hi there! We’re thrilled that you’d like to contribute to this project. @@ -6,71 +6,23 @@ Your help is essential for keeping this project great and for making it better. ## Branching Strategy -Development happens directly on branch main. Open a PR targeting main +In general, contributors should develop on branches based off of `master` and pull requests should be made against `master`. ## Submitting a pull request -1. Please read our [code of conduct](CODE-OF-CONDUCT.md) and [license](LICENSE.txt). -1. [Fork](https://github.com/qualcomm-linux/pkg-template/fork) and clone the repository. - - ```bash - git clone https://github.com/qualcomm-linux/pkg-template.git - ``` - -1. Create a new branch based on `main`: - - ```bash - git checkout -b main - ``` - -1. Create an upstream `remote` to make it easier to keep your branches up-to-date: - - ```bash - git remote add upstream https://github.com/qualcomm/.git - ``` - +1. Please read our [code of conduct](CODE-OF-CONDUCT.md) and [license](LICENSE). +1. Fork and clone the repository. +1. Create a new branch based on `master`: `git checkout -b master`. 1. Make your changes, add tests, and make sure the tests still pass. -1. Commit your changes using the [DCO](https://developercertificate.org/). You can attest to the DCO by commiting with the **-s** or **--signoff** options or manually adding the "Signed-off-by": - - ```bash - git commit -s -m "Really useful commit message"` - ``` - -1. After committing your changes on the topic branch, sync it with the upstream branch: - - ```bash - git pull --rebase upstream main - ``` - -1. Push to your fork. - - ```bash - git push -u origin - ``` - - The `-u` is shorthand for `--set-upstream`. This will set up the tracking reference so subsequent runs of `git push` or `git pull` can omit the remote and branch. - -1. [Submit a pull request](https://github.com/qualcomm//pulls) from your branch to `main`. +1. Commit your changes using the [DCO](http://developercertificate.org/). You can attest to the DCO by commiting with the **-s** or **--signoff** options or manually adding the "Signed-off-by": +1. Push to your fork and submit a pull request from your branch to `master`. 1. Pat yourself on the back and wait for your pull request to be reviewed. -## Security Analysis of Pull Requests - -To maintain the security and integrity of this project, all pull requests from external contributors are automatically scanned using [Semgrep](https://github.com/semgrep/semgrep) to detect insecure coding patterns and potential security flaws. - -**Static Analysis with Semgrep:** We use Semgrep to perform lightweight, fast static analysis on every PR. This helps identify risky code patterns and logic flaws early in the development process. - -**Contributor Responsibility:** If any issues are flagged, contributors are expected to resolve them before the PR can be merged. - -**Continuous Improvement:** Our Semgrep ruleset evolves over time to reflect best practices and emerging security concerns. - -By submitting a PR, you agree to participate in this process and help us keep the project secure for everyone. - - Here are a few things you can do that will increase the likelihood of your pull request to be accepted: -- Follow the existing style where possible. **INSERT LINK TO STYLE, e.g. PEP8 for python** +- Follow the existing style where possible. We try and adhere to [pep8](https://www.python.org/dev/peps/pep-0008/). - Write tests. - Keep your change as focused as possible. If you want to make multiple independent changes, please consider submitting them as separate pull requests. -- Write a [good commit message](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). +- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). - It's a good idea to arrange a discussion with other developers to ensure there is consensus on large features, architecture changes, and other core code changes. PR reviews will go much faster when there are no surprises. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..db77a87 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +SPDX-License-Identifier: BSD-3-Clause diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 389b547..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..41944f5 --- /dev/null +++ b/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = spf ar_osal ar_util acdb gpr gsl acdb/ats diff --git a/README.md b/README.md index d8a956b..0937a4b 100644 --- a/README.md +++ b/README.md @@ -1,146 +1,18 @@ -# pkg-template +# AudioReach Graph Service -This repository serves as a template for creating Debian package repositories within the Qualcomm Linux ecosystem. It provides the essential structure, GitHub workflows, and configuration necessary to integrate with the [qcom-build-utils](https://github.com/qualcomm-linux/qcom-build-utils) repository, enabling standardized Debian package building processes. +## Introduction -## Quick Start +This repository hosts a set of platform independent graph service libraries and implementation of abstraction layer for different OS and platform. These libraries together setup and manage audio graphs in the signal processing framework. -To create a new Debian package repository using this template: +## Documentation -1. Navigate to this repository's GitHub page and click the **"Use this template"** button located in the top right corner. -2. Select **qualcomm-linux** as the organization in the drop-down menu. This is necessary. -3. Name the new repository with the prefix `pkg-` to adhere to the naming convention for package repositories. This is necessary. -4. Ensure the **"Include all branches"** option is enabled. Otherwise by default, only the default branch "main" is cloned. +Refer AudioReach docs [here](https://audioreach.github.io/design/args_design.html) -## Branches +## Build instructions -- **main**: The primary branch containing workflow logic in the `.github/` folder, along with boilerplate documentation files such as license, contribution guidelines, and this README. -- **debian/qcom-next**: An orphan branch with unrelated history from main. It contains a debian/ folder with template files. Its just to give a starting point and structure. The first job for the user templating from this repo will be to update this debian/ folder. The information about the name **debian/qcom-next** and other naming conventions can be found [here](https://qualcomm-confluence.atlassian.net/wiki/spaces/LinuxCoreOS/pages/2879858691/pkg-+repository+specification) - -## Workflows - -The `main` branch includes the following workflows in the `.github/workflows/` directory: - -- **qcom-preflight-checks.yml**: A sanity check workflow inherited from the base Qualcomm template. -- **stale-issues.yml**: A workflow for managing stale issues, also inherited from the base template. -- **build-debian-package.yml**: Builds the Debian package for this repository. This workflow serves as an entry point that invokes reusable workflows from the centralized qcom-build-utils repository. -- **pr-pre-post-merge.yml**: This workflow executes during a PR, and once the PR is merged. -- **promote-upstream.yml**: Promotes the package's tracking version to a new upstream release. This workflow also triggers reusable workflows in qcom-build-utils. -- **release**: Used to trigger a release of a package - -## IMPORTANT: Workflow to paste in the upstream source repo - -The .github/TO_PASTE_IN_UPSTREAM_REPO/pkg-build-pr-check.yml needs to be transfered over to the source repo. -Once this is done, delete the TO_PASTE_IN_UPSTREAM_REPO as it is not necessary to keep in this repository once the workflow has been transfered. - -**This workflow needs to be put in the default branch of the source repo (likely branch main unless you modify it), otherwise it wont work** This is per new December Github update - -## Repository Configuration - -### Runners - -All the workflows are running on the github arm64 runners. Some sections need to run on the AWS runners where access to S3 buckets and artifactory. You will need to ask **Steve Manley** to enable the repo for the AWS runners. - -### GHCR Registry Access - -The build workflows rely on the `pkg-builder` container image hosted in the qualcomm-linux GitHub Container Registry (GHCR). For your newly created repository to be able to pull this image, it must be explicitly granted `packages:read` access. - -To request this, please contact **Mark Matyas** (mmatyas@qti.qualcomm.com) and ask him to add your repository to the list of repositories authorized to access the `pkg-builder` package. The relevant settings page is: - -https://github.com/orgs/qualcomm-linux/packages/container/pkg-builder/settings - -### Repository Variables - -Set the following repository variables to establish links between upstream and package repositories: - -- **UPSTREAM_REPO_GITHUB_NAME**: In this package repo, this is the GitHub name of the upstream repository (e.g. in the case of the pkg-example, `qualcomm-linux/qcom-example-package-source`). -- **PKG_REPO_GITHUB_NAME**: This variable is set in the upstream project repo; the GitHub name of the package repository (e.g., `qualcomm-linux/pkg-example`). - -### Branch Protection Rules - -Configure branch protection for `debian/**` and `qcom/**`: - -- Restrict deletions. -- Require pull requests before merging. -- Block force pushes. -- Add `build / build-debian-package` as a required status check. -- Add the `qcom-service-bot` account with admin rights -- Add the Admin role to the branche protection ruleset so that the qcom-service-bot can push directly to those branches -### Additional Settings - -- Enable **"Automatically delete head branches"** for pull requests. -- Allow only merge commits for pull request merges. -- Enable **release immutability** in the upstream repository. -- Add the Qualcomm Github Service bot as a user with write access : - - While the repo is private, add the Github user **qcom-service-bot**. - - If/when the repo is made public, there will be a big change in how the contributors are handled. - After that, the contributors list is cleared, and one need to re-enroll as a contributor. The way - to do that is completely different from when the repo was private. When it was private, the creator - of the repo had the possibility to go into the repo settings and add whoever. When made public, the - repo's maintainer/contributor list is managed by a Qualcomm internal mailing list. If the repo is - named pkg-foo, then the Maintainer list will be named Maintainers.pkg-foo, and one need to request - access via https://lists.qualcomm.com, find the list and ask access. For the bot, you must add it via - its qualcomm username **githubservice**@qti.qualcomm.com, as opposed to its Github handle above. - -## Making your pkg-repo to public - -When your pkg-repo is mature enough, it will need to be made public. - -### How to make the repo go public - -The first step in making a repo go public is the Tradesmark/legal process. -Your POC (Person of Contact) in this step is [Stephanie Arce](sarce@qti.qualcomm.com) - -You need to [complete an OSS Contribution Request](https://jira-dc4.qualcomm.com/jira/secure/CreateIssue.jspa?pid=46536&issuetype=13440) - -Here is a bit of help on the mandatory fields when filling the form: - -- Components : Select "Other" -- Summary : Give a short description such as "Debian packaging repository for X" -- Project name: This would be the repo name, such as "pkg-example" -- Destination URL: Give the Github URL, such as "www.github.com/qualcomm-linux/pkg-example" -- Description: Give a description about the repo being a debian packaging repo, which packages another upstream project X -- Project Licenses: Give the license of the repo. Unless something changes, it should remain BSD-3-Clause License. -- Contribution plan: - - Project Description: You can give the same project description as above - - What are ourr general plan with the Project: Talk about it being the debian packaging for project X - - Do we have any Leadership positions in the project: Give yourself/manager - - Is Qualcomm expanding the project by contributing technology implementations: Likely a simple no - -More information can be found [here](https://github.qualcomm.com/pages/osdo/handbook/qcom-github/docs/new-project-checklist/) - -Once submitted, it will generally take a couple of days to a week to get approval from Legal. - -The, once you receive an email about the acceptance of the Legal team, you will have to submit a ticket about enabling the repo. - -In this process, your POC will be [Mark Matyas](mmatyas@qti.qualcomm.com) - -Complete the form : https://ossops.qualcomm.com/github/enable-repo/ - -### Note about Github Repo roles after going public - -When creating a repo withing the organization, it always starts as a private repo and one need to go through an approval -process in order to have the repo go public. - -Upon creation of the repo, the person who created it gets to be assigned the maintainer responsability and has full control -over it in the settings. When the repo goes public, this changes. The repo creator stops having all the powers over the repo, -and in order to join the repo as a contributor, one needs to enroll via a github mailing list instead of directly through the repo -settings. - -This is the link to go to in order to ask to be a contributor or a maintainer of a Qualcomm publib github repo : -https://lists.qualcomm.com/ListManager - -In the searchbox, one need to find the contributor/maintainer list corresponding to the repo. -If the repo is named "pkg-example", then the list(s) to search for are : - -- contributors.pkg-example -- maintainers.pkg-example - -It takes about an hour between the list acceptance and the new role to reflect in Github - -## Getting in Contact - -For support or inquiries, contact sbeaudoi@qti.qualcomm.com. +Graph service repository supports various build systems: Android, Autotools. CMake is work in progress. +Refer meta-audioreach [README](https://github.com/Audioreach/meta-audioreach?tab=readme-ov-file#openembedded-build--development-process) for instructions to use Graph Service on OpenEmbedded system. ## License -pkg-template is licensed under the [BSD-3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html). See [LICENSE.txt](LICENSE.txt) for the full license text. +Graph service is licensed under the BSD-3-Clause. Check out the [LICENSE](LICENSE) for more details. \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 468eda6..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,31 +0,0 @@ -How to Report a Potential Vulnerability? -======================================== - -If you would like to report a public issue (for example, one with a released -CVE number), please report it as a -[GitHub issue](https://github.com/qualcomm/REPLACE-ME/issues/new). -If you have a patch ready, submit it following the same procedure as any -other patch as described in [CONTRIBUTING.md](CONTRIBUTING.md). - -If you are dealing with a not-yet released or urgent issue, please contact us -via our [Product Security team](mailto:product-security@qualcomm.com) or -see our -[Report a Bug](https://www.qualcomm.com/company/product-security/report-a-bug) -page. Please include the following details while reporting a vulnerability: -- Description of the vulnerability -- Steps to reproduce -- Affected versions -- Potential impact -- Any relevant logs or screenshots - -## Coordinated Disclosure - -We follow a Coordinated Vulnerability Disclosure (CVD) process: - -- **Initial Response**: We will acknowledge your report within 48 hours. - -- **Investigation**: Our team will investigate the issue and provide updates. - -- **Resolution**: We will work with you to resolve the issue and prepare a fix. - -- **Disclosure**: Once the fix is ready, we will disclose the vulnerability and notify affected users. diff --git a/acdb/Android.mk b/acdb/Android.mk new file mode 100644 index 0000000..896f95b --- /dev/null +++ b/acdb/Android.mk @@ -0,0 +1,180 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +#---------------------------------------------------------------------------- +# Common definitons +#---------------------------------------------------------------------------- + +acdb-def += -D_ANDROID_ + +#---------------------------------------------------------------------------- +# Make the Shared library (libar-acdb) +#---------------------------------------------------------------------------- + +#LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc + +LOCAL_CFLAGS := $(acdb-def) + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/api\ + $(LOCAL_PATH)/inc + +LOCAL_SRC_FILES := \ + src/acdb.c \ + src/acdb_command.c \ + src/acdb_delta_file_mgr.c \ + src/acdb_delta_parser.c \ + src/acdb_file_mgr.c \ + src/acdb_init.c \ + src/acdb_init_utility.c \ + src/acdb_parser.c \ + src/acdb_utility.c\ + src/acdb_data_proc.c\ + src/acdb_heap.c\ + src/acdb_context_mgr.c + +LOCAL_MODULE := libar-acdb +LOCAL_MODULE_OWNER := qti +LOCAL_MODULE_TAGS := optional +LOCAL_VENDOR_MODULE := true + +LOCAL_HEADER_LIBRARIES := \ + libcutils_headers \ + libutils_headers \ + vendor_common_inc + +LOCAL_SHARED_LIBRARIES := \ + liblx-osal + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/api +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH)/inc + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +#---------------------------------------------------------------------------- +# Common definitons +#---------------------------------------------------------------------------- + +ats-def += -D_ANDROID_ -DAR_ATS_USE_CUTILS + +#---------------------------------------------------------------------------- +# Make the Shared library (libats) +#---------------------------------------------------------------------------- + +#LOCAL_C_INCLUDES := $(MYLOCAL_PATH)/inc + +LOCAL_CFLAGS := $(ats-def) + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MCS)),true) + LOCAL_CFLAGS += -DMCS_ENABLED +endif + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/ats/inc \ + $(LOCAL_PATH)/ats/rtc/common/inc \ + $(LOCAL_PATH)/ats/online/common/inc/ \ + $(LOCAL_PATH)/ats/mcs/common/inc/ \ + $(LOCAL_PATH)/ats/mcs/common/api/ \ + $(LOCAL_PATH)/ats/fts/common/inc/ \ + $(LOCAL_PATH)/ats/transports/diag/linux/actp/inc/ \ + $(LOCAL_PATH)/ats/transports/diag/linux/audtp/inc/ \ + $(LOCAL_PATH)/ats/adie/common/inc \ + $(LOCAL_PATH)/ats/adie/common/api \ + $(LOCAL_PATH)/ats/api \ + $(LOCAL_PATH)/ats/sockets/common/api/ \ + $(LOCAL_PATH)/ats/transports/common/api/ \ + $(LOCAL_PATH)/ats/transports/common/inc/ \ + $(LOCAL_PATH)/ats/transports/tcpip_server/inc/ \ + $(LOCAL_PATH)/ats/transports/tcpip_server/api/ \ + $(LOCAL_PATH)/ats/dls/common/inc + +LOCAL_SRC_FILES := \ + ats/src/ats.c \ + ats/src/ats_command.c \ + ats/rtc/common/src/ats_rtc.c \ + ats/online/common/src/ats_online.c \ + ats/mcs/common/src/ats_mcs.c \ + ats/mcs/linux/mcs.c \ + ats/fts/common/src/ats_fts.c \ + ats/transports/diag/linux/actp/src/actp.c \ + ats/transports/diag/linux/audtp/src/audtp.c \ + ats/adie/common/src/ats_adie_rtc.c \ + ats/adie/linux/adie_rtc.c \ + ats/sockets/linux/src/ar_sockets.cpp \ + ats/transports/common/src/ats_transport.c \ + ats/transports/tcpip_server/src/tcpip_cmd_server.cpp \ + ats/transports/tcpip_server/src/tcpip_dls_server.cpp \ + ats/transports/tcpip_server/src/tcpip_socket_util.cpp \ + ats/dls/common/src/ats_dls.c + +LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/diag/include + +LOCAL_MODULE := libats +LOCAL_MODULE_OWNER := qti +LOCAL_MODULE_TAGS := optional +LOCAL_VENDOR_MODULE := true + +LOCAL_HEADER_LIBRARIES := \ + libcutils_headers \ + libutils_headers \ + libdiag_headers \ + vendor_common_inc + +LOCAL_SHARED_LIBRARIES := \ + liblx-osal\ + libutils\ + libcutils \ + libdiag \ + libar-gsl\ + libar-acdb + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/ats/api +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH)/ats/inc +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH)/ats/adie/common/api +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH)/ats/mcs/common/api + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +#---------------------------------------------------------------------------- +# Common definitons +#---------------------------------------------------------------------------- + +ats-gateway-def += -D_ANDROID + +#---------------------------------------------------------------------------- +# Make the Application (ats_gateway.out) +#---------------------------------------------------------------------------- +LOCAL_MODULE := ats_gateway.out +LOCAL_MODULE_OWNER := qti +LOCAL_MODULE_TAGS := optional +LOCAL_PROPRIETARY_MODULE := true +LOCAL_VENDOR_MODULE := true + +LOCAL_CPPFLAGS := $(ats-gateway-def) \ + -DSOCK_PATH='"/vendor/app/GatewayServer/ATS_sockets"' \ + -DSOCK_PATH_SERVER='"/vendor/app/GatewayServer/ATS_sockets/unix_sock.server"' \ + -DSOCK_PATH_GATEWAY='"/vendor/app/GatewayServer/ATS_sockets/unix_sock.gateway"' + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/ats/transports/tcpip_gateway/inc \ + $(LOCAL_PATH)/ats/sockets/common/api/ +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/include/mm-audio/casa/ar_osal + +LOCAL_SRC_FILES := \ + ats/transports/tcpip_gateway/src/tcpip_gateway_main.cpp \ + ats/transports/tcpip_gateway/src/tcpip_gateway_cmd_server.cpp \ + ats/transports/tcpip_gateway/src/tcpip_gateway_dls_server.cpp \ + ats/transports/tcpip_gateway/src/tcpip_gateway_socket_util.cpp \ + ats/sockets/linux/src/ar_sockets.cpp + +LOCAL_SHARED_LIBRARIES := \ + liblx-osal \ + libutils \ + libcutils + +LOCAL_LDLIBS := -llog + +include $(BUILD_EXECUTABLE) diff --git a/acdb/Makefile.am b/acdb/Makefile.am new file mode 100644 index 0000000..32595ad --- /dev/null +++ b/acdb/Makefile.am @@ -0,0 +1,51 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = acdb.pc +EXTRA_DIST = $(pkgconfig_DATA) + +AM_CFLAGS = -Wall -Wno-unknown-pragmas -Wno-error=comment -Wno-error=discarded-qualifiers \ + -Wno-error=address-of-packed-member -Wno-error=unused-but-set-variable \ + -Wno-error=incompatible-pointer-types + +AM_CFLAGS += -I$(srcdir)/inc +AM_CFLAGS += -I$(srcdir)/api +AM_CFLAGS += -I$(top_srcdir)/ar_osal/api + +acdb_sources = ./inc/acdb_command.h \ + ./inc/acdb_common.h \ + ./inc/acdb_context_mgr.h \ + ./inc/acdb_delta_file_mgr.h \ + ./inc/acdb_delta_parser.h \ + ./inc/acdb_file_mgr.h \ + ./inc/acdb_init.h \ + ./inc/acdb_init_utility.h \ + ./inc/acdb_parser.h \ + ./inc/acdb_types.h \ + ./inc/acdb_utility.h \ + ./inc/acdb_data_proc.h \ + ./inc/acdb_heap.h\ + ./api/acdb.h \ + ./api/acdb_begin_pack.h \ + ./api/acdb_end_pack.h + +acdb_c_sources = ./src/acdb.c \ + ./src/acdb_command.c \ + ./src/acdb_context_mgr.c \ + ./src/acdb_delta_file_mgr.c \ + ./src/acdb_delta_parser.c \ + ./src/acdb_file_mgr.c \ + ./src/acdb_init.c \ + ./src/acdb_init_utility.c \ + ./src/acdb_parser.c \ + ./src/acdb_utility.c \ + ./src/acdb_data_proc.c \ + ./src/acdb_heap.c + +lib_includedir = $(includedir) +lib_include_HEADERS = $(acdb_sources) + +lib_LTLIBRARIES = libar-acdb.la +libar_acdb_la_CC = @CC@ +libar_acdb_la_LIBADD = -lar-osal -L$(top_builddir)/ar_osal +libar_acdb_la_SOURCES = $(acdb_c_sources) +libar_acdb_la_CFLAGS = $(AM_CFLAGS) +libar_acdb_la_LDFLAGS = -shared -version-number @LT_VERSION_NUMBER@ diff --git a/acdb/acdb.pc.in b/acdb/acdb.pc.in new file mode 100644 index 0000000..6898b4f --- /dev/null +++ b/acdb/acdb.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: acdb +Description: acdb library +Version: @LT_VERSION@ +Libs: -L${libdir} -lar-acdb +Cflags: -I${includedir} diff --git a/acdb/api/acdb.h b/acdb/api/acdb.h new file mode 100644 index 0000000..46d4337 --- /dev/null +++ b/acdb/api/acdb.h @@ -0,0 +1,2338 @@ +#ifndef __ACDB_API_H__ +#define __ACDB_API_H__ +/** +*============================================================================= +* \file acdb.h +* +* \brief +* Contains the public interface definitions for the Audio Calibration +* Database (ACDB) module. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- +* Include Files +*--------------------------------------------------------------------------- */ +#include +#include "ar_osal_types.h" +#include "ar_osal_file_io.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ + +/**< The ACDB Software Major Version */ +#define ACDB_SOFTWARE_VERSION_MAJOR 0x00000001 + +/**< The ACDB Software Minor Version */ +#define ACDB_SOFTWARE_VERSION_MINOR 0x00000030 + +/**< The ACDB Software Revision */ +#define ACDB_SOFTWARE_VERSION_REVISION 0x00000000 + +/**< The ACDB Software CPL Info */ +#define ACDB_SOFTWARE_VERSION_CPLINFO 0x00000000 + +/**< The max character length of a file name string */ +#define MAX_FILENAME_LENGTH 256 + +/**< The max allowed number databases to manage */ +#define MAX_ACDB_FILE_COUNT 16 + +/**< The max number of files that can be init'ed/added to the database */ +#define ACDB_MAX_FILE_ADD_LIMIT 2 + +#define INF 4294967295U + +/*! Ex. ACDB_CMD_ID(1) is 0xACDB0001*/ +#define ACDB_CMD_ID(x) ((0xACDBUL << 16) | (0xFFFFUL & x)) +#define ACDB_MEM_CPY(dst,src,src_size) memcpy((uint8_t *)dst, (uint8_t *)src, src_size) +#define ACDB_MEM_CMP(x, y, len) memcmp(x,y,len) +#define ACDB_CLEAR_BUFFER(x) memset(&x, 0, sizeof(x)) + +/* --------------------------------------------------------------------------- +* Type Declarations +*-------------------------------------------------------------------------- */ + +/**< A handle to a database */ +typedef void *acdb_handle_t; + +/** @addtogroup GENERIC_STRUCTURES +@{ */ + +/**< Represents one key value pair.*/ +typedef struct _acdb_key_value_t AcdbKeyValuePair; +#include "acdb_begin_pack.h" +struct _acdb_key_value_t { + /**< Key ID*/ + uint32_t key; + /**< Key value*/ + uint32_t value; +} +#include "acdb_end_pack.h" +; + +/**< Generic response structure. BLOB stands for binary large object.*/ +typedef struct _acdb_blob_t AcdbBlob; +#include "acdb_begin_pack.h" +struct _acdb_blob_t { + /**< Buffer size. */ + uint32_t buf_size; + /**< Point to the query buffer. */ + void* buf; +} +#include "acdb_end_pack.h" +; + +/**< Maintains buffer context information.*/ +typedef struct _acdb_buffer_context_t AcdbBufferContext; +#include "acdb_begin_pack.h" +struct _acdb_buffer_context_t +{ + /*Total size of the buffer 'buf'*/ + uint32_t size; + /*Number of bytes filled in the buffer 'buf'*/ + uint32_t bytes_filled; + /*The buffer that contains a data blob*/ + uint8_t *buf; +} +#include "acdb_end_pack.h" +; + +/**< Request structure used to query for AMDB bootup +modules, registration, and deregistration data*/ +typedef struct _acdb_amdb_proc_id_t AcdbAmdbProcID; +#include "acdb_begin_pack.h" +struct _acdb_amdb_proc_id_t +{ + /**< The the ID of processor domain that the AMDB modules operate under */ + uint32_t proc_id; +} +#include "acdb_end_pack.h" +; + +/**< Request structure used to query for AMDB bootup +modules, registration, and deregistration data*/ +typedef struct _acdb_amdb_db_handle_t AcdbAmdbDbHandle; +#include "acdb_begin_pack.h" +struct _acdb_amdb_db_handle_t +{ + /*Handle for the database to retreive AMDB information from */ + acdb_handle_t acdb_handle; + /**< The the ID of processor domain that the AMDB modules operate under */ + uint32_t proc_id; +} +#include "acdb_end_pack.h" +; + +/**< A Key Vector with a zero sized array */ +typedef struct _acdb_key_vector_t AcdbKeyVector; +#include "acdb_begin_pack.h" +struct _acdb_key_vector_t { + /**< number of keys*/ + uint32_t num_keys; + /**< Graph key vector*/ + AcdbKeyValuePair graph_key_vector[0]; +} +#include "acdb_end_pack.h" +; + +/**< A Tag Key Vector with a zero sized array */ +typedef struct _acdb_tag_key_vector_t AcdbTagKeyVector; +#include "acdb_begin_pack.h" +struct _acdb_tag_key_vector_t { + /**< The module tag identifier*/ + uint32_t tag_id; + /**< number of keys*/ + uint32_t num_keys; + /**< Graph key vector*/ + AcdbKeyValuePair graph_key_vector[0]; +} +#include "acdb_end_pack.h" +; + +/**< List of uint32_t with a pointer to an array of uint32_t*/ +typedef struct _acdb_uint_list_t AcdbUintList; +struct _acdb_uint_list_t +{ + /**< number of elemts in the list */ + uint32_t count; + /**< Array of uints */ + uint32_t *list; +}; + +/**< List of uint32_t with a zero sized array*/ +typedef struct _acdb_uint_list_zs_t AcdbUintListZS; +#include "acdb_begin_pack.h" +struct _acdb_uint_list_zs_t +{ + /**< number of elemts in the list */ + uint32_t count; + /**< Array of uints */ + uint32_t list[0]; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup GENERIC_STRUCTURES */ + +/* --------------------------------------------------------------------------- +* Public API Declarations and Documentation +*-------------------------------------------------------------------------- */ + +typedef struct _acdb_file_t AcdbFile; +#include "acdb_begin_pack.h" +struct _acdb_file_t { + /**< Full file path name length */ + uint32_t fileNameLen; + /**< Array that holds the ACDB file path and name, which cannot exceed + 256 characters, including the NULL-termiated character */ + char fileName[MAX_FILENAME_LENGTH]; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_data_files_t AcdbDataFiles; +#include "acdb_begin_pack.h" +struct _acdb_data_files_t { + /**< Number of ACDB files*/ + uint32_t num_files; + /**< Array of ACDB file full paths. size: num_files*/ + AcdbFile acdbFiles[ACDB_MAX_FILE_ADD_LIMIT]; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_database_files_t AcdbDatabaseFiles; +#include "acdb_begin_pack.h" +struct _acdb_database_files_t { + /**< Number of database files */ + uint32_t num_files; + /**< An array containing the full path to one *.acdb and one *.qwsp file */ + AcdbFile database_files[ACDB_MAX_FILE_ADD_LIMIT]; +} +#include "acdb_end_pack.h" +; + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_GRAPH Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** @addtogroup ACDB_CMD_GET_GRAPH +@{ */ + +/** + Queries ACDB SW for a subgraph sequence(a usecase graph) given a graph key vector. + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_GRAPH. + @param[in] cmd + Pointer to AcdbGraphKeyVector. + @param[in] cmd_size + Size of AcdbGraphKeyVector. + @param[out] rsp + Pointer to AcdbGetGraphRsp + @param[in] rsp_size + Size of AcdbGetGraphRsp + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + @sa + acdb_ioctl + AcdbGraphKeyVectorCmd + AcdbGetGraphRsp +*/ +#define ACDB_CMD_GET_GRAPH ACDB_CMD_ID(1) + +typedef struct _acdb_subgraph_t AcdbSubgraph; +#include "acdb_begin_pack.h" +struct _acdb_subgraph_t { + /** */ + uint32_t cal_Id; +} +#include "acdb_end_pack.h" +; +/** @} */ /* end_addtogroup ACDB_CMD_GET_SUBGRAPH_GLB_PSIST_CALDATA */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_DRIVER_DATA Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** @addtogroup ACDB_CMD_GET_DRIVER_DATA +@{ */ + +/** + Queries ACDB SW for a specific parameter payload given the + Module ID and a Key Vector(CKV/TKV/GKV/etc...). + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_DRIVER_DATA. + @param[in] cmd + A pointer to AcdbDriverGetDataCmd + @param[in] cmd_size + This must equal the size of AcdbDriverGetDataCmd + @param[out] rsp + Pointer to AcdbBlob. Blob contains PID,PayloadSize, Payload for all PIDs in that module. + @param[in] rsp_size + This must equal the size of AcdbBlob + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + @sa + acdb_ioctl +*/ +#define ACDB_CMD_GET_DRIVER_DATA ACDB_CMD_ID(8) + +/**< Input: Represents component IDs along with a calibration key vector*/ +typedef struct _acdb_driver_data_t AcdbDriverData; +#include "acdb_begin_pack.h" +struct _acdb_driver_data_t { + /**< Key Vector associated with the driver data*/ + AcdbGraphKeyVector key_vector; + /**< Driver Module ID*/ + uint32_t module_id; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_DRIVER_DATA */ + + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_MODULE_TAG_DATA Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** @addtogroup ACDB_CMD_GET_MODULE_TAG_DATA +@{ */ + +/** + Query for all necessary data for the given SGID, module_tag, and keys. Clients should provide “Don’t care” value for those tag indices which are not used in a tag_key_vec. + For a given tag, all its indices should be provided with a value. + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_MODULE_TAG_DATA. + @param[in] cmd + This is a pointer to AcdbGetModuleTagCmd. + @param[in] cmd_size + This is the size of AcdbGetModuleTagCmd. + @param[out] rsp + This is a pointer to AcdbBlob. + @param[in] rsp_size + This is the size of AcdbBlob. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + @sa + acdb_ioctl + AcdbCalDataRsp +*/ +#define ACDB_CMD_GET_MODULE_TAG_DATA ACDB_CMD_ID(9) +/** Input: +*/ + +typedef struct _acdb_module_tag_t AcdbModuleTag; +#include "acdb_begin_pack.h" +struct _acdb_module_tag_t { + /**< Module tag ID*/ + uint32_t tag_id; + AcdbGraphKeyVector tag_key_vector; +} +#include "acdb_end_pack.h" +; + +/** Input: +*/ +typedef struct _acdb_sgid_module_tag_t AcdbSgIdModuleTag; +#include "acdb_begin_pack.h" +struct _acdb_sgid_module_tag_t { + /**< Num of Subgraph IDs*/ + uint32_t num_sg_ids; + /**< Subgraph IDs*/ + uint32_t* sg_ids; + /**< Module tag*/ + AcdbModuleTag module_tag; + +} +#include "acdb_end_pack.h" +; + + +/** @} */ /* end_addtogroup ACDB_CMD_GET_MODULE_TAG_DATA */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_TAGGED_MODULES Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_TAGGED_MODULES + +@{ */ + +/** + Query for tagged module ID(s) and instance ID(s). + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_TAGGED_MODULES. + @param[in] cmd + This is a pointer to AcdbGetTaggedModulesReq. + @param[in] cmd_size + This is the size of AcdbGetTaggedModulesReq. + @param[out] rsp + This is a pointer to AcdbGetTaggedModulesRsp. + @param[in] rsp_size + This is the size of AcdbGetTaggedModulesRsp. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + @sa + acdb_ioctl + */ +#define ACDB_CMD_GET_TAGGED_MODULES ACDB_CMD_ID(10) + +//Input +typedef struct _acdb_get_tagged_modules_req_t AcdbGetTaggedModulesReq; +#include "acdb_begin_pack.h" +struct _acdb_get_tagged_modules_req_t { + /**< Num of Subgraph IDs*/ + uint32_t num_sg_ids; + /**< Subgraph ID list*/ + uint32_t* sg_ids; + /**< tag ID*/ + uint32_t tag_id; +} +#include "acdb_end_pack.h" +; + +//output + +typedef struct _acdb_module_instance_t AcdbModuleInstance; +#include "acdb_begin_pack.h" +struct _acdb_module_instance_t { + /**< Module ID*/ + uint32_t mid_id; + /**< Module instance ID*/ + uint32_t mid_iid; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_get_tagged_modules_t AcdbGetTaggedModulesRsp; +#include "acdb_begin_pack.h" +struct _acdb_get_tagged_modules_t { + /**< Number of tagged modules*/ + uint32_t num_tagged_mids; + /**< Pointer to array of tagged modules*/ + AcdbModuleInstance* tagged_mid_list; +} +#include "acdb_end_pack.h" +; + + +/** @} */ /* end_addtogroup ACDB_CMD_GET_TAGGED_MODULES */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_KEY_CAPABILITIES Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_KEY_CAPABILITIES + +@{ */ + +/** + Query for tagged module ID(s) and instance ID(s). + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_KEY_CAPABILITIES. + @param[in] cmd + There is no input structure; set this to NULL. + @param[in] cmd_size + There is no input structure; set this to 0. + @param[out] rsp + There is no output structure; set this to NULL. + @param[in] rsp_size + There is no output structure; set this to 0. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + @sa + acdb_ioctl +*/ +#define ACDB_CMD_GET_KEY_CAPABILITIES ACDB_CMD_ID(11) + +//output + +typedef struct _acdb_get_key_capabilities_t AcdbGetKeyCapabilitiesRsp; +#include "acdb_begin_pack.h" +struct _acdb_get_key_capabilities_t { + AcdbGraphKeyVector cal_key_vector; + /**< Number of modules*/ + uint32_t num_modules; + /**< Pointer to array of Module instances*/ + AcdbModuleInstance* module_Instances; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_KEY_CAPABILITIES */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_SET_CAL_DATA Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_SET_CAL_DATA +@{ */ + +/** +* Sets cal data to the AML heap and persists it to delta file. Delta file +* persistence needs to be enabled through ACDB_CMD_ENABLE_PERSISTANCE to +* persist data accross system reboots. +* +* The input cal blob is in the format of: +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* ... +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_SET_CAL_DATA. +* @param[in] cmd +* This is a pointer to AcdbSetCalDataReq. +* @param[in] cmd_size +* This is the size of AcdbSetCalDataReq. +* @param[out] rsp +* There is no output structure; set this to NULL. +* @param[in] rsp_size +* There is no output structure; set this to 0. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* +* @sa +* acdb_ioctl +* ACDB_CMD_GET_CAL_DATA +* ACDB_CMD_ENABLE_PERSISTANCE +* +*/ +#define ACDB_CMD_SET_CAL_DATA ACDB_CMD_ID(12) + +/* Request structure for setting cal data to the AML heap and delta file */ +typedef struct _acdb_set_cal_data_t AcdbSetCalDataReq; +#include "acdb_begin_pack.h" +struct _acdb_set_cal_data_t { + /**< The graph keys that describe the usecase the modules are under */ + AcdbGraphKeyVector graph_key_vector; + /**< cal key vector */ + AcdbGraphKeyVector cal_key_vector; + /**< cal blob size */ + uint32_t cal_blob_size; + /**< cal blob */ + void* cal_blob; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_SET_CAL_DATA */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_ENABLE_PERSISTANCE Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_ENABLE_PERSISTANCE +@{ */ + +/** + Enable ACDB calibration data persistance. Calibration data set to ACDB + will be persisted to a *.acdbdelta file + + @param[in] cmd_id + Command ID is ACDB_CMD_ENABLE_PERSISTANCE. + @param[in] cmd + There is no input structure; set this to NULL. + @param[in] cmd_size + There is no input structure; set this to 0. + @param[out] rsp + There is no output structure; set this to NULL. + @param[in] rsp_size + There is no output structure; set this to 0. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + @sa + acdb_ioctl +*/ +#define ACDB_CMD_ENABLE_PERSISTANCE ACDB_CMD_ID(13) + +/** @} */ /* end_addtogroup ACDB_CMD_ENABLE_PERSISTANCE */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_AMDB_REGISTRATION_DATA Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_AMDB_REGISTRATION_DATA +@{ */ + +/** + Queries AMDB data for one Processor ID to register all dynamic custom + modules + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_AMDB_REGISTRATION_DATA. + @param[in] cmd + This is a pointer to AcdbAmdbProcID. + @param[in] cmd_size + This is the size of AcdbAmdbProcID. + @param[out] rsp + This is a pointer to AcdbBlob. + @param[in] rsp_size + This is the size of AcdbBlob. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + - AR_ENOTEXIST -- No Proc ID is found. + + @sa + acdb_ioctl + AcdbAmdbProcID +*/ +#define ACDB_CMD_GET_AMDB_REGISTRATION_DATA ACDB_CMD_ID(15) + +/** @} */ /* end_addtogroup ACDB_CMD_GET_AMDB_REGISTRATION_DATA */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA +@{ */ + +/** + Queries AMDB data for one Processor ID to deregister all dynamic custom + modules + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA. + @param[in] cmd + This is a pointer to AcdbAmdbProcID. + @param[in] cmd_size + This is the size of AcdbAmdbProcID. + @param[out] rsp + This is a pointer to AcdbBlob. Blob contains procID, num of modules, moduleID1,... + @param[in] rsp_size + This is the size of AcdbBlob. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + - AR_ENOTEXIST -- No Proc ID is found. + + @sa + acdb_ioctl + AcdbAmdbProcID +*/ +#define ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA ACDB_CMD_ID(16) + +/** @} */ /* end_addtogroup ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_SUBGRAPH_PROCIDS Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_SUBGRAPH_PROCIDS +@{ */ + +/** + Queries all supported proc ids for a given list of subgraphs + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_SUBGRAPH_PROCIDS. + @param[in] cmd + This is a pointer to AcdbCmdGetSubgraphProcIdsReq. + @param[in] cmd_size + This is the size of AcdbCmdGetSubgraphProcIdsReq. + @param[out] rsp + This is a pointer to AcdbCmdGetSubgraphProcIdsRsp. + @param[in] rsp_size + This is the size of AcdbCmdGetSubgraphProcIdsRsp. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + - AR_ENOTEXIST -- No Subgraph ID or Proc ID is found. + + @sa + acdb_ioctl +*/ +#define ACDB_CMD_GET_SUBGRAPH_PROCIDS ACDB_CMD_ID(17) + +/**< Maps the subgraph to a list of processors*/ +typedef struct _acdb_sg_proc_id_map_t AcdbSgProcIdsMap; +#include "acdb_begin_pack.h" +struct _acdb_sg_proc_id_map_t +{ + /**< Subgraph ID*/ + uint32_t sg_id; + /**< Number of Processor*/ + uint32_t num_proc_ids; + /**< Array of Processor IDs*/ + uint32_t proc_ids[0]; +} +#include "acdb_end_pack.h" +; + +/**< Request structure that contains the list of subgraphs to retrieve +processor lists for*/ +typedef struct _acdb_get_subgraph_proc_ids_req_t AcdbCmdGetSubgraphProcIdsReq; +#include "acdb_begin_pack.h" +struct _acdb_get_subgraph_proc_ids_req_t +{ + /**< Number of subgraphs*/ + uint32_t num_sg_ids; + /**< Array of Subgraph IDs*/ + uint32_t *sg_ids; +} +#include "acdb_end_pack.h" +; + +/**< Response structure that contains a list of mappings between subgraphs and +their associated processors*/ +typedef struct _acdb_get_subgraph_proc_ids_rsp_t AcdbCmdGetSubgraphProcIdsRsp; +#include "acdb_begin_pack.h" +struct _acdb_get_subgraph_proc_ids_rsp_t +{ + /**< Number of subgraphs*/ + uint32_t num_sg_ids; + /**< Size of sg_proc_ids array*/ + uint32_t size; + /**< Array of maps that associate a subgraph to a list of processors*/ + AcdbSgProcIdsMap *sg_proc_ids; +} +#include "acdb_end_pack.h" +; +/** @} */ /* end_addtogroup ACDB_CMD_GET_SUBGRAPH_PROCIDS */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES +@{ */ + +/** + Queries all supported proc ids for a given list of subgraphs + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES. + @param[in] cmd + This is a pointer to AcdbAmdbProcID. + @param[in] cmd_size + This is the size of AcdbAmdbProcID. + @param[out] rsp + This is a pointer to AcdbBlob. Blob contains procID, errorCode, Num of modules, moduleID1, lsw_handle1, msw_handle1, moduleID2, lsw_handle2, msw_handle2....(all are uint32_t type) + @param[in] rsp_size + This is the size of AcdbBlob. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + - AR_ENOTEXIST -- Proc ID is found. + + @sa + acdb_ioctl + AcdbAmdbProcID +*/ +#define ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES ACDB_CMD_ID(18) + +/** @} */ /* end_addtogroup ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_TAGS_FROM_GKV Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_TAGS_FROM_GKV +@{ */ + +/** + Query ACDB SW for all the tags(and their associated modules) that are used + within a usecase given the graph key vector + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_TAGS_FROM_GKV. + @param[in] cmd + This is a pointer to AcdbCmdGetTagsFromGkvReq. + @param[in] cmd_size + This is the size of AcdbCmdGetTagsFromGkvReq. + @param[out] rsp + This is a pointer to AcdbCmdGetTagsFromGkvRsp. + @param[in] rsp_size + This is the size of AcdbCmdGetTagsFromGkvRsp. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + - AR_ENOTEXIST - The grah key vector does not exist or there are no tags to return. + + @sa + acdb_ioctl +*/ +#define ACDB_CMD_GET_TAGS_FROM_GKV ACDB_CMD_ID(19) + +/**< Request structure that contains the graph key vector*/ +typedef struct _acdb_cmd_get_tags_from_gkv_req AcdbCmdGetTagsFromGkvReq; +#include "acdb_begin_pack.h" +struct _acdb_cmd_get_tags_from_gkv_req { + /**< Graph Key Vector representing the usecase*/ + AcdbGraphKeyVector *graph_key_vector; +} +#include "acdb_end_pack.h" +; + +/**< Contains a Modules ID and Instance ID*/ +typedef struct _acdb_module AcdbModule; +#include "acdb_begin_pack.h" +struct _acdb_module { + /**< Module ID*/ + uint32_t module_id; + /**< Module Instance ID*/ + uint32_t module_iid; +} +#include "acdb_end_pack.h" +; + +/**< Contains the mapping beween a Tag and one or more module*/ +typedef struct _acdb_tag_module AcdbTagModule; +#include "acdb_begin_pack.h" +struct _acdb_tag_module { + /**< Tag ID associated with the module(s)*/ + uint32_t tag_id; + /**< Number of modules associated with this tag*/ + uint32_t num_modules; + /**< List of modules associated with this tag*/ + AcdbModule modules[0]; +} +#include "acdb_end_pack.h" +; + +/**< Response structure that contains a list of Tag + Module(s) mapping*/ +typedef struct _acdb_cmd_get_tags_from_gkv_rsp AcdbCmdGetTagsFromGkvRsp; +#include "acdb_begin_pack.h" +struct _acdb_cmd_get_tags_from_gkv_rsp { + /**< Number of tags found*/ + uint32_t num_tags; + /**< Size of tag_module_list in bytes*/ + uint32_t list_size; + /**< List of Tags plus their associated module(s)*/ + AcdbTagModule *tag_module_list; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_TAGS_FROM_GKV */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_GRAPH_CAL_KVS Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_GRAPH_CAL_KVS +@{ */ + +/** +* Queries for all SPF module calibration key vectors under a given graph +* key vector. +* +* Example: +* If the ACDB file contains the usecase GKV: +* +* +* and this usecase contains the calibration key Tables: +* +* Volume Step | Sample Rate +* ------------|------------ +* 1 | 8k +* 2 | 8k +* +* Volume Step +* ------------ +* 1 +* 2 +* +* The resulting key vector list will contain: +* CKV [] (default CKV aka zero CKV) +* CKV [] +* CKV [] +* CKV [] +* CKV [] +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_GET_GRAPH_CAL_KVS. +* @param[in] cmd +* This is a pointer to AcdbGraphKeyVector. +* @param[in] cmd_size +* This is the size of AcdbGraphKeyVector. +* @param[out] rsp +* This is a pointer to AcdbKeyVectorList. +* @param[in] rsp_size +* This is the size of AcdbKeyVectorList. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* - AR_ENOTEXIST -- The graph key vector does not exist or no data was found. +* +* @sa +* acdb_ioctl +*/ +#define ACDB_CMD_GET_GRAPH_CAL_KVS ACDB_CMD_ID(20) + +/**< Maintains a list of key vectors */ +typedef struct _acdb_key_vector_list_t AcdbKeyVectorList; +#include "acdb_begin_pack.h" +struct _acdb_key_vector_list_t +{ + /**< Number of key vectors in the key vector list */ + uint32_t num_key_vectors; + /**< Size of the key vector list in bytes */ + uint32_t list_size; + /**< List of Key Vectors in the format of + [#keys, kvPair+,..., #keys, kvPair+] */ + AcdbKeyVector *key_vector_list; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_GRAPH_CAL_KVS */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_SUPPORTED_GKVS Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_SUPPORTED_GKVS +@{ */ + +/** +* Queries for all graph key vectors that contain a subset of the provided +* key ids. A graph key vector supports certain capabiliies if it matches +* the key id subset. If the subset contains zero keys, this api will gather +* all the graph key vectors defined in the ACDBs. +* +* Example: +* If the input keys contain: +* +* +* and the following tables are in the database: +* +* Volume Step | Sample Rate +* ------------|------------ +* 1 | 8k +* 2 | 8k +* +* Volume Step | Sample Rate | Bit Width +* ------------|-------------|----------- +* 1 | 8k | 16 +* 1 | 8k | 32 +* 2 | 16k | 16 +* 2 | 16k | 32 +* +* The resulting key vector list will contain: +* GKV [] +* GKV [] +* GKV [] +* GKV [] +* GKV [] +* GKV [] +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_GET_SUPPORTED_GKVS. +* @param[in] cmd +* This is a pointer to AcdbUintList. +* @param[in] cmd_size +* This is the size of AcdbUintList. +* @param[out] rsp +* This is a pointer to AcdbKeyVectorList. +* @param[in] rsp_size +* This is the size of AcdbKeyVectorList. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* - AR_ENOTEXIST -- No data was found. +* +* @sa +* acdb_ioctl +*/ +#define ACDB_CMD_GET_SUPPORTED_GKVS ACDB_CMD_ID(21) +/** @} */ /* end_addtogroup ACDB_CMD_GET_SUPPORTED_GKVS */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_DRIVER_MODULE_KVS Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_DRIVER_MODULE_KVS +@{ */ + +/** +* Queries for all driver key vectors used by a driver module. +* +* Example: +* If the input keys contain: +* +* +* and the following tables are in the database: +* +* Volume Step | Sample Rate +* ------------|------------ +* 1 | 8k +* +* Volume Step | Sample Rate | Bit Width +* ------------|-------------|----------- +* 1 | 8k | 16 +* 1 | 8k | 32 +* +* The resulting key vector list will contain: +* KV [] +* KV [] +* KV [] +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_GET_DRIVER_MODULE_KVS. +* @param[in] cmd +* This is a pointer to a uint32_t. +* @param[in] cmd_size +* This is the size of a uint32_t. +* @param[out] rsp +* This is a pointer to AcdbKeyVectorList. +* @param[in] rsp_size +* This is the size of AcdbKeyVectorList. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* - AR_ENOTEXIST -- No data was found. +* +* @sa +* acdb_ioctl +*/ +#define ACDB_CMD_GET_DRIVER_MODULE_KVS ACDB_CMD_ID(22) +/** @} */ /* end_addtogroup ACDB_CMD_GET_DRIVER_MODULE_KVS */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_GRAPH_TAG_KVS Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_GRAPH_TAG_KVS +@{ */ + +/** +* Retrieves all Tag and tag key vector variations defined in a usecase +* +* Example: +* Consider the following diagram and table: +* +* + Subgraph 1 + + Subgraph 2 + +* | SGKV(A) | | SGKV(B) | +* |_____________| |_____________| +* | Module 1 |---->| Module 2 | +* | (tag: SV) | | (tag: REI) | +* +-------------+ +-------------+ +* +* Tag | Tag Key Vector +* ________________________|_______________________________________ +* Stream Volume(SV) | Min Range | Max Range | Default Volume +* |_______________________________________ +* | -0dB | 10dB | 0dB +* | -10dB | 20dB | 5dB +* | -20dB | 30dB | 10dB +* ---------------------------------------------------------------- +* Render Endpoint Info | Sample Rate | Bit Width | Num Ch +* (REI) |_______________________________________ +* | 48kHz |16 | 2 +* | 48kHz |24 | 2 +* | 48kHz |32 | 2 +* +* If there were two subgraphs with two tagged modules in the usecase GKV[A,B], +* the output of the API would be: +* +* Stream Volume : [Min Range: -0db][Max Range: 10dB][Default Volume: 0dB] +* Stream Volume : [Min Range: -10db][Max Range: 20dB][Default Volume: 5dB] +* Stream Volume : [Min Range: -20db][Max Range: 30dB][Default Volume: 10dB] +* Render Endpoint Info : [Sample Rate: 48kHz][Bit Width: 16][Num Ch: 2] +* Render Endpoint Info : [Sample Rate: 48kHz][Bit Width: 24][Num Ch: 2] +* Render Endpoint Info : [Sample Rate: 48kHz][Bit Width: 32][Num Ch: 2] +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_GET_GRAPH_TAG_KVS. +* @param[in] cmd +* This is a pointer to AcdbGraphKeyVector. +* @param[in] cmd_size +* This is the size of AcdbGraphKeyVector. +* @param[out] rsp +* This is a pointer to AcdbTagKeyVectorList. +* @param[in] rsp_size +* This is the size of AcdbTagKeyVectorList. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* - AR_ENOTEXIST -- No data was found. +* +* @sa +* acdb_ioctl +*/ +#define ACDB_CMD_GET_GRAPH_TAG_KVS ACDB_CMD_ID(23) + +/**< Maintains a list of key vectors */ +typedef struct _acdb_tag_key_vector_list_t AcdbTagKeyVectorList; +#include "acdb_begin_pack.h" +struct _acdb_tag_key_vector_list_t +{ + /**< Number of tag key vectors in the key vector list */ + uint32_t num_key_vectors; + /**< Size of the tag key vector list in bytes */ + uint32_t list_size; + /**< List of Tag Key Vectors in the format of + [#keys, kvPair+,..., #keys, kvPair+] */ + AcdbTagKeyVector *key_vector_list; +} +#include "acdb_end_pack.h" +; +/** @} */ /* end_addtogroup ACDB_CMD_GET_GRAPH_TAG_KVS */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_CAL_DATA Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_CAL_DATA +@{ */ + +/** +* Retrieves calibration under the specified subgraph and module +* instance. If parameter_list.count = 0, this API will return calibration +* for the entire module. If parameter_list.count > 0, this API will +* return calibration for the specified parameters. +* +* Module instances can be retrieved from that database using +* ACDB_CMD_GET_TAGGED_MODULES or ACDB_CMD_GET_TAGS_FROM_GKV. +* The module instance can be used here to retrieve data. +* +* The output AcdbBlob is in the format of: +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* ... +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_GET_CAL_DATA. +* @param[in] cmd +* This is a pointer to AcdbGetCalDataReq. +* @param[in] cmd_size +* This is the size of AcdbGetCalDataReq. +* @param[out] rsp +* This is a pointer to AcdbBlob. +* @param[in] rsp_size +* This is the size of AcdbBlob. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* - AR_ENOTEXIST -- No data was found. +* - AR_ENEEDMORE -- Need more memory to write response +* +* @sa +* acdb_ioctl +* ACDB_CMD_SET_CAL_DATA +* ACDB_CMD_GET_TAGGED_MODULES +* ACDB_CMD_GET_TAGS_FROM_GKV +* +*/ +#define ACDB_CMD_GET_CAL_DATA ACDB_CMD_ID(24) + +typedef struct _acdb_module_param_list AcdbModuleParamList; +#include "acdb_begin_pack.h" +struct _acdb_module_param_list { + /**< The module instance to get parameter data from */ + uint32_t instance_id; + /**< List of parameters to get data for. The list can be empty.*/ + AcdbUintListZS parameter_list; +} +#include "acdb_end_pack.h" +; + +/**< Request structure for retrieving cal data for modules under a usecase*/ +typedef struct _acdb_get_cal_data_req_t AcdbGetCalDataReq; +#include "acdb_begin_pack.h" +struct _acdb_get_cal_data_req_t { + /**< The graph keys that describe the usecase the modules are under */ + AcdbGraphKeyVector graph_key_vector; + /**< The usecase calibration keys assigned to the modules */ + AcdbGraphKeyVector cal_key_vector; + /**< The number of module instances in the instance_param_list */ + uint32_t num_module_instance; + /**< List of module instances plus their parameters to get data for */ + AcdbModuleParamList* instance_param_list; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_CAL_DATA */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_TAG_DATA Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_TAG_DATA +@{ */ + +/** +* Retrieves tag under the specified subgraph and module instance. +* If parameter_list.count = 0, this API will return tag data +* for the entire module. If parameter_list.count > 0, this API will +* return calibration for the specified parameters. +* +* Module instances can be retrieved from that database using +* ACDB_CMD_GET_TAGGED_MODULES or ACDB_CMD_GET_TAGS_FROM_GKV. +* The module instance can be used here to retrieve data. +* +* The output AcdbBlob is in the format of: +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* ... +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_GET_TAG_DATA. +* @param[in] cmd +* This is a pointer to AcdbGetTagDataReq. +* @param[in] cmd_size +* This is the size of AcdbGetTagDataReq. +* @param[out] rsp +* This is a pointer to AcdbBlob. +* @param[in] rsp_size +* This is the size of AcdbBlob. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* - AR_ENOTEXIST -- No data was found. +* - AR_ENEEDMORE -- Need more memory to write response +* +* @sa +* acdb_ioctl +* ACDB_CMD_SET_TAG_DATA +* +*/ +#define ACDB_CMD_GET_TAG_DATA ACDB_CMD_ID(25) + +/**< Request structure for retrieving tag data for multiple +module instance with the same tag */ +typedef struct _acdb_get_tag_data_req_t AcdbGetTagDataReq; +#include "acdb_begin_pack.h" +struct _acdb_get_tag_data_req_t { + /**< The graph keys that describe the usecase the modules are under */ + AcdbGraphKeyVector graph_key_vector; + /**< The module tag for the all the module in the module/param list */ + AcdbModuleTag module_tag; + /**< The number of module instances in the instance_param_list */ + uint32_t num_module_instance; + /**< List of module instances plus their parameters to get data for */ + AcdbModuleParamList* instance_param_list; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_TAG_DATA */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_SET_TAG_DATA Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_SET_TAG_DATA +@{ */ + +/** +* Sets tag data to the AML heap and persist to delta file +* +* The input blob is in the format of: +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* ... +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_SET_TAG_DATA. +* @param[in] cmd +* This is a pointer to AcdbGetTagDataReq. +* @param[in] cmd_size +* This is the size of AcdbGetTagDataReq. +* @param[out] rsp +* There is no output structure; set this to NULL. +* @param[in] rsp_size +* There is no output structure; set this to 0. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* +* @sa +* acdb_ioctl +* ACDB_CMD_GET_TAG_DATA +* ACDB_CMD_ENABLE_PERSISTANCE +* +*/ +#define ACDB_CMD_SET_TAG_DATA ACDB_CMD_ID(26) + +/* Request structure for setting tag data to the AML heap and delta file */ +typedef struct _acdb_set_tag_data_t AcdbSetTagDataReq; +#include "acdb_begin_pack.h" +struct _acdb_set_tag_data_t { + /**< The graph keys that describe the usecase the modules are under */ + AcdbGraphKeyVector graph_key_vector; + /**< The tag + take key vector for the modules in the blob */ + AcdbModuleTag module_tag; + /**< Size of the tag data blob */ + uint32_t blob_size; + /**< Pointer to blob containing tag data */ + void* blob; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_SET_TAG_DATA */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_SET_TEMP_PATH Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_SET_TEMP_PATH +@{ */ + +/** +* Updates the read/write temporary path that AML uses for the reinit/delta +* persistence functionality. +* This function also updates the delta file manager to use the read/write +* delta file if it exists in the read/write path provided. +* The delta data from the read/write path will be merged on top of the +* delta data that is provided during acdb_init(...). +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_SET_TEMP_PATH. +* @param[in] cmd +* This is a pointer to AcdbSetTempPathReq. +* @param[in] cmd_size +* This is the size of AcdbSetTempPathReq. +* @param[out] rsp +* There is no output structure; set this to NULL. +* @param[in] rsp_size +* There is no output structure; set this to 0. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* +* @sa +* acdb_ioctl +* +*/ +#define ACDB_CMD_SET_TEMP_PATH ACDB_CMD_ID(27) + +/**< Request structure for setting the writeable path */ +typedef struct _acdb_set_temp_path_req_t AcdbSetTempPathReq; +#include "acdb_begin_pack.h" +struct _acdb_set_temp_path_req_t { + /**< The length of the path including the null terminating character */ + uint32_t path_length; + /**< The path string including the null terminating character */ + char_t path[MAX_FILENAME_LENGTH]; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_SET_TEMP_PATH */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_HW_ACCEL_SUBGRAPH_INFO Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_HW_ACCEL_SUBGRAPH_INFO +@{ */ + +/** +* Sets tag data to the AML heap and persist to delta file +* +* The input blob is in the format of: +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* ... +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_GET_HW_ACCEL_SUBGRAPH_INFO. +* @param[in] cmd +* This is a pointer to AcdbGetTagDataReq. +* @param[in] cmd_size +* This is the size of AcdbGetTagDataReq. +* @param[out] rsp +* There is no output structure; set this to NULL. +* @param[in] rsp_size +* There is no output structure; set this to 0. +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* +* @sa +* acdb_ioctl +* ACDB_CMD_GET_TAG_DATA +* ACDB_CMD_ENABLE_PERSISTANCE +* +*/ +#define ACDB_CMD_GET_HW_ACCEL_SUBGRAPH_INFO ACDB_CMD_ID(28) + +/**< An enumeration of memory types for hardware acceleration. */ +typedef enum _acdb_hw_accel_mem_type_t +{ + ACDB_HW_ACCEL_MEM_DEFAULT, + ACDB_HW_ACCEL_MEM_CMA, + ACDB_HW_ACCEL_MEM_BOTH, +}AcdbHwAccelMemType; + +/**< Request structure for retrieving hw accelerator info for subgraphs. */ +typedef struct _acdb_hw_accel_subgraphs_info_req_t AcdbHwAccelSubgraphInfoReq; +#include "acdb_begin_pack.h" +struct _acdb_hw_accel_subgraphs_info_req_t { + /**< List of Subgraph IDs */ + AcdbUintList subgraph_list; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_hw_accel_subgraph_t AcdbHwAccelSubgraph; +#include "acdb_begin_pack.h" +struct _acdb_hw_accel_subgraph_t { + /**< Subgraph ID*/ + uint32_t subgraph_id; + /**< The type of memory used by the calibration in the subgraph */ + AcdbHwAccelMemType mem_type; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_hw_accel_subgraph_info_rsp_t AcdbHwAccelSubgraphInfoRsp; +#include "acdb_begin_pack.h" +struct _acdb_hw_accel_subgraph_info_rsp_t { + /**< Number of Subgraphs*/ + uint32_t num_subgraphs; + /**< Size of the subgraph list in bytes */ + uint32_t list_size; + /**< Subgraph IDs*/ + AcdbHwAccelSubgraph* subgraph_list; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_HW_ACCEL_SUBGRAPH_INFO */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_PROC_SUBGRAPH_CAL_DATA_PERSIST Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_PROC_SUBGRAPH_CAL_DATA_PERSIST +@{ */ + +/** +* Retrieves subgraph calibration data for persistent parameters under a +* given processor. +* +* The output blob is in the format of: +* +* +----------------------------------------------------------+ +* | Subgraph #1 | +* +----------------------------------------------------------+ +* | Subgraph ID | Persist Data Size | +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* ... +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* ... +* +----------------------------------------------------------+ +* | Subgraph #N | +* +----------------------------------------------------------+ +* | Subgraph ID | Persist Data Size | +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* ... +* +-------------+----------+------+------------+-------------+ +* | Instance ID | Param ID | Size | Error Code | Data[Size] | +* +-------------+----------+------+------------+-------------+ +* +* @param[in] cmd_id +* Command ID is ACDB_CMD_GET_PROC_SUBGRAPH_CAL_DATA_PERSIST +* @param[in] cmd +* This is a pointer to AcdbProcSubgraphPersistCalReq +* @param[in] cmd_size +* This is the size of AcdbProcSubgraphPersistCalReq +* @param[out] rsp +* This is a pointer to AcdbSgIdsPersistCalData +* @param[in] rsp_size +* This is the size of AcdbSgIdsPersistCalData +* +* @return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* +* @sa +* acdb_ioctl +* ACDB_CMD_GET_SUBGRAPH_CALIBRATION_DATA_PERSIST +* ACDB_CMD_GET_HW_ACCEL_SUBGRAPH_INFO +* +*/ +#define ACDB_CMD_GET_PROC_SUBGRAPH_CAL_DATA_PERSIST ACDB_CMD_ID(29) + +/**< Applies the memory type to the Proc ID. The upper two bits of the +Proc ID represent memory types that AML will use to filter calibration. +The memory types are: System Heap(0x0), Physically Contiguous Memory (0x01) +*/ +#define ACDB_HW_ACCEL_MEM_TYPE_MASK(proc_id, mem_type) (proc_id + (mem_type << 30)) + +/**< Extracts the hardware acceleration memory type from the +processor domain ID */ +#define ACDB_HW_ACCEL_MEM_TYPE(proc_id) ((AcdbHwAccelMemType)(proc_id >> 30)) + +/**< Extracts proc id from processor domain ID */ +#define ACDB_HW_ACCEL_PROC_ID(proc_id) (proc_id & 0x3FFFFFFF) + +typedef struct _acdb_subgraph_proc_pair_t AcdbSubgraphProcPair; +struct _acdb_subgraph_proc_pair_t +{ + /**< The ID of the subgraph to get calibration for*/ + uint32_t subgraph_id; + /**< The processor to get calibration for. The most significan 2 bits + * indicates whether to retrieve Default/CMA/Both calibration, + * the remaining bytes describe the Proc ID */ + uint32_t proc_id; +}; + +/**< Request structure for retrieving persistent calibration based on processor */ +typedef struct _acdb_proc_subgraph_persist_cal_req_t AcdbProcSubgraphPersistCalReq; +#include "acdb_begin_pack.h" +struct _acdb_proc_subgraph_persist_cal_req_t +{ + /**< Number of subgraphs */ + uint32_t num_subgraphs; + /**< List of Subgraph and Proc IDs */ + AcdbSubgraphProcPair *subgraph_list; + /**< Calibration Key vector prior */ + AcdbGraphKeyVector cal_key_vector_prior; + /**< Calibration Key vector new */ + AcdbGraphKeyVector cal_key_vector_new; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_PROC_SUBGRAPH_CAL_DATA_PERSIST */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_AMDB_REGISTRATION_DATA_V2 Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ACDB_CMD_GET_AMDB_REGISTRATION_DATA_V2 +\{ */ + +/** + * Retrieves AMDB registration data for all dynamic custom modules using + * the acdb_handle_t returned from acdb_add_database(...) or + * acdb_get_handle(...) + * + * Output Blob Format: + * + * @param[in] cmd_id + * Command ID is ACDB_CMD_GET_AMDB_REGISTRATION_DATA_V2. + * @param[in] cmd + * This is a pointer to AcdbAmdbDbHandle. + * @param[in] cmd_size + * This is the size of AcdbAmdbDbHandle. + * @param[out] rsp + * This is a pointer to AcdbBlob. + * @param[in] rsp_size + * This is the size of AcdbBlob. + * + * @return + * - AR_EOK -- Command executed successfully. + * - AR_EBADPARAM -- Invalid input parameters were provided. + * - AR_EFAILED -- Command execution failed. + * - AR_ENOTEXIST -- No Proc ID is found. + * @sa + * acdb_ioctl + * AcdbAmdbProcID + */ +#define ACDB_CMD_GET_AMDB_REGISTRATION_DATA_V2 ACDB_CMD_ID(30) + + /** @} */ /* end_addtogroup ACDB_CMD_GET_AMDB_REGISTRATION_DATA_V2*/ + + /* --------------------------------------------------------------------------- + * ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA_V2 Declarations and Documentation + *-------------------------------------------------------------------------- */ + /** @addtogroup ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA_V2 + @{ */ + + /** + * Retrieves AMDB deregistration data for all dynamic custom modules using + * the acdb_handle_t returned from acdb_add_database(...) or + * acdb_get_handle(...) + * + * Output Blob Format: + * + * @param[in] cmd_id + * Command ID is ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA_V2. + * @param[in] cmd + * This is a pointer to AcdbAmdbDbHandle. + * @param[in] cmd_size + * This is the size of AcdbAmdbDbHandle. + * @param[out] rsp + * This is a pointer to AcdbBlob. + * @param[in] rsp_size + * This is the size of AcdbBlob. + * + * @return + * - AR_EOK -- Command executed successfully. + * - AR_EBADPARAM -- Invalid input parameters were provided. + * - AR_EFAILED -- Command execution failed. + * - AR_ENOTEXIST -- No Proc ID is found. + * @sa + * acdb_ioctl + * AcdbAmdbProcID + */ +#define ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA_V2 ACDB_CMD_ID(31) + + /** @} */ /* end_addtogroup ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA_V2*/ + + /* --------------------------------------------------------------------------- + * ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES_V2 Declarations and Documentation + *-------------------------------------------------------------------------- */ + /** @addtogroup ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES_V2 + @{ */ + + /** + * Retrieves AMDB bootup data for all custom modules using the acdb_handle_t + * returned from acdb_add_database(...) or acdb_get_handle(...) + * + * Output Blob Format: + * + * +------------------+ + * | proc domain id | + * +------------------+ + * | error code | + * +------------------+ + * | module count | + * +------------------+ + * | MODULE #1 | + * |~~~~~~~~~~~~~~~~~~| + * | msw handle | + * | ---------- | + * | lsw handle | + * +------------------+ + * | .... | + * +------------------+ + * + * @param[in] cmd_id + * Command ID is ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES_V2. + * @param[in] cmd + * This is a pointer to AcdbAmdbDbHandle. + * @param[in] cmd_size + * This is the size of AcdbAmdbDbHandle. + * @param[out] rsp + * This is a pointer to AcdbBlob. + * @param[in] rsp_size + * This is the size of AcdbBlob. + * + * @return + * - AR_EOK -- Command executed successfully. + * - AR_EBADPARAM -- Invalid input parameters were provided. + * - AR_EFAILED -- Command execution failed. + * - AR_ENOTEXIST -- No Proc ID is found. + * @sa + * acdb_ioctl + * AcdbAmdbProcID + */ +#define ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES_V2 ACDB_CMD_ID(32) + + /** @} */ /* end_addtogroup ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES_V2*/ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_GRAPH_ALIAS Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ACDB_CMD_GET_GRAPH_ALIAS +\{ */ + +/** + Retrieves an alias of the graph key vector. The alias includes the the + usecase ID followed by a human readable graph key vector with names + for keys and values. The string length is limited to 255 bytes. + + Example + Usecase ID with GKV: "100 [Device: Speaker] [Instance: 1]" + Just Usecase ID: "100" + + \param[in] cmd_id + Command ID is ACDB_CMD_GET_GRAPH_ALIAS. + \param[in] cmd + There is a pointer to AcdbGraphKeyVector + \param[in] cmd_size + There is the size of AcdbGraphKeyVector + \param[out] rsp + This is a pointer to AcdbString + \param[in] rsp_size + This is the size of AcdbString + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + - AR_ENOTEXIST -- Graph Key Vector not found + - AR_ENOMEMORY -- Not enough memory to write the alias string + \sa + acdb_ioctl +*/ +#define ACDB_CMD_GET_GRAPH_ALIAS ACDB_CMD_ID(33) + +typedef struct _acdb_string_t AcdbString; +#include "acdb_begin_pack.h" +struct _acdb_string_t +{ + /**< The length of the string including the null terminating character */ + uint32_t length; + /**< A pointer to the string */ + char_t* string; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_GRAPH_ALIAS */ + +/* --------------------------------------------------------------------------- +* ACDB_CMD_GET_PROC_TAGGED_MODULES Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** @addtogroup ACDB_CMD_GET_PROC_TAGGED_MODULES + +@{ */ + +/** + Retrieves a list of tagged modules orderd by processor domain ID. + + @param[in] cmd_id + Command ID is ACDB_CMD_GET_PROC_TAGGED_MODULES. + @param[in] cmd + This is a pointer to AcdbGetProcTaggedModulesReq. + @param[in] cmd_size + This is the size of AcdbGetProcTaggedModulesReq. + @param[out] rsp + This is a pointer to AcdbGetProcTaggedModulesRsp. + @param[in] rsp_size + This is the size of AcdbGetProcTaggedModulesRsp. + + @return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + @sa + acdb_ioctl + */ +#define ACDB_CMD_GET_PROC_TAGGED_MODULES ACDB_CMD_ID(34) + +/**< Request structure for getting modules tagged with tag_id under the specified subgraphs */ +typedef struct _acdb_get_proc_tagged_modules_req_t AcdbGetProcTaggedModulesReq; +#include "acdb_begin_pack.h" +struct _acdb_get_proc_tagged_modules_req_t { + /**< Number of Subgraphs*/ + uint32_t num_sg_ids; + /**< Subgraph ID list*/ + uint32_t* sg_ids; + /**< The tag to search for */ + uint32_t tag_id; +} +#include "acdb_end_pack.h" +; + +/**< Maps tagged modules to a processor domain */ +typedef struct _acdb_proc_tagged_modules_t AcdbProcTaggedModules; +#include "acdb_begin_pack.h" +struct _acdb_proc_tagged_modules_t { + uint32_t proc_domain_id; + /**< Number of tagged modules*/ + uint32_t num_tagged_mids; + /**< Pointer to array of tagged modules*/ + AcdbModuleInstance tagged_mid_list[0]; +} +#include "acdb_end_pack.h" +; + +/**< Response struture containing a mapping of tagged modules to processor domain ID */ +typedef struct _acdb_get_proc_tagged_modules_rsp_t AcdbGetProcTaggedModulesRsp; +#include "acdb_begin_pack.h" +struct _acdb_get_proc_tagged_modules_rsp_t { + /**< Number of tagged modules*/ + uint32_t num_procs; + /**< size of the proc_tagged_module_list */ + uint32_t list_size; + /**< A pointer to contiguous block of memory + containing tagged module ID and IID ordered by processor domain */ + AcdbProcTaggedModules *proc_tagged_module_list; +} +#include "acdb_end_pack.h" +; + +/** @} */ /* end_addtogroup ACDB_CMD_GET_PROC_TAGGED_MODULES */ + +/* --------------------------------------------------------------------------- +* Public Function API Definitions and Documentation +*-------------------------------------------------------------------------- */ + +/** @addtogroup PUBLIC_API +@param[in] AcdbDataFiles structure for holding ACDB DATA files +@return An ACDB Status Code +*/ +int32_t acdb_init(AcdbDataFiles* acdb_data_files, AcdbFile* delta_file_path); + +/** @addtogroup PUBLIC_API +@param[in] uint32 acdbdata_base_addr Base address for ACDB DATA +@return An ACDB Status Code +*/ +int32_t acdb_flash_init(uint32_t* acdbdata_base_addr); + +/** @addtogroup PUBLIC_API +*/ +int32_t acdb_deinit(void); + +/** @addtogroup PUBLIC_API +*/ +int32_t acdbCmdIsPersistenceSupported(uint32_t *resp); + +/** +* \brief +* Extends the database by adding database files (*.acdb and *.qwsp) at runtime. +* \param[in] acdb_data_files: A list of database file paths containing *.acdb and *.qwsp +* \param[in] writable_file_path: The delta data file path and temp files +* \param[in/out] acdb_handle: A handle to the database provided +* \return 0 on success, non-zero on failure +*/ +int32_t acdb_add_database(AcdbDatabaseFiles* acdb_files, + AcdbFile* writable_file_path, acdb_handle_t* acdb_handle); + +/** +* \brief +* Shrinks the database by removing all data associated with the given +* database handle at runtime. This includes database files (*.qwsp or *.acdb) and heap data +* \param[in] acdb_handle: A handle to the database to remove +* \return 0 on success, non-zero on failure +*/ +int32_t acdb_remove_database(const acdb_handle_t* acdb_handle); + +/** +* \brief +* Retrieves a handle associated with the given acdb file which can be used +* in APIs to retrieve information from a database. +* \param[in] acdb_file: The file to get the handle for +* \param[in/out] acdb_handle: The acdb hande for the given file +* \return 0 on success, non-zero on failure +*/ +int32_t acdb_get_handle(AcdbFile* acdb_file, acdb_handle_t* acdb_handle); + +/** @ingroup ACDB_IOCTL + + Main entry function to the ACDB. This entry function takes any + supported ACDB IOCTL and provides the appropriate response. + + See the individual command documentation for more details on the + expectations of the command. + + @param[in] cmd_id + Command ID to execute on the Audio Calibration Database. The + cmd and the rsp must match the expected + structures for that command. If not, the command fails. + @param[in] cmd + Pointer to the command structure. + @param[in] cmd_size + Size of the command structure. + @param[out] rsp + Pointer to the response structure. + @param[in] rsp_size + Size of the response structure. + + @return + The result of the call as defined by the command. + + @dependencies + None + +*/ +int32_t acdb_ioctl(uint32_t cmd_id, + const void *cmd_struct, uint32_t cmd_struct_size, + void *rsp_struct, uint32_t rsp_struct_size); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + + +#endif /* __ACDB_API_H__ */ + + + diff --git a/acdb/api/acdb_begin_pack.h b/acdb/api/acdb_begin_pack.h new file mode 100644 index 0000000..79d6700 --- /dev/null +++ b/acdb/api/acdb_begin_pack.h @@ -0,0 +1,40 @@ +/** +*============================================================================= +* \file acdb_begin_pack.h +* +* \brief +* This file defines pack attributes for different compilers to be used to +* pack ACPH API data structures. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/** @addtogroup acph_api_pack +@{ */ + +#if defined( __qdsp6__ ) +/* No packing atrributes for Q6 compiler; all structs manually packed */ +#elif defined( __GNUC__ ) && !defined( __INTEGRITY ) +#elif defined( __INTEGRITY ) +#elif defined( ACDB_WP_PACK ) +#pragma warning( disable:4103 ) /* Another header changing "pack". */ +#pragma pack( push, 1 ) +#pragma warning(push) +#pragma warning(disable: 4200) +#elif defined( __arm__ ) +#elif defined( _MSC_VER ) && !defined(_KERNEL_MODE) +#pragma warning( disable:4103 ) /* Another header changing "pack". */ +#pragma pack( push, 1 ) +#pragma warning(push) +#pragma warning(disable: 4200) +#elif defined(_KERNEL_MODE) +#pragma warning(disable: 4200) +#else +#error "Unsupported compiler." +#endif /* __GNUC__ */ + +/** @} */ /* end_addtogroup acph_api_pack */ diff --git a/acdb/api/acdb_end_pack.h b/acdb/api/acdb_end_pack.h new file mode 100644 index 0000000..d321c61 --- /dev/null +++ b/acdb/api/acdb_end_pack.h @@ -0,0 +1,38 @@ +/** +*============================================================================= +* \file acdb_end_pack.h +* +* \brief +* This file defines pack attributes for different compilers to be used to +* pack aDSP API data structures. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/** @addtogroup acph_api_pack +@{ */ + +#if defined( __qdsp6__ ) +/* No packing atrributes for Q6 compiler; all structs manually packed */ +#elif defined( __GNUC__ ) && !defined( __INTEGRITY ) +#ifndef ARSDK +__attribute__((packed, aligned(1))); +#endif +#elif defined( __INTEGRITY ) +#elif defined( ACDB_WP_PACK ) +#pragma pack( pop ) +#pragma warning(pop) +#elif defined( __arm__ ) +#elif defined( _MSC_VER ) && !defined(_KERNEL_MODE) +#pragma pack( pop ) +#pragma warning(pop) +#elif defined(_KERNEL_MODE) +#else +#error "Unsupported compiler." +#endif /* __GNUC__ */ + +/** @} */ /* end_ addtogroup acph_api_pack */ diff --git a/acdb/ats/Makefile.am b/acdb/ats/Makefile.am new file mode 100644 index 0000000..89a1222 --- /dev/null +++ b/acdb/ats/Makefile.am @@ -0,0 +1,131 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = ats.pc +EXTRA_DIST = $(pkgconfig_DATA) + +ACLOCAL_AMFLAGS = -I m4 +AM_CFLAGS = -Wall \ + -Wundef \ + -O2 +AM_CFLAGS += @GLIB_CFLAGS@ -include glib.h + +if USE_G_STR_FUNC +AM_CFLAGS += -Dstrlcpy=g_strlcpy -Dstrlcat=g_strlcat +endif + +AM_CFLAGS += -I$(top_srcdir)/ar_osal/api \ + -I$(top_srcdir)/acdb/api \ + -I$(top_srcdir)/acdb/inc \ + -I$(top_srcdir)/gsl/api \ + -I$(top_srcdir)/gsl/rtc_api \ + -I$(top_srcdir)/gsl/dls_client_api + + +AM_CFLAGS += -I ${srcdir}/inc \ + -I ${srcdir}/api \ + -I ${srcdir}/transports/diag/linux/actp/inc \ + -I ${srcdir}/transports/diag/linux/audtp/inc \ + -I ${srcdir}/online/common/inc \ + -I ${srcdir}/rtc/common/inc \ + -I ${srcdir}/fts/common/inc \ + -I ${srcdir}/mcs/common/inc \ + -I ${srcdir}/mcs/common/api \ + -I ${srcdir}/adie/common/inc \ + -I ${srcdir}/adie/common/api \ + -I ${srcdir}/sockets/common/api/ \ + -I ${srcdir}/transports/common/api/ \ + -I ${srcdir}/transports/common/inc/ \ + -I ${srcdir}/transports/tcpip_server/inc/ \ + -I ${srcdir}/transports/tcpip_server/api/ \ + -I ${srcdir}/dls/common/inc + +AM_CPPFLAGS = $(AM_CFLAGS) + +ats_headers = ./api/ats.h + +ats_c_sources = ./src/ats.c \ + ./src/ats_command.c \ + ./adie/common/src/ats_adie_rtc.c \ + ./adie/linux/adie_rtc.c \ + ./transports/diag/linux/actp/src/actp.c \ + ./transports/diag/linux/audtp/src/audtp.c \ + ./fts/common/src/ats_fts.c \ + ./mcs/common/src/ats_mcs.c \ + ./mcs/linux/mcs.c \ + ./online/common/src/ats_online.c \ + ./rtc/common/src/ats_rtc.c \ + ./sockets/linux/src/ar_sockets.cpp \ + ./transports/common/src/ats_transport.c \ + ./transports/tcpip_server/src/tcpip_cmd_server.cpp \ + ./transports/tcpip_server/src/tcpip_dls_server.cpp \ + ./transports/tcpip_server/src/tcpip_socket_util.cpp \ + ./dls/common/src/ats_dls.c + +#Includes +lib_includedir = $(includedir) +lib_include_HEADERS = $(ats_headers) +requiredlibs = -lrt + +lib_LTLIBRARIES = libar-ats.la +libar_ats_la_CC = @CC@ +libar_ats_la_LIBADD = -lar-osal -L$(top_builddir)/ar_osal +libar_ats_la_LIBADD += -lar-acdb -L$(top_builddir)/acdb +if CUTILS_SUPPORTED +libar_ats_la_LIBADD += -lcutils +AM_CFLAGS += -DAR_ATS_USE_CUTILS +endif + +if USE_DUMMY_DIAG +AM_CFLAGS += -DATS_USES_DUMMY_DIAG \ + -I ${srcdir}/transports/diag/linux/inc +else +AM_CFLAGS += @DIAG_CFLAGS@ +AM_CPPFLAGS += -DFEATURE_LE_DIAG +requiredlibs += @DIAG_LIBS@ +libar_ats_la_LIBADD += @DIAG_LIBS@ +endif + +libar_ats_la_SOURCES = $(ats_c_sources) +libar_ats_la_CFLAGS = $(AM_CFLAGS) +libar_ats_la_CPPFLAGS = $(AM_CPPFLAGS) +if USES_ATS_TRANSPORT_TCPIP +libar_ats_la_CFLAGS += -DATS_TRANSPORT_TCPIP +libar_ats_la_CPPFLAGS += -DATS_TRANSPORT_TCPIP +endif + +if USES_ATS_DATA_LOGGING +libar_ats_la_CFLAGS += -DATS_DATA_LOGGING +libar_ats_la_CPPFLAGS += -DATS_DATA_LOGGING +endif + +libar_ats_la_LDFLAGS = -shared -version-number @LT_VERSION_NUMBER@ + +AM_CPPFLAGS += -DSOCK_PATH='"/usr/bin/gateway/ats_sockets"' \ + -DSOCK_PATH_SERVER='"/usr/bin/gateway/ats_sockets/unix_sock.server"' \ + -DSOCK_PATH_GATEWAY='"/usr/bin/gateway/ats_sockets/unix_sock.gateway"' + +AM_CPPFLAGS += -I$(srcdir)/transports/tcpip_gateway/inc +AM_CPPFLAGS += -I$(top_srcdir)/ar_osal/api +AM_CPPFLAGS += -I$(top_srcdir)/acdb/ats/sockets/common/api/ + +AM_CPPFLAGS += @GLIB_CFLAGS@ -include glib.h + +if USE_G_STR_FUNC +AM_CPPFLAGS += -Dstrlcpy=g_strlcpy -Dstrlcat=g_strlcat +endif + +gateway_sources = ./transports/tcpip_gateway/src/tcpip_gateway_main.cpp \ + ./transports/tcpip_gateway/src/tcpip_gateway_cmd_server.cpp \ + ./transports/tcpip_gateway/src/tcpip_gateway_dls_server.cpp \ + ./transports/tcpip_gateway/src/tcpip_gateway_socket_util.cpp \ + ./sockets/linux/src/ar_sockets.cpp + +bin_PROGRAMS = ats_gateway +ats_gateway_CC = @CC@ +ats_gateway_SOURCES = $(gateway_sources) +ats_gateway_LDADD = $(top_builddir)/ar_osal/libar-osal.la +ats_gateway_CPPFLAGS = $(AM_CPPFLAGS) + +if USES_ATS_DATA_LOGGING +ats_gateway_CFLAGS = -DATS_DATA_LOGGING +ats_gateway_CPPFLAGS += -DATS_DATA_LOGGING +endif diff --git a/acdb/ats/adie/common/api/adie_rtc_api.h b/acdb/ats/adie/common/api/adie_rtc_api.h new file mode 100644 index 0000000..f2a9598 --- /dev/null +++ b/acdb/ats/adie/common/api/adie_rtc_api.h @@ -0,0 +1,238 @@ +/** +*============================================================================== +* \file adie_rtc_api.h +* \brief +* A D I E R T C A P I H E A D E R F I L E +* +* This header defines the APIs nessesary to operate on codec registers. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ + +#ifndef ADIE_RTC_API_H +#define ADIE_RTC_API_H + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum adie_rtc_api_major_version_t +{ + ADIE_RTC_API_MAJOR_VERSION_1 = 0x1, +}adie_rtc_api_major_version_t; + +typedef enum adie_rtc_api_minor_version_t +{ + /**< Initial version */ + ADIE_RTC_API_MINOR_VERSION_0 = 0x0, + /**< Introduces bug fixes */ + ADIE_RTC_API_MINOR_VERSION_1 = 0x1, + /**< + * Update to adie_rtc_codec_handle_v2 to include codec revison number + * Update to adie_rtc_codec_info_v2 to include structure version + * Added adie_rtc_get_codec_info_v2 api + */ + ADIE_RTC_API_MINOR_VERSION_2 = 0x2, +}adie_rtc_api_minor_version_t; + +typedef enum adie_chipset_id_t +{ + MSM8X52 = 1, + WCD9335 = 2, + WSA881X_ANALOG = 3, + WSA881X_SOUNDWIRE = 4, + WSA881X = 5, + MSM8909 = 6, + WCD9330 = 7, + WCD9326 = 8, + WCD9320 = 9, + WCD9310 = 10, + WCD9306 = 11, + WCD9302 = 12, + MSM8X16 = 13, + MSM8X10 = 14, + RESERVED_1 = 15, + WCD9340 = 16, + WCD9341 = 17, + RESERVED_2 = 18, + RESERVED_3 = 19, + RESERVED_4 = 20, + WHS9410 = 21, + WHS9420 = 22, + RESERVED_5 = 23, + WCD9360 = 24, + AQT1000 = 25, + BOLERO = 26, + WCD937X = 27, //Tanguu + WCD938X = 28, //Traverso + ROULER = 29, + WSA883X = 30, + WSA884X = 31, + SLATE = 32, + BESBEV = 33, + WCD939X = 34, + WCD9378 = 35, + CODEC_UNDEFINED = ((uint16_t)-1) +}adie_chipset_id_t; + +struct adie_rtc_codec_handle { + uint32_t handle; + uint32_t chipset_id; + uint32_t chipset_major_version; + uint32_t chipset_minor_version; +}; + +#define CODEC_INFO_STRUCT_VERSION_V2 2 + +struct adie_rtc_codec_handle_v2 { + uint32_t handle; + uint32_t chipset_id; + uint32_t chipset_major_version; + uint32_t chipset_minor_version; + uint32_t chipset_revision; +}; + +struct adie_rtc_codec_info { + uint32_t num_of_entries; /**< number of codec entries */ + struct adie_rtc_codec_handle handle[0]; /**< codec entry list (in-band). */ + +}; + +struct adie_rtc_codec_info_v2 { + uint32_t version; + uint32_t num_of_entries; /**< number of codec entries */ + uint8_t handle[0]; /**< codec entry list (in-band). */ + +}; + +struct adie_rtc_register { + uint32_t register_id; + uint32_t register_mask; + uint32_t value; + /**< value is output in get_register and acts as input in set_register */ +}; + + +struct adie_rtc_register_req { + uint32_t codec_handle; /**< The codec handle */ + struct adie_rtc_register reg; /**< The codec register */ +}; + +struct adie_rtc_multi_register_req { + uint32_t codec_handle; /**< The codec to set registers for */ + uint32_t num_registers; /**< the number of registers being set */ + struct adie_rtc_register + register_list[0]; /**< the list of registers to set */ +}; + +struct adie_rtc_version +{ + /**< Major version for changes that break backward compatibility */ + uint32_t major; + /**< Major version for changes that do not break backward compatibility */ + uint32_t minor; +}; + +/** +* \brief +* Initializes the platforms ADIE RTC layer +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_init(void); + +/** +* \brief +* Deinitializes the platforms ADIE RTC layer +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_deinit(void); + +/** +* \brief +* Retrieves the ADIE RTC version being used. The version can be specified +* using the enumations defined in adie_api_major_version_t and +* adie_api_minor_version_t +* +* \params[in/out] api_version: The api version used by the platform +* +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_get_api_version(struct adie_rtc_version *api_version); + +/** +* \brief +* Retreives codec information for the list of chipset(s) specified +* in the adie_rtc_codec_info::handle array. +* +* \params[in/out] codec_info: The chipsets to get information for +* \params[in] size: The size of the info structure in bytes +* +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_get_codec_info(struct adie_rtc_codec_info *codec_info, uint32_t size); + +/** +* \brief +* Retreives codec information for the list of chipset(s) specified +* in the adie_rtc_codec_info_v2::handle array. +* +* \params[in/out] codec_info: The chipsets to get information for +* \params[in] size: The size of the info structure in bytes +* +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_get_codec_info_v2(struct adie_rtc_codec_info_v2 *codec_info, uint32_t size); + +/** +* \brief +* Get data for a register from the specified codec. +* +* \params[in/out] req: The register to get data for +* +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_get_register(struct adie_rtc_register_req *req); + +/** +* \brief +* Set data to a register for the specified codec. +* +* \params[in/out] req: The register to set data to +* +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_set_register(struct adie_rtc_register_req *req); + +/** +* \brief +* Get data for multiple registers from the specified codec. +* +* \params[in/out] req: The registers to get data for +* \params[in] size: The size of the request structure in bytes +* +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_set_multiple_registers(struct adie_rtc_multi_register_req *req, uint32_t size); + +/** +* \brief +* Set data to multiple registers for the specified codec. +* +* \params[in/out] req: The registers to set data for +* \params[in] size: The size of the request structure in bytes +* +* \return 0 on success, non-zero otherwise +*/ +int32_t adie_rtc_get_multiple_registers(struct adie_rtc_multi_register_req *req, uint32_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* ADIE_RTC_API_H */ + diff --git a/acdb/ats/adie/common/inc/ats_adie_rtc.h b/acdb/ats/adie/common/inc/ats_adie_rtc.h new file mode 100644 index 0000000..73ef0e3 --- /dev/null +++ b/acdb/ats/adie/common/inc/ats_adie_rtc.h @@ -0,0 +1,74 @@ +#ifndef _ATS_ADIE_RTC_H_ +#define _ATS_ADIE_RTC_H_ +/** +*============================================================================== +* \file ats_adie-rtc.h +* \brief +* A T S A D I E R T C H E A D E R F I L E +* +* The ADIE(Codec) RTC Service(ARTC) header file contains all the +* definitions necessary for ATS to handle requests that operate on +* codec registers. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ +#include "ats.h" +#include "acdb.h" + +/*----------------------------------------------------------------------------- +* Defines and Constants +*----------------------------------------------------------------------------*/ +#define ATS_ADIE_RTC_MAJOR_VERSION 0x1 +#define ATS_ADIE_RTC_MINOR_VERSION 0x2 + +//const char* LOG_TAG = "ATS-ADIE-RTC"; +/* --------------------------------------------------------------------------- +* Public Functions +*-------------------------------------------------------------------------- */ + +/** +* \brief +* The Codec Realtime Calibration Service IOCTL +* \param [in] svc_cmd_id: The command to be issued +* \param [in] cmd_buf: Pointer to the command structure. +* \param [in] cmd_buf_size: Size of the command structure +* \param [out] rsp_buf: The response structre +* \param [in] rsp_buf_size: The size of the response +* \param [out] rsp_buf_bytes_filled: Number of bytes written to the response buffer +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t ats_adie_rtc_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +); + +/** +* \brief +* Initializes the codec realtime calibration service to +* allow interaction between ATS Clients device codec registers +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t ats_adie_rtc_init(void); + +/** +* \brief +* Deinitializes the codec realtime calibration service +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t ats_adie_rtc_deinit(void); + +/** +* \brief +* Gets the ADIE RTC service version used by the platform layer +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t ats_adie_rtc_get_version(uint32_t* major, uint32_t* minor); +#endif /*_ATS_ADIE_RTC_H_*/ \ No newline at end of file diff --git a/acdb/ats/adie/common/src/ats_adie_rtc.c b/acdb/ats/adie/common/src/ats_adie_rtc.c new file mode 100644 index 0000000..2b217b5 --- /dev/null +++ b/acdb/ats/adie/common/src/ats_adie_rtc.c @@ -0,0 +1,474 @@ +/** +*============================================================================== +* \file ats_adie_rtc.c +* \brief +* A T S A D I E R T C S O U R C E F I L E +* +* The ADIE(Codec) RTC Service(ARTC) header file contains all the +* definitions necessary for ATS to handle requests that operate on +* codec registers. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ats_adie_rtc.h" +#include "ats_i.h" +#include "acdb_utility.h" +#include "ats_common.h" +#include "adie_rtc_api.h" + +/*------------------------------------------ +* Defines and Constants +*------------------------------------------*/ + +/*------------------------------------------ +* Private Functions +*------------------------------------------*/ + +int32_t ats_adie_get_codec_info_v1_1(uint8_t* rsp_buf, + uint32_t rsp_buf_size, uint32_t* rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + struct adie_rtc_codec_info* rsp = NULL; + + ar_mem_set(rsp_buf, 0, rsp_buf_size); + uint32_t sz_codec_properties = 0; + rsp = (struct adie_rtc_codec_info*)rsp_buf; + + // Get Size (number of properties) + status = adie_rtc_get_codec_info(rsp, sizeof(struct adie_rtc_codec_info)); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get size of codec properties.", status); + return status; + } + + sz_codec_properties = sizeof(uint32_t) + rsp->num_of_entries * + sizeof(struct adie_rtc_codec_handle); + if (sz_codec_properties > rsp_buf_size) + { + ATS_ERR("Not enough memory to store codec properties"); + return AR_ENOMEMORY; + } + + // Get Data + status = adie_rtc_get_codec_info(rsp, sz_codec_properties); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get codec properties.", status); + return status; + } + + *rsp_buf_bytes_filled = sz_codec_properties; + + return status; +} + +int32_t ats_adie_get_codec_info_v1_2(uint8_t* rsp_buf, + uint32_t rsp_buf_size, uint32_t *rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + uint32_t sz_codec_properties = 0; + + ar_mem_set(rsp_buf, 0, rsp_buf_size); + struct adie_rtc_codec_info_v2* rsp = NULL; + + rsp = (struct adie_rtc_codec_info_v2*)rsp_buf; + + //Get Size(number of properties) + status = adie_rtc_get_codec_info_v2(rsp, sizeof(struct adie_rtc_codec_info_v2)); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get size of codec properties.", status); + return status; + } + + if (rsp->version == CODEC_INFO_STRUCT_VERSION_V2) + { + sz_codec_properties = 2 * sizeof(uint32_t) + rsp->num_of_entries * + sizeof(struct adie_rtc_codec_handle_v2); + } + + if (sz_codec_properties > rsp_buf_size) + { + ATS_ERR("Error[%d]: Not enough memory to write codec info." + " Required is %d where as available is %d", + AR_ENOMEMORY, sz_codec_properties, rsp_buf_size); + return AR_ENOMEMORY; + } + + //Get Data + status = adie_rtc_get_codec_info_v2(rsp, sz_codec_properties); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get codec properties V2.", status); + return status; + } + + *rsp_buf_bytes_filled = sz_codec_properties; + + return status; +} + +int32_t ats_adie_get_codec_info( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + int32_t status = AR_EOK; + uint32_t sz_codec_properties = 0; + struct adie_rtc_version api_version = { 0 }; + + ats_adie_rtc_get_version(&api_version.major, &api_version.minor); + + /* Fallback to version 1.0 if latest fails */ + switch (api_version.minor) + { + case ADIE_RTC_API_MINOR_VERSION_2: + status = ats_adie_get_codec_info_v1_2( + rsp_buf, rsp_buf_size, &sz_codec_properties); + + if(AR_SUCCEEDED(status)) + break; + + case ADIE_RTC_API_MINOR_VERSION_1: + case ADIE_RTC_API_MINOR_VERSION_0: + default: + status = ats_adie_get_codec_info_v1_1( + rsp_buf, rsp_buf_size, &sz_codec_properties); + break; + } + + *rsp_buf_bytes_filled = sz_codec_properties; + return status; +} + +int32_t ats_adie_get_register( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf_size); + int32_t status = AR_EOK; + uint32_t *reg_value = NULL; + uint32_t min_req_size = + sizeof(struct adie_rtc_register_req) - sizeof(uint32_t); + struct adie_rtc_register_req req = { 0 }; + + ACDB_MEM_CPY_SAFE( + &req, min_req_size, + cmd_buf, min_req_size); + + if (IsNull(cmd_buf) || IsNull(rsp_buf) || cmd_buf_size < min_req_size) + { + ATS_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + + status = adie_rtc_get_register(&req); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get register.\ + Handle(0x%x) ID(0x%x) Mask(0x%x)", + status, req.codec_handle, + req.reg.register_id, req.reg.register_mask); + return AR_EFAILED; + } + + ATS_DBG("Register Info: Handle(0x%x) ID(0x%x) \ + Mask(0x%x) Value(0x%x)", + req.codec_handle, req.reg.register_id, + req.reg.register_mask, req.reg.value); + + reg_value = (uint32_t*)rsp_buf; + *reg_value = req.reg.value; + *rsp_buf_bytes_filled = sizeof(uint32_t); + + return status; +} + +int32_t ats_adie_get_multiple_register( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + uint32_t min_req_size = + sizeof(struct adie_rtc_multi_register_req); + uint32_t req_size = 0; + struct adie_rtc_multi_register_req *req = NULL; + struct adie_rtc_register *codec_reg = NULL; + uint32_t *reg_values = NULL; + + if (IsNull(cmd_buf) || IsNull(rsp_buf) || cmd_buf_size < min_req_size) + { + ATS_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + + req = (struct adie_rtc_multi_register_req*)cmd_buf; + + req_size = sizeof(struct adie_rtc_multi_register_req) + + req->num_registers * sizeof(struct adie_rtc_register); + status = adie_rtc_get_multiple_registers(req, req_size); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: An error occured while getting multiple registers", + status); + return status; + } + + *rsp_buf_bytes_filled = req->num_registers * sizeof(uint32_t); + + if (rsp_buf_size < *rsp_buf_bytes_filled) + { + ATS_ERR("Error[%d]: Not enough memory to copy response. " + "The memory avalible is %d bytes and the size needed is &d bytes", + AR_ENEEDMORE, rsp_buf_size, *rsp_buf_bytes_filled); + } + + reg_values = (uint32_t*)rsp_buf; + codec_reg = (struct adie_rtc_register*)(req->register_list); + + for (uint32_t i = 0; i < req->num_registers; i++) + { + reg_values[i] = codec_reg[i].value; + } + + return status; +} + +int32_t ats_adie_set_register( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + int32_t status = AR_EOK; + struct adie_rtc_register_req req = { 0 }; + uint32_t min_req_size = + sizeof(struct adie_rtc_multi_register_req); + + if (IsNull(cmd_buf) || cmd_buf_size < min_req_size) + { + ATS_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + + ACDB_MEM_CPY_SAFE( + &req, sizeof(struct adie_rtc_register_req), + cmd_buf, sizeof(struct adie_rtc_register_req)); + + status = adie_rtc_set_register(&req); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to set register." + "Handle(%d) ID(%x) Mask(%x) Value(%d)", + status, + req.codec_handle, req.reg.register_id, + req.reg.register_mask, req.reg.value); + return AR_EFAILED; + } + + return status; +} + +int32_t ats_adie_set_multiple_register( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t min_req_size = + sizeof(struct adie_rtc_multi_register_req); + uint32_t req_size = 0; + struct adie_rtc_multi_register_req *req = NULL; + + if (IsNull(cmd_buf) || cmd_buf_size < min_req_size) + { + ATS_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + + req = (struct adie_rtc_multi_register_req*)cmd_buf; + + req_size = sizeof(struct adie_rtc_multi_register_req) + + req->num_registers * sizeof(struct adie_rtc_register); + status = adie_rtc_set_multiple_registers(req, req_size); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: An error occured while setting multiple registers", + status); + return status; + } + + return status; +} + + +/*------------------------------------------ +* Public Functions +*------------------------------------------*/ + +int32_t ats_adie_rtc_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +) +{ + int32_t status = AR_EOK; + + int32_t(*func_cb)( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled + ) = NULL; + + switch (svc_cmd_id) + { + case ATS_CMD_ADIE_GET_CODEC_INFO: + func_cb = ats_adie_get_codec_info; + break; + case ATS_CMD_ADIE_GET_REGISTER: + func_cb = ats_adie_get_register; + break; + case ATS_CMD_ADIE_GET_MULTIPLE_REGISTER: + func_cb = ats_adie_get_multiple_register; + break; + case ATS_CMD_ADIE_SET_REGISTER: + func_cb = ats_adie_set_register; + break; + case ATS_CMD_ADIE_SET_MULTIPLE_REGISTER: + func_cb = ats_adie_set_multiple_register; + break; + default: + ATS_ERR("Command[%x] is not supported", svc_cmd_id); + status = AR_EUNSUPPORTED; + } + + if (status == AR_EOK) + { + status = func_cb(cmd_buf, + cmd_buf_size, + rsp_buf, + rsp_buf_size, + rsp_buf_bytes_filled); + } + + return status; +} + + +int32_t ats_adie_rtc_init(void) +{ + ATS_INFO("Registering ADIE Realtime Calibration Service..."); + + int32_t status = AR_EOK; + + status = adie_rtc_init(); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to initialize ADIE RTC.", status); + return status; + } + + status = ats_register_service(ATS_CODEC_RTC_SERVICE_ID, ats_adie_rtc_ioctl); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to register the ADIE Realtime Calibration Service.", status); + } + + return status; +} + +int32_t ats_adie_rtc_deinit(void) +{ + ATS_DBG("Deregistering ADIE Realtime Calibration Service..."); + + int32_t status = AR_EOK; + + status = ats_deregister_service(ATS_CODEC_RTC_SERVICE_ID); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to deregister the ADIE Realtime Calibration Service.", status); + } + + status = adie_rtc_deinit(); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to deinitialize ADIE RTC.", status); + return status; + } + + return status; +} + +int32_t ats_adie_rtc_get_version(uint32_t *major, uint32_t *minor) +{ + int32_t status = AR_EOK; + struct adie_rtc_version version = { 0 }; + + if (IsNull(major) || IsNull(minor)) + return AR_EBADPARAM; + + status = adie_rtc_get_api_version(&version); + + if (AR_FAILED(status)) + { + /* Default to initial version. There are no api + differences between 1.0 and 1.1, so 1.1 is used */ + *major = ADIE_RTC_API_MAJOR_VERSION_1; + *minor = ADIE_RTC_API_MINOR_VERSION_1; + ATS_ERR("Warning[%d]: Unable to get MCS API version. " + "Defaulting to v%d.%d", status, + *major, *minor); + return AR_EOK; + } + + *major = version.major; + *minor = version.minor; + + return status; +} diff --git a/acdb/ats/adie/linux/adie_rtc.c b/acdb/ats/adie/linux/adie_rtc.c new file mode 100644 index 0000000..4cc36a6 --- /dev/null +++ b/acdb/ats/adie/linux/adie_rtc.c @@ -0,0 +1,1216 @@ +/* + * adie_rtc.c + * + * This file has implementation of adie rtc for LX platform + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adie_rtc_api.h" +#include "ar_osal_error.h" +#include "ar_osal_file_io.h" +#include "ar_osal_log.h" + +#define CDC_REG_DIG_BASE_READ 0x200 +#define CDC_REG_DIG_OFFSET 0x000 +#define CDC_REG_DIG_BASE_WRITE 0x200 +#define FILE_NAME_LENGTH 200 +#define MAX_NUMBER_OF_CODECS 20 +#define CODEC_INFO_PATH "/proc/asound/card0/codecs/" +#define READ_STEP_SIZE 4000 +#define WCD939X_I2C_REG_MAX 0x4FF +#define WCD939X_I2C_REG_MIN 0 +#define IS_I2C_REG(reg) (((reg) >= WCD939X_I2C_REG_MIN) && ((reg) <= WCD939X_I2C_REG_MAX)) + +#define LOG_TAG "ADIE_RTC" + +struct chipset_id_info { + char *name; + enum adie_chipset_id_t id; +}; + +static struct chipset_id_info codec_chipset[] = { + {"BOLERO", BOLERO}, + {"LPASS", BOLERO}, + {"LPASS-CDC", BOLERO}, + {"WCD939X", WCD939X}, + {"WCD938X", WCD938X}, + {"WCD937X", WCD937X}, + {"WCD9378", WCD9378}, + {"WCD9360", WCD9360}, + {"AQT1000", AQT1000}, + {"WCD9341", WCD9341}, + {"WCD9340", WCD9340}, + {"MSM8X52", MSM8X52}, + {"WHS9410", WHS9410}, + {"WHS9420", WHS9420}, + {"WCD9335", WCD9335}, + {"WSA881X-ANALOG", WSA881X_ANALOG}, + {"WSA881X-SOUNDWIRE", WSA881X_SOUNDWIRE}, + {"WSA881X", WSA881X}, + {"WSA883X", WSA883X}, + {"WSA884X", WSA884X}, + {"MSM8909", MSM8909}, + {"WCD9330", WCD9330}, + {"WCD9326", WCD9326}, + {"WCD9320", WCD9320}, + {"WCD9310", WCD9310}, + {"WCD9306", WCD9306}, + {"WCD9302", WCD9302}, + {"MSM8X16", MSM8X16}, + {"MSM8X10", MSM8X10}, + {"CODEC_UNDEFINED", CODEC_UNDEFINED} +}; + +struct codec_info { + uint32_t handle; + uint32_t chipset_id; + uint32_t major_version; + uint32_t minor_version; + char codec_name[FILE_NAME_LENGTH]; + char reg_path[FILE_NAME_LENGTH]; + char address_path[FILE_NAME_LENGTH]; /* regmap/codec_name/address */ + char data_path[FILE_NAME_LENGTH]; /* regmap/codec_name/path */ + int is_address_data_paths_available; + }; + +struct wcd939x_i2c_reg_info { + char reg_path[FILE_NAME_LENGTH]; + char address_path[FILE_NAME_LENGTH]; /* regmap/codec_name/address */ + char data_path[FILE_NAME_LENGTH]; /* regmap/codec_name/path */ +} wcd939x_i2c_info; + +static struct codec_info *codec_info; +static uint32_t found_codec_path; +static uint32_t number_of_codecs; +static uint32_t register_length = 4; + +static int lnx_to_ar(int lx_err) +{ + switch(lx_err) { + case -EINVAL: + return AR_EBADPARAM; + case -ENODEV: + return AR_ENORESOURCE; + case -ENOMEM: + return AR_ENOMEMORY; + case 0: + return AR_EOK; + default: + return AR_EFAILED; + } +} + +static int find_codec_index(uint32_t handle) + { + int i; + for (i=0; i < (int)number_of_codecs; i++) + if (codec_info[i].handle == handle) + goto done; + AR_LOG_ERR(LOG_TAG,"%s->could not find codec with handle %d\n", __func__, handle); + i = -EINVAL; + done: + return i; + } + + +static int get_chipset_id(char *chipset_name) +{ + int ret = 0; + unsigned int i; + if(chipset_name == NULL){ + AR_LOG_ERR(LOG_TAG,"chipset_name is null"); + ret = -EINVAL; + goto done; + } + + for (i = 0; i < sizeof(codec_chipset)/sizeof(codec_chipset[0]);i++) { + if (!strncmp(chipset_name, codec_chipset[i].name, strlen(chipset_name)+1)) { + codec_info[number_of_codecs].chipset_id = codec_chipset[i].id; + goto done; + } + } + ret = -EINVAL; + done: + return ret; +} + +static int read_version_file(char *version_path) +{ + int ret = 0; + ar_fhandle file_handle; + int fd; + char *token; + char *token2; + char *save; + size_t num_read; + char version_entry[FILE_NAME_LENGTH]; + if(version_path == NULL) { + AR_LOG_ERR(LOG_TAG,"version_path is null"); + ret = -EINVAL; + goto done; + } + + fd = ar_fopen(&file_handle, version_path, AR_FOPEN_READ_ONLY); + if (fd != 0) { + AR_LOG_ERR(LOG_TAG,"%s: file open failed for path %s\n", __func__, version_path); + ret = -ENODEV; + goto done; + } + + fd = ar_fread(file_handle, version_entry, sizeof(version_entry)-1, &num_read); + version_entry[FILE_NAME_LENGTH-1]='\0'; + if (fd != 0) { + AR_LOG_ERR(LOG_TAG,"%s: file read failed for path %s\n", __func__); + ret = -ENODEV; + goto done; + } + + token = strtok_r(version_entry, "_", &save); + if (token == NULL) { + AR_LOG_ERR(LOG_TAG,"%s: strtok failed to get chipset name\n", __func__); + ret = -EINVAL; + goto close; + } + + ret = get_chipset_id(token); + if (ret < 0) { + AR_LOG_ERR(LOG_TAG,"%s: get_chipset_id failed error %d\n", __func__, ret); + ret = -EINVAL; + goto close; + } + + token = strtok_r(NULL, "_", &save); + if (token == NULL) { + AR_LOG_ERR(LOG_TAG,"%s: strtok failed to get chipset major version\n", __func__); + ret = -EINVAL; + goto close; + } + + token2 = strtok_r(NULL, "\n", &save); + if (token2 == NULL) { + AR_LOG_ERR(LOG_TAG,"%s: strtok failed to get chipset minor version\n", __func__); + ret = -EINVAL; + goto close; + } + + codec_info[number_of_codecs].major_version = atoi(token); + codec_info[number_of_codecs].minor_version = atoi(token2); + + close: + fclose(file_handle); + done: + return ret; +} + +static int get_address_path(char **match_strings, int array_size) +{ + DIR *dir; + int i; + int ret = -EINVAL; + struct dirent *dirent; + char path[FILE_NAME_LENGTH] = "/sys/kernel/debug"; + + if(*match_strings == NULL){ + ret = -EINVAL; + AR_LOG_ERR(LOG_TAG,"Empty array of string"); + } + + for(i = 0; i < array_size; i++) { + dir = opendir(path); + if (dir == NULL) { + AR_LOG_INFO(LOG_TAG,"%d (%s) opendir %s failed\n", errno, strerror(errno), path); + return -EINVAL; + } + + while (NULL != (dirent = readdir(dir))) { + if (strstr(dirent->d_name, match_strings[i])) + { + strlcat(path, "/", sizeof(path)); + strlcat(path, dirent->d_name, sizeof(path)); + + /* If "reg" found don't search anymore */ + if (i == array_size - 1) { + strlcpy(codec_info[number_of_codecs].address_path, path, + sizeof(codec_info[number_of_codecs].address_path)); + ret = 0; + closedir(dir); + goto done; + } + } + } + closedir(dir); + } + done: + return ret; +} + +static int get_data_path(char **match_strings, int array_size) +{ + DIR *dir; + int i; + int ret = -EINVAL; + struct dirent *dirent; + char path[FILE_NAME_LENGTH] = "/sys/kernel/debug"; + + if(*match_strings == NULL){ + ret = -EINVAL; + AR_LOG_ERR(LOG_TAG,"Empty array of string"); + } + + for(i = 0; i < array_size; i++) { + dir = opendir(path); + if (dir == NULL) { + AR_LOG_INFO(LOG_TAG,"%d (%s) opendir %s failed\n", errno, strerror(errno), path); + return -EINVAL; + } + + while (NULL != (dirent = readdir(dir))) { + if (strstr(dirent->d_name, match_strings[i])) + { + strlcat(path, "/", sizeof(path)); + strlcat(path, dirent->d_name, sizeof(path)); + + /* If "reg" found don't search anymore */ + if (i == array_size - 1) { + strlcpy(codec_info[number_of_codecs].data_path, path, + sizeof(codec_info[number_of_codecs].data_path)); + ret = 0; + closedir(dir); + goto done; + } + } + } + closedir(dir); + } + done: + return ret; +} + +static int get_reg_path(char **match_strings, int array_size) +{ + DIR *dir; + int i; + int ret = -EINVAL; + struct dirent *dirent; + char path[FILE_NAME_LENGTH] = "/sys/kernel/debug"; + + if(*match_strings == NULL){ + ret = -EINVAL; + AR_LOG_ERR(LOG_TAG,"Empty array of string"); + } + + for(i = 0; i < array_size; i++) { + dir = opendir(path); + if (dir == NULL) { + AR_LOG_INFO(LOG_TAG,"%d (%s) opendir %s failed\n", errno, strerror(errno), path); + return -EINVAL; + } + + while (NULL != (dirent = readdir(dir))) { + if (strstr(dirent->d_name, match_strings[i])) + { + strlcat(path, "/", sizeof(path)); + strlcat(path, dirent->d_name, sizeof(path)); + + /* If "reg" found don't search anymore */ + if (i == array_size - 1) { + strlcpy(codec_info[number_of_codecs].reg_path, path, + sizeof(codec_info[number_of_codecs].reg_path)); + found_codec_path = 1; + ret = 0; + closedir(dir); + goto done; + } + } + } + closedir(dir); + } + done: + return ret; +} + +enum { + REG_PATH, + ADDRESS_PATH, + DATA_PATH, +}; + +static int set_i2c_path(char **match_strings, int array_size, int path_id) +{ + DIR *dir; + int i; + int ret = -EINVAL; + struct dirent *dirent; + char path[FILE_NAME_LENGTH] = "/sys/kernel/debug"; + + if(*match_strings == NULL){ + ret = -EINVAL; + AR_LOG_ERR(LOG_TAG,"Empty array of string"); + } + + for(i = 0; i < array_size; i++) { + dir = opendir(path); + if (dir == NULL) { + AR_LOG_INFO(LOG_TAG,"%d (%s) opendir %s failed\n", errno, strerror(errno), path); + return -EINVAL; + } + + while (NULL != (dirent = readdir(dir))) { + if (strstr(dirent->d_name, match_strings[i])) + { + strlcat(path, "/", sizeof(path)); + strlcat(path, dirent->d_name, sizeof(path)); + + /* If "reg" found don't search anymore */ + if (i == array_size - 1) { + if (path_id == REG_PATH) + strlcpy(wcd939x_i2c_info.reg_path, path, + sizeof(wcd939x_i2c_info.reg_path)); + + if (path_id == ADDRESS_PATH) + strlcpy(wcd939x_i2c_info.address_path, path, + sizeof(wcd939x_i2c_info.address_path)); + + if (path_id == DATA_PATH) + strlcpy(wcd939x_i2c_info.data_path, path, + sizeof(wcd939x_i2c_info.data_path)); + ret = 0; + closedir(dir); + goto done; + } + } + } + closedir(dir); + } + done: + return ret; +} + +static int populate_wcd939x_i2c_info(void) +{ + int ret = 0; + char *match_strings[] = {"regmap", "-000e", "registers"}; + char *match_strings1[] = {"regmap", "-000e", "address"}; + char *match_strings2[] = {"regmap", "-000e", "data"}; + + ret = set_i2c_path(match_strings, sizeof(match_strings)/sizeof(char *), REG_PATH); + if (ret) { + AR_LOG_ERR(LOG_TAG,"%s: set_i2c_reg_path failed, err %d\n", __func__, ret); + } else { + AR_LOG_INFO(LOG_TAG,"%s: reg path : %s\n", __func__, wcd939x_i2c_info.reg_path); + } + + ret = set_i2c_path(match_strings1, sizeof(match_strings1)/sizeof(char *), ADDRESS_PATH); + if (ret) { + AR_LOG_ERR(LOG_TAG,"%s: set_i2c_address_path failed, err %d\n", __func__, ret); + } else { + AR_LOG_INFO(LOG_TAG,"%s: address path : %s\n", __func__, wcd939x_i2c_info.address_path); + } + ret = set_i2c_path(match_strings2, sizeof(match_strings2)/sizeof(char *), DATA_PATH); + if (ret) { + AR_LOG_ERR(LOG_TAG,"%s: set_i2c_data_path failed, err %d\n", __func__, ret); + } else { + AR_LOG_INFO(LOG_TAG,"%s: data path : %s\n", __func__, wcd939x_i2c_info.data_path); + } + + + return ret; +} + +static int find_codecs_info(void) +{ + DIR *dir; + struct dirent *dentry; + int ret = 0, ret1 = 0, ret2 = 0; + char version_path[FILE_NAME_LENGTH] = CODEC_INFO_PATH; + + dir = opendir(version_path); + if (dir == NULL) { + AR_LOG_ERR(LOG_TAG,"%s: %d (%s) opendir %s failed\n", __func__, errno, strerror(errno), CODEC_INFO_PATH); + ret = -ENODEV; + goto done; + } + + while ((dentry = readdir(dir)) != NULL) { + if (!strncmp(dentry->d_name, ".", 1)) + continue; + ret = snprintf(codec_info[number_of_codecs].codec_name, + sizeof(codec_info[number_of_codecs].codec_name), "%s", dentry->d_name); + if (ret < 0) { + AR_LOG_ERR(LOG_TAG,"%s: snprintf failed: %s in %s, err %d\n", + __func__, dentry->d_name, CODEC_INFO_PATH, ret); + continue; + } + ret = snprintf(version_path, sizeof(version_path), + "%s%s/version", CODEC_INFO_PATH, dentry->d_name); + if (ret < 0) { + AR_LOG_ERR(LOG_TAG,"%s: snprintf failed: %s in %s, err %d\n", + __func__, dentry->d_name, CODEC_INFO_PATH, ret); + continue; + } + ret = read_version_file(version_path); + if (ret < 0) { + AR_LOG_ERR(LOG_TAG,"%s: read_version_file failed, err %d path %s\n", + __func__, ret, version_path); + continue; + } + char *match_strings[] = {"regmap", codec_info[number_of_codecs].codec_name, "registers"}; + ret = get_reg_path(match_strings, sizeof(match_strings)/sizeof(char *)); + if (ret < 0) { + AR_LOG_ERR(LOG_TAG,"%s: get_reg_path failed, err %d, path %s\n", + __func__, ret, version_path); + continue; + } + char *match_strings1[] = {"regmap", codec_info[number_of_codecs].codec_name, "address"}; + ret1 = get_address_path(match_strings1, sizeof(match_strings1)/sizeof(char *)); + if (ret1 < 0) { + AR_LOG_DEBUG(LOG_TAG,"%s: get_address_path failed, err %d, path %s\n", + __func__, ret1, version_path); + } + char *match_strings2[] = {"regmap", codec_info[number_of_codecs].codec_name, "data"}; + ret2 = get_data_path(match_strings2, sizeof(match_strings2)/sizeof(char *)); + if (ret2 < 0) { + AR_LOG_DEBUG(LOG_TAG,"%s: get_data_path failed, err %d, path %s\n", + __func__, ret2, version_path); + } + codec_info->is_address_data_paths_available = 0; + if (ret1 == 0 && ret2 == 0) { + codec_info->is_address_data_paths_available = 1; + AR_LOG_INFO(LOG_TAG,"%s: address path : %s\n", __func__, + codec_info[number_of_codecs].address_path); + AR_LOG_INFO(LOG_TAG,"%s: data path : %s\n", __func__, + codec_info[number_of_codecs].data_path); + } + codec_info[number_of_codecs].handle = number_of_codecs + 1; + number_of_codecs++; + } + closedir(dir); + done: + return ret; +} + +static int find_codecs(void) +{ + int ret = 0; + unsigned int i; + char *old_match_strings[] = {"regmap", "-000d", "registers"}; + + number_of_codecs = 0; + ret = find_codecs_info(); + if (number_of_codecs == 0) { + ret = get_reg_path(old_match_strings, sizeof(old_match_strings)/sizeof(char *)); + if (ret < 0) { + AR_LOG_ERR(LOG_TAG,"%s: get_reg_path failed, err %d\n",__func__, ret); + goto done; + } + + codec_info[number_of_codecs].handle = number_of_codecs+1; + number_of_codecs++; + } + for (i=0; i < number_of_codecs; i++) + AR_LOG_VERBOSE(LOG_TAG,"%s: codec %s: handle %d, chipset id %d, major %d, minor %d, reg path %s\n", + __func__, codec_info[i].codec_name, codec_info[i].handle, codec_info[i].chipset_id, + codec_info[i].major_version, codec_info[i].minor_version, codec_info[i].reg_path); + done: + return ret; +} + +static int parse_codec_reg_file(char_t **rtc_io_buf_base, int32_t *rtc_io_buf_size, + int fd, int32_t codec_idx) +{ + char_t *rtc_io_buf = NULL; + char_t *temp; + int32_t buf_size = 0, rc = 0; + int32_t numBytes; + + if (fd < 0) + { + rc = -EINVAL; + *rtc_io_buf_base = NULL; + AR_LOG_ERR(LOG_TAG,"Invalid fd"); + goto done; + } + + while (1) + { + temp = realloc(*rtc_io_buf_base, buf_size + READ_STEP_SIZE); + if (!temp) + { + rc = -ENOMEM; + free(*rtc_io_buf_base); + *rtc_io_buf_base = NULL; + buf_size = 0; + AR_LOG_ERR(LOG_TAG,"cannot allocate memory: %d, path: %s", + READ_STEP_SIZE, codec_info[codec_idx].reg_path); + goto done; + } + *rtc_io_buf_base = temp; + rtc_io_buf = *rtc_io_buf_base + buf_size; + numBytes = read(fd, rtc_io_buf, READ_STEP_SIZE); + if (numBytes <= 0) + break; + + buf_size += numBytes; + } +done: + *rtc_io_buf_size = buf_size; + + return rc; +} + +int32_t adie_rtc_get_api_version(struct adie_rtc_version *api_version) +{ + if (!api_version) + return 0; + + api_version->major = ADIE_RTC_API_MAJOR_VERSION_1; + api_version->minor = ADIE_RTC_API_MINOR_VERSION_1; + + return 0; +} + +int32_t adie_rtc_init(void) +{ + int ret = 0, i = 0; + + codec_info = (struct codec_info *) calloc(1, MAX_NUMBER_OF_CODECS * + sizeof(struct codec_info)); + if (codec_info == NULL) { + ret = -ENOMEM; + AR_LOG_ERR(LOG_TAG, "malloc failed\n"); + goto done; + } + if (!found_codec_path) { + if (find_codecs() < 0) { + ret = -EINVAL; + AR_LOG_ERR(LOG_TAG, "failed to get register paths \n"); + } + + for(i = 0; i < number_of_codecs; ++i) { + if (codec_info[i].chipset_id != WCD939X) + continue; + populate_wcd939x_i2c_info(); + break; + } + } + + done: + if (ret) { + free(codec_info); + codec_info = NULL; + } + return lnx_to_ar(ret); +} + +int32_t adie_rtc_deinit(void) +{ + free(codec_info); + codec_info = NULL; + + return AR_EOK; +} + +//TODO: Stubbing this function for now to avoid compilation. +//Need to add support when required to enable adie rtc via v2 function. +int32_t adie_rtc_get_codec_info_v2(struct adie_rtc_codec_info_v2 *codec_info, uint32_t size) +{ + if (!codec_info || (size == 0)) { + AR_LOG_ERR(LOG_TAG, "adie_rtc_get_codec_info_v2 failed"); + return AR_EBADPARAM; + } + + AR_LOG_ERR(LOG_TAG, "adie_rtc_get_codec_info_v2 not supported"); + return AR_ENOTIMPL; +} + +int32_t adie_rtc_get_codec_info(struct adie_rtc_codec_info *cdc_info, uint32_t size) +{ + int i, ret = 0, j = 0; + + if (!cdc_info || (size == 0)) { + AR_LOG_ERR(LOG_TAG, "get codec info failed"); + return AR_EBADPARAM; + } + + if (size == sizeof(struct adie_rtc_codec_info)) { + cdc_info->num_of_entries = number_of_codecs; + for(i = 0, j = 0; i < number_of_codecs; ++i) { + if (codec_info[i].chipset_id == BOLERO) + continue; + ++j; + } + cdc_info->num_of_entries = j; + AR_LOG_DEBUG(LOG_TAG, "num codec entries: %d", cdc_info->num_of_entries); + } else { + if (size < (sizeof(uint32_t) + (number_of_codecs - 1) * + sizeof(struct adie_rtc_codec_handle))) { + AR_LOG_ERR(LOG_TAG, "insufficient memory"); + ret = AR_ENEEDMORE; + goto done; + } + + for(i = 0, j = 0; i < number_of_codecs; ++i) { + if (codec_info[i].chipset_id == BOLERO) + continue; + cdc_info->handle[j].handle = codec_info[i].handle; + cdc_info->handle[j].chipset_id = codec_info[i].chipset_id; + cdc_info->handle[j].chipset_major_version = codec_info[i].major_version; + cdc_info->handle[j].chipset_minor_version = codec_info[i].minor_version; + ++j; + } + } + done: + return ret; +} + +int32_t adie_rtc_get_register(struct adie_rtc_register_req *req) +{ + int res = 0; + int result = 0; + int fd = -1; + char_t *rtc_io_buf = NULL; + char_t *rtc_io_buf_base = NULL; + int found = 0; + uint32_t ultempRegAddr = 0; + int32_t lRegValue = 0; + uint32_t handle = req->codec_handle; + int32_t codec_idx = 0; + uint32_t regAddr = req->reg.register_id; + uint32_t regMask = req->reg.register_mask; + size_t numBytes = 0; + char_t *pCurInputBuf = NULL; + int32_t rtc_io_buf_size = 0; + char_t reg[5], val[3]; + reg[4] = '\0', val[2] = '\0'; + uint32_t offset = 0; + int reg_len, i2c_file_open = 0; + char *save; + char *token; + + codec_idx = find_codec_index(handle); + if (codec_idx < 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"could not find codec index for handle %d", handle); + goto done; + } else if (strlen(codec_info[codec_idx].reg_path) == 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"codec path is empty\n %d", handle); + goto done; + } + //AR_LOG_INFO(LOG_TAG,"reg path= %s",codec_info[codec_idx].reg_path); + if (codec_info[codec_idx].chipset_id == WCD939X) { + if (IS_I2C_REG(regAddr)) { + if (strlen(wcd939x_i2c_info.reg_path) == 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"codec (i2c reg) path is empty\n %d", handle); + goto done; + } + fd = open(wcd939x_i2c_info.reg_path, O_RDWR); + i2c_file_open = 1; + } else { + fd = open(codec_info[codec_idx].reg_path, O_RDWR); + } + } else { + fd = open(codec_info[codec_idx].reg_path, O_RDWR); + } + if(fd < 0) + { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"cannot open adie peek error: %d, path: %s", + fd, codec_info[codec_idx].reg_path); + goto done; + } + result = parse_codec_reg_file(&rtc_io_buf_base, &rtc_io_buf_size, fd, codec_idx); + if (rtc_io_buf_base == NULL || result < 0) + { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"cannot allocate memory: %d, path: %s", + READ_STEP_SIZE, codec_info[codec_idx].reg_path); + goto close_fd; + } + if (rtc_io_buf_size <= 0) + { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"length of written bytes does not match expected value %d", rtc_io_buf_size); + goto close_fd; + } + numBytes = rtc_io_buf_size; + rtc_io_buf = rtc_io_buf_base; + memcpy((void*)reg, (void*)(rtc_io_buf+offset), sizeof(uint32_t)); + token = strtok_r(reg, ":", &save); + if (token == NULL) { + AR_LOG_ERR(LOG_TAG,"%s: strtok failed to find register length : delimiter!\n", __func__); + result = -EINVAL; + goto done; + } + reg_len = strlen(token); + if (reg_len <= 0) { + AR_LOG_ERR(LOG_TAG,"%s: register length is %d!\n", __func__, reg_len); + result = -EINVAL; + goto done; + } + register_length = reg_len; + AR_LOG_DEBUG(LOG_TAG,"%s: valid register length is %d\n", __func__, register_length); + while(numBytes>offset) + { + memcpy((void*)reg, (void*)(rtc_io_buf+offset), sizeof(uint32_t)); + offset += register_length; + ultempRegAddr = strtoul(reg, NULL, 16); + offset += 2; + memcpy((void*)val, (void*)(rtc_io_buf+offset), sizeof(uint16_t)); + lRegValue = strtol(val, NULL, 16); + offset += 3; + if (ultempRegAddr >= CDC_REG_DIG_BASE_READ) + ultempRegAddr -= CDC_REG_DIG_OFFSET; + if(ultempRegAddr == regAddr) + { + found = 1; + AR_LOG_DEBUG(LOG_TAG,"register[%08X] found from the file!\n",regAddr); + break; + } + } + if (found == 0) + { + result = -EINVAL; + if (i2c_file_open) { + AR_LOG_ERR(LOG_TAG,"get adie register[0x%x] failed Peek(%s) Poke(%s)", + regAddr, wcd939x_i2c_info.reg_path, wcd939x_i2c_info.reg_path); + } else { + AR_LOG_ERR(LOG_TAG,"get adie register[0x%x] failed Peek(%s) Poke(%s)", + regAddr, codec_info[codec_idx].reg_path, codec_info[codec_idx].reg_path); + } + goto close_fd; + } + else + { + AR_LOG_ERR(LOG_TAG,"Found the value for register = 0x%X, value = 0x%X\n",regAddr,lRegValue); + } + /* return a masked value */ + lRegValue &= regMask; + req->reg.value = lRegValue;/* output value*/ + +close_fd: + close(fd); +done: + free(rtc_io_buf_base); + return lnx_to_ar(result); +} + +int32_t _adie_rtc_set_register(int32_t codec_idx, uint32_t regAddr, uint32_t ulRegValue) +{ + int result = 0; + int fd = -1, fd1 = -1; + size_t numBytes1 = 0, val_numBytes1 = 0; + size_t numBytes2 = 0, val_numBytes2 = 0; + char *temp = NULL; + char *val_temp = NULL; + + numBytes1 = asprintf(&temp, "0x%x", regAddr); + if (codec_info[codec_idx].chipset_id == WCD939X) { + if (IS_I2C_REG(regAddr)) { + if (strlen(wcd939x_i2c_info.address_path) == 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"codec (i2c address) path is empty\n %d", codec_idx); + if (temp != NULL) + { + free(temp); + temp = NULL; + } + goto done; + } + fd = open(wcd939x_i2c_info.address_path, O_RDWR); + } else { + fd = open(codec_info[codec_idx].address_path, O_RDWR); + } + } else { + fd = open(codec_info[codec_idx].address_path, O_RDWR); + } + if(fd < 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"ERROR! cannot open adie address path error: %d, path: %s", + fd, codec_info[codec_idx].address_path); + if (temp != NULL) + { + free(temp); + temp = NULL; + } + goto done; + } + val_numBytes1 = asprintf(&val_temp, "0x%x", ulRegValue); + if (codec_info[codec_idx].chipset_id == WCD939X) { + if (IS_I2C_REG(regAddr)) { + if (strlen(wcd939x_i2c_info.data_path) == 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"codec (i2c data) path is empty\n %d", codec_idx); + if (val_temp != NULL) + { + free(val_temp); + val_temp = NULL; + } + close(fd); + if (temp != NULL) + { + free(temp); + temp = NULL; + } + goto done; + } + fd1 = open(wcd939x_i2c_info.data_path, O_RDWR); + } else { + fd1 = open(codec_info[codec_idx].data_path, O_RDWR); + } + } else { + fd1 = open(codec_info[codec_idx].data_path, O_RDWR); + } + if(fd1 < 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"ERROR! cannot open adie data path error: %d, path: %s", + fd1, codec_info[codec_idx].data_path); + if (val_temp != NULL) + { + free(val_temp); + val_temp = NULL; + } + close(fd); + if (temp != NULL) + { + free(temp); + temp = NULL; + } + goto done; + } + numBytes2 = write(fd, temp, numBytes1); + val_numBytes2 = write(fd1, val_temp, val_numBytes1); + if (temp != NULL) { + free(temp); + temp = NULL; + } + if (val_temp != NULL) { + free(val_temp); + val_temp = NULL; + } + close(fd); + close(fd1); + /* make sure the write is successful */ + if (numBytes1 != numBytes2) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"set adie register failed for Register[0x%X], addressBytes[%zu], valBytes[%zu]", + regAddr ,numBytes1, val_numBytes1); + } +done: + return result; +} + +int32_t adie_rtc_set_register(struct adie_rtc_register_req *req) +{ + int result = 0; + int fd = -1; + uint32_t ulRegValue = req->reg.value; + uint32_t handle = req->codec_handle; + int32_t codec_idx = 0; + uint32_t regAddr = req->reg.register_id; + uint32_t regMask = req->reg.register_mask; + size_t numBytes1 = 0; + size_t numBytes2 = 0; + char *temp = NULL; + + codec_idx = find_codec_index(handle); + if (codec_idx < 0) { + AR_LOG_ERR(LOG_TAG,"could not find codec index for handle\n %d", handle); + goto done; + } else if (strlen(codec_info[codec_idx].reg_path) == 0) { + AR_LOG_ERR(LOG_TAG,"codec path is empty\n %d", handle); + goto done; + } + + /* set the value as masked one*/ + ulRegValue &= regMask; + + if (regAddr >= CDC_REG_DIG_BASE_WRITE) + regAddr += CDC_REG_DIG_OFFSET; + + AR_LOG_DEBUG(LOG_TAG,"set register request received for ==> reg[%X], val[%X], bytes[%zu]\n", + regAddr, ulRegValue, numBytes1); + if (codec_info->is_address_data_paths_available) { + result = _adie_rtc_set_register(codec_idx, regAddr, ulRegValue); + } else { + numBytes1 = asprintf(&temp, "0x%x 0x%x", regAddr, ulRegValue); + fd = open(codec_info[codec_idx].reg_path, O_RDWR); + if(fd < 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"ERROR! cannot open adie poke error: %d, path: %s", + fd, codec_info[codec_idx].reg_path); + if (temp != NULL) + { + free(temp); + temp = NULL; + } + + goto done; + } + numBytes2 = write(fd, temp, numBytes1); + AR_LOG_DEBUG(LOG_TAG,"set register ==> actual bytes written[%zu]\n", numBytes2); + if (temp != NULL) { + free(temp); + temp = NULL; + } + close(fd); + /* make sure the write is successful */ + if (numBytes1 != numBytes2) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"set adie register failed for Register[0x%X], numBytes[%zu]",regAddr ,numBytes1); + goto done; + } + } + //*resp_buf_bytes_filled = 0; + if (result == 0) + AR_LOG_INFO(LOG_TAG,"Set Register Success\n"); + done: + return lnx_to_ar(result); +} + +int32_t adie_rtc_set_multiple_registers(struct adie_rtc_multi_register_req *req, uint32_t size) +{ + struct adie_rtc_register_req sreq; + uint32_t i = 0, regAddr = 0, regMask = 0; + size_t numBytes1 = 0; + size_t numBytes2 = 0; + uint32_t ulRegValue = 0; + char *temp = NULL; + int32_t result = 0; + uint32_t handle; + int32_t codec_idx = 0; + int fd = -1; + + if (!req || (size == 0)) + return lnx_to_ar(-EINVAL); + + if (req->num_registers == 0) + return lnx_to_ar(-EINVAL); + + handle = req->codec_handle; + codec_idx = find_codec_index(handle); + if (codec_idx < 0) { + AR_LOG_ERR(LOG_TAG, "could not find codec index for handle %d", + handle); + result = -EINVAL; + goto done; + } else if (strlen(codec_info[codec_idx].reg_path) == 0) { + AR_LOG_ERR(LOG_TAG, "codec path is empty %d", handle); + result = -EINVAL; + goto done; + } + for (i = 0; i < req->num_registers; ++i) { + temp = NULL; + regAddr = req->register_list[i].register_id; + regMask = req->register_list[i].register_mask; + ulRegValue = req->register_list[i].value; + ulRegValue &= regMask; + + if (regAddr >= CDC_REG_DIG_BASE_WRITE) + regAddr += CDC_REG_DIG_OFFSET; + + + if (codec_info->is_address_data_paths_available) { + result = _adie_rtc_set_register(codec_idx, regAddr, ulRegValue); + if (result) + goto done; + } else { + numBytes1 = asprintf(&temp, "0x%x 0x%x", regAddr, ulRegValue); + + fd = open(codec_info[codec_idx].reg_path, O_RDWR); + if (fd < 0) { + AR_LOG_ERR(LOG_TAG, "ERROR! cannot open adie poke error: %d, path: %s", + fd, codec_info[codec_idx].reg_path); + result = -EINVAL; + if (temp != NULL) { + free(temp); + temp = NULL; + } + goto done; + } + numBytes2 = write(fd, temp, numBytes1); + if (temp != NULL) { + free(temp); + temp = NULL; + } + close(fd); + + if (numBytes1 != numBytes2) { + AR_LOG_ERR(LOG_TAG, "set multi registers failed, numBytes1[%zu], numBytes2[%zu]", + numBytes1, numBytes2); + result = -EINVAL; + goto done; + } + } + usleep(30); + } + +done: + return lnx_to_ar(result); +} + +int32_t adie_rtc_get_multiple_registers(struct adie_rtc_multi_register_req *req, uint32_t size) +{ + struct adie_rtc_register_req sreq; + uint32_t i = 0; + uint32_t handle; + int32_t codec_idx = 0; + int fd = -1; + int result = -EINVAL; + int found = 0; + uint32_t ultempRegAddr = 0; + int32_t lRegValue = 0; + char_t *rtc_io_buf_base = NULL; + char_t *rtc_io_buf = NULL; + int32_t rtc_io_buf_size = 0; + size_t numBytes = 0; + uint32_t regAddr, regMask; + char_t reg[5], val[3]; + char *save; + char *token; + int reg_len; + uint32_t count = 0; + uint32_t offset = 0; + + if (!req || (size == 0)) + return lnx_to_ar(-EINVAL); + + if (req->num_registers == 0) + return lnx_to_ar(-EINVAL); + + handle = req->codec_handle; + codec_idx = find_codec_index(handle); + if (codec_idx < 0) { + AR_LOG_ERR(LOG_TAG, "could not find codec index for handle %d", + handle); + goto done; + } else if (strlen(codec_info[codec_idx].reg_path) == 0) { + AR_LOG_ERR(LOG_TAG, "codec path is empty %d", handle); + goto done; + } + regAddr = req->register_list[0].register_id; //read first reg + if (codec_info[codec_idx].chipset_id == WCD939X) { + if (IS_I2C_REG(regAddr)) { + if (strlen(wcd939x_i2c_info.reg_path) == 0) { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"codec (i2c reg) path is empty\n %d", handle); + goto done; + } + fd = open(wcd939x_i2c_info.reg_path, O_RDWR); + } else { + fd = open(codec_info[codec_idx].reg_path, O_RDWR); + } + } else { + fd = open(codec_info[codec_idx].reg_path, O_RDWR); + } + if(fd < 0) + { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"cannot open adie peek error: %d, path: %s", + fd, codec_info[codec_idx].reg_path); + goto done; + } + result = parse_codec_reg_file(&rtc_io_buf_base, &rtc_io_buf_size, fd, codec_idx); + if (rtc_io_buf_base == NULL || result < 0) + { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"cannot allocate memory: %d, path: %s", + READ_STEP_SIZE, codec_info[codec_idx].reg_path); + goto close_fd; + } + if (rtc_io_buf_size <= 0) + { + result = -EINVAL; + AR_LOG_ERR(LOG_TAG,"length of written bytes does not match expected value %d", rtc_io_buf_size); + goto close_fd; + } + numBytes = rtc_io_buf_size; + rtc_io_buf = rtc_io_buf_base; + + reg[4] = '\0', val[2] = '\0'; + for (i = 0; i < req->num_registers; ++i) { + regAddr = req->register_list[i].register_id; + regMask = req->register_list[i].register_mask; + + found = 0; + offset = 0; + if (rtc_io_buf == NULL) { + AR_LOG_ERR(LOG_TAG, "rtc_io_buf is NULL"); + result = -EINVAL; + goto close_fd; + } + memcpy((void*)reg, (void*)(rtc_io_buf+offset), sizeof(uint32_t)); + token = strtok_r(reg, ":", &save); + if (token == NULL) { + AR_LOG_ERR(LOG_TAG,"%s: strtok failed to find register length : delimiter!\n", __func__); + result = -EINVAL; + goto close_fd; + } + reg_len = strlen(token); + if (reg_len <= 0) { + AR_LOG_ERR(LOG_TAG,"%s: register length is %d!\n", __func__, reg_len); + result = -EINVAL; + goto done; + } + register_length = reg_len; + AR_LOG_DEBUG(LOG_TAG,"%s: valid register length is %d\n", __func__, register_length); + while(numBytes > offset) { + memcpy((void*)reg, (void*)(rtc_io_buf+offset), sizeof(uint32_t)); + offset += register_length; + ultempRegAddr = strtoul(reg, NULL, 16); + offset += 2; + memcpy((void*)val, (void*)(rtc_io_buf+offset), sizeof(uint16_t)); + lRegValue = strtol(val, NULL, 16); + offset += 3; + if (ultempRegAddr >= CDC_REG_DIG_BASE_READ) + ultempRegAddr -= CDC_REG_DIG_OFFSET; + + if(ultempRegAddr == regAddr) + { + count++; + found = 1; + /* return a masked value */ + lRegValue &= regMask; + req->register_list[i].value = lRegValue; + usleep(30); + AR_LOG_DEBUG(LOG_TAG, "reg[%08X],val[%08X], count[%d]\n", + ultempRegAddr, lRegValue,count); + break; + } + } + } + if (found == 0) { + AR_LOG_ERR(LOG_TAG, "GetMultipleAdieReg failed because reg[%08x] is not found\n", regAddr); + result = -EINVAL; + goto close_fd; + } + + if (result == 0 && req->num_registers != count) { + AR_LOG_ERR(LOG_TAG, "Error in lengths of input or output buffers or total registers"); + result = 0; + goto close_fd; + } + +close_fd: + if (fd != -1) + close(fd); + +done: + if(rtc_io_buf_base) + free(rtc_io_buf_base); + + return lnx_to_ar(result); +} + diff --git a/acdb/ats/api/ats.h b/acdb/ats/api/ats.h new file mode 100644 index 0000000..a3bc798 --- /dev/null +++ b/acdb/ats/api/ats.h @@ -0,0 +1,52 @@ +#ifndef __ATS_H__ +#define __ATS_H__ +/** +*============================================================================= +* \file ats.h +* \brief +* A T S H E A D E R F I L E +* +* This header file contains all the definitions necessary for the QACT +* Tuning Service to handle request buffer and operate ACDB +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ar_osal_error.h" +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* --------------------------------------------------------------------------- +* Public API Definitions +*-------------------------------------------------------------------------- */ + +/** +* \brief ats_init +* Initializes the QACT Tuning Service. +* +* \return 0 on success, non-zero on failure +*/ +int32_t ats_init(void); + +/** +* \brief ats_deinit +* Resets the QACT Tuning Service. +* +* \return 0 on success, non-zero on failure +*/ +int32_t ats_deinit(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*__ATS_H__*/ diff --git a/acdb/ats/ats.pc.in b/acdb/ats/ats.pc.in new file mode 100644 index 0000000..8e53a21 --- /dev/null +++ b/acdb/ats/ats.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ats +Description: ats library +Version: @LT_VERSION@ +Libs: -L${libdir} -lar-ats +Cflags: -I${includedir}\ats diff --git a/acdb/ats/dls/common/inc/ats_dls.h b/acdb/ats/dls/common/inc/ats_dls.h new file mode 100644 index 0000000..2992952 --- /dev/null +++ b/acdb/ats/dls/common/inc/ats_dls.h @@ -0,0 +1,72 @@ +#ifndef __ATS_DLS_H__ +#define __ATS_DLS_H__ +/** +*============================================================================== +* \file ats_dls.h +* \brief +* A T S D L S + H E A D E R F I L E +* +* The Data Logging Service header file defines an interface for initializing, +* handling dls commands from the ATS realtime tuning client, and +* pushing binary log packet push events to the ATS realtime tuning client. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ + +#include "gsl_dls_client_intf.h" + +#define ATS_DLS_MAJOR_VERSION 0x1 +#define ATS_DLS_MINOR_VERSION 0x0 + +typedef int32_t (*ATS_DSL_TCPIP_SEND_CALLBACK)(const uint8_t* buffer, uint32_t buffer_size); +// int32_t ats_transport_dls_send_callback(const uint8_t* buffer, uint32_t buffer_size); + +/** + \brief + The Data Logging Service IOCTL + + \param [in] svc_cmd_id: The command to be issued + \param [in] cmd_buf: Pointer to the command structure. + \param [in] cmd_buf_size: + \param [out] rsp_buf: The response structre + \param [in] rsp_buf_size: The size of the response + \param [out] rsp_buf_bytes_filled: Number of bytes written to the response buffer + + \return 0 on success, non-zero on failure +*/ + int32_t ats_dls_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +); + +/** +* \brief Initializes the gsl dls client +* +* \param [in] callback: The callback function that is invoked when spf notifies +* gsl about ready dls log buffers +* \return 0 on success, non-zero on failure +*/ +int32_t ats_dls_init(ATS_DSL_TCPIP_SEND_CALLBACK callback); + + +/** +* \brief Releases resources aquired during ats_dls_init(...). These resources +* include: +* 1. the dls shared memory pool +* 2. the ats dls packet buffer for sending binary packets through the dls tcpip server +* +* \param [in] callback: The callback function that is invoked when spf notifies +* gsl about ready dls log buffers +* \return 0 on success, non-zero on failure +*/ +int32_t ats_dls_deinit(void); + +#endif /*__ATS_DLS_H__*/ diff --git a/acdb/ats/dls/common/src/ats_dls.c b/acdb/ats/dls/common/src/ats_dls.c new file mode 100644 index 0000000..f621145 --- /dev/null +++ b/acdb/ats/dls/common/src/ats_dls.c @@ -0,0 +1,480 @@ +/** + *============================================================================== + * \file ats_dls.c + * \brief + * A T S D L S + * S O U R C E F I L E + * + * Contains the implemnentation of the ats dls service. This service is used by + * the ats tuning client for registering log codes to recieve binary log packetg + * data which is used for realtime monitoring. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + *============================================================================== + */ + +/* Notes + * size_t is used in calculating the size of the gsl structure headers + * becaause the last element in those structures is a pointer. The size + * of a pointer may very between x86 and x64 architectures + */ + +#include "ats.h" +#include "ats_i.h" +#include "ats_dls.h" +#include "ats_common.h" +#include "ar_osal_mutex.h" +#include "ar_osal_thread.h" +#include "acdb_utility.h" +#include "acdb_common.h" + +/*The version number of the ATS DLS get log packet header */ +#define ATS_DLS_HEADER_VERSION 1 +/*ARTM Tag in ASCII*/ +#define ATS_DLS_HEADER_TAG 0x4D545241 +/**< The byte size of one DLS buffer. A DLS buffer contains one log packet */ +#define ATS_DEFAULT_DLS_BUFFER_SIZE 5120 +/**< The number of DLS buffers in shared memory */ +#define ATS_DEFAULT_DLS_BUFFER_COUNT 30 + +/* The dls buffer pool configuration */ +struct gsl_dls_buffer_pool_config_t buffer_pool_config; +//buffer that stores binary log packets before sending to tcpip dls server +AtsBuffer dls_data_send_buffer; +ar_osal_mutex_t buffer_ready_lock; +ATS_DSL_TCPIP_SEND_CALLBACK ats_dls_tcpip_send_callback; +ar_osal_thread_t thd_ready_buffer_routine; +bool thd_ready_buffer_routine_active = true; + +#if defined(_DEVICE_SIM) +int32_t gsl_dls_client_is_feature_supported() +{ + return AR_EOK; +} +int32_t gsl_dls_client_init(struct gsl_dls_buffer_pool_config_t* gbuffer_pool_config, GSL_DLS_CLIENT_BUFFER_READY_CALLBACK callback) +{ + __UNREFERENCED_PARAM(gbuffer_pool_config); + __UNREFERENCED_PARAM(callback); + return AR_EOK; +} +int32_t gsl_dls_client_deinit() +{ + return AR_EOK; +} +int32_t gsl_dls_client_create_buffer_pool(struct gsl_dls_buffer_pool_config_t* gbuffer_pool_config) +{ + __UNREFERENCED_PARAM(gbuffer_pool_config); + return AR_EOK; +} +void gsl_dls_client_get_ready_dls_buffer_list(struct gsl_dls_ready_buffer_index_list_t* buffer_ready_list) +{ + __UNREFERENCED_PARAM(buffer_ready_list); +} +int32_t gsl_dls_client_get_log_buffer(uint32_t log_buffer_index, struct gls_dls_buffer_t* dls_log_buffer) +{ + __UNREFERENCED_PARAM(log_buffer_index); + __UNREFERENCED_PARAM(dls_log_buffer); + return AR_EOK; +} +int32_t gsl_dls_client_return_used_buffers(struct gsl_dls_ready_buffer_index_list_t* buffer_index_list) +{ + __UNREFERENCED_PARAM(buffer_index_list); + return AR_EOK; +} +int32_t gsl_dls_client_register_deregister_log_code(uint32_t log_code, bool_t is_log_code_enabled) +{ + __UNREFERENCED_PARAM(log_code); + __UNREFERENCED_PARAM(is_log_code_enabled); + return AR_EOK; +} +#endif + +int32_t ats_dls_buffer_ready_callback(void); + +int32_t ats_dls_register_log_code( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + uint32_t status = AR_EOK; + uint32_t log_code = 0; + uint32_t offset = 0; + + if (cmd_buf_size != sizeof(uint16_t)) + return AR_EBADPARAM; + + ATS_READ_SEEK_UI16(log_code, cmd_buf, offset); + + status = gsl_dls_client_register_deregister_log_code(log_code, TRUE); + + *rsp_buf_bytes_filled = 0; + return status; +} + +int32_t ats_dls_deregister_log_code( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + uint32_t status = AR_EOK; + uint32_t log_code = 0; + uint32_t offset = 0; + + if (cmd_buf_size != sizeof(uint16_t)) + return AR_EBADPARAM; + + ATS_READ_SEEK_UI16(log_code, cmd_buf, offset); + + status = gsl_dls_client_register_deregister_log_code(log_code, FALSE); + + *rsp_buf_bytes_filled = 0; + return status; +} + +int32_t ats_dls_set_buffer_config( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + + if (cmd_buf_size < sizeof(struct gsl_dls_buffer_pool_config_t)) + return AR_EBADPARAM; + + ATS_MEM_CPY_SAFE(&buffer_pool_config, cmd_buf_size, cmd_buf, cmd_buf_size); + + status = gsl_dls_client_create_buffer_pool(&buffer_pool_config); + if(AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to create dls buffer pool.", status, 0); + } + + *rsp_buf_bytes_filled = 0; + return status; +} +/** +* The DLS log buffers are bundled to gether and sent to the ATS client in the format below: +* +* .+-- +================================+ +* | | 'A''R''T''M' | bytes: 4 +* | | ---------------------------- | +* Header-->| | Version | bytes: 2 +* | | # Log Packets | bytes: 2 +* .+-- | Log Data Size | bytes: 4 +* .+-- .--------------------------------. +* | | Log Packet #1 | +* | | ---------------------------- | +* | | Packet Size | bytes: 4 +* | | Packet Data [packet size] | bytes: Packet Size bytes +* | |--------------------------------| +* Log Data--> | : ... : +* | |--------------------------------| +* | | Log Packet #n | +* | | ---------------------------- | +* | | Packet Size | bytes: 4 +* | | Packet Data [packet size] | bytes: Packet Size bytes +* .+-- +.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~+ +* +* Note: the Log Data Size referes to the size of the data section (not including header +* size of 12 bytes) +* + */ +int32_t ats_dls_get_log_data( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t dls_log_data_rsp_header_size = 12; + struct gsl_dls_ready_buffer_index_list_t ready_buffer_index_list; + struct gls_dls_buffer_t log_buffer; + AtsDlsLogDataHeader rsp = {0}; + + *rsp_buf_bytes_filled = 0; + + gsl_dls_client_get_ready_dls_buffer_list(&ready_buffer_index_list); + + if (ready_buffer_index_list.buffer_count == 0) + return status; + + /* skip the header and write it later + * the header isn't 4-byte aligned so subtract 4 bytes due to struct alignment + */ + offset += dls_log_data_rsp_header_size; + + ATS_DBG("#dls ready buffers %d", ready_buffer_index_list.buffer_count); + + for (uint16_t index = 0; index < ready_buffer_index_list.buffer_count; index++) + { + status = gsl_dls_client_get_log_buffer(ready_buffer_index_list.buffer_index_list[index], &log_buffer); + if(AR_FAILED(status)) + { + continue; + } + + ATS_DBG("Buffer size received from dls client is %d bytes", log_buffer.size); + + ATS_MEM_CPY_SAFE(rsp_buf + offset, sizeof(uint32_t), &log_buffer.size, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + ATS_MEM_CPY_SAFE(rsp_buf + offset, log_buffer.size, log_buffer.buffer, log_buffer.size); + offset += log_buffer.size; + + //include log buffer size filed and data in the total size + rsp.total_log_data_size += sizeof(uint32_t) + log_buffer.size; + } + + //Write header + ATS_DBG("writing header"); + rsp.header_id = ATS_DLS_HEADER_TAG; + rsp.header_version = ATS_DLS_HEADER_VERSION; + rsp.log_buffer_count = ready_buffer_index_list.buffer_count; + status = AR_EOK; + + offset = 0; + ATS_MEM_CPY_SAFE(rsp_buf + offset, sizeof(uint32_t), &rsp.header_id, sizeof(uint32_t)); + offset += sizeof(uint32_t); + ATS_MEM_CPY_SAFE(rsp_buf + offset, sizeof(uint16_t), &rsp.header_version, sizeof(uint16_t)); + offset += sizeof(uint16_t); + ATS_MEM_CPY_SAFE(rsp_buf + offset, sizeof(uint16_t), &rsp.log_buffer_count, sizeof(uint16_t)); + offset += sizeof(uint16_t); + ATS_MEM_CPY_SAFE(rsp_buf + offset, sizeof(uint32_t), &rsp.total_log_data_size, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + // ATS_MEM_CPY_SAFE(rsp_buf, sizeof(uint32_t), &rsp, sizeof(AtsDlsLogDataHeader)); + *rsp_buf_bytes_filled += sizeof(AtsDlsLogDataHeader) + rsp.total_log_data_size; + + ATS_DBG("set used buffers to gsl"); + gsl_dls_client_set_used_buffers(&ready_buffer_index_list); + ATS_DBG("done returning buffers to spf"); + + return status; +} + +void ats_dls_ready_buffer_thd(void* params){ + + while(thd_ready_buffer_routine_active) + { + //wait for signal and release ready buffers to dsp + ATS_DBG("return buffers to spf"); + gsl_dls_client_return_used_buffers(NULL); + ATS_DBG("done returning buffers to spf"); + } +} + +int32_t ats_dls_create_ready_buffer_thread() +{ + int32_t status = AR_EOK; + char_t* thd_name = "ATS_DLS_RDY_THD"; + ar_osal_thread_attr_t thd_attr = + { + thd_name, + 0xF4240, + 0, + }; + + ar_osal_thread_start_routine r = \ + (ar_osal_thread_start_routine)(ats_dls_ready_buffer_thd); + + status = ar_osal_thread_create(&thd_ready_buffer_routine, &thd_attr, r, NULL); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to create thread %s", status, thd_name); + return status; + } + + return status; +} + +int32_t ats_dls_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +) +{ + int32_t status = AR_EOK; + + int32_t(*func_cb)( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled + ) = NULL; + + switch (svc_cmd_id) + { + case ATS_CMD_DLS_START: + func_cb = ats_dls_register_log_code; + break; + case ATS_CMD_DLS_STOP: + func_cb = ats_dls_deregister_log_code; + break; + /*Online get service returns version of DLS service as well*/ + /*case ATS_CMD_DLS_GET_VERSION: + func_cb = get_dls_version; + break;*/ + case ATS_CMD_DLS_CONFIGURE: + func_cb = ats_dls_set_buffer_config; + break; + case ATS_CMD_DLS_GET_LOG_DATA: + func_cb = ats_dls_get_log_data; + break; + default: + ATS_ERR("Command[%x] is not supported", svc_cmd_id); + status = AR_EUNSUPPORTED; + break; + } + + if (!AR_FAILED(status)) + { + status = func_cb(cmd_buf, cmd_buf_size, rsp_buf, rsp_buf_size, rsp_buf_bytes_filled); + } + + return status; +} + + +int32_t ats_dls_init(ATS_DSL_TCPIP_SEND_CALLBACK callback) +{ + int32_t status = AR_EOK; + + status = gsl_dls_client_is_feature_supported(); + if (AR_FAILED(status)) + { + ATS_DBG("dls support is not enabled in this build"); + return status; + } + + // ar_set_log_level(AR_CRITICAL|AR_ERROR|AR_INFO|AR_DEBUG); + + ATS_DBG("Registering ATS Relatime Monitoring Service..."); + + status = ar_osal_mutex_create(&buffer_ready_lock); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to create buffer ready lock", status); + return status; + } + + status = ats_register_service(ATS_DLS_SERVICE_ID, ats_dls_ioctl); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to register the ATS Data Logging Service.", status); + goto destroy_lock; + } + + buffer_pool_config.buffer_size = ATS_DEFAULT_DLS_BUFFER_SIZE; + buffer_pool_config.buffer_count = ATS_DEFAULT_DLS_BUFFER_COUNT; + + status = gsl_dls_client_init(&buffer_pool_config, ats_dls_buffer_ready_callback); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed initialize dls client", status); + goto destroy_lock; + } + //allocate buffer for storing dls log buffer + + dls_data_send_buffer.buffer_size = buffer_pool_config.buffer_count *buffer_pool_config.buffer_size; + dls_data_send_buffer.buffer = ACDB_MALLOC(uint8_t, dls_data_send_buffer.buffer_size); + + ats_dls_tcpip_send_callback = callback; + + //start ready buffer thread + ats_dls_create_ready_buffer_thread(); +destroy_lock: + if(AR_FAILED(status)) + { + ar_osal_thread_join_destroy(thd_ready_buffer_routine); + ar_osal_mutex_destroy(buffer_ready_lock); + } + + return status; +} + +int32_t ats_dls_deinit(void) +{ + int32_t status = AR_EOK; + + status = gsl_dls_client_is_feature_supported(); + if (AR_FAILED(status)) + { + ATS_DBG("dls support is not enabled in this build"); + return status; + } + + ATS_DBG("Deregistering ATS Data Logging Service..."); + + status = gsl_dls_client_deinit(); + if (status != AR_EOK) + { + ATS_DBG("Error[%d]: Failed to deinitialize gsl dls client", status, 0); + } + + status = ats_deregister_service(ATS_DLS_SERVICE_ID); + if (status != AR_EOK) + { + ATS_DBG("Error[%d]: Failed to deregister ATS Data Logging Service.", status, 0); + } + + ar_osal_mutex_destroy(buffer_ready_lock); + + thd_ready_buffer_routine_active = false; + ar_osal_thread_join_destroy(thd_ready_buffer_routine); + //free ats dls send buffer + + return status; +} + +int32_t ats_dls_buffer_ready_callback(void) +{ + int32_t status = AR_EOK; + uint32_t bytes_written = 0; + + ACDB_MUTEX_LOCK(buffer_ready_lock); + + ar_mem_set(dls_data_send_buffer.buffer, 0, dls_data_send_buffer.buffer_size); + + status = ats_dls_get_log_data(NULL, 0, + dls_data_send_buffer.buffer, + dls_data_send_buffer.buffer_size, + &bytes_written); + + ATS_DBG("calling ats dls tcpip send callback. sending %d bytes", bytes_written); + ats_dls_tcpip_send_callback(dls_data_send_buffer.buffer, bytes_written); + + ACDB_MUTEX_UNLOCK(buffer_ready_lock); + + return status; +} diff --git a/acdb/ats/fts/common/inc/ats_fts.h b/acdb/ats/fts/common/inc/ats_fts.h new file mode 100644 index 0000000..83bb9e2 --- /dev/null +++ b/acdb/ats/fts/common/inc/ats_fts.h @@ -0,0 +1,76 @@ +#ifndef _ATS_FTS_H_ +#define _ATS_FTS_H_ +/** +*============================================================================== +* \file ats_fts.h +* \brief +* A T S F T S H E A D E R F I L E +* +* The File Transfer Service(FTS) header file contains all the +* definitions necessary for ATS to handle requests that operate ACDB SW +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ +#include "ats_i.h" +#include "ar_osal_mutex.h" +/*----------------------------------------------------------------------------- +* Defines and Constants +*----------------------------------------------------------------------------*/ +#define ATS_FTS_MAJOR_VERSION 0x1 +#define ATS_FTS_MINOR_VERSION 0x0 + +#define FTS_MAX_FILE_COUNT 100 + +typedef struct fts_file_table_t FtsFileTable; +#include "acdb_begin_pack.h" +struct fts_file_table_t { + ar_osal_mutex_t lock; + ar_fhandle fhandle[FTS_MAX_FILE_COUNT]; +} +#include "acdb_end_pack.h" +; + +/* --------------------------------------------------------------------------- +* Public Functions +*-------------------------------------------------------------------------- */ + +/** +* \brief +* The File Transfer Service IOCTL +* \param [in] svc_cmd_id: The command to be issued +* \param [in] cmd_buf: Pointer to the command structure. +* \param [in] cmd_buf_size: Size of the command structure +* \param [out] rsp_buf: The response structre +* \param [in] rsp_buf_size: The size of the response +* \param [out] rsp_buf_bytes_filled: Number of bytes written to the response buffer +* \return 0 on success, non-zero on failure +*/ +int32_t ats_fts_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +); + +/** +* \brief +* Initializes the file transfer service to allow interaction between +* ACDB SW and and QST clients. +* \return AR_EOK, AR_EFAILED, AR_EHANDLE +*/ +int32_t ats_fts_init(void); + +/** +* \brief +* Deinitializes the file transfer service to allow interaction between +* ACDB SW and and QST clients. +* \return AR_EOK, AR_EFAILED, AR_EHANDLE +*/ +int32_t ats_fts_deinit(void); +#endif /*_ATS_FTS_H_*/ \ No newline at end of file diff --git a/acdb/ats/fts/common/src/ats_fts.c b/acdb/ats/fts/common/src/ats_fts.c new file mode 100644 index 0000000..bf6de66 --- /dev/null +++ b/acdb/ats/fts/common/src/ats_fts.c @@ -0,0 +1,333 @@ +/** +*============================================================================== +* \file ats_fts.c +* \brief +* A T S F T S S O U R C E F I L E +* +* The File Transfer Service(FTS) source file contains all the +* definitions necessary for ATS to handle requests that operate ACDB SW +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ats_fts.h" +#include "ats_i.h" +#include "acdb_utility.h" +#include "ats_common.h" + +/*------------------------------------------ +* Defines, Constants, Globals +*------------------------------------------*/ + +static FtsFileTable *fts_file_table = NULL; + +/*------------------------------------------ +* Private Functions +*------------------------------------------*/ + +int32_t fts_open_file( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t findex = 0; + AtsCmdFtsOpenFileReq req = { 0 }; + + *rsp_buf_bytes_filled = 0; + + if (cmd_buf_size < sizeof(AtsCmdFtsOpenFileReq)) + { + return AR_EBADPARAM; + } + + //Read Command Request + ATS_MEM_CPY_SAFE(&req.file_path_length, sizeof(uint32_t), cmd_buf + offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + req.file_path = (char*)cmd_buf + offset; + offset += req.file_path_length; + + ATS_MEM_CPY_SAFE(&req.access, sizeof(uint32_t), cmd_buf + offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + ATS_DBG("Opening/creating %s...", req.file_path); + + //Search for avalible file slot + for (; findex < FTS_MAX_FILE_COUNT; findex++) + if (fts_file_table->fhandle[findex] == NULL) + break; + + if (findex >= FTS_MAX_FILE_COUNT) + { + ATS_ERR("Max number of files reached"); + return AR_ENORESOURCE; + } + + //fts_file_table->fhandle[findex] = ACDB_MALLOC(ar_fhandle, 1); + //if (IsNull(fts_file_table->fhandle[findex])) + //{ + // ATS_ERR("Failed to allocate memory for file handle"); + // return AR_ENOMEMORY; + //} + + status = ar_fopen(&fts_file_table->fhandle[findex], req.file_path, req.access); + if (AR_FAILED(status)) + { + ATS_ERR("Error(%d), FileAccessType(%d): Failed to open/create %s", status, req.access, req.file_path); + ACDB_FREE(fts_file_table->fhandle[findex]); + return status; + } + + //Add file handle to resonse buffer + ATS_MEM_CPY_SAFE(rsp_buf, sizeof(uint32_t), &findex, sizeof(uint32_t)); + *rsp_buf_bytes_filled = sizeof(uint32_t); + + return status; +} + +int32_t fts_write_file( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + size_t bytes_written = 0; + AtsCmdFtsWriteFileReq req = { 0 }; + + if (cmd_buf_size < sizeof(AtsCmdFtsWriteFileReq)) + { + return AR_EBADPARAM; + } + + //Read Command Request + ATS_MEM_CPY_SAFE(&req.findex, sizeof(uint32_t), cmd_buf, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + ATS_MEM_CPY_SAFE(&req.write_size, sizeof(uint32_t), cmd_buf + offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + req.buf_ptr = cmd_buf + offset; + + //ATS_DBG("Writing to %s...", req.file_path); + ATS_DBG("Writing to file..."); + + if (req.findex >= FTS_MAX_FILE_COUNT) + { + ATS_ERR("Invalid file index"); + return AR_EHANDLE; + } + + if (fts_file_table->fhandle[req.findex] == NULL) + { + ATS_ERR("Invalid file handle"); + return AR_EHANDLE; + } + + status = ar_fwrite(fts_file_table->fhandle[req.findex], req.buf_ptr, req.write_size, &bytes_written); + if (AR_FAILED(status)) + { + ATS_ERR("Error(%d), WriteSize(%d) BytesWritten(%d): Failed to write data to file.", + status, req.write_size, bytes_written); + } + + //Write Command Response - add bytes written to response + req.bytes_writen = (uint32_t*)&bytes_written; + ATS_MEM_CPY_SAFE(rsp_buf, sizeof(uint32_t), &bytes_written, sizeof(uint32_t)); + *rsp_buf_bytes_filled = sizeof(uint32_t); + return status; +} + +int32_t fts_close_file( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + AtsCmdFtsCloseFileReq req = { 0 }; + + if (cmd_buf_size < sizeof(AtsCmdFtsCloseFileReq)) + { + return AR_EBADPARAM; + } + + ATS_MEM_CPY_SAFE(&req.findex, sizeof(uint32_t), cmd_buf, sizeof(uint32_t)); + + if (req.findex >= FTS_MAX_FILE_COUNT) + { + ATS_ERR("Invalid file index"); + return AR_EHANDLE; + } + + if (fts_file_table->fhandle[req.findex] == NULL) + { + ATS_ERR("Invalid file handle"); + return AR_EHANDLE; + } + + //ATS_DBG("Closing %s...", req.file_path); + ATS_DBG("Closing file..."); + + status = ar_fclose(fts_file_table->fhandle[req.findex]); + if (AR_FAILED(status)) + { + return status; + } + + *rsp_buf_bytes_filled = 0; + + return status; +} + +/*------------------------------------------ +* Public Functions +*------------------------------------------*/ + +int32_t ats_fts_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +) +{ + int32_t status = AR_EOK; + + int32_t(*func_cb)( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled + ) = NULL; + + status = ar_osal_mutex_lock(fts_file_table->lock); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to lock.", status); + return status; + } + + switch (svc_cmd_id) + { + case ATS_CMD_FTS_OPEN_FILE: + func_cb = fts_open_file; + break; + case ATS_CMD_FTS_WRITE_FILE: + func_cb = fts_write_file; + break; + case ATS_CMD_FTS_CLOSE_FILE: + func_cb = fts_close_file; + break; + default: + ATS_ERR("Command[%x] is not supported", svc_cmd_id); + status = AR_EUNSUPPORTED; + } + + if (status == AR_EOK) + { + status = func_cb(cmd_buf, + cmd_buf_size, + rsp_buf, + rsp_buf_size, + rsp_buf_bytes_filled); + } + + status = ar_osal_mutex_unlock(fts_file_table->lock); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to unlock.", status); + return status; + } + return status; +} + + +int32_t ats_fts_init(void) +{ + ATS_DBG("Registering File Transfer Service..."); + + int32_t status = AR_EOK; + + fts_file_table = ACDB_MALLOC(FtsFileTable, 1); + if (IsNull(fts_file_table)) + { + ATS_ERR("Error[%d]: Failed to allocate memory for file table.", status); + return status; + } + + ACDB_CLEAR_BUFFER(fts_file_table->fhandle); + + status = ar_osal_mutex_create(&fts_file_table->lock); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to create lock.", status); + return status; + } + + //status = ar_osal_mutex_init(fts_file_table->lock); + //if (AR_FAILED(status)) + //{ + // ATS_ERR("Error[%d]: Initialize lock.", status); + // return status; + //} + + status = ats_register_service(ATS_FTS_SERVICE_ID, ats_fts_ioctl); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to register the File Transfer Service.", status); + } + + return status; +} + +int32_t ats_fts_deinit(void) +{ + ATS_DBG("Deregistering File Transfer Service..."); + + int32_t status = AR_EOK; + + status = ats_deregister_service(ATS_FTS_SERVICE_ID); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to deregister the File Transfer Service.", status); + } + + status = ar_osal_mutex_destroy(fts_file_table->lock); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to destroy lock.", status); + return status; + } + + if (!IsNull(fts_file_table)) + ACDB_FREE(fts_file_table); + + return status; +} + diff --git a/acdb/ats/inc/ats_command.h b/acdb/ats/inc/ats_command.h new file mode 100644 index 0000000..a37f40a --- /dev/null +++ b/acdb/ats/inc/ats_command.h @@ -0,0 +1,55 @@ +#ifndef _ATS_COMMAND_H_ +#define _ATS_COMMAND_H_ +/** +*============================================================================== +* \file ats_command.h +* \brief +* A T S C M D H E A D E R F I L E +* +* The ATS CMD header file defines functionality that process requests +* from ATS clients and retrieves the response from ACDB. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +#include "acdb.h" +#include "acdb_file_mgr.h" +#include "acdb_delta_file_mgr.h" +#include "acdb_utility.h" +#include "acdb_data_proc.h" +#include "ats_common.h" +#include "ats_i.h" + +int32_t AtsCmdGetHostDatabaseFileSetInfo(AcdbFileManBlob *rsp); + +int32_t AtsCmdGetAllDatabasesFileSetInfo(AcdbFileManBlob* rsp); + +int32_t AtsCmdGetLoadedFileData(AcdbFileManGetFileDataReq *req, AcdbFileManBlob *rsp); + +int32_t AtsCmdGetHeapEntryInfo(acdb_handle_t acdb_handle, AcdbBufferContext* rsp); + +int32_t AtsCmdGetHeapEntryData(acdb_handle_t acdb_handle, AcdbGraphKeyVector* key_vector, AcdbBufferContext* rsp); + +int32_t AtsCmdGetCalDataNonPersist(AtsGetSubgraphCalDataReq *req, AcdbBufferContext *rsp); + +int32_t AtsCmdSetCalDataNonPersist(bool_t should_persist, AcdbGraphKeyVector* cal_key_vector, + AcdbSubgraphParamData* subgraph_param_data); + +int32_t AtsCmdGetCalDataPersist(AtsGetSubgraphCalDataReq *req, AcdbBufferContext *rsp); + +int32_t AtsCmdSetCalDataPersist(bool_t should_persist, AcdbGraphKeyVector* cal_key_vector, + AcdbSubgraphParamData* subgraph_param_data); + +int32_t AtsCmdGetTagData(AtsGetSubgraphTagDataReq* req, AcdbBufferContext *rsp); + +int32_t AtsCmdSetTagData(bool_t should_persist, AcdbModuleTag* module_tag, + AcdbSubgraphParamData* subgraph_param_data); + +int32_t AtsCmdDeleteDeltaFiles(void); + +int32_t AtsCmdGetTempFilePath(uint32_t acdb_handle, AtsGetTempPath* path); +#endif /*_ATS_COMMAND_H_*/ diff --git a/acdb/ats/inc/ats_common.h b/acdb/ats/inc/ats_common.h new file mode 100644 index 0000000..a634859 --- /dev/null +++ b/acdb/ats/inc/ats_common.h @@ -0,0 +1,40 @@ +#ifndef _ATS_COMMON_H_ +#define _ATS_COMMON_H_ +/** +*============================================================================= +* \file ats_common.h +* +* \brief +* Common header file used by ATS modules. +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#include +#include +#include + +#include "ar_osal_types.h" +#include "ar_osal_log.h" +#include "ar_osal_mem_op.h" + +#define ATS_LOG_TAG "ATS" +#define ATS_ERR(...) AR_LOG_ERR(ATS_LOG_TAG, __VA_ARGS__) +#define ATS_DBG(...) AR_LOG_DEBUG(ATS_LOG_TAG, __VA_ARGS__) +#define ATS_INFO(...) AR_LOG_INFO(ATS_LOG_TAG, __VA_ARGS__) + +/* Error/Debug Message Format 1 +* \param msg Brief message describing the error +* \param err_code Error code to be logged +*/ +#define ATS_ERR_MSG_1(msg, err_code, ...) ATS_ERR("Error[%d]:%s", err_code, msg, __VA_ARGS__) +#define ATS_DBG_MSG_1(msg, err_code, ...) ATS_DBG("Error[%d]:%s", err_code, msg, __VA_ARGS__) + +#define ATS_ERR_MSG_2(msg, err_code, ...) ATS_ERR("Error[%d]:%s"##msg, err_code) + +#define ATS_MEM_CPY_SAFE(dest, dest_size, src, src_size) ar_mem_cpy((int8_t*) dest, dest_size, (int8_t*)src, src_size) + +#endif /*_ATS_COMMON_H_*/ diff --git a/acdb/ats/inc/ats_i.h b/acdb/ats/inc/ats_i.h new file mode 100644 index 0000000..f03b845 --- /dev/null +++ b/acdb/ats/inc/ats_i.h @@ -0,0 +1,3153 @@ +#ifndef __ATS_H_I__ +#define __ATS_H_I__ +/** +*============================================================================= +* \file ats.h +* \brief +* A T S I N T E R N A L +* H E A D E R F I L E +* +* This header file contains all the definitions necessary for the Audio +* Tuning Service to handle request buffer and operate ACDB +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#include "ar_osal_error.h" +#include "ar_osal_types.h" +#include "acdb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------------------------- +** flag, page size, and buffer length definition for ats_main_buffer +*----------------------------------------------------------------------------*/ +#define ATS_1_KB 1024UL +#define ATS_BUFFER_LENGTH 0x200000 +#define ATS_MIN_BUFFER_LENGTH ATS_1_KB * 32UL +#define ATS_HEADER_LENGTH 8 + +#define ATS_SERVICE_COMMAND_ID_LENGTH 4 +#define ATS_DATA_LENGTH_LENGTH 4 +#define ATS_ERROR_CODE_LENGTH 4 +#define ATS_ERROR_FRAME_LENGTH 12 + +#define ATS_SERVICE_COMMAND_ID_POSITION 0 +#define ATS_DATA_LENGTH_POSITION 4 +#define ATS_ACDB_BUFFER_POSITION 8 + +/*----------------------------------------------------------------------------- +* Macros for ATS Services +*----------------------------------------------------------------------------*/ + +/**< Extract the service id from the MSW of the 4byte service command id x*/ +#define ATS_GET_SERVICE_ID(x) ((0xFFFF0000 & x)) + +#define ATS_SERVICE_ID_INITIALIZER(x){ (char)(x >> 24), (char)(x >> 16), 0} +#define ATS_SEVICE_ID_STR_LEN (3) +/**< Set the 'x'(the service command id) to the arr to create a service command id string x. +* arr must be initialized with 3 bytes +*/ +#define ATS_SERVICE_ID_STR(arr, sz, x) \ +do {\ +int svc_str_len = ATS_SEVICE_ID_STR_LEN; \ +if(sz == svc_str_len)\ +{ \ +arr[0] = (char)(x >> 24); \ +arr[1] = (char)(x >> 16); \ +arr[2] = 0; \ +}\ +break; \ +}while(0) + +#define ATS_READ_SEEK_I(value, buf, offset, type)\ +do {\ +value = *(uint32_t*)&buf[offset]; \ +offset += sizeof(type); \ +break; \ +}while(0) + +#define ATS_READ_SEEK_I_ANY(value, buf, offset, type)\ +do {\ +value = *(type*)&buf[offset]; \ +offset += sizeof(type); \ +break; \ +}while(0) + +#define ATS_READ_SEEK_UI32(value, buf, offset) \ + ATS_READ_SEEK_I(value, buf, offset, uint32_t) + +#define ATS_READ_SEEK_I32(value, buf, offset) \ + ATS_READ_SEEK_I(value, buf, offset, int32_t) + +#define ATS_READ_SEEK_UI16(value, buf, offset) \ + ATS_READ_SEEK_I_ANY(value, buf, offset, uint16_t) + +/**< Extract the command id from the LSW of the 4byte service command id x*/ +#define ATS_GET_COMMAND_ID(x) ((0x0000FFFFul & x)) + +/**< Defines command IDs for the Online Calibration service */ +#define ATS_ONLINE_CMD_ID(x) ((0x4F4Eul << 16) | (0xFFFFul & x)) +#define ATS_ONLINE_SERVICE_ID (0x4F4Eul << 16) + +/**< Defines command IDs for the Real Time Tuning service */ +#define ATS_RTC_SERVICE_ID (0x5254ul << 16) +#define ATS_RTC_CMD_ID(x) ((0x5254ul << 16) | (0xFFFFul & x)) + +/**< Defines command IDs for the Data logging service */ +#define ATS_DLS_SERVICE_ID (0x524dul << 16) +#define ATS_DLS_CMD_ID(x) ((0x524dul << 16) | (0xFFFFul & x)) + +/**< Defines command IDs for the File Transfer service */ +#define ATS_FTS_CMD_ID(x) ((0x4654ul << 16) | (0xFFFFul & x)) +#define ATS_FTS_SERVICE_ID (0x4654ul << 16) + +/**< Defines command IDs for the Media Control Service */ +#define ATS_MCS_CMD_ID(x) ((0x4D43ul << 16) | (0xFFFFul & x)) +#define ATS_MCS_SERVICE_ID (0x4D43ul << 16) + +/**< Defines command IDs for the Adie Codec RTC service */ +#define ATS_CODEC_RTC_CMD_ID(x) ((0x4152ul << 16) | (0xFFFFul & x)) +#define ATS_CODEC_RTC_SERVICE_ID (0x4152ul << 16) + +#define ATS_MAX_FILENAME_LENGTH 256 + +/*----------------------------------------------------------------------------- +* Common Types +*----------------------------------------------------------------------------*/ + +typedef struct _ats_buffer_t AtsBuffer; +struct _ats_buffer_t +{ + uint32_t buffer_size; + uint8_t *buffer; +}; + +typedef struct _ats_buffer_man_t AtsBufferManager; +struct _ats_buffer_man_t +{ + /**< Main ATS buffer used for storing the response of commands*/ + AtsBuffer main_buffer; + /**< Main ATS Server message buffer used for storing complete messages recieved from TCP/IP clients*/ + AtsBuffer msg_buffer; + /**< Main ATS Server recieve buffer used for storing messages recieved from TCP/IP clients*/ + AtsBuffer recieve_buffer; +}; + +extern AtsBufferManager *ats_buffer_manager; +extern AtsBuffer ats_main_buffer; + +//TODO: Move to bottom of file +//void GetBufferManager(AtsBufferManager** buffer_man) +//{ +// *buffer_man = ats_buffer_manager; +//} + +/**< Holds the version information*/ +typedef struct _ats_version_t AtsVersion; +#include "acdb_begin_pack.h" +struct _ats_version_t +{ + /**< Major version*/ + uint32_t major; + /**< Minor version*/ + uint32_t minor; +} +#include "acdb_end_pack.h" +; +/*----------------------------------------------------------------------------- +* ATS Commands +*----------------------------------------------------------------------------*/ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_GET_VERSION Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_GET_VERSION +\{ */ + +/** + Queries for the ATS Real Time Calibration service version. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_GET_VERSION. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + Pointer to AtsVersion + \param[in] rsp_size + Size of AtsVersion + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_RT_GET_VERSION ATS_RTC_CMD_ID(1) +/** \} */ /* end_addtogroup ATS_CMD_RT_GET_VERSION */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_GET_ACTIVE_INFO Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_GET_ACTIVE_INFO +\{ */ + +/** + Queries ATS for the active usecase information. The active usecase is + provided by GSL. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_GET_ACTIVE_INFO. + \param[in] cmd + Pointer to AtsActiveUsecaseInfo. + \param[in] cmd_size + Size of AtsActiveUsecaseInfo. + \param[out] rsp + Pointer to AtsCmdRtGetActiveInfoRsp + \param[in] rsp_size + Size of AtsCmdRtGetActiveInfoRsp + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_RT_GET_ACTIVE_INFO ATS_RTC_CMD_ID(2) +/**< Holds the active usecase information provided by GSL*/ +typedef struct ats_cmd_rt_active_usecase_info_t AtsActiveUsecaseInfo; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_active_usecase_info_t +{ + /**< Handle to a usecase(collection of graphs) provided by gsl_open*/ + uint32_t usecase_handle; + /**< Number of active graphs*/ + uint32_t num_graphs; + /**< List of Graph Key vectors for each graph*/ + AcdbGraphKeyVector *graph_key_vector; + /**< Number of Calibration Key vectors. There is one for each Graph Key Vector*/ + uint32_t num_cal_key_vectors; + /**< Calibration key vector*/ + AcdbGraphKeyVector *cal_key_vector; +} +#include "acdb_end_pack.h" +; + +/**< The response structure for ATS_CMD_RT_GET_ACTIVE_INFO*/ +typedef struct ats_cmd_rt_get_active_info_rsp_t AtsCmdRtGetActiveInfoRsp; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_get_active_info_rsp_t +{ + /**< Total size of the active usecase information*/ + uint32_t size; + /**< Number of active usecases*/ + uint32_t num_usecases; + /**< List of currently active usecases*/ + AtsActiveUsecaseInfo *active_usecases; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_GET_ACTIVE_INFO */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_GET_CAL_DATA_NON_PERSISTENT Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_GET_CAL_DATA_NON_PERSISTENT +\{ */ + +/** + Queries ATS for the non-persistent calibration data for all SPF modules + instances for a given subgraph. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_GET_CAL_DATA_NON_PERSISTENT. + \param[in] cmd + Pointer to AtsCmdRtGetCalDataNonPersistentReq. + \param[in] cmd_size + Size of AtsCmdRtGetCalDataNonPersistentReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_RT_GET_CAL_DATA_NON_PERSISTENT ATS_RTC_CMD_ID(3) +/**< The request structure for ATS_CMD_RT_GET_CAL_DATA_NON_PERSISTENT*/ +typedef struct ats_cmd_rt_get_cal_data_non_persist_req_t AtsCmdRtGetCalDataNonPersistentReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_get_cal_data_non_persist_req_t +{ + /**< Handle to a graph provided by gsl_open*/ + uint32_t graph_handle; + /**< Subgraph ID*/ + uint32_t subgraph_id; + /**< Size of the subgraph calibration data*/ + uint32_t data_size; + /**< [in/out] Subgraph calibration data. Format: + [module_id, param_id, param_size, err_code, payload[param_size]] + */ + uint8_t *subgraph_cal_data; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_GET_CAL_DATA_NON_PERSISTENT */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_GET_CAL_DATA_PERSISTENT Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_GET_CAL_DATA_PERSISTENT +\{ */ + +/** + Queries ATS for the persistent calibration data for all SPF modules + instances for a given subgraph. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_GET_CAL_DATA_PERSISTENT. + \param[in] cmd + Pointer to AtsCmdRtGetCalDataPersistentReq. + \param[in] cmd_size + Size of AtsCmdRtGetCalDataPersistentReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_RT_GET_CAL_DATA_PERSISTENT ATS_RTC_CMD_ID(4) +/**< The request structure for ATS_CMD_RT_GET_CAL_DATA_PERSISTENT*/ +typedef struct ats_cmd_rt_get_cal_data_persist_req_t AtsCmdRtGetCalDataPersistentReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_get_cal_data_persist_req_t +{ + /**< Handle to a graph provided by gsl_open*/ + uint32_t graph_handle; + /**< Subgraph ID*/ + uint32_t subgraph_id; + /**< Size of the subgraph calibration data*/ + uint32_t data_size; + /**< [in/out] Subgraph calibration data. Format: + [module_id, param_id, param_size, err_code, payload[param_size]] + */ + uint8_t *subgraph_cal_data; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_GET_CAL_DATA_PERSISTENT */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_GET_CAL_DATA_GBL_PERSISTENT Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_GET_CAL_DATA_GBL_PERSISTENT +\{ */ + +/** + Queries ATS for the globally-persisent calibration data for a signle + PID of a module instance from GSL. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_GET_CAL_DATA_GBL_PERSISTENT. + \param[in] cmd + Pointer to AtsCmdRtGetCalDataGblPersistentReq. + \param[in] cmd_size + Size of AtsCmdRtGetCalDataGblPersistentReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_RT_GET_CAL_DATA_GBL_PERSISTENT ATS_RTC_CMD_ID(5) +/**< The request structure for ATS_CMD_RT_GET_CAL_DATA_GBL_PERSISTENT*/ +typedef struct ats_cmd_rt_get_cal_data_global_persist_req_t AtsCmdRtGetCalDataGblPersistentReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_get_cal_data_global_persist_req_t +{ + /**< Calibration identifier*/ + uint32_t cal_id; + /**< Size of the parameter calibration data*/ + uint32_t data_size; + /**< [in/out] Parameter calibration data. Format: + [param_id, param_size, err_code, payload[param_size]] + */ + uint8_t *param_cal_data; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_GET_CAL_DATA_GBL_PERSISTENT */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_SET_CAL_DATA_NON_PERSISTENT Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_SET_CAL_DATA_NON_PERSISTENT +\{ */ + +/** + Set non-persistent subgraph calibration data to SPF. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_SET_CAL_DATA_NON_PERSISTENT. + \param[in] cmd + Pointer to AtsCmdRtSetCalDataNonPersistentReq. + \param[in] cmd_size + Size of AtsCmdRtSetCalDataNonPersistentReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_RT_SET_CAL_DATA_NON_PERSISTENT ATS_RTC_CMD_ID(6) +/**< The request structure for ATS_CMD_RT_SET_CAL_DATA_NON_PERSISTENT*/ +typedef struct ats_cmd_rt_set_cal_data_non_persist_req_t AtsCmdRtSetCalDataNonPersistentReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_set_cal_data_non_persist_req_t +{ + /**< Handle to a graph provided by gsl_open*/ + uint32_t graph_handle; + /**< Subgraph ID*/ + uint32_t subgraph_id; + /**< Size of the subgraph calibration data*/ + uint32_t data_size; + /**< [out] Subgraph calibration data. Format: + [module_id, param_id, param_size, err_code, payload[param_size]] + */ + uint8_t *subgraph_cal_data; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_SET_CAL_DATA_NON_PERSISTENT */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_SET_CAL_DATA_PERSISTENT Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_SET_CAL_DATA_PERSISTENT +\{ */ + +/** + Set persistent subgraph calibration data to SPF. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_SET_CAL_DATA_PERSISTENT. + \param[in] cmd + Pointer to AtsCmdRtSetCalDataPersistentReq. + \param[in] cmd_size + Size of AtsCmdRtSetCalDataPersistentReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_RT_SET_CAL_DATA_PERSISTENT ATS_RTC_CMD_ID(7) +/**< The request structure for ATS_CMD_RT_SET_CAL_DATA_PERSISTENT*/ +typedef struct ats_cmd_rt_set_cal_data_persist_req_t AtsCmdRtSetCalDataPersistentReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_set_cal_data_persist_req_t +{ + /**< Handle to a graph provided by gsl_open*/ + uint32_t graph_handle; + /**< Subgraph ID*/ + uint32_t subgraph_id; + /**< Size of the subgraph calibration data*/ + uint32_t data_size; + /**< [out] Subgraph calibration data. Format: + [module_id, param_id, param_size, err_code, payload[param_size]] + */ + uint8_t *subgraph_cal_data; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_SET_CAL_DATA_PERSISTENT */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH + \{ */ + +/** + Notifies GSL about graph modifications that are going to take place. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH. + \param[in] cmd + Pointer to AtsCmdRtGmUpdateDataReq. + \param[in] cmd_size + Size of AtsCmdRtGmUpdateDataReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa none +*/ +#define ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH ATS_RTC_CMD_ID(8) + +typedef struct _ats_list_t AtsList; +#include "acdb_begin_pack.h" +struct _ats_list_t +{ + /**< Number of items in list */ + uint32_t count; + /**< list of items */ + void *list; +} +#include "acdb_end_pack.h" +; + +/**< The request structure for ATS_CMD_RT_GM_UPDATE_DATA*/ +typedef struct ats_cmd_rt_gm_prep_change_graph_req_t AtsCmdRtGmPrepChangeGraphReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_gm_prep_change_graph_req_t +{ + /**< Handle to a graph provided by gsl_open */ + uint32_t graph_handle; + /**< The old graph keys for the updated/new usecase */ + AcdbGraphKeyVector old_graph_key_vector; + /**< The new graph keys for the updated/new usecase */ + AcdbGraphKeyVector new_graph_key_vector; + /**< The updated calibration keys for the updated/new usecase */ + AcdbGraphKeyVector new_cal_key_vector; + /**< List of subgraph after modifications */ + AtsList post_modification_subgraph_list; + /**< List of subgraph modified at run-time */ + AtsList modified_subgraph_list; + /**< List of subgraph pairs */ + AtsList subgraph_conn_list; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_GM_CHANGE_GRAPH Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_GM_UPDATE_DATA + \{ */ + +/** + Notifies GSL about graphs that have been prepared using ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH + + \param[in] cmd_id + Command ID is ATS_CMD_RT_GM_CHANGE_GRAPH. + \param[in] cmd + Pointer to AtsCmdRtGmUpdateDataReq. + \param[in] cmd_size + Size of AtsCmdRtGmUpdateDataReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa none +*/ +#define ATS_CMD_RT_GM_CHANGE_GRAPH ATS_RTC_CMD_ID(9) + +/**< The request structure for ATS_CMD_RT_GM_CHANGE_GRAPH*/ +typedef struct ats_cmd_rt_gm_change_graph_req_t AtsCmdRtGmChangeGraphReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_gm_change_graph_req_t +{ + /**< Handle to a graph provided by gsl_open */ + uint32_t graph_handle; + /**< The old graph keys for the updated/new usecase */ + AcdbGraphKeyVector old_graph_key_vector; + /**< The new graph keys for the updated/new usecase */ + AcdbGraphKeyVector new_graph_key_vector; + /**< The updated calibration keys for the updated/new usecase */ + AcdbGraphKeyVector new_cal_key_vector; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_GM_UPDATE_DATA */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_OPEN_GRAPH Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_OPEN_GRAPH + \{ */ + +/** + Opens a graph on GSL and returns a graph handle for the opened graph + + \param[in] cmd_id + Command ID is ATS_CMD_RT_GM_CHANGE_GRAPH. + \param[in] cmd + Pointer to AtsCmdRtGmUpdateDataReq. + \param[in] cmd_size + Size of AtsCmdRtGmUpdateDataReq. + \param[out] rsp + A uint32_t graph handle + \param[in] rsp_size + Size of a uint32_t + + \return + - CASA_EOK -- Command executed successfully. + - CASA_EBADPARAM -- Invalid input parameters were provided. + - CASA_EFAILED -- Command execution failed. + - CASA_EHANDLE -- Graph handle is invalid. + + \sa + ATS_CMD_RT_CLOSE_GRAPH +*/ +#define ATS_CMD_RT_OPEN_GRAPH ATS_RTC_CMD_ID(10) + +/**< The request structure for ATS_CMD_RT_OPEN_GRAPH*/ +typedef struct ats_cmd_rt_graph_open_req_t AtsCmdRtGraphOpenReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_graph_open_req_t +{ + /**< The new graph keys for the updated/new usecase */ + AcdbGraphKeyVector graph_key_vector; + /**< The updated calibration keys for the updated/new usecase */ + AcdbGraphKeyVector cal_key_vector; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_OPEN_GRAPH */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_OPEN_GRAPH Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_CLOSE_GRAPH + \{ */ + +/** + Closes an open graph on GSL + + \param[in] cmd_id + Command ID is ATS_CMD_RT_CLOSE_GRAPH. + \param[in] cmd + Pointer to AtsCmdRtGraphClose. + \param[in] cmd_size + Size of AtsCmdRtGraphClose. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + Size of AtsCmdRtGraphClose. + + \return + - CASA_EOK -- Command executed successfully. + - CASA_EBADPARAM -- Invalid input parameters were provided. + - CASA_EFAILED -- Command execution failed. + - CASA_EHANDLE -- Graph handle is invalid. + + \sa + ATS_CMD_RT_OPEN_GRAPH +*/ +#define ATS_CMD_RT_CLOSE_GRAPH ATS_RTC_CMD_ID(11) + +/**< The request structure for ATS_CMD_RT_CLOSE_GRAPH*/ +typedef struct ats_cmd_rt_graph_close_req_t AtsCmdRtGraphCloseReq; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_graph_close_req_t +{ + /**< Handle to a graph provided by gsl_open */ + uint32_t graph_handle; +} +#include "acdb_end_pack.h" +; + +/** \} */ /* end_addtogroup ATS_CMD_RT_CLOSE_GRAPH */ + + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_NOTIFY_CONNECTION_STATE Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_NOTIFY_CONNECTION_STATE + \{ */ + +/** +* Notifies the Audio Driver about the ATS client's connection state. +* +* NOTE: This API must be called before performing any RTGM operations with +* ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH and ATS_CMD_RT_GM_CHANGE_GRAPH +* +* \param[in] cmd_id +* Command ID is ATS_CMD_RT_GM_SET_SESSION_STATE. +* \param[in] cmd +* Pointer to AtsCmdRtSetSessionState. +* \param[in] cmd_size +* Size of AtsCmdRtSetSessionState. +* \param[out] rsp +* There is no output structure; set this to NULL. +* \param[in] rsp_size +* There is no output structure; set this to 0. +* Size of AtsCmdRtGraphClose. +* +* \return +* - CASA_EOK -- Command executed successfully. +* - CASA_EBADPARAM -- Invalid input parameters were provided. +* - CASA_EFAILED -- Command execution failed. +* - CASA_EHANDLE -- Graph handle is invalid. +* +* \sa +* ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH +* ATS_CMD_RT_GM_CHANGE_GRAPH +*/ +#define ATS_CMD_RT_NOTIFY_CONNECTION_STATE ATS_RTC_CMD_ID(12) + + /**< The request structure for ATS_CMD_RT_CLOSE_GRAPH*/ +typedef struct ats_cmd_rt_notify_connection_state_t AtsCmdRtNotifyConnectionState; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_notify_connection_state_t +{ + /**< Handle to a graph provided by gsl_open */ + uint32_t graph_handle; +} +#include "acdb_end_pack.h" +; + +/** \} */ /* end_addtogroup ATS_CMD_RT_NOTIFY_CONNECTION_STATE */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_GET_CAL_DATA_PERSISTENT_V2 Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_GET_CAL_DATA_PERSISTENT_V2 +\{ */ + +/** +* Retrieves persistent calibration for a subgraph from the shared memory +* managed by GSL. Calibration is returned for a persistent PIDs that +* have the tool policies: +* 1. RTC_READ_ONLY +* 2. RTC_CALIBRATION +* +* The format of the response blob is: +* +* *------------------------------------------* +* | Buffer Size | +* *------------------------------------------* +* | | +* *------------------------------------------* +* | ... | +* *------------------------------------------* +* | | +* *------------------------------------------* +* +* \param[in] cmd_id +* Command ID is ATS_CMD_RT_GET_CAL_DATA_PERSISTENT_V2. +* \param[in] cmd +* Pointer to AtsCmdRtGetCalDataPersistentReq. +* \param[in] cmd_size +* Size of AtsCmdRtGetCalDataPersistentReq. +* \param[out] rsp +* Pointer to AcdbBlob +* \param[in] rsp_size +* Size of AcdbBlob +* +* \return +* - AR_EOK -- Command executed successfully. +* - AR_EBADPARAM -- Invalid input parameters were provided. +* - AR_EFAILED -- Command execution failed. +* +* \sa TODO +*/ +#define ATS_CMD_RT_GET_CAL_DATA_PERSISTENT_V2 ATS_RTC_CMD_ID(13) + +typedef enum ats_calibration_type_t +{ + ATS_CAL_TYPE_AUDIO = 0x0, + ATS_CAL_TYPE_VOICE = 0x1, +}AtsCalibrationType; + +typedef struct ats_uint_list_za_t AtsUintList; +#include "acdb_begin_pack.h" +struct ats_uint_list_za_t +{ + uint32_t count; + uint32_t list[0]; +} +#include "acdb_end_pack.h" +; + +/**< The request structure for ATS_CMD_RT_GET_CAL_DATA_PERSISTENT*/ +typedef struct ats_cmd_rt_get_cal_data_persist_req_v2_t AtsCmdRtGetCalDataPersistV2Req; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_get_cal_data_persist_req_v2_t +{ + /**< Handle to a graph provided by gsl_open*/ + uint32_t graph_handle; + /**< Subgraph ID*/ + uint32_t subgraph_id; + /**< The ID of the processor the sugraph is running on */ + uint32_t proc_id; + /**< The type of subgraph cal data: voice, audio, etc.. */ + uint32_t cal_type; + /**< Size of [iid, pid] pair list */ + uint32_t list_size; + /**< List of IID, PIDs to get persistent cal for */ + AtsUintList iid_pid_pair_list; +} +#include "acdb_end_pack.h" +; + +/**< The response structure for ATS_CMD_RT_GET_CAL_DATA_PERSISTENT*/ +typedef struct ats_cmd_rt_get_cal_data_persist_v2_rsp_t AtsCmdRtGetCalDataPersistV2Rsp; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_get_cal_data_persist_v2_rsp_t +{ + /**< Handle to a graph provided by gsl_open*/ + uint32_t graph_handle; + /**< Subgraph ID*/ + uint32_t subgraph_id; + /**< Size of the subgraph calibration data*/ + uint32_t data_size; + uint32_t sg_cal_type; + /**< [in/out] Subgraph calibration data. Format: + [module_id, param_id, param_size, err_code, payload[param_size]] + */ + uint32_t count; + uint32_t *iid_pid_list; + AcdbUintList param_list; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_GET_CAL_DATA_PERSISTENT_V2 */ + + +/* --------------------------------------------------------------------------- +* ATS_CMD_RT_SET_CAL_DATA_PERSISTENT_V2 Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_RT_SET_CAL_DATA_PERSISTENT_V2 +\{ */ + +/** + Set persistent subgraph calibration data to SPF. + + \param[in] cmd_id + Command ID is ATS_CMD_RT_SET_CAL_DATA_PERSISTENT_V2. + \param[in] cmd + Pointer to AtsCmdRtSetCalDataPersistentReq. + \param[in] cmd_size + Size of AtsCmdRtSetCalDataPersistentReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_RT_SET_CAL_DATA_PERSISTENT_V2 ATS_RTC_CMD_ID(14) +/**< The request structure for ATS_CMD_RT_SET_CAL_DATA_PERSISTENT_V2*/ +typedef struct ats_cmd_rt_set_cal_data_persist_req_v2_t AtsCmdRtSetCalDataPersistentReqV2; +#include "acdb_begin_pack.h" +struct ats_cmd_rt_set_cal_data_persist_req_v2_t +{ + /**< Handle to a graph provided by gsl_open*/ + uint32_t graph_handle; + /**< Subgraph ID*/ + uint32_t subgraph_id; + /**< Processor ID*/ + uint32_t proc_id; + /**< Size of the subgraph calibration data*/ + uint32_t data_size; + /**< [out] Subgraph calibration data. Format: + [module_id, param_id, param_size, err_code, payload[param_size]] + */ + uint8_t *subgraph_cal_data; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_RT_SET_CAL_DATA_PERSISTENT_V2 */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_MCS_PLAY Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_MCS_PLAY +\{ */ + +/** + Start a playback session with the provided usecase, calibration, and + audio file. + + \param[in] cmd_id + Command ID is ATS_CMD_MCS_PLAY. + \param[in] cmd + Pointer to AtsCmdMcsPlayReq. + \param[in] cmd_size + Size of AtsCmdMcsPlayReq. + \param[out] rsp + There is no ouput structure; set this to NULL. + \param[in] rsp_size + There is no ouput structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_MCS_PLAY ATS_MCS_CMD_ID(1) + +/**< Specifies the set of playback modes used in the ATS_CMD_MCS_PLAY request*/ +typedef enum ATS_MCS_PLAYBACK_MODE +{ + ATS_PLAYBACK_REGULAR, + ATS_PLAYBACK_ANC_S_PATH, + ATS_PLAYBACK_ANC_E_PATH, + ATS_PLAYBACK_RAS, +} AtsMcsPlaybackMode; + +/**< Media properties for a device or stream*/ +typedef struct ats_mcs_properties_t McsProperties; +#include "acdb_begin_pack.h" +struct ats_mcs_properties_t +{ + /**< The device/stream sample rate*/ + uint32_t sample_rate; + /**< The bit width of each sample*/ + uint16_t bit_width; + /**< Indicates the alignment of bits_per_sample in sample_word_size.Relevant only when bits_per_sample is 24 and word_size is 32*/ + uint16_t alignment; + /**< Bits needed to store one sample*/ + uint16_t bits_per_sample; + /**< Q factor of the PCM data*/ + uint16_t q_factor; + /**< Indicates whether PCM samples are stored in little endian or big endian format.*/ + uint16_t endianness; + /**< Number of channels*/ + uint16_t num_channels; + /**< Determines what channels are used. Up to 32 channels are supported. If not supported set to 0*/ + uint8_t *channel_mapping; +} +#include "acdb_end_pack.h" +; + +/**< The request structure for ATS_CMD_MCS_PLAY*/ +typedef struct ats_cmd_mcs_play_req_t AtsCmdMcsPlayReq; +#include "acdb_begin_pack.h" +struct ats_cmd_mcs_play_req_t +{ + /**< playback device properties*/ + McsProperties device_properties; + /**< playback stream properties*/ + McsProperties stream_properties; + /**< Graph Key Vector representing the playback usecase*/ + AcdbGraphKeyVector graph_key_vector; + /**< Type of playback: 0(regular), 1(anc_spath), 2(anc_epath), 3(ras)*/ + AtsMcsPlaybackMode playback_mode; + /**< Playback duration in seconds*/ + int32_t playback_duration_sec; + /**< Length of the file name/path*/ + int32_t filename_len; + /**< Name of/path to file to save recording to*/ + char filename[ATS_MAX_FILENAME_LENGTH]; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_MCS_PLAY */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_MCS_RECORD Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_MCS_RECORD +\{ */ + +/** + Start a record session and save the output to the specified file using + the provided record usecase, duration, and calibration. + + \param[in] cmd_id + Command ID is ATS_CMD_MCS_RECORD. + \param[in] cmd + Pointer to AtsCmdMcsRecordReq. + \param[in] cmd_size + Size of AtsCmdMcsRecordReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_MCS_RECORD ATS_MCS_CMD_ID(2) + +/**< Specifies the set of recording modes used in the ATS_CMD_MCS_RECORD request*/ +typedef enum ATS_MCS_RECORD_MODE +{ + ATS_RECORD_REGULAR, + ATS_RECORD_ANC_P_PATH, + ATS_RECORD_ANC_S_PATH, + ATS_RECORD_ANC_E_PATH +} AtsMcsRecordMode; + +/**< The request structure for ATS_CMD_MCS_RECORD*/ +typedef struct ats_cmd_mcs_record_req_t AtsCmdMcsRecordReq; +#include "acdb_begin_pack.h" +struct ats_cmd_mcs_record_req_t +{ + /**< record device properties*/ + McsProperties device_properties; + /**< record stream properties*/ + McsProperties stream_properties; + /**< Graph Key Vector representing the record usecase*/ + AcdbGraphKeyVector graph_key_vector; + /**< Type of record: 0(regular), 1(aanc_path), 2(aanc_spath), 3(aanc_epath)*/ + AtsMcsRecordMode record_mode; + /**< Save recording to file: 0 (ignore write), 1 (write data)*/ + uint32_t write_to_file; + /**< Record duration in seconds*/ + int32_t record_duration_sec; + /**< Length of the file name/path*/ + int32_t filename_len; + /**< Name of/path to file to save recording to*/ + char filename[ATS_MAX_FILENAME_LENGTH]; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_MCS_RECORD */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_MCS_PLAY_RECORD Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_MCS_PLAY_RECORD +\{ */ + +/** + Start playback and record simultaneously. + + \param[in] cmd_id + Command ID is ATS_CMD_MCS_PLAY_RECORD. + \param[in] cmd + Pointer to AtsCmdMcsPlayRecordReq. + \param[in] cmd_size + Size of AtsCmdMcsPlayRecordReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa + - AtsCmdMcsPlayReq + - AtsCmdMcsRecordReq +*/ +#define ATS_CMD_MCS_PLAY_RECORD ATS_MCS_CMD_ID(3) +/**< The request structure for ATS_CMD_MCS_PLAY_RECORD*/ +typedef struct ats_cmd_mcs_play_record_req_t AtsCmdMcsPlayRecordReq; +#include "acdb_begin_pack.h" +struct ats_cmd_mcs_play_record_req_t +{ + AtsCmdMcsPlayReq playback_session; + AtsCmdMcsRecordReq record_session; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_MCS_PLAY_RECORD */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_MCS_STOP Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_MCS_STOP +\{ */ + +/** + Stop the active playback, record, or playback-record session. Releases all + resources allocated to MCS. + + \param[in] cmd_id + Command ID is ATS_CMD_MCS_STOP. + \param[in] cmd + There is no intput structure; set this to NULL. + \param[in] cmd_size + There is no intput structure; set this to 0. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_MCS_STOP ATS_MCS_CMD_ID(4) +/** \} */ /* end_addtogroup ATS_CMD_MCS_STOP */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_MCS_PLAY_2 Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_MCS_PLAY_2 +\{ */ + +/** + Start a playback session with the provided usecase, calibration, and + audio file. This provides the same functionality as ATS_CMD_MCS_PLAY + except that it allows the client to apply calibration, tag config, and + tag custom config data before starting the usecase. + + See MCS_CMD_PLAY_2 in mcs_api.h for command/response input and output + + \sa ATS_CMD_MCS_PLAY +*/ +#define ATS_CMD_MCS_PLAY_2 ATS_MCS_CMD_ID(5) +/** \} */ /* end_addtogroup ATS_CMD_MCS_PLAY_2 */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_MCS_RECORD_2 Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_MCS_RECORD_2 +\{ */ + +/** + Start a record session and save the output to the specified file using + the provided record usecase, duration, and calibration. This provides the + same functionality as ATS_CMD_MCS_RECORD except that it allows the client + to apply calibration, tag config, and tag custom config data before + + See MCS_CMD_REC_2 in mcs_api.h for command/response input and output + + \sa ATS_CMD_MCS_RECORD +*/ +#define ATS_CMD_MCS_RECORD_2 ATS_MCS_CMD_ID(6) +/** \} */ /* end_addtogroup ATS_CMD_MCS_RECORD_2 */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_MCS_MULTI_PLAY_REC Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_MCS_MULTI_PLAY_REC +\{ */ + +/** + Start the active playback, record, or playback-record session. Releases all + resources allocated to MCS. + + See MCS_CMD_MULTI_PLAY_REC in mcs_api.h for command/response input and output + + \sa ATS_CMD_MCS_PLAY_REC +*/ +#define ATS_CMD_MCS_MULTI_PLAY_REC ATS_MCS_CMD_ID(7) +/** \} */ /* end_addtogroup ATS_CMD_MCS_MULTI_PLAY_REC */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_MCS_STOP_2 Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_MCS_STOP_2 +\{ */ + +/** + Stop the active playback, record, or playback-record session. Releases all + resources allocated to MCS. + + See MCS_CMD_STOP_2 mcs_api.h for command/response input and output + + \sa ATS_CMD_MCS_STOP +*/ +#define ATS_CMD_MCS_STOP_2 ATS_MCS_CMD_ID(8) +/** \} */ /* end_addtogroup ATS_CMD_MCS_STOP_2 */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_FTS_OPEN_FILE Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_FTS_OPEN_FILE +\{ */ + +/** + Open or create a file on the file system with write permissions. + + \param[in] cmd_id + Command ID is ATS_CMD_FTS_OPEN_FILE. + \param[in] cmd + Pointer to AtsCmdFtsOpenFileReq. + \param[in] cmd_size + Size of AtsCmdFtsOpenFileReq. + \param[out] rsp + 4 byte file index + \param[in] rsp_size + Size of uint32_t + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_FTS_OPEN_FILE ATS_FTS_CMD_ID(1) +/**< The request structure for ATS_CMD_FTS_OPEN_FILE*/ +typedef struct ats_cmd_fts_open_file_req_t AtsCmdFtsOpenFileReq; +#include "acdb_begin_pack.h" +struct ats_cmd_fts_open_file_req_t +{ + /**< File path length*/ + uint32_t file_path_length; + /**< File path*/ + char *file_path; + /**< AR file access flag*/ + uint32_t access; +} +#include "acdb_end_pack.h" +; + +/** \} */ /* end_addtogroup ATS_CMD_FTS_OPEN_FILE */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_FTS_WRITE_FILE Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_FTS_WRITE_FILE +\{ */ + +/** + Writes data to a file using the provided file handle. + + \param[in] cmd_id + Command ID is ATS_CMD_FTS_WRITE_FILE. + \param[in] cmd + Pointer to AtsCmdFtsWriteFileReq. + \param[in] cmd_size + Size of AtsCmdFtsWriteFileReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa + - ATS_CMD_FTS_OPEN_FILE +*/ +#define ATS_CMD_FTS_WRITE_FILE ATS_FTS_CMD_ID(2) +/**< The request structure for ATS_CMD_FTS_WRITE_FILE*/ +typedef struct ats_cmd_fts_write_file_req_t AtsCmdFtsWriteFileReq; +#include "acdb_begin_pack.h" +struct ats_cmd_fts_write_file_req_t +{ + /**< File index for a file to write to*/ + uint32_t findex; + /**< [in] Size of the data to write*/ + uint32_t write_size; + /**< Pointer to the data to be written*/ + void *buf_ptr; + /**< [out] Number of bytes that are written*/ + uint32_t *bytes_writen; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_FTS_WRITE_FILE */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_FTS_CLOSE_FILE Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_FTS_CLOSE_FILE +\{ */ + +/** + Closes a file using the provided file handle. + + \param[in] cmd_id + Command ID is ATS_CMD_FTS_CLOSE_FILE. + \param[in] cmd + Pointer to AtsCmdFtsCloseFileReq. + \param[in] cmd_size + Size of AtsCmdFtsCloseFileReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa + - ATS_CMD_FTS_OPEN_FILE +*/ +#define ATS_CMD_FTS_CLOSE_FILE ATS_FTS_CMD_ID(3) +/**< The request structure for ATS_CMD_FTS_CLOSE_FILE*/ +typedef struct ats_cmd_fts_close_file_req_t AtsCmdFtsCloseFileReq; +#include "acdb_begin_pack.h" +struct ats_cmd_fts_close_file_req_t +{ + /**< File index for a file to close*/ + uint32_t findex; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_FTS_CLOSE_FILE */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ADIE_GET_VERSION Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ADIE_GET_VERSION +\{ */ + +/** + Queries ATS for the ADIE(Codec) Service version. + + \param[in] cmd_id + Command ID is ATS_CMD_ADIE_GET_VERSION. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + Pointer to AtsVersion + \param[in] rsp_size + Size of AtsVersion + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +//#define ATS_CMD_ADIE_GET_VERSION ATS_CODEC_RTC_CMD_ID(1) +/** \} */ /* end_addtogroup ATS_CMD_ADIE_GET_VERSION */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ADIE_GET_CODEC_INFO Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ADIE_GET_CODEC_INFO +\{ */ + +/** + Queries ATS for the Real Time Tuning service version. + + \param[in] cmd_id + Command ID is ATS_CMD_ADIE_GET_CODEC_INFO. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + Pointer to AtsCmdAdieGetCodecInfoRsp + \param[in] rsp_size + Size of AtsCmdAdieGetCodecInfoRsp + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_ADIE_GET_CODEC_INFO ATS_CODEC_RTC_CMD_ID(1) +/**< Holds the chipset ID and version information for a codec*/ +typedef struct codec_properties_t CodecProperties; +#include "acdb_begin_pack.h" +struct codec_properties_t +{ + /**< Codec handle*/ + uint32_t handle; + /**< ID of the codec chipset*/ + uint32_t chipset_id; + /**< Major version of the chipset*/ + uint32_t chipset_major; + /**< Minor version of the chipset*/ + uint32_t chipset_minor; +} +#include "acdb_end_pack.h" +; + +/**< The response structure for ATS_CMD_ADIE_GET_CODEC_INFO.*/ +typedef struct ats_cmd_adie_get_codec_info_rsp_t AtsCmdAdieGetCodecInfoRsp; +#include "acdb_begin_pack.h" +struct ats_cmd_adie_get_codec_info_rsp_t +{ + /**< Number of codec properties*/ + uint32_t property_count; + /**< List of codec properties*/ + CodecProperties *codec_properties; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_ADIE_GET_CODEC_INFO */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ADIE_GET_REGISTER Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ADIE_GET_REGISTER +\{ */ + +/** + Queries ATS for the register value for a given register. + + \param[in] cmd_id + Command ID is ATS_CMD_ADIE_GET_REGISTER. + \param[in] cmd + Pointer to AtsCmdAdieGetRegisterReq. + \param[in] cmd_size + Size of AtsCmdAdieGetRegisterReq. + \param[out] rsp + Pointer to AtsCmdAdieGetRegisterRsp. + \param[in] rsp_size + Size of AtsCmdAdieGetRegisterRsp. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_ADIE_GET_REGISTER ATS_CODEC_RTC_CMD_ID(2) +/**< The request structure for ATS_CMD_ADIE_GET_REGISTER.*/ +typedef struct ats_cmd_adie_get_register_req_t AtsCmdAdieGetRegisterReq; +#include "acdb_begin_pack.h" +struct ats_cmd_adie_get_register_req_t +{ + /**< Codec handle*/ + uint32_t codec_handle; + /**< ID of the register*/ + uint32_t register_id; + /**< The bit-mask for the register*/ + uint32_t register_mask; +} +#include "acdb_end_pack.h" +; + +/**< The response structure for ATS_CMD_ADIE_GET_REGISTER.*/ +typedef struct ats_cmd_adie_get_register_rsp_t AtsCmdAdieGetRegisterRsp; +#include "acdb_begin_pack.h" +struct ats_cmd_adie_get_register_rsp_t +{ + /**< The register value*/ + uint32_t register_value; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_ADIE_GET_REGISTER */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ADIE_GET_MULTIPLE_REGISTER Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ADIE_GET_MULTIPLE_REGISTER +\{ */ + +/** + Calls ATS_CMD_ADIE_GET_REGISTER for each ADIE register + + \param[in] cmd_id + Command ID is ATS_CMD_ADIE_GET_MULTIPLE_REGISTER. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa + - ATS_CMD_ADIE_GET_REGISTER +*/ +#define ATS_CMD_ADIE_GET_MULTIPLE_REGISTER ATS_CODEC_RTC_CMD_ID(3) +/** \} */ /* end_addtogroup ATS_CMD_ADIE_GET_MULTIPLE_REGISTER */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ADIE_SET_REGISTER Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ADIE_SET_REGISTER +\{ */ + +/** + Set the register value for the given ADIE register. + + \param[in] cmd_id + Command ID is ATS_CMD_ADIE_SET_REGISTER. + \param[in] cmd + Pointer to AtsCmdAdieSetRegisterReq. + \param[in] cmd_size + Size of AtsCmdAdieSetRegisterReq. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa + - TODO +*/ +#define ATS_CMD_ADIE_SET_REGISTER ATS_CODEC_RTC_CMD_ID(4) +/**< The request structure for ATS_CMD_ADIE_SET_REGISTER.*/ +typedef struct ats_cmd_adie_set_register_req_t AtsCmdAdieSetRegisterReq; +#include "acdb_begin_pack.h" +struct ats_cmd_adie_set_register_req_t +{ + /**< Codec handle*/ + uint32_t codec_handle; + /**< ID of the register*/ + uint32_t register_id; + /**< The bit-mask for the register*/ + uint32_t register_mask; + /**< The value stored in the register*/ + uint32_t register_value; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_ADIE_SET_REGISTER */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ADIE_SET_MULTIPLE_REGISTER Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ADIE_SET_MULTIPLE_REGISTER +\{ */ + +/** + Calls ATS_CMD_ADIE_SET_REGISTER for each ADIE register + + \param[in] cmd_id + Command ID is ATS_CMD_ADIE_SET_MULTIPLE_REGISTER. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_ADIE_SET_MULTIPLE_REGISTER ATS_CODEC_RTC_CMD_ID(5) +/** \} */ /* end_addtogroup ATS_CMD_ADIE_SET_MULTIPLE_REGISTER */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ONC_GET_SERVICE_INFO Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ONC_GET_SERVICE_INFO +\{ */ + +/** + Queries the Online Calibration Service Version + + \param[in] cmd_id + Command ID is ATS_CMD_ONC_GET_SERVICE_INFO. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + This is a pointer to AtsCmdGetServiceInfoRsp + \param[in] rsp_size + There is the size of AtsCmdGetServiceInfoRsp + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa TODO +*/ +#define ATS_CMD_ONC_GET_SERVICE_INFO ATS_ONLINE_CMD_ID(1) +/**< Holds the service information of a service*/ +typedef struct ats_service_info_t AtsServiceInfo; +#include "acdb_begin_pack.h" +struct ats_service_info_t +{ + /**< Service ID*/ + uint32_t service_id; + /**< Major version*/ + uint32_t major; + /**< Minor version*/ + uint32_t minor; +} +#include "acdb_end_pack.h" +; + +/**< The response structure for retrieving information about the registered services*/ +typedef struct ats_cmd_get_service_info_rsp_t AtsCmdGetServiceInfoRsp; +#include "acdb_begin_pack.h" +struct ats_cmd_get_service_info_rsp_t +{ + /**< Number of ATS services*/ + uint32_t service_count; + /**< Array of service information*/ + AtsServiceInfo *services_info; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_ONC_GET_SERVICE_INFO */ + +/*---------------------------------------------------------------------------- +* ATS_CMD_ONC_CHECK_CONNECTION Declarations and Documentation +*---------------------------------------------------------------------------*/ + +/** \addtogroup ATS_CMD_ONC_CHECK_CONNECTION +\{ */ + +/** + Checks to see if a connection between ATS and its client can be + established or is still active. + + \param[in] cmd_id + Command ID is ATS_CMD_ONC_CHECK_CONNECTION. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + This is a pointer to a uint32_t + \param[in] rsp_size + This is the size of a uint32_t + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa ats_online_ioctl +*/ +#define ATS_CMD_ONC_CHECK_CONNECTION ATS_ONLINE_CMD_ID(2) +/** \} */ /* end_addtogroup ATS_CMD_ONC_CHECK_CONNECTION */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ONC_GET_MAX_BUFFER_LENGTH Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ONC_GET_MAX_BUFFER_LENGTH +\{ */ + +/** + Queries ATS for its maximum buffer length. + + \param[in] cmd_id + Command ID is ATS_CMD_ONC_GET_MAX_BUFFER_LENGTH. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + This is a pointer to a uint32_t + \param[in] rsp_size + This is the size of a uint32_t + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa ats_online_ioctl +*/ +#define ATS_CMD_ONC_GET_MAX_BUFFER_LENGTH ATS_ONLINE_CMD_ID(3) +/** \} */ /* end_addtogroup ATS_CMD_ONC_GET_MAX_BUFFER_LENGTH */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH +\{ */ + +/** + Set the maximum buffer size to be used by ATS + + \param[in] cmd_id + Command ID is ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa ats_online_ioctl +*/ +#define ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH ATS_ONLINE_CMD_ID(4) +/** \} */ /* end_addtogroup ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ONC_GET_ACDB_FILES_INFO Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ONC_GET_ACDB_FILES_INFO +\{ */ + +/** + Queries ATS for ACDB file information for all ACDB files loaded into RAM. + File info includes the ACDB file name and file size for each ACDB file. + + \param[in] cmd_id + Command ID is ATS_CMD_ONC_GET_ACDB_FILES_INFO. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + This is a pointer to AtsCmdGetAcdbFileInfoRsp + \param[in] rsp_size + This is the size of AtsCmdGetAcdbFileInfoRsp + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa ats_online_ioctl +*/ +#define ATS_CMD_ONC_GET_ACDB_FILES_INFO ATS_ONLINE_CMD_ID(5) + +/**< Holds basic Acdb file information */ +typedef struct ats_get_acdb_file_info_t AtsGetAcdbFileInfo; +#include "acdb_begin_pack.h" +struct ats_get_acdb_file_info_t +{ + /**< Acdb file size*/ + uint32_t file_size; + /**< Acdb file name length*/ + uint32_t file_name_len; + /**< Acdb file name*/ + char* file_name; +} +#include "acdb_end_pack.h" +; + +/**< The response structure for retrieving information about the Acdb files loaded in memory*/ +typedef struct ats_cmd_get_acdb_file_info_rsp_t AtsCmdGetAcdbFileInfoRsp; +#include "acdb_begin_pack.h" +struct ats_cmd_get_acdb_file_info_rsp_t +{ + /**< Number of acdb files*/ + uint32_t file_count; + /**< Array of acdb file info*/ + AtsGetAcdbFileInfo *files_info; +} +#include "acdb_end_pack.h" +; +/** \} */ /* end_addtogroup ATS_CMD_ONC_GET_ACDB_FILES_INFO */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_ONC_GET_ACDB_FILE Declarations and Documentation +*-------------------------------------------------------------------------- */ + +/** \addtogroup ATS_CMD_ONC_GET_ACDB_FILE +\{ */ + +/** + Downloads the requested ACDB data and delta data file(s) from the target + to the client. The client retrieves the file name from + ATS_CMD_ONC_GET_ACDB_FILES_INFO + + \param[in] cmd_id + Command ID is ATS_CMD_ONC_GET_ACDB_FILE. + \param[in] cmd + There is a pointer to AtsOcsGetAcdbFile + \param[in] cmd_size + There is the size of AtsOcsGetAcdbFile + \param[out] rsp + This is a pointer to AcdbBlob + \param[in] rsp_size + This is the size of AcdbBlob + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa + ats_online_ioctl + ATS_CMD_ONC_GET_ACDB_FILES_INFO +*/ +#define ATS_CMD_ONC_GET_ACDB_FILE ATS_ONLINE_CMD_ID(6) + +typedef struct _ats_ocs_get_acdb_file_req_t AtsOcsGetAcdbFile; +#include "acdb_begin_pack.h" +struct _ats_ocs_get_acdb_file_req_t +{ + /**| | Version | bytes: 2 +* | | # Log Packets | bytes: 2 +* .+-- | Log Data Size | bytes: 4 +* .+-- .--------------------------------. +* | | Log Packet #1 | +* | | ---------------------------- | +* | | Packet Size | bytes: 4 +* | | Packet Data [packet size] | bytes: Packet Size bytes +* | |--------------------------------| +* Log Data--> | : ... : +* | |--------------------------------| +* | | Log Packet #n | +* | | ---------------------------- | +* | | Packet Size | bytes: 4 +* | | Packet Data [packet size] | bytes: Packet Size bytes +* .+-- +.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~+ +* + * \param[in] cmd_id + * Command ID is ATS_CMD_DLS_GET_LOG_DATA + * \param[in] cmd + * There is no input structure; set this to NULL. + * \param[in] cmd_size + * There is no input structure; set this to 0. + * \param[out] rsp + * TThis is a pointer to AtsDlsLogDataHeader + * \param[in] rsp_size + * This is the size of AtsDlsLogDataHeader + * + * \return + * - AR_EOK -- Command executed successfully. + * - AR_EBADPARAM -- Invalid input parameters were provided. + * - AR_EFAILED -- Command execution failed. + * + * \sa ats_dls_ioctl + */ +#define ATS_CMD_DLS_GET_LOG_DATA ATS_DLS_CMD_ID(4) + +typedef struct _ats_dls_get_dls_log_data_header_t AtsDlsLogDataHeader; +#include "acdb_begin_pack.h" +struct _ats_dls_get_dls_log_data_header_t { + /**<'A''R''T''M'*/ + uint32_t header_id; + /**< command version*/ + uint16_t header_version; + /**< the number of log buffers to send*/ + uint16_t log_buffer_count; + /**< the total size of all the log buffers*/ + uint32_t total_log_data_size; + /* Following this header is a list of log buffers: + AtsBuffer log_data[]; + */ +} +#include "acdb_end_pack.h" +; +/** @} */ /* end_addtogroup ATS_CMD_DLS_GET_LOG_DATA */ + +/* --------------------------------------------------------------------------- +* ATS_CMD_DLS_GET_VERSION Declarations and Documentation +*-------------------------------------------------------------------------- */ +/** \addtogroup ATS_CMD_DLS_GET_VERSION +\{ */ +/** + * Retrieves the DLS service Version. This is actually handled + * by ATS_CMD_ONC_GET_SERVICE_INFO + * \param[in] cmd_id + * Command ID is ATS_CMD_DLS_GET_VERSION + * \param[in] cmd + * This is a pointer to ... + * \param[in] cmd_size + * This is the size of ... + * \param[out] rsp + * There is no input structure; set this to NULL. + * \param[in] rsp_size + * There is no input structure; set this to NULL. + * + * \return + * - AR_EOK -- Command executed successfully. + * - AR_EBADPARAM -- Invalid input parameters were provided. + * - AR_EFAILED -- Command execution failed. + * + * \sa ats_dls_ioctl + */ +#define ATS_CMD_DLS_GET_VERSION ATS_DLS_CMD_ID(5) +/** @} */ /* end_addtogroup ATS_CMD_DLS_GET_VERSION */ + +/* --------------------------------------------------------------------------- +* API Definitions +*-------------------------------------------------------------------------- */ + +/** +* \brief ATS_CALLBACK +* A function callback for used for various ATS services +* \param [in] svc_cmd_id: The service command to be issued. Contains the 2 byte + service id and 2byte command id +* \param [in/out] cmd_buf: Pointer to the command structure. +* \param [in] cmd_buf_size: +* \param [out] rsp_buf: The response structre +* \param [in] rsp_buf_size: The size of the response +* \param [out] rsp_buf_bytes_filled: Number of bytes written to the response buffer +* \return 0 on success, non-zero on failure +*/ +typedef int32_t(*ATS_CALLBACK)( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled); + +typedef int32_t(*ATS_VERSION_CALLBACK)( + AtsServiceInfo *service_info); + +typedef struct _ats_callback_table_t AtsCallbackTable; +struct _ats_callback_table_t +{ + ATS_CALLBACK *service_callback; + ATS_VERSION_CALLBACK *version_callback; +}; + +#if defined(ATS_OTTP) || defined(_DEVICE_SIM) +typedef int(__stdcall *ATS_SIM_CALLBACK)( + uint32_t sz_request, uint8_t* request, + uint32_t *sz_response, uint8_t* response); +#else +typedef int(*ATS_SIM_CALLBACK)( + uint32_t sz_request, uint8_t* request, + uint32_t *sz_response, uint8_t* response); +#endif + + + +/** +* \brief +* Sets the simulation callback for ATS to retrieve response buffers from +* the Communication capture *.bin +* +* \return 0 on success, non-zero on failure +*/ +void ats_register_simulation(ATS_SIM_CALLBACK sim_callback); + +/** +* \brief ats_register_service +* Registers the specified service. +* \param [in] servie_id: The service ID of a ATS service +* \param [in] service_callback: The callback used to execute commands for the service. +* \return 0 on success, non-zero on failure +*/ +int32_t ats_register_service(uint32_t service_id, ATS_CALLBACK service_callback); + +/** +* \brief ats_deregister_service +* Deregisters the specified service. +* \param [in] servie_id: The service ID of a ATS service +* \return 0 on success, non-zero on failure +*/ +int32_t ats_deregister_service(uint32_t servie_id); + +/** +* \brief ats_get_service_info +* Get service information for each service registered +* \param [in] servie_id: The service ID of a ATS service +* \return 0 on success, non-zero on failure +*/ +int32_t ats_get_service_info(AtsCmdGetServiceInfoRsp *svc_info_rsp, uint32_t rsp_buf_len); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*__ATS_H_I__*/ diff --git a/acdb/ats/mcs/common/api/mcs_api.h b/acdb/ats/mcs/common/api/mcs_api.h new file mode 100644 index 0000000..f5c71d1 --- /dev/null +++ b/acdb/ats/mcs/common/api/mcs_api.h @@ -0,0 +1,447 @@ +/** +*============================================================================== +* \file adie_rtc_api.h +* \brief +* M C S A P I H E A D E R F I L E +* +* This header defines the APIs nessesary to control basic audio media +* services such as playback and record +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +#ifndef MCS_API_H +#define MCS_API_H + +#include "ar_osal_types.h" +#include "ar_osal_error.h" + +#define MCS_MAX_FILENAME_LENGTH 256 + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------------------------------------------------- +** Structure Definitions and Enums +** ----------------------------------------------------------------------- */ + +typedef enum mcs_api_major_version_t +{ + MCS_API_MAJOR_VERSION_1 = 0x1, +}mcs_api_major_version_t; + +typedef enum mcs_api_minor_version_t +{ + /**< Initial version */ + MCS_API_MINOR_VERSION_0 = 0x0, + /**< Added support for MCS v2 APIs: + 1. MCS_CMD_PLAY_2 + 2. MCS_CMD_REC_2 + 3. MCS_CMD_MULTI_PLAY_REC + 4. MCS_CMD_STOP_2 */ + MCS_API_MINOR_VERSION_1 = 0x1, +}mcs_api_minor_version_t; + +/**< Media control commands */ +typedef enum mcs_command_t +{ + MCS_CMD_UNKNOWN = 0x00, + + /**< + * The command for triggering a playback usecase with a path to the playback + * file for a specified duration. + * + * \param[in] cmd: this command ID + * \param[in] cmd_buf: A pointer to mcs_play_t + * \param[in] cmd_buf_size: size of mcs_play_t + * \param[out] rsp: There is no output structure; set this to NULL. + * \param[in] rsp_size: There is no output structure; set this to 0. + * + * \sa mcs_stream_cmd + */ + MCS_CMD_PLAY = 0x01, + /**< + * The command for triggering a capture usecase with a path to the file + * to write to for a specified duration. + * + * \param[in] cmd: this command ID + * \param[in] cmd_buf: A pointer to mcs_rec_t + * \param[in] cmd_buf_size: size of mcs_rec_t + * \param[out] rsp: There is no output structure; set this to NULL. + * \param[in] rsp_size: There is no output structure; set this to 0. + * + * \sa mcs_stream_cmd + */ + MCS_CMD_REC = 0x02, + /**< + * The command for triggering a simultaneous playback + record session. + * This command combines the structures used in MCS_CMD_PLAY and + * MCS_CMD_REC. + * + * \param[in] cmd: this command ID + * \param[in] cmd_buf: A pointer to mcs_play_rec_t + * \param[in] cmd_buf_size: size of mcs_play_rec_t + * \param[out] rsp: There is no output structure; set this to NULL. + * \param[in] rsp_size: There is no output structure; set this to 0. + * + * \sa mcs_stream_cmd + */ + MCS_CMD_PLAY_REC = 0x03, + /**< + * The command for stopping an audio session + * + * \param[in] cmd: this command ID + * \param[in] cmd_buf: There is no output structure; set this to NULL. + * \param[in] cmd_buf_size: There is no output structure; set this to 0. + * \param[out] rsp: There is no output structure; set this to NULL. + * \param[in] rsp_size: There is no output structure; set this to 0. + * + * \sa mcs_stream_cmd + */ + MCS_CMD_STOP = 0x04, + /**< + * The command for triggering a playback usecase with a path to the playback + * file for a specified duration. + * Calibration and tag data can be configured here unlike MCS_CMD_PLAY + * + * \param[in] cmd: this command ID + * \param[in] cmd_buf: A pointer to mcs_play_2_t + * \param[in] cmd_buf_size: size of mcs_play_2_t + * \param[out] rsp: A pointer to mcs_session_handles_t + * \param[in] rsp_size: size of mcs_session_handles_t + * + * \sa mcs_stream_cmd + */ + MCS_CMD_PLAY_2 = 0x05, + /**< + * The command for triggering a capture usecase with a path to the file + * to write to for a specified duration. + * Calibration and tag data can be configured here unlike MCS_CMD_REC + * + * \param[in] cmd: this command ID + * \param[in] cmd_buf: A pointer to mcs_record_2_t. + * \param[in] cmd_buf_size: size of mcs_record_2_t. + * \param[out] rsp: A pointer to mcs_session_handles_t + * \param[in] rsp_size: size of mcs_session_handles_t + * + * \sa mcs_stream_cmd + */ + MCS_CMD_REC_2 = 0x06, + /**< + * The command for stopping one or more audio sessions given one or more session handles + * + * \param[in] cmd: this command ID + * \param[in] cmd_buf: A pointer to mcs_session_handles_t. + * \param[in] cmd_buf_size: size of mcs_session_handles_t. + * \param[out] rsp: There is no output structure; set this to NULL. + * \param[in] rsp_size: There is no output structure; set this to 0. + * + * \sa mcs_stream_cmd + */ + MCS_CMD_STOP_2 = 0x07, + /**< + * The command for triggering multiple simultaneous playback + record + * sessions. + * This command combines the structures used in MCS_CMD_PLAY_2 and + * MCS_CMD_REC_2 and contains arrays of playback and record usecases. + * + * \param[in] cmd: this command ID + * \param[in] cmd_buf: A pointer to mcs_multi_play_rec_t + * \param[in] cmd_buf_size: size of mcs_multi_play_rec_t + * \param[out] rsp: A pointer to mcs_multi_play_rec_handle_list_t + * \param[in] rsp_size: size of mcs_multi_play_rec_handle_list_t + * + * \sa mcs_stream_cmd + */ + MCS_CMD_MULTI_PLAY_REC = 0x08, +} mcs_command_t; + +/**< Specifies the set of playback modes used in mcs_play_t */ +typedef enum mcs_playback_mode_t +{ + MCS_PLAYBACK_REGULAR, + MCS_PLAYBACK_ANC_S_PATH, + MCS_PLAYBACK_ANC_E_PATH, + MCS_PLAYBACK_RAS, +} mcs_playback_mode_t; + +/**< Specifies the set of recording modes used in the ATS_CMD_MCS_RECORD request*/ +typedef enum mcs_record_mode_t +{ + MCS_RECORD_REGULAR, + MCS_RECORD_ANC_P_PATH, + MCS_RECORD_ANC_S_PATH, + MCS_RECORD_ANC_E_PATH +} mcs_record_mode_t; + +/**< A pair */ +typedef struct mcs_key_value_pair_t +{ + uint32_t key; + uint32_t value; + +}mcs_key_value_pair_t; + +/**< Maintains a list of key value pairs */ +typedef struct mcs_key_vector_t +{ + /**< number of key-value pairs */ + uint32_t num_kvps; + /**< key-value pairs */ + mcs_key_value_pair_t *kvp; +}mcs_key_vector_t; + +/**< Maintains a list of key value pairs */ +typedef struct mcs_tag_key_vector_t +{ + /**< Module tag ID*/ + uint32_t tag_id; + /**< Tag key vector */ + mcs_key_vector_t tag_key_vector; +}mcs_tag_key_vector_t; + +/**< Media properties for a device or stream*/ +typedef struct mcs_properties_t +{ + /**< The device/stream sample rate*/ + uint32_t sample_rate; + /**< The bit width of each sample*/ + uint16_t bit_width; + /**< Indicates the alignment of bits_per_sample in sample_word_size.Relevant only when bits_per_sample is 24 and word_size is 32*/ + uint16_t alignment; + /**< Bits needed to store one sample*/ + uint16_t bits_per_sample; + /**< Q factor of the PCM data*/ + uint16_t q_factor; + /**< Indicates whether PCM samples are stored in little endian or big endian format.*/ + uint16_t endianness; + /**< Number of channels*/ + uint16_t num_channels; + /**< Determines what channels are used. Up to 32 channels are supported. If not supported set to 0*/ + uint8_t *channel_mapping; +}mcs_properties_t; + +/**< An array of audio session handles for active session */ +typedef struct mcs_session_handles_t +{ + /**< The number of handles for active audio sessions */ + uint32_t num_handles; + /**< A pointer to an array of handles for active audio sessions */ + uint32_t* handles; +}mcs_session_handles_t; + +/**< Contains properties for controlling audio playback */ +typedef struct mcs_play_t +{ + /**< playback device properties*/ + mcs_properties_t device_properties; + /**< playback stream properties*/ + mcs_properties_t stream_properties; + /**< Graph Key Vector representing the playback usecase*/ + mcs_key_vector_t graph_key_vector; + /**< Type of playback: 0(regular), 1(anc_spath), 2(anc_epath), 3(ras)*/ + mcs_playback_mode_t playback_mode; + /**< Playback duration in seconds*/ + int32_t playback_duration_sec; + /**< Length of the file name/path*/ + int32_t filename_len; + /**< Name of/path to file to save recording to*/ + char filename[MCS_MAX_FILENAME_LENGTH]; +}mcs_play_t; + + +/**< Contains properties for controlling audio record */ +typedef struct mcs_record_t +{ + /**< record device properties*/ + mcs_properties_t device_properties; + /**< record stream properties*/ + mcs_properties_t stream_properties; + /**< Graph Key Vector representing the record usecase*/ + mcs_key_vector_t graph_key_vector; + /**< Type of record: 0(regular), 1(aanc_path), 2(aanc_spath), 3(aanc_epath)*/ + mcs_record_mode_t record_mode; + /**< Save recording to file: 0 (ignore write), 1 (write data)*/ + uint32_t write_to_file; + /**< Record duration in seconds*/ + int32_t record_duration_sec; + /**< Length of the file name/path*/ + int32_t filename_len; + /**< Name of/path to file to save recording to*/ + char filename[MCS_MAX_FILENAME_LENGTH]; +}mcs_record_t; + +/**< Contains properties for controlling audio playback and record simultaneously */ +typedef struct mcs_play_rec_t +{ + mcs_play_t playback_session; + mcs_record_t record_session; +}mcs_play_rec_t; + +typedef struct mcs_version +{ + /**< Major version for changes that break backward compatibility */ + uint32_t major; + /**< Major version for changes that do not break backward compatibility */ + uint32_t minor; +}mcs_version_t; + +/**< Contains the session config information for triggering an + * audio playback usecase. Unlike the mcs_play_t structure, this structure + * allows the client to apply specific calibration/config before starting + * the usecase. The client can: + * 1. select specific calibraiton data using the ckv + * 2. select data base defined tag data using TKVs + * 3. provide custom tag data (this is not stored in the database) + */ +typedef struct mcs_play_2_t +{ + /**< playback device properties */ + mcs_properties_t device_properties; + /**< playback stream properties */ + mcs_properties_t stream_properties; + /**< Graph Key Vector representing the playback usecase */ + mcs_key_vector_t graph_key_vector; + /**< The usecase calibration key vector for selecting specific calibraion + to apply before starting a usecase */ + mcs_key_vector_t cal_key_vector; + /**< The number of tag key vectors. Setting this to zero indicates + that tkvs are unused */ + uint32_t num_tag_key_vectors; + /**< length of the tkv list */ + uint32_t tkv_list_size; + /**< An array of all the tag key vectors within a usecase. Used for + applying a specific configuration stored in the *.acdb before the + starting a useecase */ + mcs_tag_key_vector_t* tag_key_vectors; + /**< Type of playback: + 0(regular), 1(anc_spath), 2(anc_epath), 3(ras) */ + mcs_playback_mode_t playback_mode; + /**< Playback duration in seconds */ + int32_t playback_duration_sec; + /**< Length of the file name/path */ + int32_t filename_len; + /**< Name of/path to file to save recording to */ + char filename[MCS_MAX_FILENAME_LENGTH]; + /**< Size of tag data blob. Set to 0 to indicate none included */ + uint32_t tag_data_size; + /**< A pointer to the custom tag data blob. The format of this data is + [IID, Parameter ID, Data Size, Payload[Data Size], 8 Byte Aligned Padding] + ... + [IID, Parameter ID, Data Size, Payload[Data Size], 8 Byte Aligned Padding] */ + uint8_t* tag_data; +}mcs_play_2_t; + +/**< Contains the session config information for triggering an + * audio capture usecase. Unlike the mcs_record_t structure, this structure + * allows the client to apply specific calibration/config before starting + * the usecase. The client can: + * 1. select specific calibraiton data using the ckv + * 2. select data base defined tag data using TKVs + * 3. provide custom tag data (this is not stored in the database) + */ +typedef struct mcs_record_2_t +{ + /**< record device properties*/ + mcs_properties_t device_properties; + /**< record stream properties*/ + mcs_properties_t stream_properties; + /**< Graph Key Vector representing the record usecase*/ + mcs_key_vector_t graph_key_vector; + /**< The usecase calibration key vector for selecting specific calibraion + to apply before starting a usecase */ + mcs_key_vector_t cal_key_vector; + /**< The number of tag key vectors. Setting this to zero indicates + that tkvs are unused */ + uint32_t num_tag_key_vectors; + /**< length of the tkv list */ + uint32_t tkv_list_size; + /**< An array of all the tag key vectors within a usecase. Used for + applying a specific configuration stored in the *.acdb before the + starting a useecase */ + mcs_tag_key_vector_t* tag_key_vectors; + /**< Type of record: 0(regular), 1(aanc_path), 2(aanc_spath), 3(aanc_epath)*/ + mcs_record_mode_t record_mode; + /**< Save recording to file: 0 (ignore write), 1 (write data)*/ + uint32_t write_to_file; + /**< Record duration in seconds*/ + int32_t record_duration_sec; + /**< Length of the file name/path*/ + int32_t filename_len; + /**< Name of/path to file to save recording to*/ + char filename[MCS_MAX_FILENAME_LENGTH]; + /**< Size of tag data blob. Set to 0 to indicate none included */ + uint32_t tag_data_size; + /**< A pointer to the custom tag data blob. The format of this data is + [IID, Parameter ID, Data Size, Payload[Data Size], 8 Byte Aligned Padding] + ... + [IID, Parameter ID, Data Size, Payload[Data Size], 8 Byte Aligned Padding] */ + uint8_t* tag_data; +}mcs_record_2_t; + +/**< Holds pointers to a playback and record session configurations. The +* pointers can be null to indicate no configuration is provided. */ +typedef struct mcs_multi_play_rec_session_t +{ + /**< A pointer to a playback session request. Set to null if not provided */ + mcs_play_2_t* playback; + /**< A pointer to a record session request. Set to null if not provided */ + mcs_record_2_t* record; +}mcs_multi_play_rec_session_t; + +/**< The request structure for MCS_CMD_MULTI_PLAY_REC */ +typedef struct mcs_multi_play_rec_t +{ + /**< The number of playback + record sessions */ + uint32_t num_sessions; + /**< An array of playback + record sessions */ + mcs_multi_play_rec_session_t* sessions; +}mcs_multi_play_rec_t; + +/**< Handles to a playback and/or record session. Handles can be zero to signify no handle is set. */ +typedef struct mcs_multi_play_rec_handle_t +{ + /**< The handle for the playback session. Set this to zero if no handle is provided */ + uint32_t playback_handle; + /**< The handle for the record session. Set this to zero if no handle is provided */ + uint32_t record_handle; +}mcs_multi_play_rec_handle_t; + +/**< The response structure for MCS_CMD_MULTI_PLAY_REC */ +typedef struct mcs_multi_play_rec_handle_list_t +{ + /**< The number of playback + record sessions */ + uint32_t num_sessions; + /**< An array of playback + record session handles*/ + mcs_multi_play_rec_handle_t* handles; +}mcs_multi_play_rec_handle_list_t; + +/**************************************************************************** +** Functions +*****************************************************************************/ + +int32_t mcs_init(void); + +int32_t mcs_deinit(void); + +int32_t mcs_get_api_version(mcs_version_t* api_version); + +int32_t mcs_stream_cmd( + uint32_t cmd, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled); + +#ifdef __cplusplus +} +#endif + +#endif /* MCS_API_H */ + diff --git a/acdb/ats/mcs/common/inc/ats_mcs.h b/acdb/ats/mcs/common/inc/ats_mcs.h new file mode 100644 index 0000000..e049f23 --- /dev/null +++ b/acdb/ats/mcs/common/inc/ats_mcs.h @@ -0,0 +1,75 @@ +#ifndef _ATS_MCS_H_ +#define _ATS_MCS_H_ +/** +*============================================================================== +* \file ats_mcs.h +* \brief +* A T S F T S H E A D E R F I L E +* +* The Media Control Service(MCS) header file contains all the +* definitions necessary for ATS to handle requests that operate +* the platform media controller. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +#include "ar_osal_types.h" + +/*----------------------------------------------------------------------------- +* Defines and Constants +*----------------------------------------------------------------------------*/ +#define ATS_MCS_MAJOR_VERSION 0x1 +#define ATS_MCS_MINOR_VERSION 0x1 + +/* --------------------------------------------------------------------------- +* Public Functions +*-------------------------------------------------------------------------- */ + +/** +* \brief +* The Media Control Service IOCTL +* \param [in] svc_cmd_id: The command to be issued +* \param [in] cmd_buf: Pointer to the command structure. +* \param [in] cmd_buf_size: Size of the command structure +* \param [out] rsp_buf: The response structre +* \param [in] rsp_buf_size: The size of the response +* \param [out] rsp_buf_bytes_filled: Number of bytes written to the response buffer +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t ats_mcs_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +); + +/** +* \brief +* Initializes the file transfer service to allow interaction between +* ACDB SW and and QST clients. +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t ats_mcs_init(void); + +/** +* \brief +* Deinitializes the file transfer service to allow interaction between +* ACDB SW and and QST clients. +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t ats_mcs_deinit(void); + +/** +* \brief +* Gets the MCS service version used by the platform layer. +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t ats_mcs_get_version(uint32_t *major, uint32_t *minor); +#endif /*_ATS_MCS_H_*/ diff --git a/acdb/ats/mcs/common/src/ats_mcs.c b/acdb/ats/mcs/common/src/ats_mcs.c new file mode 100644 index 0000000..3db0b8b --- /dev/null +++ b/acdb/ats/mcs/common/src/ats_mcs.c @@ -0,0 +1,961 @@ +/** +*============================================================================== +* \file ats_mcs.c +* \brief +* A T S M C S S O U R C E F I L E +* +* The Media Control Service(MCS) source file contains the +* implementation for ATS to handle requests that operate the +* platform media controller. This allows ATS to start and stop +* playback and capture sessions. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ats_mcs.h" +#include "mcs_api.h" +#include "ats_i.h" +#include "ats_common.h" +#include "acdb_utility.h" + +/*------------------------------------------ +* Defines and Constants Typedefs +*------------------------------------------*/ + +/*------------------------------------------ +* Private Functions +*------------------------------------------*/ + +int32_t mcs_read_properties(mcs_properties_t *properties, uint8_t* buffer, uint32_t buffer_size, uint32_t* offset) +{ + int32_t status = AR_EOK; + uint32_t sz_mcs_property = sizeof(mcs_properties_t) - sizeof(size_t); + + if (IsNull(properties) || IsNull(buffer) || IsNull(offset) || buffer_size < sizeof(mcs_properties_t)) + { + status = AR_EBADPARAM; + ATS_ERR("Error[%d]: Null parameter passed in.", status); + return status; + } + + ATS_MEM_CPY_SAFE(properties, sz_mcs_property, + buffer + *offset, sz_mcs_property); + *offset += sz_mcs_property; + + properties->channel_mapping = buffer + *offset; + *offset += properties->num_channels * sizeof(uint8_t); + + return status; +} + +int32_t mcs_read_playback_req(mcs_play_t *req, uint8_t *cmd_buf, uint32_t cmd_buf_size, uint32_t* bytes_read) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + + if (IsNull(req) || IsNull(cmd_buf) || IsNull(bytes_read) || + cmd_buf_size <= 0) + { + status = AR_EBADPARAM; + ATS_ERR("Error[%d]: Null parameter passed in.", status); + return status; + } + + //Read Device and Stream Properties + status = mcs_read_properties(&req->device_properties, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read device properties."); + return status; + } + + status = mcs_read_properties(&req->stream_properties, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read stream properties."); + return status; + } + + //Read GKV + ATS_READ_SEEK_UI32(req->graph_key_vector.num_kvps, cmd_buf, offset); + req->graph_key_vector.kvp = + (mcs_key_value_pair_t*)(cmd_buf + offset); + offset += req->graph_key_vector.num_kvps * 2UL * (uint32_t)sizeof(uint32_t); + + //Read Playback Info (Playback file, Duration, Playback Mode) + //memcpy starting from the address of playback_mode + ATS_READ_SEEK_UI32(req->playback_mode, cmd_buf, offset); + ATS_READ_SEEK_I32(req->playback_duration_sec, cmd_buf, offset); + ATS_READ_SEEK_I32(req->filename_len, cmd_buf, offset); + ATS_MEM_CPY_SAFE(&req->filename, req->filename_len, + cmd_buf + offset, req->filename_len); + offset += req->filename_len; + *bytes_read = offset; + + return status; +} + +int32_t mcs_read_record_req(mcs_record_t *req, uint8_t *cmd_buf, uint32_t cmd_buf_size, uint32_t* bytes_read) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + + if (IsNull(req) || IsNull(cmd_buf) || IsNull(bytes_read) || + cmd_buf_size <= 0) + { + status = AR_EBADPARAM; + ATS_ERR("Error[%d]: Null parameter passed in.", status); + return status; + } + + //Read Device and Stream Properties + status = mcs_read_properties(&req->device_properties, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read device properties."); + return status; + } + + status = mcs_read_properties(&req->stream_properties, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read stream properties."); + return status; + } + + //Read GKV + ATS_READ_SEEK_UI32(req->graph_key_vector.num_kvps, cmd_buf, offset); + req->graph_key_vector.kvp = + (mcs_key_value_pair_t*)(cmd_buf + offset); + offset += req->graph_key_vector.num_kvps * 2UL * (uint32_t)sizeof(uint32_t); + + //Read Playback Info (Playback file, Duration, Playback Mode) + //memcpy starting from the address of record_mode + ATS_READ_SEEK_UI32(req->record_mode, cmd_buf, offset); + ATS_READ_SEEK_UI32(req->write_to_file, cmd_buf, offset); + ATS_READ_SEEK_I32(req->record_duration_sec, cmd_buf, offset); + ATS_READ_SEEK_I32(req->filename_len, cmd_buf, offset); + ATS_MEM_CPY_SAFE(&req->filename, req->filename_len, + cmd_buf + offset, req->filename_len); + offset += req->filename_len; + *bytes_read = offset; + + return status; +} + +int32_t mcs_read_playback_2_req(mcs_play_2_t* req, uint8_t* cmd_buf, uint32_t cmd_buf_size, uint32_t* bytes_read) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + + if (IsNull(req) || IsNull(cmd_buf) || IsNull(bytes_read) || + cmd_buf_size <= 0) + { + status = AR_EBADPARAM; + ATS_ERR("Error[%d]: Null parameter passed in.", status); + return status; + } + + offset = *bytes_read; + //Read Device and Stream Properties + status = mcs_read_properties(&req->device_properties, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read device properties."); + return status; + } + + status = mcs_read_properties(&req->stream_properties, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read stream properties."); + return status; + } + + //Read GKV + ATS_READ_SEEK_UI32(req->graph_key_vector.num_kvps, cmd_buf, offset); + req->graph_key_vector.kvp = NULL; + if (req->graph_key_vector.num_kvps > 0) + { + req->graph_key_vector.kvp = + (mcs_key_value_pair_t*)(cmd_buf + offset); + offset += req->graph_key_vector.num_kvps + * 2UL * (uint32_t)sizeof(uint32_t); + } + + //Read CKV + ATS_READ_SEEK_UI32(req->cal_key_vector.num_kvps, cmd_buf, offset); + req->cal_key_vector.kvp = NULL; + if (req->cal_key_vector.num_kvps > 0) + { + req->cal_key_vector.kvp = + (mcs_key_value_pair_t*)(cmd_buf + offset); + offset += req->cal_key_vector.num_kvps + * 2UL * (uint32_t)sizeof(uint32_t); + } + + //Read TKVs + ATS_READ_SEEK_UI32(req->num_tag_key_vectors, cmd_buf, offset); + ATS_READ_SEEK_UI32(req->tkv_list_size, cmd_buf, offset); + req->tag_key_vectors = NULL; + if (req->tkv_list_size > 0) + { + req->tag_key_vectors = + (mcs_tag_key_vector_t*)(cmd_buf + offset); + offset += req->tkv_list_size; + } + + //Read Playback Info (Playback file, Duration, Playback Mode) + //memcpy starting from the address of playback_mode + ATS_READ_SEEK_UI32(req->playback_mode, cmd_buf, offset); + ATS_READ_SEEK_I32(req->playback_duration_sec, cmd_buf, offset); + ATS_READ_SEEK_I32(req->filename_len, cmd_buf, offset); + ATS_MEM_CPY_SAFE(&req->filename, req->filename_len, + cmd_buf + offset, req->filename_len); + offset += req->filename_len;// MCS_MAX_FILENAME_LENGTH; + + //Read Tag Data + ATS_READ_SEEK_UI32(req->tag_data_size, cmd_buf, offset); + req->tag_data = NULL; + if (req->tag_data_size > 0) + { + req->tag_data = (uint8_t*)(cmd_buf + offset); + offset += req->tag_data_size; + } + + *bytes_read = offset; + + return status; +} + +int32_t mcs_read_record_2_req(mcs_record_2_t* req, uint8_t* cmd_buf, uint32_t cmd_buf_size, uint32_t* bytes_read) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + + if (IsNull(req) || IsNull(cmd_buf) || IsNull(bytes_read) || + cmd_buf_size <= 0) + { + status = AR_EBADPARAM; + ATS_ERR("Error[%d]: Null parameter passed in.", status); + return status; + } + + offset = *bytes_read; + //Read Device and Stream Properties + status = mcs_read_properties(&req->device_properties, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read device properties."); + return status; + } + + status = mcs_read_properties(&req->stream_properties, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read stream properties."); + return status; + } + + //Read GKV + ATS_READ_SEEK_UI32(req->graph_key_vector.num_kvps, cmd_buf, offset); + req->graph_key_vector.kvp = NULL; + if (req->graph_key_vector.num_kvps > 0) + { + req->graph_key_vector.kvp = + (mcs_key_value_pair_t*)(cmd_buf + offset); + offset += req->graph_key_vector.num_kvps + * 2UL * (uint32_t)sizeof(uint32_t); + } + + //Read CKV + ATS_READ_SEEK_UI32(req->cal_key_vector.num_kvps, cmd_buf, offset); + req->cal_key_vector.kvp = NULL; + if (req->cal_key_vector.num_kvps > 0) + { + req->cal_key_vector.kvp = + (mcs_key_value_pair_t*)(cmd_buf + offset); + offset += req->cal_key_vector.num_kvps + * 2UL * (uint32_t)sizeof(uint32_t); + } + + //Read TKVs + ATS_READ_SEEK_UI32(req->num_tag_key_vectors, cmd_buf, offset); + ATS_READ_SEEK_UI32(req->tkv_list_size, cmd_buf, offset); + req->tag_key_vectors = NULL; + if (req->tkv_list_size > 0) + { + req->tag_key_vectors = + (mcs_tag_key_vector_t*)(cmd_buf + offset); + offset += req->tkv_list_size; + } + + //Read Playback Info (Playback file, Duration, Playback Mode) + //memcpy starting from the address of record_mode + ATS_READ_SEEK_UI32(req->record_mode, cmd_buf, offset); + ATS_READ_SEEK_UI32(req->write_to_file, cmd_buf, offset); + ATS_READ_SEEK_I32(req->record_duration_sec, cmd_buf, offset); + ATS_READ_SEEK_I32(req->filename_len, cmd_buf, offset); + ATS_MEM_CPY_SAFE(&req->filename, req->filename_len, + cmd_buf + offset, req->filename_len); + offset += req->filename_len;// MCS_MAX_FILENAME_LENGTH; + + //Read Tag Data + ATS_READ_SEEK_UI32(req->tag_data_size, cmd_buf, offset); + req->tag_data = NULL; + if (req->tag_data_size > 0) + { + req->tag_data = (uint8_t*)(cmd_buf + offset); + offset += req->tag_data_size; + } + + *bytes_read = offset; + + return status; +} + +void print_mcs_play_2(mcs_play_2_t* req) +{ + //Device Properties + ATS_DBG("Device Properties"); + ATS_DBG("Sample Rate: %d", req->device_properties.sample_rate); + ATS_DBG("Bits per sample: %d", req->device_properties.bits_per_sample); + ATS_DBG("Bit Width: %d", req->device_properties.bit_width); + ATS_DBG("Alignment: %d", req->device_properties.alignment); + ATS_DBG("Endianness: %d", req->device_properties.endianness); + ATS_DBG("Qfactor %d", req->device_properties.q_factor); + ATS_DBG("Channel Count: %d", req->device_properties.num_channels); + + for (uint32_t i = 0; i < req->device_properties.num_channels; i++) + { + ATS_DBG("Channel #%d: %d", i, req->device_properties.channel_mapping[i]); + } + + //Stream Properties + ATS_DBG("Stream Properties"); + ATS_DBG("Sample Rate: %d", req->stream_properties.sample_rate); + ATS_DBG("Bits per sample: %d", req->stream_properties.bits_per_sample); + ATS_DBG("Bit Width: %d", req->stream_properties.bit_width); + ATS_DBG("Alignment: %d", req->stream_properties.alignment); + ATS_DBG("Endianness: %d", req->stream_properties.endianness); + ATS_DBG("Qfactor %d", req->stream_properties.q_factor); + ATS_DBG("Channel Count: %d", req->stream_properties.num_channels); + + for (uint32_t i = 0; i < req->stream_properties.num_channels; i++) + { + ATS_DBG("Channel #%d: %d", i, req->stream_properties.channel_mapping[i]); + } + + ATS_DBG("Graph Key Vector with %d key(s):", req->graph_key_vector.num_kvps); + for (uint32_t i = 0; i < req->graph_key_vector.num_kvps; i++) + { + ATS_DBG("[Key:0x%08x Val:0x%08x]", + req->graph_key_vector.kvp[i].key, + req->graph_key_vector.kvp[i].value); + } + + ATS_DBG("Cal Key Vector with %d key(s):", req->cal_key_vector.num_kvps); + for (uint32_t i = 0; i < req->cal_key_vector.num_kvps; i++) + { + ATS_DBG("[Key:0x%08x Val:0x%08x]", + req->cal_key_vector.kvp[i].key, + req->cal_key_vector.kvp[i].value); + } + + //TKVs + ATS_DBG("TKV Count: %d", req->num_tag_key_vectors); + ATS_DBG("TKV list size: %d", req->tkv_list_size); + + ATS_DBG("Mode: %d", req->playback_mode); + ATS_DBG("Duration: %d", req->playback_duration_sec); + ATS_DBG("File name len: %d", req->filename_len); + ATS_DBG("File name: %s", req->filename); + ATS_DBG("Tag data size: %d", req->tag_data_size); +} + +void print_mcs_record_2(mcs_record_2_t* req) +{ + //Device Properties + ATS_DBG("Device Properties"); + ATS_DBG("Sample Rate: %d", req->device_properties.sample_rate); + ATS_DBG("Bits per sample: %d", req->device_properties.bits_per_sample); + ATS_DBG("Bit Width: %d", req->device_properties.bit_width); + ATS_DBG("Alignment: %d", req->device_properties.alignment); + ATS_DBG("Endianness: %d", req->device_properties.endianness); + ATS_DBG("Qfactor %d", req->device_properties.q_factor); + ATS_DBG("Channel Count: %d", req->device_properties.num_channels); + + for (uint32_t i = 0; i < req->device_properties.num_channels; i++) + { + ATS_DBG("Channel #%d: %d", i, req->device_properties.channel_mapping[i]); + } + + //Stream Properties + ATS_DBG("Stream Properties"); + ATS_DBG("Sample Rate: %d", req->stream_properties.sample_rate); + ATS_DBG("Bits per sample: %d", req->stream_properties.bits_per_sample); + ATS_DBG("Bit Width: %d", req->stream_properties.bit_width); + ATS_DBG("Alignment: %d", req->stream_properties.alignment); + ATS_DBG("Endianness: %d", req->stream_properties.endianness); + ATS_DBG("Qfactor %d", req->stream_properties.q_factor); + ATS_DBG("Channel Count: %d", req->stream_properties.num_channels); + + for (uint32_t i = 0; i < req->stream_properties.num_channels; i++) + { + ATS_DBG("Channel #%d: %d", i, req->stream_properties.channel_mapping[i]); + } + + ATS_DBG("Graph Key Vector with %d key(s):", req->graph_key_vector.num_kvps); + for (uint32_t i = 0; i < req->graph_key_vector.num_kvps; i++) + { + ATS_DBG("[Key:0x%08x Val:0x%08x]", + req->graph_key_vector.kvp[i].key, + req->graph_key_vector.kvp[i].value); + } + + ATS_DBG("Cal Key Vector with %d key(s):", req->cal_key_vector.num_kvps); + for (uint32_t i = 0; i < req->cal_key_vector.num_kvps; i++) + { + ATS_DBG("[Key:0x%08x Val:0x%08x]", + req->cal_key_vector.kvp[i].key, + req->cal_key_vector.kvp[i].value); + } + + //TKVs + ATS_DBG("TKV Count: %d", req->num_tag_key_vectors); + ATS_DBG("TKV list size: %d", req->tkv_list_size); + + ATS_DBG("Mode: %d", req->record_mode); + ATS_DBG("Write Flag: %d", req->write_to_file); + ATS_DBG("Duration: %d", req->record_duration_sec); + ATS_DBG("File name len: %d", req->filename_len); + ATS_DBG("File name: %s", req->filename); + ATS_DBG("Tag data size: %d", req->tag_data_size); +} + +int32_t mcs_play( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + mcs_play_t req = { 0 }; + uint32_t offset = 0; + status = mcs_read_playback_req(&req, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read MCS Playback Request"); + return status; + } + + status = mcs_stream_cmd((uint32_t)MCS_CMD_PLAY, + (uint8_t*)&req, sizeof(mcs_play_t), NULL, 0, NULL); + + return status; +} + +int32_t mcs_rec( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + mcs_record_t req = {0}; + uint32_t offset = 0; + + status = mcs_read_record_req(&req, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read MCS Record Request"); + return status; + } + + status = mcs_stream_cmd((uint32_t)MCS_CMD_REC, + (uint8_t*)&req, sizeof(mcs_record_t), NULL, 0, NULL); + + return status; +} + +int32_t mcs_play_rec( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + mcs_play_rec_t req = { 0 }; + uint32_t offset = 0; + + status = mcs_read_playback_req(&req.playback_session, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read MCS Playback Request"); + return status; + } + + status = mcs_read_record_req(&req.record_session, cmd_buf + offset, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read MCS Record Request"); + return status; + } + + status = mcs_stream_cmd((uint32_t)MCS_CMD_PLAY_REC, + (uint8_t*)&req, sizeof(mcs_play_rec_t), NULL, 0, NULL); + + return status; +} + +int32_t mcs_stop( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + + status = mcs_stream_cmd((uint32_t)MCS_CMD_STOP, NULL, 0, NULL, 0, NULL); + + return status; +} + +int32_t mcs_play_2( + uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + int32_t status = AR_EOK; + mcs_play_2_t req = { 0 }; + mcs_session_handles_t rsp = { 0 }; + uint32_t offset = 0; + + status = mcs_read_playback_2_req(&req, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to read MCS Playback 2 Request"); + return status; + } + + print_mcs_play_2(&req); + + rsp.num_handles = 1; + rsp.handles = (uint32_t*)(rsp_buf + sizeof(uint32_t)); + + ATS_INFO("Starting MCS record session"); + + status = mcs_stream_cmd((uint32_t)MCS_CMD_PLAY_2, + (uint8_t*)&req, sizeof(mcs_play_2_t), + (uint8_t*)&rsp, sizeof(mcs_session_handles_t), rsp_buf_bytes_filled); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Unable to start playback session", status); + return status; + } + + *(uint32_t*)(rsp_buf) = rsp.num_handles; + *rsp_buf_bytes_filled = sizeof(rsp.num_handles) + sizeof(uint32_t); + + if(rsp.handles != NULL) + ATS_ERR("Started playback session with handle 0x%x", rsp.handles[0]); + return status; +} + +int32_t mcs_rec_2( + uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + int32_t status = AR_EOK; + mcs_record_2_t req = { 0 }; + mcs_session_handles_t rsp = { 0 }; + uint32_t offset = 0; + + status = mcs_read_record_2_req(&req, cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to read MCS Record 2 Request", status); + return status; + } + + print_mcs_record_2(&req); + + rsp.num_handles = 1; + rsp.handles = (uint32_t*)(rsp_buf + sizeof(uint32_t)); + + ATS_INFO("Starting MCS record session"); + + status = mcs_stream_cmd((uint32_t)MCS_CMD_REC_2, + (uint8_t*)&req, sizeof(mcs_record_2_t), + (uint8_t*)&rsp, sizeof(mcs_session_handles_t), rsp_buf_bytes_filled); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Unable to start record session", status); + return status; + } + + *(uint32_t*)(rsp_buf) = rsp.num_handles; + *rsp_buf_bytes_filled = sizeof(rsp.num_handles) + sizeof(uint32_t); + + if (rsp.handles != NULL) + ATS_ERR("Started record session with handle 0x%x", rsp.handles[0]); + return status; +} + +int32_t mcs_multi_play_rec( + uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + mcs_multi_play_rec_t req = { 0 }; + mcs_multi_play_rec_handle_list_t rsp = { 0 }; + + *rsp_buf_bytes_filled = 0; + ATS_INFO("Starting mcs multi-play-record session(s)"); + + ATS_READ_SEEK_UI32(req.num_sessions, cmd_buf, offset); + ATS_DBG("============ Multi-play-rec ============"); + ATS_DBG("multi-play-rec config count: %d", req.num_sessions); + req.sessions = ACDB_MALLOC(mcs_multi_play_rec_session_t, req.num_sessions); + if (IsNull(req.sessions)) + { + status = AR_ENOMEMORY; + ATS_ERR("Error[%d]: mcs multi-play-rec: Unable to allocate memory" + " for session structure", status); + goto end; + } + + ar_mem_set(req.sessions, 0, req.num_sessions * sizeof(mcs_multi_play_rec_session_t)); + for (uint32_t i = 0; i < req.num_sessions; i++) + { + uint32_t is_playback_provided = 0; + uint32_t is_record_provided = 0; + + ATS_READ_SEEK_UI32(is_playback_provided, cmd_buf, offset); + ATS_READ_SEEK_UI32(is_record_provided, cmd_buf, offset); + + ATS_DBG("------------ Config #%d ------------", i + 1); + ATS_DBG("Is playback config provided?: %d", is_playback_provided); + ATS_DBG("Is record config provided?: %d", is_record_provided); + + if (is_playback_provided) + { + req.sessions[i].playback = ACDB_MALLOC(mcs_play_2_t, 1); + if (IsNull(req.sessions[i].playback)) + { + status = AR_ENOMEMORY; + ATS_ERR("Error[%d]: mcs multi-play-rec: Unable to allocate memory" + " for playback structure #%d", status, i); + goto cleanup; + } + + ar_mem_set(req.sessions[i].playback, 0, sizeof(mcs_play_2_t)); + status = mcs_read_playback_2_req(req.sessions[i].playback, + cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + goto cleanup; + + ATS_DBG("________ playback config #%d ________", i+1); + print_mcs_play_2(req.sessions[i].playback); + } + + if (is_record_provided) + { + req.sessions[i].record = ACDB_MALLOC(mcs_record_2_t, 1); + if (IsNull(req.sessions[i].record)) + { + status = AR_ENOMEMORY; + ATS_ERR("Error[%d]: mcs multi-play-rec: Unable to allocate memory" + " for record structure #%d", status, i); + goto cleanup; + } + + ar_mem_set(req.sessions[i].record, 0, sizeof(mcs_record_2_t)); + status = mcs_read_record_2_req(req.sessions[i].record, + cmd_buf, cmd_buf_size, &offset); + if (AR_FAILED(status)) + goto cleanup; + + ATS_DBG("________ record config #%d ________", i + 1); + print_mcs_record_2(req.sessions[i].record); + } + } + + rsp.num_sessions = req.num_sessions; + rsp.handles = (mcs_multi_play_rec_handle_t*)(rsp_buf + sizeof(uint32_t)); + + status = mcs_stream_cmd((uint32_t)MCS_CMD_MULTI_PLAY_REC, + (uint8_t*)&req, sizeof(mcs_multi_play_rec_t), + (uint8_t*)&rsp, sizeof(mcs_multi_play_rec_handle_list_t), rsp_buf_bytes_filled); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Unable to start multi-play-record session(s)", status); + return status; + } + +cleanup: + + for (uint32_t i = 0; i < req.num_sessions; i++) + { + if (req.sessions[i].playback != NULL) + { + ACDB_FREE(req.sessions[i].playback); + } + if (req.sessions[i].record != NULL) + { + ACDB_FREE(req.sessions[i].record); + } + } + ACDB_FREE(req.sessions); + +end: + if (AR_FAILED(status)) + *rsp_buf_bytes_filled = 0; + else + { + *(uint32_t*)(rsp_buf) = rsp.num_sessions; + *rsp_buf_bytes_filled = sizeof(rsp.num_sessions) + + rsp.num_sessions * sizeof(mcs_multi_play_rec_handle_t); + + if (rsp.handles != NULL) + { + ATS_ERR("Started multi-play-record session(s) with handles:"); + for (uint32_t j = 0; j < rsp.num_sessions; j++) + { + ATS_ERR("[Session %d] playback handle 0x%x, record handle 0x%x", + j, rsp.handles[j].playback_handle, rsp.handles[j].record_handle); + } + } + } + + return status; +} + +int32_t mcs_stop_2( + uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + uint32_t offset = 0; + mcs_session_handles_t req = { 0 }; + + ATS_READ_SEEK_UI32(req.num_handles, cmd_buf, offset); + req.handles = (uint32_t*)(cmd_buf + offset); + + ATS_INFO("Stopping MCS media session(s)"); + + status = mcs_stream_cmd((uint32_t)MCS_CMD_STOP_2, (uint8_t*)&req, sizeof(mcs_session_handles_t), + NULL, 0, NULL); + + if(AR_FAILED(status)) + ATS_ERR("Error[%d]: Failed to stop session(s)", status); + + return status; +} + +/*------------------------------------------ +* Public Functions +*------------------------------------------*/ + + +int32_t ats_mcs_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +) +{ + int32_t status = AR_EOK; + + int32_t(*func_cb)( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled + ) = NULL; + + switch (svc_cmd_id) + { + case ATS_CMD_MCS_PLAY: + func_cb = mcs_play; + break; + case ATS_CMD_MCS_RECORD: + func_cb = mcs_rec; + break; + case ATS_CMD_MCS_PLAY_RECORD: + func_cb = mcs_play_rec; + break; + case ATS_CMD_MCS_STOP: + func_cb = mcs_stop; + break; + case ATS_CMD_MCS_PLAY_2: + func_cb = mcs_play_2; + break; + case ATS_CMD_MCS_RECORD_2: + func_cb = mcs_rec_2; + break; + case ATS_CMD_MCS_MULTI_PLAY_REC: + func_cb = mcs_multi_play_rec; + break; + case ATS_CMD_MCS_STOP_2: + func_cb = mcs_stop_2; + break; + default: + ATS_ERR("Command[%x] is not supported", svc_cmd_id); + status = AR_EUNSUPPORTED; + } + + if (status == AR_EOK) + { + status = func_cb(cmd_buf, + cmd_buf_size, + rsp_buf, + rsp_buf_size, + rsp_buf_bytes_filled); + } + + return status; +} + + +int32_t ats_mcs_init(void) +{ + ATS_INFO("Registering Media Control Service..."); + + int32_t status = AR_EOK; + + status = mcs_init(); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to initialize Media Control Service.", status); + return status; + } + + status = ats_register_service(ATS_MCS_SERVICE_ID, ats_mcs_ioctl); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to register the Media Control Service.", status); + } + + return status; +} + +int32_t ats_mcs_deinit(void) +{ + ATS_INFO("Deregistering Media Control Service..."); + + int32_t status = AR_EOK; + + status = mcs_deinit(); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to deinitialize Media Control Service.", status); + } + + status = ats_deregister_service(ATS_MCS_SERVICE_ID); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to deregister the Media Control Service.", status); + } + + return status; +} + +int32_t ats_mcs_get_version(uint32_t* major, uint32_t* minor) +{ + int32_t status = AR_EOK; + struct mcs_version version = { 0 }; + + if (IsNull(major) || IsNull(minor)) + return AR_EBADPARAM; + + status = mcs_get_api_version(&version); + + if (AR_FAILED(status)) + { + /* Default to initial version. */ + *major = MCS_API_MAJOR_VERSION_1; + *minor = MCS_API_MINOR_VERSION_0; + ATS_ERR("Warning[%d]: Unable to get MCS API version. " + "Defaulting to v%d.%d", status, + *major, *minor); + return AR_EOK; + } + + *major = version.major; + *minor = version.minor; + + return status; +} + + diff --git a/acdb/ats/mcs/linux/mcs.c b/acdb/ats/mcs/linux/mcs.c new file mode 100644 index 0000000..0ee6e0d --- /dev/null +++ b/acdb/ats/mcs/linux/mcs.c @@ -0,0 +1,171 @@ + /* +* mcs.c +* +*This file has implementation of mcs for LX platform +* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "mcs_api.h" +#include "ats_common.h" + +#ifdef MCS_ENABLED +typedef int32_t(*mcs_stream_cmd_t)( + uint32_t cmd, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t*rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled); + +typedef int32_t(*mcs_init_t)(void); +typedef int32_t(*mcs_deinit_t)(void); +mcs_init_t pal_mcs_init; +mcs_deinit_t pal_mcs_deinit; +mcs_stream_cmd_t pal_mcs_stream_cmd; + +/*------------------------------------------ +* MCS Dynamic loading +*------------------------------------------*/ + +#include +#define MCS_LIB "libmcs.so" +void* mcsLibHandle = NULL; + +/** +* \brief +* Dynamically load mcs.so +* +* \return 0 on success, non-zero on failure +*/ + +int32_t load_mcs_lib() +{ + int32_t status = AR_EOK; + ATS_DBG("Enter."); + if (!mcsLibHandle) { + mcsLibHandle = dlopen(MCS_LIB, RTLD_NOW); + if (NULL == mcsLibHandle) { + const char *err_str = dlerror(); + ATS_ERR("DLOPEN failed for %s, %s", + MCS_LIB, err_str ? err_str : "unknown"); + status = AR_EFAILED; + return status; + } + } + + + /*Loading the mcs function symbols*/ + pal_mcs_stream_cmd = (mcs_stream_cmd_t)dlsym(mcsLibHandle, "mcs_stream_cmd"); + if (!pal_mcs_stream_cmd) { + ATS_ERR("dlsym error %s for mcs_stream_cmd", dlerror()); + status = AR_EFAILED; + dlclose(mcsLibHandle); + mcsLibHandle = NULL; + return status; + } + + pal_mcs_init = (mcs_init_t)dlsym(mcsLibHandle, "mcs_init"); + if (!pal_mcs_init) { + ATS_ERR("dlsym error %s for mcs_init", dlerror()); + status = AR_EFAILED; + dlclose(mcsLibHandle); + mcsLibHandle = NULL; + return status; + } + + pal_mcs_deinit = (mcs_deinit_t)dlsym(mcsLibHandle, "ats_mcs_deinit"); + if (!pal_mcs_deinit) { + ATS_ERR("dlsym error %s for pal_mcs_deinit", dlerror()); + status = AR_EFAILED; + dlclose(mcsLibHandle); + mcsLibHandle = NULL; + } + return status; +} + +int32_t mcs_init(void) +{ + int32_t status = AR_EOK; + + status = load_mcs_lib(); + if(AR_FAILED(status)) { + ATS_ERR("Error[%d]: Failed to load mcs lib", status); + return status; + } + + status = pal_mcs_init(); + if(AR_FAILED(status)) { + ATS_ERR("Error[%d]: libmcs init failed", status); + return status; + } + + return status; +} + +int32_t mcs_stream_cmd( + uint32_t cmd, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t*rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + return pal_mcs_stream_cmd(cmd, + cmd_buf, cmd_buf_size, + rsp_buf, rsp_buf_size, + rsp_buf_bytes_filled); +} + +int32_t mcs_get_api_version(mcs_version_t* api_version) +{ + if (!api_version) + return 0; + + api_version->major = MCS_API_MAJOR_VERSION_1; + api_version->minor = MCS_API_MINOR_VERSION_0; + return 0; +} + +int32_t mcs_deinit(void) +{ + int32_t status = AR_EOK; + + status = pal_mcs_deinit ? pal_mcs_deinit() : AR_EFAILED; + if (mcsLibHandle != NULL) { + dlclose(mcsLibHandle); + mcsLibHandle = NULL; + } + pal_mcs_init = NULL; + pal_mcs_deinit = NULL; + return status; +} +#else +int32_t mcs_get_api_version(mcs_version_t* api_version __attribute__((unused))) +{ + return AR_ENOTIMPL; +} + +int32_t mcs_init(void) +{ + return AR_ENOTIMPL; +} + +int32_t mcs_stream_cmd( + uint32_t cmd __attribute__((unused)), + uint8_t *cmd_buf __attribute__((unused)), + uint32_t cmd_buf_size __attribute__((unused)), + uint8_t*rsp_buf __attribute__((unused)), + uint32_t rsp_buf_size __attribute__((unused)), + uint32_t *rsp_buf_bytes_filled __attribute__((unused))) +{ + return AR_ENOTIMPL; +} + +int32_t mcs_deinit(void) +{ + return AR_ENOTIMPL; +} +#endif + diff --git a/acdb/ats/online/common/inc/ats_online.h b/acdb/ats/online/common/inc/ats_online.h new file mode 100644 index 0000000..ad83e11 --- /dev/null +++ b/acdb/ats/online/common/inc/ats_online.h @@ -0,0 +1,70 @@ +#ifndef _ATS_ONLINE_H_ +#define _ATS_ONLINE_H_ +/** +*============================================================================== +* \file ats_online.h +* \brief +* A T S O N L I N E H E A D E R F I L E +* +* The Online Calibration Service(ONC) header file contains all the +* definitions necessary for ATS to handle requests that operate ACDB SW +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/*----------------------------------------------------------------------------- +* Includes +*----------------------------------------------------------------------------*/ +#include "acdb.h" + +/*----------------------------------------------------------------------------- +* Defines and Constants +*----------------------------------------------------------------------------*/ +#define ATS_ONC_MAJOR_VERSION 0x1 +#define ATS_ONC_MINOR_VERSION 0x4 + +/* --------------------------------------------------------------------------- +* Public Functions +*-------------------------------------------------------------------------- */ + +/** +* \brief ats_online_ioctl +* The Online Service IOCTL +* \param [in] cmd_id: The command to be issued +* \param [in] cmd_buf: Pointer to the command structure. +* \param [in] cmd_buf_size: +* \param [out] rsp_buf: The response structre +* \param [in] rsp_buf_size: The size of the response +* \param [out] rsp_buf_bytes_filled: Number of bytes written to the response buffer +* \return 0 on success, non-zero on failure +*/ +int32_t ats_online_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +); + +/** +* \brief ats_online_init +* Initializes the online service to allow interaction between +* ACDB SW and and QST clients. +* \return 0 on success, non-zero on failure +*/ +int32_t ats_online_init(void); + +/** +* \brief ats_online_deinit +* Initializes the online service to allow interaction between +* ACDB SW and and QST clients. +* \return 0 on success, non-zero on failure +*/ +int32_t ats_online_deinit(void); + +#endif /*_ATS_ONLINE_H_*/ diff --git a/acdb/ats/online/common/src/ats_online.c b/acdb/ats/online/common/src/ats_online.c new file mode 100644 index 0000000..e1d8756 --- /dev/null +++ b/acdb/ats/online/common/src/ats_online.c @@ -0,0 +1,1566 @@ +/** +*============================================================================== +* \file ats_online.c +* \brief +* A T S O N L I N E S O U R C E F I L E +* +* The Online Calibration Service(ONC) source file contains the +* implementation for ATS to handle requests that operate ACDB SW +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ats_online.h" +#include "ats_i.h" +#include "acdb_utility.h" +#include "ats_common.h" +#include "ats_command.h" +#include "ar_osal_mutex.h" +#include "acdb_common.h" + +/*------------------------------------------ +* Defines and Constants +*------------------------------------------*/ +//uint8_t *ats_main_buffer = NULL; + +ar_osal_mutex_t acdb_client_lock; + +/*------------------------------------------ +* Private Functions +*------------------------------------------*/ + +/** +* \brief get_service_info +* Queries ATS for information about each service (FTS, MCS, RTS, ADIE, etc?) +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_get_service_info( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + + if (IsNull(rsp_buf) || (rsp_buf_size < sizeof(uint32_t))) + { + return AR_ENOMEMORY; + } + else + { + AtsCmdGetServiceInfoRsp rsp = { 0 }; + + rsp.services_info = (AtsServiceInfo*)(rsp_buf + sizeof(uint32_t)); + + status = ats_get_service_info(&rsp, rsp_buf_size - sizeof(uint32_t)); + + if (AR_SUCCEEDED(status)) + { + ACDB_MEM_CPY_SAFE(rsp_buf, sizeof(uint32_t), &rsp.service_count, sizeof(uint32_t)); + + *rsp_buf_bytes_filled = sizeof(rsp.service_count) + (rsp.service_count * sizeof(AtsServiceInfo)); + } + + return AR_EOK; + } + + //return status; +} + +/** +* \brief get_online_version +* Queries ATS for the Online Calibration service version. +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +//int32_t get_online_version( +// uint8_t *cmd_buf, +// uint32_t cmd_buf_size, +// uint8_t *rsp_buf, +// uint32_t rsp_buf_size, +// uint32_t *rsp_buf_bytes_filled) +//{ +// int32_t status = AR_EOK; +// +// UNUSED(cmd_buf_size); +// UNUSED(*cmd_buf); +// +// if ((NULL == rsp_buf) || (rsp_buf_size < 2 * sizeof(uint32_t))) +// { +// return AR_ENOMEMORY; +// } +// else +// { +// AtsVersion version = { ATS_ONC_MAJOR_VERSION , ATS_ONC_MINOR_VERSION }; +// ACDB_MEM_CPY_SAFE(rsp_buf, sizeof(AtsVersion), &version, sizeof(AtsVersion)); +// *rsp_buf_bytes_filled = sizeof(AtsVersion); +// return AR_EOK; +// } +// +// return status; +//} + +/** +* \brief check_connection +* Checks to see if a connection between ATS and its client can be established or is still alive. +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_check_connection( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + + *rsp_buf_bytes_filled = 0; + return status; +} + +/** +* \brief get_max_buffer_length +* Queries ATS for its maximum buffer length. +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_get_max_buffer_length( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + + uint32_t ats_buf_len = rsp_buf_size; + + if ((NULL == rsp_buf) || (rsp_buf_size < sizeof(uint32_t))) + { + return AR_ENOMEMORY; + } + else + { + ACDB_MEM_CPY_SAFE((void*)(rsp_buf), sizeof(uint32_t), (void*)&ats_buf_len, sizeof(uint32_t)); + *rsp_buf_bytes_filled = sizeof(uint32_t); + return AR_EOK; + } +} + +/** +* \brief set_max_buffer_length +* Queries ATS for its maximum buffer length. +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_set_max_buffer_length( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t ats_max_buf_len = 0; + + ACDB_MEM_CPY_SAFE(&ats_max_buf_len, sizeof(uint32_t), &cmd_buf, sizeof(uint32_t)); + + uint32_t ats_buf_len = rsp_buf_size; + + if ((NULL == rsp_buf) || (rsp_buf_size < sizeof(uint32_t))) + { + //add generic function that will fill in rsp_buf + return AR_ENOMEMORY; + } + else + { + ACDB_MEM_CPY_SAFE((void*)(rsp_buf), sizeof(uint32_t), (void*)&ats_buf_len, sizeof(uint32_t)); + *rsp_buf_bytes_filled = sizeof(uint32_t); + return AR_EOK; + } +} + +/** +* \brief get_acdb_files_info +* Queries ATS for ACDB file information for all acdb files loaded into RAM. +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_get_acdb_files_info( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + AcdbFileManBlob rsp = { 0 }; + + if (IsNull(rsp_buf)) + { + return AR_EBADPARAM; + } + + rsp.size = rsp_buf_size; + rsp.buf = rsp_buf; + + status = AtsCmdGetHostDatabaseFileSetInfo(&rsp); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to retrieve loaded acdb file info"); + } + + *rsp_buf_bytes_filled = rsp.bytes_filled; + + return status; +} + +/** +* \brief get_acdb_file +* Downloads the requested ACDB data file from the target. +* +* \sa ats_online_ioctl +* \sa get_acdb_files_info +*/ +int32_t ats_onc_get_acdb_file( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + AcdbFileManBlob rsp = { 0 }; + AcdbFileManGetFileDataReq req = { 0 }; + int32_t sz_request = sizeof(AcdbFileManGetFileDataReq) + - sizeof(size_t) - sizeof(req.acdb_handle); + + if (IsNull(rsp_buf)) + { + return AR_EBADPARAM; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)&req + sizeof(req.acdb_handle), + sz_request, cmd_buf, sz_request); + req.file_name = &cmd_buf[sz_request]; + req.acdb_handle = 0; + + rsp.size = rsp_buf_size; + rsp.buf = rsp_buf; + + status = AtsCmdGetLoadedFileData(&req, &rsp); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to retrieve loaded acdb file info", status); + } + + *rsp_buf_bytes_filled = rsp.bytes_filled; + return status; +} + +/** +* \brief get_heap_entry_count +* Queries ATS for the number of heap entries in the ACDB SW Heap. +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_get_heap_entry_info( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + AcdbBufferContext rsp = { 0 }; + rsp.buf = rsp_buf; + rsp.size = rsp_buf_size; + + status = AtsCmdGetHeapEntryInfo(0, &rsp); + + *rsp_buf_bytes_filled = rsp.bytes_filled; + return status; +} + +/** +* \brief +* Retrieves the entries in the ACDB SW Heap +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_get_heap_entry_data( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + uint32_t num_key_vectors = 0; + uint32_t num_key_vectors_found = 0; + AcdbBufferContext rsp = { 0 }; + AcdbGraphKeyVector key_vector = { 0 }; + uint32_t offset = 0; + uint32_t rsp_offset = sizeof(num_key_vectors_found); + + rsp.buf = &rsp_buf[rsp_offset];//make room to write num key vectors found + rsp.size = rsp_buf_size; + rsp.bytes_filled = 0; + + ACDB_MEM_CPY_SAFE(&num_key_vectors, sizeof(num_key_vectors), cmd_buf, sizeof(num_key_vectors)); + offset += sizeof(num_key_vectors); + + for (uint32_t i = 0; i < num_key_vectors; i++) + { + ACDB_MEM_CPY_SAFE(&key_vector.num_keys, sizeof(key_vector.num_keys), &cmd_buf[offset], sizeof(key_vector.num_keys)); + offset += sizeof(key_vector.num_keys); + + key_vector.graph_key_vector = (AcdbKeyValuePair*)&cmd_buf[offset]; + offset += key_vector.num_keys * sizeof(AcdbKeyValuePair); + + status = AtsCmdGetHeapEntryData(0, &key_vector, &rsp); + if (AR_FAILED(status)) + break;//todo: print key vector that failed + else + num_key_vectors_found++; + } + + ACDB_MEM_CPY_SAFE(rsp_buf, sizeof(num_key_vectors_found), &num_key_vectors_found, sizeof(num_key_vectors_found)); + + *rsp_buf_bytes_filled = rsp_offset + rsp.bytes_filled; + return status; +} + +/** +* \brief +* Get non-persistent calibration data from the ACDB SW Heap or the data files. +* +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_get_cal_data_non_persist( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) + +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + AtsGetSubgraphCalDataReq req = { 0 }; + AcdbBufferContext rsp = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ATS_READ_SEEK_UI32(req.subgraph_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.module_iid, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.param_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.cal_key_vector.num_keys, cmd_buf, offset); + + if (req.cal_key_vector.num_keys) + { + req.cal_key_vector.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + } + + rsp.buf = rsp_buf; + rsp.size = rsp_buf_size; + + status = AtsCmdGetCalDataNonPersist(&req, &rsp); + + *rsp_buf_bytes_filled = rsp.bytes_filled; + return status; +} + +/** +* \brief +* Set non-persistent calibration data to the ACDB SW Heap or the data files. +* +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_set_cal_data_non_persist( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) + +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + AcdbGraphKeyVector ckv = { 0 }; + AcdbSubgraphParamData subgraph_param_data = {0}; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + + ATS_READ_SEEK_UI32(subgraph_param_data.subgraph_id_list.count, + cmd_buf, offset); + subgraph_param_data.subgraph_id_list.list = + (uint32_t*)&cmd_buf[offset]; + offset += subgraph_param_data.subgraph_id_list.count * sizeof(uint32_t); + + ATS_READ_SEEK_UI32(ckv.num_keys, cmd_buf, offset); + + if (ckv.num_keys) + { + ckv.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + offset += ckv.num_keys + * 2UL * (uint32_t)sizeof(uint32_t); + } + + ATS_READ_SEEK_UI32(subgraph_param_data.data_size, cmd_buf, offset); + + if (subgraph_param_data.data_size) + { + subgraph_param_data.data = &cmd_buf[offset]; + } + + status = AtsCmdSetCalDataNonPersist(FALSE, &ckv, &subgraph_param_data); + + return status; +} + +/** +* \brief +* Set non-persistent calibration data to the ACDB SW Heap or the data files. +* +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_set_cal_data_non_persist_2( + uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) + +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t should_persist = 0; + AcdbGraphKeyVector ckv = { 0 }; + AcdbSubgraphParamData subgraph_param_data = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + ATS_READ_SEEK_UI32(should_persist, + cmd_buf, offset); + ATS_READ_SEEK_UI32(subgraph_param_data.subgraph_id_list.count, + cmd_buf, offset); + subgraph_param_data.subgraph_id_list.list = + (uint32_t*)&cmd_buf[offset]; + offset += subgraph_param_data.subgraph_id_list.count * sizeof(uint32_t); + + ATS_READ_SEEK_UI32(ckv.num_keys, cmd_buf, offset); + + if (ckv.num_keys) + { + ckv.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + offset += ckv.num_keys + * 2UL * (uint32_t)sizeof(uint32_t); + } + + ATS_READ_SEEK_UI32(subgraph_param_data.data_size, cmd_buf, offset); + + if (subgraph_param_data.data_size) + { + subgraph_param_data.data = &cmd_buf[offset]; + } + + status = AtsCmdSetCalDataNonPersist((bool_t)should_persist, &ckv, &subgraph_param_data); + + return status; +} + +/** +* \brief +* Queries ATS for persistent calibration data from the ACDB SW Heap or the data files. +* +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_get_cal_data_persist( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + AtsGetSubgraphCalDataReq req = { 0 }; + AcdbBufferContext rsp = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ATS_READ_SEEK_UI32(req.subgraph_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.module_iid, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.param_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.cal_key_vector.num_keys, cmd_buf, offset); + + if (req.cal_key_vector.num_keys) + { + req.cal_key_vector.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + } + + rsp.buf = rsp_buf; + rsp.size = rsp_buf_size; + + status = AtsCmdGetCalDataPersist(&req, &rsp); + + *rsp_buf_bytes_filled = rsp.bytes_filled; + return status; +} + +/** +* \brief +* Set persistent calibration data to the ACDB SW Heap or the data files. +* +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_set_cal_data_persist( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) + +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + AcdbGraphKeyVector ckv = { 0 }; + AcdbSubgraphParamData subgraph_param_data = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + + ATS_READ_SEEK_UI32(subgraph_param_data.subgraph_id_list.count, + cmd_buf, offset); + subgraph_param_data.subgraph_id_list.list = + (uint32_t*)&cmd_buf[offset]; + offset += subgraph_param_data.subgraph_id_list.count * sizeof(uint32_t); + + ATS_READ_SEEK_UI32(ckv.num_keys, cmd_buf, offset); + + if (ckv.num_keys) + { + ckv.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + offset += ckv.num_keys + * 2UL * (uint32_t)sizeof(uint32_t); + } + + ATS_READ_SEEK_UI32(subgraph_param_data.data_size, cmd_buf, offset); + + if (subgraph_param_data.data_size) + { + subgraph_param_data.data = &cmd_buf[offset]; + } + + status = AtsCmdSetCalDataPersist(FALSE, &ckv, &subgraph_param_data); + + return status; +} + +/** +* \brief +* Set persistent calibration data to the ACDB SW Heap or the data files. +* +* This version alows enabling/disabling persisting the data to the delta file. +* \sa ats_online_ioctl, ats_onc_set_cal_data_persist +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_set_cal_data_persist_2( + uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) + +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t should_persist = 0; + AcdbGraphKeyVector ckv = { 0 }; + AcdbSubgraphParamData subgraph_param_data = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + ATS_READ_SEEK_UI32(should_persist, + cmd_buf, offset); + ATS_READ_SEEK_UI32(subgraph_param_data.subgraph_id_list.count, + cmd_buf, offset); + subgraph_param_data.subgraph_id_list.list = + (uint32_t*)&cmd_buf[offset]; + offset += subgraph_param_data.subgraph_id_list.count * sizeof(uint32_t); + + ATS_READ_SEEK_UI32(ckv.num_keys, cmd_buf, offset); + + if (ckv.num_keys) + { + ckv.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + offset += ckv.num_keys + * 2UL * (uint32_t)sizeof(uint32_t); + } + + ATS_READ_SEEK_UI32(subgraph_param_data.data_size, cmd_buf, offset); + + if (subgraph_param_data.data_size) + { + subgraph_param_data.data = &cmd_buf[offset]; + } + + status = AtsCmdSetCalDataPersist((bool_t)should_persist, &ckv, &subgraph_param_data); + + return status; +} + + +/** +* \brief +* Get tag data from the ACDB SW Heap or the delta file(s). +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_get_tag_data( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) + +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + AtsGetSubgraphTagDataReq req = { 0 }; + AcdbBufferContext rsp = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ATS_READ_SEEK_UI32(req.subgraph_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.tag_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.module_iid, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.param_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(req.tag_key_vector.num_keys, cmd_buf, offset); + + if (req.tag_key_vector.num_keys) + { + req.tag_key_vector.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + } + + rsp.buf = rsp_buf; + rsp.size = rsp_buf_size; + + status = AtsCmdGetTagData(&req, &rsp); + + *rsp_buf_bytes_filled = rsp.bytes_filled; + return status; +} + +/** +* \brief +* Set tag data to the ACDB SW Heap or the delta file(s). +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_set_tag_data( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) + +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + AcdbModuleTag tag = { 0 }; + AcdbSubgraphParamData subgraph_param_data = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + + ATS_READ_SEEK_UI32(subgraph_param_data.subgraph_id_list.count, + cmd_buf, offset); + subgraph_param_data.subgraph_id_list.list = + (uint32_t*)&cmd_buf[offset]; + offset += subgraph_param_data.subgraph_id_list.count * sizeof(uint32_t); + + ATS_READ_SEEK_UI32(tag.tag_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(tag.tag_key_vector.num_keys, + cmd_buf, offset); + + if (tag.tag_key_vector.num_keys) + { + tag.tag_key_vector.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + offset += tag.tag_key_vector.num_keys + * 2UL * (uint32_t)sizeof(uint32_t); + } + + ATS_READ_SEEK_UI32(subgraph_param_data.data_size, cmd_buf, offset); + + if (subgraph_param_data.data_size) + { + subgraph_param_data.data = &cmd_buf[offset]; + } + + status = AtsCmdSetTagData(FALSE, &tag, &subgraph_param_data); + + return status; +} + +/** +* \brief +* Set tag data to the ACDB SW Heap or the delta file(s). +* This version alows enabling/disabling persisting the data to the delta file. +* \sa ats_online_ioctl, ats_onc_set_tag_data +* +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_set_tag_data_2( + uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) + +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t should_persist = 0; + AcdbModuleTag tag = { 0 }; + AcdbSubgraphParamData subgraph_param_data = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + *rsp_buf_bytes_filled = 0; + ATS_READ_SEEK_UI32(should_persist, + cmd_buf, offset); + ATS_READ_SEEK_UI32(subgraph_param_data.subgraph_id_list.count, + cmd_buf, offset); + subgraph_param_data.subgraph_id_list.list = + (uint32_t*)&cmd_buf[offset]; + offset += subgraph_param_data.subgraph_id_list.count * sizeof(uint32_t); + + ATS_READ_SEEK_UI32(tag.tag_id, cmd_buf, offset); + ATS_READ_SEEK_UI32(tag.tag_key_vector.num_keys, + cmd_buf, offset); + + if (tag.tag_key_vector.num_keys) + { + tag.tag_key_vector.graph_key_vector = + (AcdbKeyValuePair*)&cmd_buf[offset]; + offset += tag.tag_key_vector.num_keys + * 2UL * (uint32_t)sizeof(uint32_t); + } + + ATS_READ_SEEK_UI32(subgraph_param_data.data_size, cmd_buf, offset); + + if (subgraph_param_data.data_size) + { + subgraph_param_data.data = &cmd_buf[offset]; + } + + status = AtsCmdSetTagData((bool_t)should_persist, &tag, &subgraph_param_data); + + return status; +} + +/** +* \brief delete_delta_files +* Removes the *.acdbdelta files from the targets file system +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_delete_delta_files( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + + status = AtsCmdDeleteDeltaFiles(); + *rsp_buf_bytes_filled = 0; + + return status; +} + +/** +* \brief +* Check to see if the target supports delta data persistence. +* +* \sa ats_online_ioctl +* \return 0 on success, non-zero on failure +*/ +int32_t ats_onc_is_delta_data_supported( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + int32_t is_delta_data_supported = acdb_delta_data_is_persist_enabled(); + + ACDB_MEM_CPY_SAFE(rsp_buf, rsp_buf_size, &is_delta_data_supported, sizeof(int32_t)); + *rsp_buf_bytes_filled = sizeof(is_delta_data_supported); + + return status; +} + +int32_t ats_onc_get_temp_file_path( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + AtsGetTempPath path = { 0 }; + path.path = (char*)(rsp_buf + sizeof(uint32_t)); + status = AtsCmdGetTempFilePath( + ACDB_CTX_MAN_DEFAULT_DB_HANDLE, &path); + if (AR_FAILED(status)) + { + return status; + } + + ACDB_MEM_CPY_SAFE(rsp_buf, sizeof(uint32_t), + &path.path_len, sizeof(uint32_t)); + + *rsp_buf_bytes_filled = sizeof(path.path_len) + + path.path_len; + + return status; +} + +/** +* \brief +* Performs a soft reinitialization of AML by clearing +* the heap, delta data, and file manager components +* +* NOTE +* soft reset is similar to acdb_deinit but it doesn't: +* 1. destroy the acdb client mutex like acdb_deinit +* 2. deinitializes the heap memory interface (see ar_heap_init) +* +* \sa acdb_deinit +* \return 0 on success, non-zero on failure +*/ +int32_t acdb_soft_reset(void) +{ + int32_t status = AR_EOK; + + status = acdb_delta_data_ioctl( + ACDB_DELTA_DATA_CMD_RESET, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to reset the Delta Data Manager."); + } + + status = acdb_file_man_ioctl( + ACDB_FILE_MAN_RESET, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to reset the File Manager."); + } + + return status; +} + +int32_t ats_onc_reinit_acdb( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + uint32_t offset = 0; + //AcdbFile *delta_file_path = NULL; + AcdbFile delta_file_path = { 0 }; + AtsAcdbReinitReq *req = NULL; + AtsGetTempPath path = { 0 }; + + *rsp_buf_bytes_filled = 0; + + req = ACDB_MALLOC(AtsAcdbReinitReq, 1); + + if (IsNull(req)) + { + ATS_ERR("Error[%d]: Unable to allocate reinit" + " request structure.", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + ACDB_MEM_CPY_SAFE(&req->acdb_files.num_files, sizeof(uint32_t), + &cmd_buf[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + if (0 == req->acdb_files.num_files) + { + status = AR_EBADPARAM; + ATS_ERR("Error[%d]: Cannot reinitialize ACDB SW with 0 files.", status); + goto end; + } + + for (uint32_t i = 0; i < req->acdb_files.num_files; i++) + { + ACDB_MEM_CPY_SAFE( + &req->acdb_files.acdbFiles[i].fileNameLen, sizeof(uint32_t), + &cmd_buf[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE( + &req->acdb_files.acdbFiles[i].fileName, + req->acdb_files.acdbFiles[i].fileNameLen, + &cmd_buf[offset], + req->acdb_files.acdbFiles[i].fileNameLen); + offset += req->acdb_files.acdbFiles[i].fileNameLen; + } + + ACDB_MEM_CPY_SAFE(&req->is_delta_data_supported, sizeof(uint32_t), + &cmd_buf[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + path.path = delta_file_path.fileName; + status = AtsCmdGetTempFilePath( + ACDB_CTX_MAN_DEFAULT_DB_HANDLE, &path); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get temp file path from File Manager."); + goto end; + } + + delta_file_path.fileNameLen = path.path_len; + + if (req->is_delta_data_supported) + { + status = acdb_ioctl((uint32_t)ACDB_CMD_ENABLE_PERSISTANCE, + NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to enable delta data " + "support. Skipping..", status); + } + } + + ATS_INFO("Re-initializing ACDB SW.."); + + status = acdb_deinit(); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Acdb deinit failed during re-init.", status); + goto end; + } + + status = acdb_init(&req->acdb_files, &delta_file_path); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Acdb init failed during re-init.", status); + goto end; + } + +end: + ACDB_FREE(req); + + return status; +} + +int32_t ats_onc_get_fileset_info(uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + AcdbFileManBlob rsp = { 0 }; + + if (IsNull(rsp_buf)) + { + return AR_EBADPARAM; + } + + rsp.size = rsp_buf_size; + rsp.buf = rsp_buf; + + status = AtsCmdGetAllDatabasesFileSetInfo(&rsp); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to retrieve loaded acdb file info"); + } + + *rsp_buf_bytes_filled = rsp.bytes_filled; + + return status; +} + +int32_t ats_onc_get_selected_acdb_file(uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + AcdbFileManBlob rsp = { 0 }; + AcdbFileManGetFileDataReq req = { 0 }; + int32_t sz_request = sizeof(AcdbFileManGetFileDataReq) - sizeof(size_t); + + if (IsNull(rsp_buf)) + { + return AR_EBADPARAM; + } + + ACDB_MEM_CPY_SAFE(&req, sz_request, cmd_buf, sz_request); + req.file_name = &cmd_buf[sz_request]; + + rsp.size = rsp_buf_size; + rsp.buf = rsp_buf; + + status = AtsCmdGetLoadedFileData(&req, &rsp); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to retrieve loaded acdb file info"); + } + + *rsp_buf_bytes_filled = rsp.bytes_filled; + + return status; +} + +int32_t ats_onc_get_selected_heap_entry_info(uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + AcdbBufferContext rsp = { 0 }; + uint32_t uint_acdb_handle = 0; + acdb_handle_t acdb_handle = 0; + uint32_t offset = 0; + + if (IsNull(cmd_buf) || cmd_buf_size == 0) + { + ATS_ERR("Error[%d]: The request recieved is empty.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ATS_READ_SEEK_UI32(uint_acdb_handle, cmd_buf, offset); + acdb_handle = ACDB_UINT_TO_HANDLE(uint_acdb_handle); + + rsp.buf = rsp_buf; + rsp.size = rsp_buf_size; + + status = AtsCmdGetHeapEntryInfo(acdb_handle, &rsp); + + *rsp_buf_bytes_filled = rsp.bytes_filled; + return status; +} + +int32_t ats_onc_get_selected_heap_entry_data(uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + + int32_t status = AR_EOK; + uint32_t num_key_vectors = 0; + uint32_t num_key_vectors_found = 0; + AcdbBufferContext rsp = { 0 }; + uint32_t uint_acdb_handle = 0; + acdb_handle_t acdb_handle = 0; + AcdbGraphKeyVector key_vector = { 0 }; + uint32_t offset = 0; + uint32_t rsp_offset = sizeof(num_key_vectors_found); + + rsp.buf = &rsp_buf[rsp_offset];//make room to write num key vectors found + rsp.size = rsp_buf_size; + rsp.bytes_filled = 0; + + ATS_READ_SEEK_UI32(uint_acdb_handle, cmd_buf, offset); + ATS_READ_SEEK_UI32(num_key_vectors, cmd_buf, offset); + acdb_handle = ACDB_UINT_TO_HANDLE(uint_acdb_handle); + + for (uint32_t i = 0; i < num_key_vectors; i++) + { + ATS_READ_SEEK_UI32(key_vector.num_keys, cmd_buf, offset); + + key_vector.graph_key_vector = (AcdbKeyValuePair*)&cmd_buf[offset]; + offset += key_vector.num_keys * sizeof(AcdbKeyValuePair); + + status = AtsCmdGetHeapEntryData(acdb_handle , &key_vector, &rsp); + if (AR_FAILED(status)) + break;//todo: print key vector that failed + else + num_key_vectors_found++; + } + + ACDB_MEM_CPY_SAFE(rsp_buf, sizeof(num_key_vectors_found), + &num_key_vectors_found, sizeof(num_key_vectors_found)); + + *rsp_buf_bytes_filled = rsp_offset + rsp.bytes_filled; + return status; +} + +int32_t ats_onc_acdb_reinit_selected_database(uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + AcdbFile writable_path = { 0 }; + ats_cmd_selected_client_db_reinit_req_t* req = NULL; + AtsGetTempPath path = { 0 }; + acdb_handle_t acdb_handle = NULL; + + *rsp_buf_bytes_filled = 0; + + req = ACDB_MALLOC(ats_cmd_selected_client_db_reinit_req_t, 1); + + if (IsNull(req)) + { + ATS_ERR("Error[%d]: Unable to allocate reinit" + " request structure.", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + ATS_READ_SEEK_UI32(req->acdb_handle, cmd_buf, offset); + ATS_READ_SEEK_UI32(req->acdb_files.num_files, cmd_buf, offset); + + if (0 == req->acdb_files.num_files) + { + status = AR_EBADPARAM; + ATS_ERR("Error[%d]: Cannot reinitialize VM-%d database with 0 files.", + status, req->acdb_handle); + goto end; + } + + for (uint32_t i = 0; i < req->acdb_files.num_files; i++) + { + ATS_READ_SEEK_UI32( + req->acdb_files.database_files[i].fileNameLen, cmd_buf, offset); + + ACDB_MEM_CPY_SAFE( + &req->acdb_files.database_files[i].fileName, + req->acdb_files.database_files[i].fileNameLen, + &cmd_buf[offset], + req->acdb_files.database_files[i].fileNameLen); + offset += req->acdb_files.database_files[i].fileNameLen; + } + + path.path = writable_path.fileName; + status = AtsCmdGetTempFilePath(req->acdb_handle, &path); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get temp file path from File Manager."); + goto end; + } + + writable_path.fileNameLen = path.path_len; + + ATS_INFO("Re-initializing database for VM-%d..", req->acdb_handle); + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_GET_ACDB_CLIENT_HANDLE, + &req->acdb_handle, sizeof(uint32_t), + &acdb_handle, sizeof(acdb_handle_t)); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: An error occured getting client " + "database handle for VM-%d.", status, req->acdb_handle); + goto end; + } + + status = acdb_remove_database(&acdb_handle); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: An error occured while removing " + "database for VM-%d.", status, req->acdb_handle); + goto end; + } + + status = acdb_add_database(&req->acdb_files, &writable_path, NULL); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: An error occured while adding the " + "database for VM-%d", status, req->acdb_handle); + goto end; + } + +end: + ACDB_FREE(req); + + return status; +} + +int32_t ats_onc_check_selected_database_connection(uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t acdb_handle = 0; + acdb_context_handle_t *ctx_handle = NULL; + + ATS_READ_SEEK_UI32(acdb_handle, cmd_buf, offset); + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_GET_CONTEXT_HANDLE, &acdb_handle, + sizeof(uint32_t), &ctx_handle, sizeof(acdb_context_handle_t)); + + if (AR_FAILED(status)) + return AR_EHANDLE; + + return status; +} + +/*------------------------------------------ +* Public Functions +*------------------------------------------*/ + +/** +* \brief ats_online_ioctl +* The Online Service IOCTL +* \param [in] svc_cmd_id: The command to be issued +* \param [in] cmd_buf: Pointer to the command structure. +* \param [in] cmd_buf_size: Size of the command structure +* \param [out] rsp_buf: The response structre +* \param [in] rsp_buf_size: The size of the response +* \param [out] rsp_buf_bytes_filled: Number of bytes written to the response buffer +* \return 0 on success, non-zero on failure +*/ +int32_t ats_online_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +) +{ + int32_t status = AR_EOK; + + int32_t(*func_cb)( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled + ) = NULL; + + switch (svc_cmd_id) + { + case ATS_CMD_ONC_GET_SERVICE_INFO: + func_cb = ats_onc_get_service_info; + break; + case ATS_CMD_ONC_CHECK_CONNECTION: + func_cb = ats_onc_check_connection; + break; + case ATS_CMD_ONC_GET_MAX_BUFFER_LENGTH: + func_cb = ats_onc_get_max_buffer_length; + break; + case ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH: + func_cb = ats_onc_set_max_buffer_length; + break; + case ATS_CMD_ONC_GET_ACDB_FILES_INFO: + func_cb = ats_onc_get_acdb_files_info; + break; + case ATS_CMD_ONC_GET_ACDB_FILE: + func_cb = ats_onc_get_acdb_file; + break; + case ATS_CMD_ONC_GET_HEAP_ENTRY_INFO: + func_cb = ats_onc_get_heap_entry_info; + break; + case ATS_CMD_ONC_GET_HEAP_ENTRY_DATA: + func_cb = ats_onc_get_heap_entry_data; + break; + case ATS_CMD_ONC_GET_CAL_DATA_NON_PERSIST: + func_cb = ats_onc_get_cal_data_non_persist; + break; + case ATS_CMD_ONC_SET_CAL_DATA_NON_PERSIST: + func_cb = ats_onc_set_cal_data_non_persist; + break; + case ATS_CMD_ONC_SET_CAL_DATA_NON_PERSIST_2: + func_cb = ats_onc_set_cal_data_non_persist_2; + break; + case ATS_CMD_ONC_GET_CAL_DATA_PERSIST: + func_cb = ats_onc_get_cal_data_persist; + break; + case ATS_CMD_ONC_SET_CAL_DATA_PERSIST: + func_cb = ats_onc_set_cal_data_persist; + break; + case ATS_CMD_ONC_SET_CAL_DATA_PERSIST_2: + func_cb = ats_onc_set_cal_data_persist_2; + break; + case ATS_CMD_ONC_GET_TAG_DATA: + func_cb = ats_onc_get_tag_data; + break; + case ATS_CMD_ONC_SET_TAG_DATA: + func_cb = ats_onc_set_tag_data; + break; + case ATS_CMD_ONC_SET_TAG_DATA_2: + func_cb = ats_onc_set_tag_data_2; + break; + case ATS_CMD_ONC_DELETE_DELTA_FILES: + func_cb = ats_onc_delete_delta_files; + break; + case ATS_CMD_ONC_IS_DELTA_DATA_SUPPORTED: + func_cb = ats_onc_is_delta_data_supported; + break; + case ATS_CMD_ONC_GET_TEMP_PATH: + func_cb = ats_onc_get_temp_file_path; + break; + case ATS_CMD_ONC_ACDB_REINIT: + func_cb = ats_onc_reinit_acdb; + break; + case ATS_CMD_ONC_GET_ALL_DB_FILE_SETS: + func_cb = ats_onc_get_fileset_info; + break; + case ATS_CMD_ONC_GET_SELECTED_CLIENT_DB_FILE: + func_cb = ats_onc_get_selected_acdb_file; + break; + case ATS_CMD_ONC_GET_SELECTED_CLIENT_DB_HEAP_INFO: + func_cb = ats_onc_get_selected_heap_entry_info; + break; + case ATS_CMD_ONC_GET_SELECTED_CLIENT_DB_HEAP_DATA: + func_cb = ats_onc_get_selected_heap_entry_data; + break; + case ATS_CMD_ONC_SELECTED_CLIENT_DB_REINIT: + func_cb = ats_onc_acdb_reinit_selected_database; + break; + case ATS_CMD_ONC_CHECK_SELECTED_CLIENT_CONNECTION: + func_cb = ats_onc_check_selected_database_connection; + break; + default: + status = AR_EUNSUPPORTED; + ATS_ERR("Error[%d]: Command[%x] is not supported", + status, svc_cmd_id); + } + + if (status == AR_EOK) + { + ACDB_MUTEX_LOCK(ACDB_CTX_MAN_CLIENT_CMD_LOCK); + + status = func_cb(cmd_buf, + cmd_buf_size, + rsp_buf, + rsp_buf_size, + rsp_buf_bytes_filled); + + ACDB_MUTEX_UNLOCK(ACDB_CTX_MAN_CLIENT_CMD_LOCK); + } + + return status; +} + +/** +* \brief ats_online_init +* Initializes the online service to allow interaction between +* ACDB SW and and QST clients. +* \return AR_EOK, AR_EFAILED, AR_EHANDLE +*/ +int32_t ats_online_init(void) +{ + ATS_DBG("Registering Online Service..."); + + int32_t status = AR_EOK; + + status = ats_register_service(ATS_ONLINE_SERVICE_ID, ats_online_ioctl); + + if (AR_FAILED(status)) + { + ATS_DBG_MSG_1("Failed to register the Online Service.", status, 0); + } + + return status; +} + +/** +* \brief ats_online_deinit +* Initializes the online service to allow interaction between +* ACDB SW and and QST clients. +* \return AR_EOK, AR_EFAILED, AR_EHANDLE +*/ +int32_t ats_online_deinit(void) +{ + ATS_DBG("Deregistering Online Service..."); + + int32_t status = AR_EOK; + + status = ats_deregister_service(ATS_ONLINE_SERVICE_ID); + + if (AR_FAILED(status)) + { + ATS_DBG_MSG_1("Failed to deregister the Online Service.", status, 0); + } + + return status; +} diff --git a/acdb/ats/rtc/common/inc/ats_rtc.h b/acdb/ats/rtc/common/inc/ats_rtc.h new file mode 100644 index 0000000..1171c85 --- /dev/null +++ b/acdb/ats/rtc/common/inc/ats_rtc.h @@ -0,0 +1,62 @@ +#ifndef __ATS_RTC_H__ +#define __ATS_RTC_H__ +/** +*============================================================================== +* \file ats_rtc.h +* \brief +* A T S R T C H E A D E R F I L E +* +* The Realtime Calibration Service(RTC) header file contains all the +* definitions necessary for ATS to handle requests that operate the DSP +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +#include "gsl_rtc_intf.h" + +#define ATS_RTC_MAJOR_VERSION 0x1 +#define ATS_RTC_MINOR_VERSION 0x3 + +/** + \brief + The Online Service IOCTL + + \param [in] svc_cmd_id: The command to be issued + \param [in] cmd_buf: Pointer to the command structure. + \param [in] cmd_buf_size: + \param [out] rsp_buf: The response structre + \param [in] rsp_buf_size: The size of the response + \param [out] rsp_buf_bytes_filled: Number of bytes written to the response buffer + + \return 0 on success, non-zero on failure +*/ +int32_t ats_rtc_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +); + +/** + \brief + Initializes the Realtime Calibration to allow interaction between ACDB SW and and QST clients. + + \return 0 on success, non-zero on failure +*/ +int32_t ats_rtc_init(void); + +/** + \brief + Deinitializes the Realtime Calibration service to allow interaction between ACDB SW and and QST clients. + + \return 0 on success, non-zero on failure +*/ +int32_t ats_rtc_deinit(void); + +#endif /*__ATS_RTC_H__*/ diff --git a/acdb/ats/rtc/common/src/ats_rtc.c b/acdb/ats/rtc/common/src/ats_rtc.c new file mode 100644 index 0000000..ce9a0f2 --- /dev/null +++ b/acdb/ats/rtc/common/src/ats_rtc.c @@ -0,0 +1,1534 @@ +/** +*============================================================================== +* \file ats_rtc.h +* \brief +* A T S R T C S O U R C E F I L E +* +* The Realtime Calibration Service(RTC) header file contains implementation +* for ATS to handle requests that operate the DSP +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/* +Notes + +size_t is used in in calculating the size of the gsl structure headers b/c the +last element in those structures is a pointer. The size of a pointer may very +between x86 and x64 architectures +*/ + +#include "ats_i.h" +#include "ats_rtc.h" +#include "ats_common.h" +#include "acdb_utility.h" + +/****************************************************************************** +* Macros +******************************************************************************/ + +#define VCPM_PTR(type, vcpm_ptr, offset) ((type*)(vcpm_ptr + offset)) +#define ATS_VCPM_MODULE_INST_ID 0x00000004 +#define ATS_VCPM_PARAM_ID_CAL_KEYS 0x080011C1 + +/****************************************************************************** +* Type Definitions +******************************************************************************/ + +typedef struct _ats_vcpm_info_chunk_t AtsVcpmInfoChunk; +struct _ats_vcpm_info_chunk_t +{ + uint32_t subgraph_count; + uint32_t subgraph_id; + uint32_t table_size; + uint32_t major_version; + uint32_t minor_version; + uint32_t offset_master_key_tbl; + uint32_t ckv_table_count; + uint8_t ckv_table_list[0]; +}; + +typedef struct _ats_vcpm_chunk_t AtsVcpmChunk; +struct _ats_vcpm_chunk_t +{ + uint32_t size; + uint8_t data[0]; +}; + +typedef struct _ats_ckv_data_table_t AtsVcpmCkvDataTable; +struct _ats_ckv_data_table_t +{ + uint32_t table_size; + uint32_t offset_voice_key_table; + uint32_t dot_size; + uint32_t data_obj_count; + uint8_t data_obj_list[0]; +}; + +typedef struct _ats_cal_data_obj_t AtsVcpmCalDataObj; +struct _ats_cal_data_obj_t +{ + uint32_t offset_ckv_lut; + uint32_t data_offset_count; + uint8_t param_info_list[0]; +}; + +typedef struct _ats_vcpm_param_info_t AtsVcpmParamInfo; +struct _ats_vcpm_param_info_t +{ + uint32_t offset_data_pool; + uint32_t is_persistent; +}; + +typedef struct _ats_vcpm_master_key_table_t AtsVcpmMasterKeyTable; +struct _ats_vcpm_master_key_table_t +{ + uint32_t total_key_id_count; + uint8_t key_info_list[0]; +}; + +typedef struct _ats_vcpm_key_info_t AtsVcpmKeyInfo; +struct _ats_vcpm_key_info_t +{ + uint32_t key_id; + uint32_t is_dynamic; +}; + +typedef struct _ats_spf_param_cal_t AtsSpfParamCal; +struct _ats_spf_param_cal_t +{ + uint32_t instance_id; + uint32_t param_id; + uint32_t size; + uint32_t error_code; + uint8_t data[0]; +}; + +typedef struct _ats_iid_pid_pair_t AtsIidPidPair; +struct _ats_iid_pid_pair_t +{ + uint32_t instance_id; + uint32_t param_id; +}; + +typedef struct _ats_key_vector_t AtsKeyVector; +struct _ats_key_vector_t +{ + uint32_t key_count; + AcdbKeyValuePair kv_pair_list[0]; +}; + +typedef struct ats_vcpm_active_ckv_info_t AtsVcpmActiveCkvInfo; +struct ats_vcpm_active_ckv_info_t +{ + /**< The voice Subgraph ID to get the active CKV for. + This is provided by ATS */ + uint32_t subgraph_id; + + /**< The total number of ckvs defined in the vcpm master table. + This is provided by ATS*/ + uint32_t num_max_ckv_pairs; + /** Client fills this value when APM_CMD_GET_CFG is called for this param_id. */ + + /**< Number of AcdbKeyValuePair structures that + follow immediately after this structure. */ + uint32_t num_ckv_pairs; +}; + +/****************************************************************************** +* Function Prototypes +******************************************************************************/ + +int32_t ats_rtc_get_audio_persist_param_data( + uint32_t instance_id, uint32_t param_id, + AcdbSgIdPersistData *subgraph_cal, + uint8_t **param_cal, uint32_t *param_cal_size); + +int32_t ats_rtc_get_active_voice_ckv(AcdbSgIdPersistData *sg_cal_data, + struct gsl_rtc_param *rtc_param, + AtsKeyVector **active_ckv); +int32_t ats_rtc_compare_voice_key_ids(AtsVcpmChunk *voice_key_table_chunk, + uint32_t voice_key_table_offset, AtsKeyVector *active_ckv); + +int32_t ats_rtc_compare_voice_key_values(AtsVcpmChunk *voice_lut_chunk, + uint32_t voice_lut_offset, AtsKeyVector *active_ckv); + +int32_t ats_rtc_is_iid_pid_in_list( + AtsSpfParamCal *param_cal, AtsUintList *id_pair_list); + +int32_t ats_rtc_get_vcpm_master_key_table( + AcdbSgIdPersistData *sg_cal_data, + AtsVcpmMasterKeyTable **master_key_table); + +int32_t ats_rtc_get_vcpm_param_data( + AcdbSgIdPersistData *sg_cal_data, + AtsUintList *iid_pid_pair_list, + AtsKeyVector *active_ckv, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled); + +void AtsLogKeyVector(const AtsKeyVector *key_vector, KeyVectorType type); + +#if defined(_DEVICE_SIM) +int32_t gsl_rtc_get_active_usecase_info(struct gsl_rtc_active_uc_info *info) +{ + __UNREFERENCED_PARAM(info); + return 0; +} + +int32_t gsl_rtc_get_persist_data(struct gsl_rtc_persist_param *rtc_persist_param) +{ + __UNREFERENCED_PARAM(rtc_persist_param); + return 0; +} + +int32_t gsl_rtc_get_non_persist_data(struct gsl_rtc_param *rtc_persist_param) +{ + __UNREFERENCED_PARAM(rtc_persist_param); + return 0; +} + +int32_t gsl_rtc_set_persist_data(struct gsl_rtc_persist_param *rtc_persist_param) +{ + __UNREFERENCED_PARAM(rtc_persist_param); + return 0; +} + +int32_t gsl_rtc_set_non_persist_data(struct gsl_rtc_param *rtc_persist_param) +{ + __UNREFERENCED_PARAM(rtc_persist_param); + return 0; +} + +int32_t gsl_rtc_change_graph(struct gsl_rtc_change_graph_info *rtc_persist_param) +{ + __UNREFERENCED_PARAM(rtc_persist_param); + return 0; +} + +int32_t gsl_rtc_prepare_change_graph( + struct gsl_rtc_prepare_change_graph_info *rtc_persist_param) +{ + __UNREFERENCED_PARAM(rtc_persist_param); + return 0; +} + +int32_t gsl_open(const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect, gsl_handle_t *graph_handle) +{ + __UNREFERENCED_PARAM(graph_key_vect); + __UNREFERENCED_PARAM(cal_key_vect); + __UNREFERENCED_PARAM(graph_handle); + return 0; +} + +int32_t gsl_close(gsl_handle_t graph_handle) +{ + __UNREFERENCED_PARAM(graph_handle); + return 0; +} + +int32_t gsl_rtc_notify_conn_state(struct gsl_rtc_conn_info *info) +{ + __UNREFERENCED_PARAM(info); + return 0; +} +#endif + +//int32_t get_rtc_version( +// uint8_t *cmd_buf, +// uint32_t cmd_buf_size, +// uint8_t *rsp_buf, +// uint32_t rsp_buf_size, +// uint32_t *rsp_buf_bytes_filled) +//{ +// int32_t status = AR_EOK; +// __UNREFERENCED_PARAM(cmd_buf); +// __UNREFERENCED_PARAM(cmd_buf_size); +// __UNREFERENCED_PARAM(rsp_buf); +// __UNREFERENCED_PARAM(rsp_buf_size); +// __UNREFERENCED_PARAM(rsp_buf_bytes_filled); +// +// AtsVersion version = { ATS_RTC_MAJOR_VERSION, ATS_RTC_MINOR_VERSION }; +// +// ATS_MEM_CPY_SAFE(rsp_buf, &version, sizeof(version)); +// +// *rsp_buf_bytes_filled = sizeof(version); +// +// return status; +//} + +int32_t ats_rtc_get_active_usecase_info( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf_size); + + struct gsl_rtc_active_uc_info act_uc_info = { 0 }; + uint32_t sz_act_uc_info_header = sizeof(struct gsl_rtc_active_uc_info) - sizeof(size_t); + //Get Size + status = gsl_rtc_get_active_usecase_info(&act_uc_info); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get size of active usecase info", status); + *rsp_buf_bytes_filled = 0; + return status; + } + + ATS_MEM_CPY_SAFE(rsp_buf, sz_act_uc_info_header, + &act_uc_info, sz_act_uc_info_header); + *rsp_buf_bytes_filled = sz_act_uc_info_header; + act_uc_info.uc_data = (struct gsl_rtc_uc_data*)(rsp_buf + sz_act_uc_info_header); + + //Data (will be copied directly into the ATS buffer) + status = gsl_rtc_get_active_usecase_info(&act_uc_info); + *rsp_buf_bytes_filled = sz_act_uc_info_header + act_uc_info.total_size; + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get active usecase info", status); + } + + return status; +} + +int32_t ats_rtc_get_non_persistent_caldata( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf_size); + + struct gsl_rtc_param rtc_param = { 0 }; + int32_t sz_gsl_rtc_param_header = sizeof(rtc_param.graph_handle) + + sizeof(rtc_param.sgid) + sizeof(rtc_param.total_size); + + ATS_MEM_CPY_SAFE(&rtc_param, sz_gsl_rtc_param_header, + cmd_buf, sz_gsl_rtc_param_header); + rtc_param.sg_cal_data = (uint8_t*)(cmd_buf + sz_gsl_rtc_param_header); + + status = gsl_rtc_get_non_persist_data(&rtc_param); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Subgraph(0x%x) | Failed to get realtime " + "non-persistent calibration data", status, rtc_param.sgid); + } + + ATS_MEM_CPY_SAFE( + rsp_buf, sizeof(rtc_param.total_size), + &rtc_param.total_size, sizeof(rtc_param.total_size)); + ATS_MEM_CPY_SAFE( + rsp_buf + sizeof(rtc_param.total_size), + rtc_param.total_size, + rtc_param.sg_cal_data, + rtc_param.total_size); + + *rsp_buf_bytes_filled = sizeof(rtc_param.total_size) + rtc_param.total_size; + + return status; +} + +int32_t ats_rtc_get_persistent_caldata( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf_size); + + struct gsl_rtc_persist_param rtc_param = { 0 }; + int32_t sz_gsl_rtc_persist_param_header = + sizeof(rtc_param.graph_handle) + sizeof(rtc_param.sgid) + + sizeof(rtc_param.proc_id); + + ATS_MEM_CPY_SAFE(&rtc_param, sz_gsl_rtc_persist_param_header, + cmd_buf, sz_gsl_rtc_persist_param_header); + rtc_param.total_size = &rsp_buf_size; + rtc_param.sg_cal_data = rsp_buf; + + status = gsl_rtc_get_persist_data(&rtc_param); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get realtime " + "persistent calibration data", status); + *rsp_buf_bytes_filled = 0; + return status; + } + + *rsp_buf_bytes_filled = *rtc_param.total_size; + + return status; +} + +int32_t ats_rtc_get_persistent_caldata_v2( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + uint32_t persist_cal_size = 0; + uint32_t param_size = 0; + uint32_t rsp_offset = 0; + uint32_t *total_size = NULL; + struct gsl_rtc_persist_param rtc_persist_param = { 0 }; + struct gsl_rtc_param rtc_param_active_voice_ckv = { 0 }; + AtsCmdRtGetCalDataPersistV2Req *req = NULL; + AtsIidPidPair *iid_pid_pair_list = NULL; + uint8_t *param_cal = NULL; + AtsKeyVector *active_ckv = NULL; + AcdbSgIdPersistData *sg_cal_data = NULL; + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf_size); + + struct ats_iid { + uint32_t instance_id; + uint32_t param_id; + }; + + req = (AtsCmdRtGetCalDataPersistV2Req*)cmd_buf; + rtc_persist_param.graph_handle = req->graph_handle; + rtc_persist_param.proc_id = req->proc_id; + rtc_persist_param.sgid = req->subgraph_id; + rtc_persist_param.total_size = &persist_cal_size; + + rtc_param_active_voice_ckv.graph_handle = rtc_persist_param.graph_handle; + rtc_param_active_voice_ckv.sgid = rtc_persist_param.sgid; + //rtc_param_active_voice_ckv.proc_id = rtc_persist_param.proc_id; + + //status = ats_test_gsl_rtc_get_persist_data(&rtc_persist_param); + status = gsl_rtc_get_persist_data(&rtc_persist_param); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get realtime " + "persistent calibration data", status); + *rsp_buf_bytes_filled = 0; + return status; + } + + /* Search for IID PID and write to response buffer */ + sg_cal_data = (AcdbSgIdPersistData*)rtc_persist_param.sg_cal_data; + iid_pid_pair_list = (AtsIidPidPair*)req->iid_pid_pair_list.list; + rsp_offset = sizeof(uint32_t); + + if (!sg_cal_data) + { + ATS_ERR("Unable to get cal data. sg_cal_data is null"); + return AR_EBADPARAM; + } + + switch (req->cal_type) + { + case ATS_CAL_TYPE_AUDIO: + + total_size = (uint32_t*)rsp_buf; + for (uint32_t i = 0; i < req->iid_pid_pair_list.count; i++) + { + status = ats_rtc_get_audio_persist_param_data( + iid_pid_pair_list[i].instance_id, + iid_pid_pair_list[i].param_id, + sg_cal_data, + ¶m_cal, ¶m_size); + if (AR_FAILED(status)) + { + ATS_DBG("Error[%d]: No persist cal found for " + "[0x%x, 0x%x]", status, + iid_pid_pair_list[i].instance_id, + iid_pid_pair_list[i].param_id); + continue; + } + + ACDB_MEM_CPY_SAFE(rsp_buf + rsp_offset, param_size, + param_cal, param_size); + rsp_offset += param_size; + *rsp_buf_bytes_filled += param_size; + } + + *rsp_buf_bytes_filled += sizeof(uint32_t); + *total_size = *rsp_buf_bytes_filled; + + break; + + case ATS_CAL_TYPE_VOICE: + + //Get Active Voice CKV + rtc_param_active_voice_ckv.sg_cal_data = rsp_buf; + rtc_param_active_voice_ckv.total_size = rsp_buf_size; + + status = ats_rtc_get_active_voice_ckv(sg_cal_data, + &rtc_param_active_voice_ckv, &active_ckv); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Unable to get the active voice ckv", status); + return status; + } + + status = ats_rtc_get_vcpm_param_data( + sg_cal_data, &req->iid_pid_pair_list, + active_ckv, rsp_buf, rsp_buf_size, rsp_buf_bytes_filled); + + break; + + default: + break; + } + + return status; +} + +int32_t ats_rtc_set_non_persistent_caldata( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + struct gsl_rtc_param rtc_param = { 0 }; + int32_t sz_gsl_rtc_param_header = sizeof(rtc_param.graph_handle) + sizeof(rtc_param.sgid) + sizeof(rtc_param.total_size); + + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + ATS_MEM_CPY_SAFE(&rtc_param, sz_gsl_rtc_param_header, + cmd_buf, sz_gsl_rtc_param_header); + rtc_param.sg_cal_data = (uint8_t*)(cmd_buf + sz_gsl_rtc_param_header); + + status = gsl_rtc_set_non_persist_data(&rtc_param); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to set realtime non-persistent calibration data", status); + } + return status; +} + +int32_t ats_rtc_set_persistent_caldata( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + //int32_t sz_gsl_rtc_persist_param_header = sizeof(struct gsl_rtc_persist_param) - sizeof(size_t); + struct gsl_rtc_persist_param rtc_param = { 0 }; + int32_t sz_gsl_rtc_persist_param_header = + sizeof(rtc_param.graph_handle) + sizeof(rtc_param.sgid) + + sizeof(rtc_param.proc_id) + sizeof(*rtc_param.total_size); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + ATS_MEM_CPY_SAFE(&rtc_param, sz_gsl_rtc_persist_param_header - sizeof(uint32_t), + cmd_buf, sz_gsl_rtc_persist_param_header - sizeof(uint32_t)); + offset += sz_gsl_rtc_persist_param_header - sizeof(uint32_t); + rtc_param.total_size = (uint32_t*)(cmd_buf + offset); + rtc_param.sg_cal_data = (uint8_t*)(cmd_buf + sz_gsl_rtc_persist_param_header); + + status = gsl_rtc_set_persist_data(&rtc_param); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to set realtime persistent calibration data", status); + } + return status; +} + +int32_t ats_rtc_set_persistent_caldata_v2( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + uint32_t offset = 0; + struct gsl_rtc_persist_param rtc_param = { 0 }; + + ATS_READ_SEEK_UI32(rtc_param.graph_handle, cmd_buf, offset); + ATS_READ_SEEK_UI32(rtc_param.sgid, cmd_buf, offset); + ATS_READ_SEEK_UI32(rtc_param.proc_id, cmd_buf, offset); + + rtc_param.total_size = (uint32_t*)(cmd_buf + offset); + offset += sizeof(uint32_t); + + if (*rtc_param.total_size > 0) + { + rtc_param.sg_cal_data = cmd_buf + offset; + offset += *rtc_param.total_size; + ATS_INFO("Directly updating 'shared' calibration memory.."); + } + else + { + rtc_param.sg_cal_data = NULL; + ATS_INFO("Refreshing 'shared' calibration memory.."); + } + + rtc_param.ckv = (struct gsl_rtc_key_vector*)(cmd_buf + offset); + + AtsLogKeyVector((AtsKeyVector*)rtc_param.ckv, CAL_KEY_VECTOR); + + status = gsl_rtc_set_persist_data(&rtc_param); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to set realtime " + "persistent calibration data", status); + } + + return status; +} + +int32_t ats_rtgm_prepare_change_graph( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + uint32_t num_keys = 0; + uint32_t offset = 0; + AcdbGraphKeyVector *tmp_key_vector = NULL; + struct gsl_rtc_prepare_change_graph_info rtgm_info = { 0 }; + struct gsl_rtc_key_vector *key_vector = NULL; + + ATS_MEM_CPY_SAFE(&rtgm_info.graph_handle, sizeof(uint32_t), + &cmd_buf[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + /* Set the pointers for the Key Vectors to point to the + * appropriate places within the cmd_buf. GSL will copy + * the data. + */ + key_vector = (struct gsl_rtc_key_vector*)&cmd_buf[offset]; + ATS_MEM_CPY_SAFE(&num_keys, + sizeof(uint32_t), &cmd_buf[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + rtgm_info.old_gkv = key_vector; + offset += num_keys * (sizeof(struct gsl_key_value_pair)); + + /* Read and point to Subgraph Connection Info blob + * num_sgs is apart of the subgraph connection blob. + */ + rtgm_info.size_of_sg_conn_info = + *((uint32_t*)&cmd_buf[offset]) - sizeof(uint32_t); + offset += sizeof(uint32_t); + + //Point to subgraph connections + rtgm_info.num_sgs = *(uint32_t*)&cmd_buf[offset]; + rtgm_info.sg_conn_info = (uint32_t*)&cmd_buf[offset + sizeof(uint32_t)]; + offset += rtgm_info.size_of_sg_conn_info + sizeof(uint32_t); + + //Read and point to modified subgraph list + ATS_MEM_CPY_SAFE(&rtgm_info.num_modified_sgs, sizeof(uint32_t), + &cmd_buf[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + if (rtgm_info.num_modified_sgs != 0) + { + rtgm_info.modified_sgs = (uint32_t*)&cmd_buf[offset]; + offset += rtgm_info.num_modified_sgs * sizeof(uint32_t); + + rtgm_info.size_of_modified_sg_conn_info = + *((uint32_t*)&cmd_buf[offset]) - sizeof(uint32_t); + offset += sizeof(uint32_t); + + /* Point to subgraph connections + * num_modified_sg_connections is apart of the modified + * subgraph connection blob + */ + rtgm_info.num_modified_sg_connections = + *(uint32_t*)&cmd_buf[offset]; + rtgm_info.modified_sg_conn_info = + (uint32_t*)&cmd_buf[offset + sizeof(uint32_t)]; + } + + status = gsl_rtc_prepare_change_graph(&rtgm_info); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: An error occured durning the runtime graph" + " update for Graph Handle(%x)", status, rtgm_info.graph_handle); + + //Log Key Vectors + KeyVectorType kv_type = GRAPH_KEY_VECTOR; + tmp_key_vector = (void*)rtgm_info.old_gkv; + + if (tmp_key_vector->num_keys != 0) + tmp_key_vector->graph_key_vector = (AcdbKeyValuePair*) + ((uint8_t*)tmp_key_vector + sizeof(uint32_t)); + else + tmp_key_vector->graph_key_vector = NULL; + + LogKeyVector(tmp_key_vector, kv_type); + } + + return status; +} + +int32_t ats_rtgm_change_graph( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_keys = 0; + uint32_t key_vector_count = 3; + AcdbGraphKeyVector *tmp_key_vector = NULL; + struct gsl_rtc_key_vector *key_vector = NULL; + struct gsl_rtc_change_graph_info rtgm_info = { 0 }; + + ATS_MEM_CPY_SAFE(&rtgm_info.graph_handle, sizeof(uint32_t), + &cmd_buf[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + /* Set the pointers for the Key Vectors to point to the + * appropriate places within the cmd_buf. GSL will copy + * the data. + */ + for (uint32_t i = 0; i < key_vector_count; i++) + { + key_vector = (struct gsl_rtc_key_vector*)&cmd_buf[offset]; + ATS_MEM_CPY_SAFE(&num_keys, + sizeof(uint32_t), &cmd_buf[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + + switch (i) + { + case 0: + rtgm_info.old_gkv = key_vector; + break; + case 1: + rtgm_info.new_gkv = key_vector; + break; + case 2: + rtgm_info.new_ckv = key_vector; + break; + } + + offset += num_keys * (sizeof(struct gsl_key_value_pair)); + } + + if (offset < cmd_buf_size - sizeof(rtgm_info.tag_data_size)) + { + rtgm_info.tag_data_size = *(uint32_t*)&cmd_buf[offset]; + offset += sizeof(uint32_t); + + if (rtgm_info.tag_data_size > 0) + { + rtgm_info.tag_data = &cmd_buf[offset]; + } + } + + status = gsl_rtc_change_graph(&rtgm_info); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: An error occured durning the runtime graph" + " update for Graph Handle(%x)", status, rtgm_info.graph_handle); + + //Log Key Vectors + KeyVectorType kv_type = GRAPH_KEY_VECTOR; + for (uint32_t i = 0; i < key_vector_count; i++) + { + switch (i) + { + case 0: + tmp_key_vector = (void*)rtgm_info.old_gkv; + break; + case 1: + tmp_key_vector = (void*)rtgm_info.new_gkv; + break; + case 2: + tmp_key_vector = (void*)rtgm_info.new_ckv; + kv_type = CAL_KEY_VECTOR; + break; + } + + if (tmp_key_vector->num_keys != 0) + tmp_key_vector->graph_key_vector = (AcdbKeyValuePair*) + ((uint8_t*)tmp_key_vector + sizeof(uint32_t)); + else + tmp_key_vector->graph_key_vector = NULL; + + LogKeyVector(tmp_key_vector, kv_type); + } + } + + *rsp_buf_bytes_filled = 0; + return status; +} + +int32_t ats_rt_graph_open( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + + int32_t status = AR_EOK; + uint32_t offset = 0; + + struct gsl_key_vector gkv = { 0 }; + struct gsl_key_vector ckv = { 0 }; + //sizeof(gkv.num_keys + ckv.num_keys + uint32_t min_req_size = 2 * sizeof(uint32_t); + uint32_t handle = 0; + gsl_handle_t graph_handle = &handle; + + *rsp_buf_bytes_filled = 0; + + + if (IsNull(cmd_buf) || cmd_buf_size < min_req_size) + { + ATS_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + gkv.num_kvps = *((uint32_t*)cmd_buf); + offset += sizeof(uint32_t); + + if (gkv.num_kvps > 0) + { + gkv.kvp = (struct gsl_key_value_pair*)((uint8_t*)cmd_buf + offset); + offset += gkv.num_kvps * sizeof(struct gsl_key_value_pair); + } + + ckv.num_kvps = *((uint32_t*)((uint8_t*)cmd_buf + offset)); + offset += sizeof(uint32_t); + if (ckv.num_kvps > 0) + { + ckv.kvp = (struct gsl_key_value_pair*)((uint8_t*)cmd_buf + offset); + offset += ckv.num_kvps * sizeof(struct gsl_key_value_pair); + } + + /* If the empty GKV is provided, this means we want to + * open a special dummy usecase */ + if (gkv.num_kvps == 0) + status = gsl_open(NULL, NULL, &graph_handle); + else + status = gsl_open(&gkv, &ckv, &graph_handle); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to open graph", status); + //LogKeyVector(tmp_key_vector, kv_type); + } + else if (AR_SUCCEEDED(status) && !IsNull(graph_handle)) + { + handle = (uint32_t)(uintptr_t)graph_handle; + + ACDB_MEM_CPY_SAFE(rsp_buf, sizeof(uint32_t), &handle, sizeof(uint32_t)); + *rsp_buf_bytes_filled = sizeof(uint32_t); + } + else if (IsNull(graph_handle)) + { + status = AR_EHANDLE; + ATS_ERR("Error[%d]: Graph handle is null", status); + } + + return status; +} + +int32_t ats_rt_graph_close( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + int32_t status = AR_EOK; + uint32_t handle = 0; + gsl_handle_t graph_handle = NULL; + + *rsp_buf_bytes_filled = 0; + + if (IsNull(cmd_buf) || cmd_buf_size < sizeof(AtsCmdRtGraphCloseReq)) + { + ATS_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + handle = *((uint32_t*)cmd_buf); + graph_handle = (gsl_handle_t)(uintptr_t)handle; + + status = gsl_close(graph_handle); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to close graph"); + } + + return status; +} + +int32_t ats_rt_notify_connection_state( + uint8_t* cmd_buf, + uint32_t cmd_buf_size, + uint8_t* rsp_buf, + uint32_t rsp_buf_size, + uint32_t* rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(cmd_buf); + __UNREFERENCED_PARAM(cmd_buf_size); + __UNREFERENCED_PARAM(rsp_buf); + __UNREFERENCED_PARAM(rsp_buf_size); + __UNREFERENCED_PARAM(rsp_buf_bytes_filled); + int32_t status = AR_EOK; + + struct gsl_rtc_conn_info session = { 0 }; + + if (IsNull(cmd_buf) || cmd_buf_size < sizeof(struct gsl_rtc_conn_info)) + { + ATS_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + session.state = *((uint32_t*)cmd_buf); + + status = gsl_rtc_notify_conn_state(&session); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to set rt connection state"); + } + + return status; +} + +int32_t ats_rtc_ioctl( + uint32_t svc_cmd_id, + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled +) +{ + int32_t status = AR_EOK; + + int32_t(*func_cb)( + uint8_t *cmd_buf, + uint32_t cmd_buf_size, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled + ) = NULL; + + switch (svc_cmd_id) + { + //case ATS_CMD_RT_GET_VERSION: + // func_cb = get_rtc_version; + // break; + case ATS_CMD_RT_GET_ACTIVE_INFO: + func_cb = ats_rtc_get_active_usecase_info; + break; + case ATS_CMD_RT_GET_CAL_DATA_NON_PERSISTENT: + func_cb = ats_rtc_get_non_persistent_caldata; + break; + case ATS_CMD_RT_GET_CAL_DATA_PERSISTENT: + func_cb = ats_rtc_get_persistent_caldata; + break; + //case ATS_CMD_RT_GET_CAL_DATA_GBL_PERSISTENT: + // func_cb = NULL; + // break; + case ATS_CMD_RT_SET_CAL_DATA_NON_PERSISTENT: + func_cb = ats_rtc_set_non_persistent_caldata; + break; + case ATS_CMD_RT_SET_CAL_DATA_PERSISTENT: + func_cb = ats_rtc_set_persistent_caldata; + break; + case ATS_CMD_RT_GM_PREPARE_CHANGE_GRAPH: + func_cb = ats_rtgm_prepare_change_graph; + break; + case ATS_CMD_RT_GM_CHANGE_GRAPH: + func_cb = ats_rtgm_change_graph; + break; + case ATS_CMD_RT_OPEN_GRAPH: + func_cb = ats_rt_graph_open; + break; + case ATS_CMD_RT_CLOSE_GRAPH: + func_cb = ats_rt_graph_close; + break; + case ATS_CMD_RT_NOTIFY_CONNECTION_STATE: + func_cb = ats_rt_notify_connection_state; + break; + case ATS_CMD_RT_GET_CAL_DATA_PERSISTENT_V2: + func_cb = ats_rtc_get_persistent_caldata_v2; + break; + case ATS_CMD_RT_SET_CAL_DATA_PERSISTENT_V2: + func_cb = ats_rtc_set_persistent_caldata_v2; + break; + default: + status = AR_EUNSUPPORTED; + ATS_ERR("Error[%d]: Command[%x] is not supported", svc_cmd_id, status); + break; + } + + if (!AR_FAILED(status)) + { + status = func_cb(cmd_buf, cmd_buf_size, + rsp_buf, rsp_buf_size, rsp_buf_bytes_filled); + } + + return status; +} + +/** +* \brief +* Initializes the rtc service to allow interaction between +* ACDB SW and and QST clients. +* +* \return AR_EOK, AR_EFAILED, AR_EHANDLE +*/ +int32_t ats_rtc_init(void) +{ + ATS_DBG("Registering ATS Relatime Calibration Service..."); + + int32_t status = AR_EOK; + + status = ats_register_service(ATS_RTC_SERVICE_ID, ats_rtc_ioctl); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to register the ATS Realtime Calibration Service.", status); + } + + return status; +} + +/** +* \brief +* Initializes the rtc service to allow interaction between +* ACDB SW and and QST clients. +* +* \return AR_EOK, AR_EFAILED, AR_EHANDLE +*/ +int32_t ats_rtc_deinit(void) +{ + ATS_DBG("Deregistering ATS Relatime Calibration Service..."); + + int32_t status = AR_EOK; + + status = ats_deregister_service(ATS_RTC_SERVICE_ID); + if (status != AR_EOK) + { + ATS_ERR("Error[%d]: Failed to deregister the ATS Realtime Calibration Service.", status); + } + + return status; +} + +/****************************************************************************** +* Utility/Helper Functions +******************************************************************************/ + +int32_t ats_rtc_get_audio_persist_param_data( + uint32_t instance_id, uint32_t param_id, + AcdbSgIdPersistData *subgraph_cal, + uint8_t **param_cal, uint32_t *param_cal_size) +{ + int32_t status = AR_EOK; + AtsSpfParamCal *m = NULL; + uint32_t offset = 0; + bool_t found = FALSE; + + if (IsNull(subgraph_cal) || IsNull(param_cal) || IsNull(param_cal_size)) + { + ATS_ERR("Error[%d]: One or more input parameter(s) are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + while (offset < subgraph_cal->persist_data_size) + { + m = (AtsSpfParamCal*)(subgraph_cal->buf + offset); + if (m->instance_id == instance_id && m->param_id == param_id) + { + *param_cal = (uint8_t*)(subgraph_cal->buf + offset); + *param_cal_size = sizeof(AtsSpfParamCal) + m->size; + found = TRUE; + break; + } + + offset += sizeof(AtsSpfParamCal) + ACDB_ALIGN_8_BYTE(m->size); + } + + if (!found) + { + status = AR_ENOTEXIST; + ATS_ERR("Error[%d]: [0x%x, 0x%x] " + "not found in persist mem.", + status); + } + + return status; +} + +void AtsLogKeyVector(const AtsKeyVector *key_vector, KeyVectorType type) +{ + if (key_vector == NULL) return; + + switch (type) + { + case GRAPH_KEY_VECTOR: + ATS_INFO("Graph Key Vector with %d key(s):", key_vector->key_count); + break; + case CAL_KEY_VECTOR: + ATS_INFO("Calibration Key Vector with %d key(s):", key_vector->key_count); + break; + case TAG_KEY_VECTOR: + ATS_INFO("Tag Key Vector with %d key(s):", key_vector->key_count); + break; + default: + return; + } + + for (uint32_t i = 0; i < key_vector->key_count; i++) + { + ATS_INFO("[Key:0x%08x Val:0x%08x]", + key_vector->kv_pair_list[i].key, + key_vector->kv_pair_list[i].value); + } +} + +int32_t ats_rtc_get_active_voice_ckv(AcdbSgIdPersistData *sg_cal_data, + struct gsl_rtc_param *rtc_param, + AtsKeyVector **active_ckv) +{ + int32_t status = AR_EOK; + uint32_t sg_cal_data_size = 0; + struct gsl_rtc_param rtc_ckv_param = { 0 }; + AtsSpfParamCal voice_ckv_param = { 0 }; + AtsVcpmActiveCkvInfo vcpm_ckv_info = { 0 }; + AtsVcpmMasterKeyTable *master_key_table = NULL; + + if (IsNull(sg_cal_data) || IsNull(rtc_param) || IsNull(active_ckv)) + { + if (!sg_cal_data) + ATS_ERR("subgraph cal data is null"); + if (!master_key_table) + ATS_ERR("vcpm master key table is null"); + if (!active_ckv) + ATS_ERR("active ckv is null"); + + ATS_ERR("Error[%d]: One or more input parameter(s) are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = ats_rtc_get_vcpm_master_key_table(sg_cal_data, &master_key_table); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Unable to get master key table for Subgraph(0x%x)", + status, rtc_param->sgid); + return status; + } + + if (!IsNull(master_key_table)) + { + vcpm_ckv_info.num_max_ckv_pairs = master_key_table->total_key_id_count; + ATS_INFO("Subgraph(0x%x) | VCPM Master Key Table Key Count: %d", + rtc_param->sgid, vcpm_ckv_info.num_max_ckv_pairs); + } + else + { + status = AR_EBADPARAM; + ATS_ERR("Error[%d]: Unable to get master key table is NULL", + status); + return status; + } + + vcpm_ckv_info.subgraph_id = rtc_param->sgid; + + voice_ckv_param.instance_id = ATS_VCPM_MODULE_INST_ID; + voice_ckv_param.param_id = ATS_VCPM_PARAM_ID_CAL_KEYS; + voice_ckv_param.error_code = 0; + voice_ckv_param.size = sizeof(AtsVcpmActiveCkvInfo) + + vcpm_ckv_info.num_max_ckv_pairs * sizeof(AcdbKeyValuePair); + + sg_cal_data_size = sizeof(AtsSpfParamCal) + + voice_ckv_param.size; + + //Use response buffer to get CKV + rtc_ckv_param.graph_handle = rtc_param->graph_handle; + rtc_ckv_param.sgid = rtc_param->sgid; + rtc_ckv_param.sg_cal_data = rtc_param->sg_cal_data; + rtc_ckv_param.total_size = sg_cal_data_size; + + ar_mem_set(rtc_ckv_param.sg_cal_data, 0, sg_cal_data_size); + + /* Copy SPF param header */ + ACDB_MEM_CPY_SAFE(rtc_ckv_param.sg_cal_data, sizeof(AtsSpfParamCal), + &voice_ckv_param, sizeof(AtsSpfParamCal)); + + /* Copy VCPM Active CKV Param Header */ + ACDB_MEM_CPY_SAFE(rtc_ckv_param.sg_cal_data + sizeof(AtsSpfParamCal), + sizeof(AtsVcpmActiveCkvInfo), + &vcpm_ckv_info, sizeof(AtsVcpmActiveCkvInfo)); + + //status = ats_test_gsl_rtc_get_non_persist_data(&rtc_ckv_param); + status = gsl_rtc_get_non_persist_data(&rtc_ckv_param); + if (AR_FAILED(status)) + { + return status; + } + + //Parse payload and store it in response buffer + *active_ckv = (AtsKeyVector*)(rtc_ckv_param.sg_cal_data + + sizeof(AtsSpfParamCal) + + sizeof(AtsVcpmActiveCkvInfo) - sizeof(uint32_t)); + + AtsLogKeyVector(*active_ckv, CAL_KEY_VECTOR); + return status; +} + +int32_t ats_rtc_compare_voice_key_ids(AtsVcpmChunk *voice_key_table_chunk, + uint32_t voice_key_table_offset, AtsKeyVector *active_ckv) +{ + int32_t status = AR_EOK; + uint32_t num_found = 0; + AtsUintList *voice_key_table = NULL; + + voice_key_table = (AtsUintList*) + ((uint8_t*)voice_key_table_chunk->data + + voice_key_table_offset); + + //Compare Key IDs + if (voice_key_table->count == active_ckv->key_count) + { + for (uint32_t i = 0; i < voice_key_table->count; i++) + { + for (uint32_t j = 0; j < voice_key_table->count; j++) + { + if (voice_key_table->list[i] == + active_ckv->kv_pair_list[j].key) + { + num_found++; + break; + } + } + } + + if (voice_key_table->count != num_found) + return AR_ENOTEXIST; + } + else + { + status = AR_ENOTEXIST; + } + + return status; +} + +int32_t ats_rtc_compare_voice_key_values(AtsVcpmChunk *voice_lut_chunk, + uint32_t voice_lut_offset, AtsKeyVector *active_ckv) +{ + int32_t status = AR_EOK; + uint32_t num_found = 0; + AtsUintList *voice_lut_table = NULL; + + voice_lut_table = (AtsUintList*) + ((uint8_t*)voice_lut_chunk->data + + voice_lut_offset); + + //Compare Key Values + if (voice_lut_table->count == active_ckv->key_count) + { + for (uint32_t i = 0; i < voice_lut_table->count; i++) + { + for (uint32_t j = 0; j < voice_lut_table->count; j++) + { + if (voice_lut_table->list[i] == + active_ckv->kv_pair_list[j].value) + { + num_found++; + break; + } + } + } + + if (voice_lut_table->count != num_found) + return AR_ENOTEXIST; + } + else + { + status = AR_ENOTEXIST; + } + + return status; +} + +int32_t ats_rtc_is_iid_pid_in_list( + AtsSpfParamCal *param_cal, AtsUintList *id_pair_list) +{ + int32_t status = AR_ENOTEXIST; + AtsIidPidPair *list = (AtsIidPidPair*) + ((uint8_t*)id_pair_list + sizeof(AtsUintList)); + + for (uint32_t i = 0; i < id_pair_list->count; i++) + { + if (0 == ar_mem_cmp(param_cal, (void*)&list[i], + sizeof(AtsIidPidPair))) + return AR_EOK; + } + + return status; +} + +int32_t ats_rtc_get_vcpm_master_key_table( + AcdbSgIdPersistData *sg_cal_data, + AtsVcpmMasterKeyTable **master_key_table) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint8_t *vcpm_cal = NULL; + AtsVcpmChunk *master_key_table_chunk = NULL; + AtsVcpmInfoChunk *info = NULL; + + if (IsNull(sg_cal_data) || IsNull(master_key_table)) + { + if (!sg_cal_data) + ATS_ERR("subgraph cal data is null"); + if (!master_key_table) + ATS_ERR("vcpm master key table is null"); + + ATS_ERR("Error[%d]: One or more input parameters(s) are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + vcpm_cal = (uint8_t*)sg_cal_data->buf; + offset += sizeof(AtsSpfParamCal); + + info = VCPM_PTR(AtsVcpmInfoChunk, vcpm_cal, offset); + offset += sizeof(info->subgraph_count) + sizeof(info->subgraph_id) + + sizeof(info->table_size) + info->table_size; + + /* Setup chunk pointers */ + master_key_table_chunk = VCPM_PTR(AtsVcpmChunk, vcpm_cal, offset); + offset += sizeof(AtsVcpmChunk); + + *master_key_table = VCPM_PTR(AtsVcpmMasterKeyTable, vcpm_cal, offset); + + return status; +} + +int32_t ats_rtc_get_vcpm_param_data( + AcdbSgIdPersistData *sg_cal_data, + AtsUintList *iid_pid_pair_list, + AtsKeyVector *active_ckv, + uint8_t *rsp_buf, + uint32_t rsp_buf_size, + uint32_t *rsp_buf_bytes_filled) +{ + __UNREFERENCED_PARAM(rsp_buf_size); + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t base_dp_offset = 0; + uint32_t blob_offset = 0; + uint32_t vckt_offset = 0; + uint32_t vlut_offset = 0; + uint32_t dp_offset = 0; + uint32_t num_params_found = 0; + uint32_t *total_size = NULL; + uint8_t *vcpm_cal = NULL; + AtsVcpmInfoChunk *info = NULL; + AtsVcpmCkvDataTable *ckv_data_table = NULL; + AtsVcpmCalDataObj *cal_data_obj = NULL; + AtsVcpmParamInfo *param_info = NULL; + AtsSpfParamCal *param_cal = NULL; + AtsVcpmChunk *master_key_table_chunk = NULL; + AtsVcpmChunk *voice_key_table_chunk = NULL; + AtsVcpmChunk *lookup_table_chunk = NULL; + AtsVcpmChunk *data_pool_chunk = NULL; + + if (IsNull(sg_cal_data) || IsNull(iid_pid_pair_list) || + IsNull(active_ckv) || IsNull(rsp_buf) || IsNull(rsp_buf_bytes_filled)) + { + ATS_ERR("Error[%d]: One or more input parameters(s) are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + /* make space to write total size */ + blob_offset = sizeof(uint32_t); + total_size = (uint32_t*)rsp_buf; + + vcpm_cal = (uint8_t*)sg_cal_data->buf; + offset += sizeof(AtsSpfParamCal); + + info = VCPM_PTR(AtsVcpmInfoChunk, vcpm_cal, offset); + offset += sizeof(info->subgraph_count) + sizeof(info->subgraph_id) + + sizeof(info->table_size) + info->table_size; + + /* Setup chunk pointers */ + master_key_table_chunk = VCPM_PTR(AtsVcpmChunk, vcpm_cal, offset); + offset += sizeof(AtsVcpmChunk) + + master_key_table_chunk->size; + voice_key_table_chunk = VCPM_PTR(AtsVcpmChunk, vcpm_cal, offset); + offset += sizeof(AtsVcpmChunk) + + voice_key_table_chunk->size; + lookup_table_chunk = VCPM_PTR(AtsVcpmChunk, vcpm_cal, offset); + offset += sizeof(AtsVcpmChunk) + + lookup_table_chunk->size; + data_pool_chunk = VCPM_PTR(AtsVcpmChunk, vcpm_cal, offset); + base_dp_offset = offset; + + /* Find active CKV Calibration and write matching to response. + * The response buffer contains the active CKV, but once the Voice CKV + * Table is found, the active CKV is no longer needed. At this point the + * response buffer can be overwritten. */ + offset = sizeof(AtsSpfParamCal) + sizeof(AtsVcpmInfoChunk); + + for (uint32_t i = 0; i < info->ckv_table_count; i++) + { + ckv_data_table = VCPM_PTR(AtsVcpmCkvDataTable, vcpm_cal, offset); + + vckt_offset = ckv_data_table->offset_voice_key_table; + + status = ats_rtc_compare_voice_key_ids( + voice_key_table_chunk, vckt_offset, active_ckv); + if (AR_FAILED(status)) + { + offset += sizeof(ckv_data_table->table_size) + + ckv_data_table->table_size; + continue; + } + + offset += sizeof(AtsVcpmCkvDataTable); + + for (uint32_t j = 0; j < ckv_data_table->data_obj_count; j++) + { + cal_data_obj = VCPM_PTR(AtsVcpmCalDataObj, vcpm_cal, offset); + + vlut_offset = cal_data_obj->offset_ckv_lut; + + status = ats_rtc_compare_voice_key_values( + lookup_table_chunk, vlut_offset, active_ckv); + if (AR_FAILED(status)) + { + offset += sizeof(AtsVcpmCalDataObj) + + cal_data_obj->data_offset_count + * sizeof(AtsVcpmParamInfo); + continue; + } + + offset += sizeof(AtsVcpmCalDataObj); + + for (uint32_t k = 0; k < cal_data_obj->data_offset_count; k++) + { + param_info = + VCPM_PTR(AtsVcpmParamInfo, vcpm_cal, offset); + + dp_offset = param_info->offset_data_pool; + + param_cal = VCPM_PTR(AtsSpfParamCal, + (uint8_t*)data_pool_chunk + sizeof(uint32_t), + dp_offset); + + status = ats_rtc_is_iid_pid_in_list( + param_cal, iid_pid_pair_list); + if (AR_FAILED(status)) + { + offset += sizeof(AtsVcpmParamInfo); + continue; + } + + /* Write SPF param header */ + status = ar_mem_cpy( + rsp_buf + blob_offset, sizeof(AtsSpfParamCal), + param_cal, sizeof(AtsSpfParamCal)); + blob_offset += sizeof(AtsSpfParamCal); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Unable to copy param header to " + "response buffer", status); + break; + } + + /* Write param data */ + status = ar_mem_cpy( + rsp_buf + blob_offset, param_cal->size, + param_cal->data, param_cal->size); + blob_offset += param_cal->size; + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Unable to copy param data to " + "response buffer", status); + break; + } + + offset += sizeof(AtsVcpmParamInfo); + + num_params_found++; + + if (num_params_found == iid_pid_pair_list->count) + { + break; + } + } + + break; + } + + break; + } + + if (num_params_found != iid_pid_pair_list->count) + { + ATS_INFO("Error[%d]: Found %d/%d params", + status, num_params_found, iid_pid_pair_list->count); + } + + if (AR_SUCCEEDED(status)) + { + *rsp_buf_bytes_filled = blob_offset; + *total_size = blob_offset; + } + + return status; +} \ No newline at end of file diff --git a/acdb/ats/sockets/common/api/ar_sockets_api.h b/acdb/ats/sockets/common/api/ar_sockets_api.h new file mode 100644 index 0000000..d421aa7 --- /dev/null +++ b/acdb/ats/sockets/common/api/ar_sockets_api.h @@ -0,0 +1,337 @@ +#ifndef __AR_OSAL_SOCKET_H__ +#define __AR_OSAL_SOCKET_H__ +/** +*============================================================================== +* \file ar_sockets_api.h +* \brief +* A u d i o R e a c h S O C K E T S +* H E A D E R F I L E +* +* This file contains the socket definitions and helper macros used by +* AR libraries. +* +* The APIs defined in this file are based off of winsock2 for windows +* and the linux socket apis. For additional information see Winsock2 +* and Unix socket documenation. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ + +#include +#if defined(__linux__) +#include +#include +#include +#include +#include +#include +#elif defined(_WIN32) || defined(_WIN64) +#include +#include +#include +#endif +#include "ar_osal_types.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" + +#if defined(__linux__) + +#define INVALID_SOCKET -1 +#define AR_SOCKET_ADDRESS_FAMILY AF_UNIX +#define TCP_PROTOCOL 0 + +typedef int ar_socket_t; +typedef socklen_t ar_socketlen_t; +typedef uint32_t ar_address_family_t; + +#elif defined(_WIN32) || defined(_WIN64) + +#define AR_SOCKET_ADDRESS_FAMILY AF_INET +#define TCP_PROTOCOL IPPROTO_TCP + +typedef UINT_PTR ar_socket_t; +typedef int ar_socketlen_t; +typedef uint16_t ar_address_family_t; +#endif + +#define AR_UNIX_PATH_MAX 108 +typedef struct ar_sockaddr_un_t +{ + uint16_t sun_family; /* AF_UNIX */ + char sun_path[AR_UNIX_PATH_MAX]; /* pathname */ +} ar_sockaddr_un_t; + +typedef struct sockaddr ar_socket_addr_t; +typedef struct sockaddr_storage ar_socket_addr_storage_t; +typedef struct sockaddr_in ar_socket_addr_in_t; +typedef struct ar_sockaddr_un_t ar_socket_addr_un_t; +typedef struct addrinfo ar_socket_addr_info_t; + +#define AR_SOCKET_LAST_ERROR ar_socket_last_error() +#define AR_SOCKET_LOG_TAG "AR SOCKET" +#define AR_SOCKET_ERR(...) AR_LOG_ERR(AR_SOCKET_LOG_TAG, __VA_ARGS__) +#define AR_SOCKET_DBG(...) AR_LOG_DEBUG(AR_SOCKET_LOG_TAG, __VA_ARGS__) + +/* \brief + * Returns the error code for the last failed socket operation + * \return A system level error code + */ +int32_t ar_socket_last_error(); + +/* \brief + * Checks if a socket is invalid + * + * \param [in] socket: The socket to verify + * + * \return True if the socket is invalid, false if its valid + */ +bool_t ar_socket_is_invalid( + ar_socket_t socket); + +/* \brief + * Initializes the socket library + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_init(); + +/* \brief + * De-initializes the socket library + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_deinit(); + +/* \brief + * Closes an opened socket + * + * \param [in] socket: The socket to close + * + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_close( + ar_socket_t socket); + +/* \brief + * Establishes a connection to the provided socket + * + * \param [in] socket: The unconnected socket + * \param [in] addr: A pointer to a ar_socket_addr_t strucutre containing the address to establish a connection with + * \param [in] addr_len: The size of the ar_socket_addr_t structure + * + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_connect( + ar_socket_t socket, + ar_socket_addr_t *addr, + uint32_t addr_len); + +/* \brief + * Associates a local address with a socket + * + * \param [in] socket: The socket to bind to + * \param [in] addr: A pointer to a ar_socket_addr_t strucutre containing the address to assign to the unbound socket + * \param [in] addr_len: The size of the ar_socket_addr_t structure + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_bind( + ar_socket_t socket, + ar_socket_addr_t *addr, + uint32_t addr_len); + +/* \brief + * Places the provided socket into a listening state. The socket listens for inomming connections + * + * \param [in] socket: A bound and unconnected socket + * \param [in] backlog: The max length of the queue of pending connections + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_listen( + ar_socket_t socket, + int32_t backlog); + +/* \brief + * Allows incomming connection requests on a socket + * + * \param [in] socket: The socket placed in the listening state using ar_socket_listen + * \param [out] addr: A pointer to a buffer containg the address of the connecting client + * \param [in] addr_len: The length of the structure pointed to by addr + * \param [out] new_socket: The socket where the connection is made + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_accept( + ar_socket_t socket, + ar_socket_addr_t *addr, + ar_socketlen_t *addr_len, + ar_socket_t *new_socket); + +/* \brief + * Sends data through a connected socket + * \param [in] socket: The connected socket + * \param [in] buf: The buffer containing the data to transmit + * \param [in] len: The length of the buffer to transmit + * \param [in] flags: A set of flags that configure the call + * \param [out] bytes_sent: The number of byes actually sent + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_send( + ar_socket_t socket, + const char_t* buf, + int32_t len, + int32_t flags, + int32_t *bytes_sent); + +/* \brief + * Recieves data from a connected socket or bound connectionless socket + * + * \param [in] socket: The connected socket + * \param [in] buf: The recieve buffer containing the incoming data + * \param [in] len: The length of the recieve buffer + * \param [in] flags: A set of flags that configure the call + * \param [out] bytes_read: The number of bytes actually read + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_recv( + ar_socket_t socket, + char_t* buf, + int32_t len, + int32_t flags, + int32_t *bytes_read); + +/* \brief + * Retrieves a socket option + * + * \param [in] socket: A socket to get options for + * \param [in] level: the option level + * \param [in] opt_name: the name of the option + * \param [out] opt_val: a pointer to a buffer to write the option value to + * \param [in/out] opt_val_len: the length of the buffer containing the option value + * + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_get_options( + ar_socket_t socket, + int32_t level, + int32_t opt_name, + char_t* opt_val, + ar_socketlen_t *opt_val_len); + +/* \brief + * Sets a socket option + * + * \param [in] socket: A socket to set an option for + * \param [in] level: the option level + * \param [in] opt_name: the name of the option + * \param [in] opt_val: a pointer to a buffer containing the option value + * \param [in] opt_val_len: the length of the buffer containing the option value + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_set_options( + ar_socket_t socket, + int32_t level, + int32_t opt_name, + const char_t* opt_val, + int32_t opt_val_len); + +/* \brief + * Creaes an IPv4 Stream based TCP socket + * + * \param [out] socket: The IPv4 TCP based socket + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_tcp( + ar_socket_t *socket); + +/* \brief + * Creaes an unix based socket + * + * \param [out] socket: The unix based socket + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_unix( + ar_socket_t *s); + +/* \brief + * The converts an IPv4 or IPv6 address from binary format to text. This is the equivalent of inet_ntop. + * + * \param [in] family: The address family + * \param [in] addr: The address to convert to a string + * \param [out] addr_string: The address as a string + * \param [out] addr_string_length: The length of the address string + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_inet_ntop( + int32_t family, + void* addr, + char_t* addr_string, + size_t addr_string_length); + +/* \brief + * The converts an IPv4 or IPv6 address string to its binary form + * + * \param [in] family: The address family + * \param [in] addr_string: A null terminated string containing the inet address + * \param [out] addr_struct: Pointer to a buffer containing the binary representation of the IP address + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_inet_pton( + int32_t family, + char_t* addr_string, + void* addr_struct); + +/* \brief + * Converts a ushort port to TCP/IP network byte order (big-endian) + * + * \param [in] port: The port to convert. This port is in host-byte order + * (big or little endian depending on what the host + supports by default) + * \return AR_EOK on success, non-zero otherwise + */ +uint16_t ar_socket_htons( + uint16_t port); + +/* \brief + * Retrieves the address of a sockets connected peer + * + * \param [in] socket: The connected socket + * \param [out] socket_addr: A to a ar_socket_addr_t structure where the address is written to + * \param [out] addr_length: A poointer to the length of the ar_socket_addr_t structure + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_get_peer_name( + ar_socket_t socket, + ar_socket_addr_t* socket_addr, + ar_socketlen_t* addr_length); + +/* \brief + * Retrieves one or more ar_socket_addr_info_t structures that contain internet address. + * + * \param [in] node: A null terminated string containing the host name or address string. + * This is optional. + * \param [in] service: A null terminated string containing a service name or string port + * number. This is optional + * \param [in] hints: A pointer to a ar_socket_addr_info_t structure that contains + * hints about the type of sockets supported by the caller. This is optional + * \param [out] addr_results: A pointer to a linked list of one or more ar_socket_addr_info_t + * containing information about the host + * \return AR_EOK on success, non-zero otherwise + */ +int32_t ar_socket_get_addr_info( + const char_t *node, + const char_t *service, + const ar_socket_addr_info_t *hints, + ar_socket_addr_info_t **addr_results); + +/* \brief + * Frees the add_results aquired when calling ar_socket_get_addr_info + * + * \param [out] addr_info: The addr_results linked list from ar_socket_get_addr_info + * \return AR_EOK on success, non-zero otherwise + */ +void ar_socket_free_addr_info( + ar_socket_addr_info_t* addr_info); +#endif /*__ar_OSAL_SOCKET_H__*/ diff --git a/acdb/ats/sockets/linux/src/ar_sockets.cpp b/acdb/ats/sockets/linux/src/ar_sockets.cpp new file mode 100644 index 0000000..6eb52fc --- /dev/null +++ b/acdb/ats/sockets/linux/src/ar_sockets.cpp @@ -0,0 +1,279 @@ +/** +*============================================================================== +* \file ar_sockets.cpp +* \brief +* A u d i o R e a c h S O C K E T S +* S O U R C E F I L E +* +* This file contains the socket implementation AR libraries. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "ar_sockets_api.h" + +bool_t ar_socket_is_invalid( + ar_socket_t socket) +{ + return socket == INVALID_SOCKET; +} + +int32_t ar_socket_last_error() +{ + return errno; +} + +char_t *ar_socket_last_error_str(int32_t error_number) +{ + __UNREFERENCED_PARAM(error_number); + //return strerror(error_number);//for linux + //char_t empty_str[2] = {' ','\0'}; + return NULL; +} + +int32_t ar_socket_init() +{ + int32_t status = AR_EOK; + return status; +} + +int32_t ar_socket_deinit() +{ + return AR_EOK; +} + +int32_t ar_socket_close(ar_socket_t socket) +{ + if (0 > close(socket)) + { + return AR_EFAILED; + } + return AR_EOK; +} + +int32_t ar_socket_connect(ar_socket_t socket, ar_socket_addr_t *addr, uint32_t addr_len) +{ + if (0 != connect(socket, addr, addr_len)) + { + AR_SOCKET_ERR( + "Error[%d]: Encounter error while connecting to socket." + " Socket Error: %d: %s", AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + + return AR_EFAILED; + } + return AR_EOK; +} + +int32_t ar_socket_bind(ar_socket_t socket, ar_socket_addr_t *addr, uint32_t addr_len) +{ + int32_t status = bind(socket, addr, addr_len); + if ( 0 > status) + { + AR_SOCKET_ERR( + "Error[%d]: Encounter error while binding socket. bind returned %d." + " Socket Error: %d: %s", status, AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + + return AR_EFAILED; + } + return AR_EOK; +} + +int32_t ar_socket_listen(ar_socket_t socket, int32_t backlog) +{ + int32_t status = listen(socket, backlog); + if (0 > status) + { + AR_SOCKET_ERR( + "Error[%d]: Encounter error while listening. listen retruend %d" + " Socket Error: %d: %s", status, AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + + return AR_EFAILED; + } + return AR_EOK; +} + +int32_t ar_socket_accept(ar_socket_t socket, ar_socket_addr_t *addr, ar_socketlen_t *addr_len, ar_socket_t *new_socket) +{ + *new_socket = accept(socket, addr, addr_len); + if (ar_socket_is_invalid(*new_socket)) + { + *new_socket = 0; + + AR_SOCKET_ERR( + "Error[%d]: Encounter error while accepting socket connection." + " Socket Error: %d: %s", + AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + return AR_EFAILED; + } + + return AR_EOK; +} + +int32_t ar_socket_send(ar_socket_t socket, const char_t* buf, int32_t len, int32_t flags, int32_t *bytes_sent) +{ + if (0 > (*bytes_sent = send(socket, (char*)buf, len, flags))) + { + AR_SOCKET_ERR( + "Error[%d]: Encounter error while sending data over socket." + " Socket Error: %d: %s", AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + + return AR_EFAILED; + } + return AR_EOK; +} + +int32_t ar_socket_recv(ar_socket_t socket, char_t* buf, int32_t len, int32_t flags, int32_t *bytes_read) +{ + if (0 > (*bytes_read = recv(socket, (char*)buf, len, flags))) + { + AR_SOCKET_ERR( + "Error[%d]: Encounter error while recieving data over socket." + " Socket Error: %d: %s", AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + + return AR_EFAILED; + } + return AR_EOK; +} + +int32_t ar_socket_get_options(ar_socket_t socket, int32_t level, int32_t opt_name, char_t* opt_val, ar_socketlen_t *opt_val_len) +{ + ar_socketlen_t tmp_opt_val_len = 0; + if (0 > getsockopt(socket, level, opt_name, opt_val, &tmp_opt_val_len)) + { + AR_SOCKET_ERR( + "Error[%d]: Encounter error while setting socket options." + " Socket Error: %d: %s", AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + + return AR_EFAILED; + } + + *opt_val_len = tmp_opt_val_len; + return AR_EOK; +} + +int32_t ar_socket_set_options(ar_socket_t socket, int32_t level, int32_t opt_name, const char_t* opt_val, int32_t opt_val_len) +{ + if (0 > setsockopt(socket, level, opt_name, opt_val, opt_val_len)) + { + AR_SOCKET_ERR( + "Error[%d]: Encounter error while setting socket options." + " Socket Error: %d: %s", AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + + return AR_EFAILED; + } + return AR_EOK; +} + +int32_t ar_socket_tcp(ar_socket_t *s) +{ + *s = socket(AF_INET, SOCK_STREAM, TCP_PROTOCOL); + if (ar_socket_is_invalid(*s)) + { + *s = 0; + + AR_SOCKET_ERR( + "Error[%d]: Encounter error while opening TCP socket." + " Socket Error: %d: %s", + AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + return AR_EFAILED; + } + + return AR_EOK; +} + +int32_t ar_socket_unix(ar_socket_t *s) +{ + *s = socket(AF_UNIX, SOCK_STREAM, 0); + if (ar_socket_is_invalid(*s)) + { + *s = 0; + + AR_SOCKET_ERR( + "Error[%d]: Encounter error while opening TCP socket." + " Socket Error: %d: %s", + AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + return AR_EFAILED; + } + + return AR_EOK; +} + +int32_t ar_socket_inet_ntop( + int32_t family, + void* addr, + char_t* addr_string, + size_t addr_string_length) +{ + const char_t* out = inet_ntop(family, addr, addr_string, addr_string_length); + if (out == NULL) + { + AR_SOCKET_ERR( + "Error[%d]: Encounter error converting binary address to string." + " Socket Error: %d: %s", + AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + return AR_EFAILED; + } + + return AR_EOK; +} + +uint16_t ar_socket_htons(uint16_t port) +{ + return htons(port); +} + +int32_t ar_socket_inet_pton( + int32_t family, + char_t* addr_string, + void* addr_struct) +{ + return inet_pton(family, addr_string, addr_struct); +} + +int32_t ar_socket_get_peer_name( + ar_socket_t socket, + ar_socket_addr_t *socket_addr, + ar_socketlen_t *addr_length) +{ + if (0 == getpeername(socket, socket_addr, addr_length)) + return AR_EOK; + + AR_SOCKET_ERR( + "Error[%d]: Encounter error while retrieving peer name." + " Socket Error: %d: %s", + AR_EFAILED, AR_SOCKET_LAST_ERROR, ar_socket_last_error_str(AR_SOCKET_LAST_ERROR)); + return AR_EFAILED; +} + +int32_t ar_socket_get_addr_info( + const char_t* node, + const char_t* service, + const ar_socket_addr_info_t* hints, + ar_socket_addr_info_t** addr_results) +{ + int32_t status = getaddrinfo(node, service, hints, addr_results); + if (0 == status) + return AR_EOK; + else + AR_SOCKET_ERR( + "Error[%d]: Encounter error while retrieving address info." + " Socket Error: %d: %s", + AR_EFAILED, status, gai_strerror(status)); + return AR_EFAILED; +} + +void ar_socket_free_addr_info( + ar_socket_addr_info_t* addr_info) +{ + freeaddrinfo(addr_info); +} diff --git a/acdb/ats/src/ats.c b/acdb/ats/src/ats.c new file mode 100644 index 0000000..8e86471 --- /dev/null +++ b/acdb/ats/src/ats.c @@ -0,0 +1,1017 @@ +/** +*============================================================================== +* \file ats.h +* \brief +* A T S H E A D E R F I L E +* +* This header file contains all the definitions necessary for the QACT +* Tuning Service to handle request buffer and operate ACDB +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/*------------------------------------------ +* Notes +*------------------------------------------*/ +/* Platform Agnostic Services +* +* The Online and FTS service are cross-platform. This means that these two +* services are fully functional in the device simulator and dont require +* retrieving packets from the *.bin file. All other services have +* dependecies on the platform or other ar componets. For simulation +* MCS/ADIE/RTC are stubbed out for compilation with the device simulator +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ + +#include "ats.h" +#include "ats_i.h" +#include "ats_online.h" +#include "ats_rtc.h" +#include "ats_dls.h" +#include "ats_fts.h" +#include "ats_mcs.h" +#include "ats_adie_rtc.h" +#include "ats_common.h" +#include "acdb_utility.h" +#include "ats_transport_api.h" + +/* --------------------------------------------------------------------------- + * Type Declarations + *--------------------------------------------------------------------------- */ + +typedef struct ats_service_node_t { + uint32_t service_id; + ATS_CALLBACK service_callback; + struct ats_service_node_t *p_next; +}AtsServiceNode; + +typedef struct ats_registry_table_t { + AtsServiceNode *p_head; + AtsServiceNode *p_tail; +}AtsRegistryTable; + +/* --------------------------------------------------------------------------- + * Global Variables + *--------------------------------------------------------------------------- */ +AtsBuffer ats_main_buffer = {0}; +ATS_SIM_CALLBACK ats_simulation_callback = NULL; +bool_t simulation_enabled = FALSE; +static AtsRegistryTable *g_ats_reg_tbl = NULL; +static uint32_t ats_init_count = 0; + +/* --------------------------------------------------------------------------- +* External Functions and Forward Declarations +*--------------------------------------------------------------------------- */ +extern int32_t actp_diag_init( + void(*callback_function)(uint8_t*, uint32_t, uint8_t**, uint32_t*) +); + +extern int32_t actp_diag_deinit(void); + +void ats_execute_command( + uint8_t *req_buf_ptr, + uint32_t req_buf_length, + uint8_t **resp_buf_ptr, + uint32_t *resp_buf_length +); + +static bool_t get_command_length( + uint8_t *req_buf_ptr, + uint32_t req_buf_length, + uint32_t *data_length +); + +static void ats_create_error_resp( + uint32_t error_code, + uint8_t *req_buf_ptr, + uint8_t *resp_buf_ptr, + uint32_t *resp_buf_length +); + +static void ats_create_suc_resp( + uint32_t error_code, + uint32_t data_length, + uint8_t *req_buf_ptr, + uint8_t *resp_buf_ptr, + uint32_t *resp_buf_length +); + +static bool_t is_service_registered(uint32_t service_id); + +void ats_register_simulation(ATS_SIM_CALLBACK sim_callback); + +void ats_simulation_switch(void); + +/*----------------------------------------------------------------------------- +* Public Functions +*----------------------------------------------------------------------------*/ + +/** + * \brief + * Initilizes ATS including all services (RTC, RTM, MCS, ADIE, Online) + * and Data transports (Diag USB, TCPIP) + * + * \return AR_EOK when success, AR_EFAILED otherwise + */ +int32_t ats_init(void) +{ + int32_t status = AR_EOK; + int32_t service_status = AR_EOK; + + if (ats_init_count) + { + ATS_ERR("Error[%d]: ATS is already initialized.", + AR_EALREADY); + return status; + } + + /*----------------------------------------------------- + * Initialize ATS Transports + *---------------------------------------------------*/ + status = ats_transport_init(ats_execute_command); + if (AR_FAILED(status)) + { + /* Dont initialize any of the services if any of + * the transports fail to initialize since the ATS + * client wont be able to communicate with ATS */ + goto end; + } + + if (NULL == ats_main_buffer.buffer) + { + ats_main_buffer.buffer_size = ATS_ACDB_BUFFER_POSITION + ATS_BUFFER_LENGTH; + ats_main_buffer.buffer = (uint8_t*)ACDB_MALLOC( + uint8_t, ats_main_buffer.buffer_size); + g_ats_reg_tbl = (AtsRegistryTable*)ACDB_MALLOC(AtsRegistryTable, 1); + + if (NULL == ats_main_buffer.buffer || NULL == g_ats_reg_tbl) + { + status = AR_ENOMEMORY; + ATS_ERR("Error[%d]: Failed to allocate memory for " + "ATS resources", + status); + } + else + { + g_ats_reg_tbl->p_head = NULL; + g_ats_reg_tbl->p_tail = NULL; + } + } + + if (AR_FAILED(status)) + { + goto release_resources; + } + + /*----------------------------------------------------- + * Initialize ATS Services + *---------------------------------------------------*/ + + /* At minimum the Online and File Transfer services must + * be registered. If these two services fail to register, + * then ats_init should fail.*/ + + status = ats_online_init(); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to initialize " + "Online service", status); + goto release_resources; + } + + status = ats_fts_init(); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to initialize " + "File Transfer service", status); + goto online_deinit; + } + + service_status = ats_rtc_init(); + if (AR_FAILED(service_status)) + { + ATS_ERR("Error[%d]: Failed to initialize " + "Realtime Calibration service", service_status); + goto core_service_deinit; + } + + service_status = ats_dls_init(ats_transport_dls_send_callback); + if (AR_FAILED(service_status)) + { + ATS_ERR("Error[%d]: Failed to initialize " + "Data Logging Service", service_status); + ats_dls_deinit(); + } + + service_status = ats_mcs_init(); + if (AR_FAILED(service_status)) + { + ATS_ERR("Error[%d]: Failed to initialize " + "Media Control service", service_status); + ats_mcs_deinit(); + } + + service_status = ats_adie_rtc_init(); + if (AR_FAILED(service_status)) + { + ATS_ERR("Error[%d]: Failed to initialize " + "Codec Realtime Calibration service", service_status); + ats_adie_rtc_deinit(); + } + + ats_simulation_switch(); + + ats_init_count++; + goto end; + +core_service_deinit: + ats_rtc_deinit(); + ats_fts_deinit(); +online_deinit: + ats_online_deinit(); +release_resources: + if (NULL != ats_main_buffer.buffer) + { + ACDB_FREE(ats_main_buffer.buffer); + ats_main_buffer.buffer = NULL; + } + if (NULL != g_ats_reg_tbl) + { + ACDB_FREE(g_ats_reg_tbl); + g_ats_reg_tbl = NULL; + } +end: + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to initialize ATS", status); + } + else + { + ATS_ERR("Error[%d]: Successfully initialized ATS", status); + } + + return status; +} + +/** + * \brief + * Deinitilizes ATS and releases resources aquired during ats_init. This + * includes all services and data transports + * + * \return AR_EOK when success, AR_EFAILED otherwise + */ +int32_t ats_deinit(void) +{ + int32_t status = AR_EOK; + + ATS_DBG("Deinitializing ATS"); + if (!ats_init_count) + { + return status; + } + + if (NULL != ats_main_buffer.buffer) + { + ACDB_FREE(ats_main_buffer.buffer); + ats_main_buffer.buffer = NULL; + } + + { + if (g_ats_reg_tbl != NULL && g_ats_reg_tbl->p_head != NULL) + { + int32_t count = 0; + AtsServiceNode *cur_node = g_ats_reg_tbl->p_head; + ATS_DBG("g_ats_reg_tbl is not NULL, g_ats_reg_tbl->p_head is not NULL\n"); + + while (cur_node) + { + count++; + ATS_DBG("Node%d is not empty, address[%p]\n", count, cur_node); + cur_node = cur_node->p_next; + } + if (g_ats_reg_tbl->p_tail != NULL) + { + ATS_DBG("g_ats_reg_tbl->p_tail is not NULL, address[%p]\n", g_ats_reg_tbl->p_tail); + } + } + } + + // Deinitializes services + (void)ats_online_deinit(); + (void)ats_rtc_deinit(); + (void)ats_fts_deinit(); + (void)ats_mcs_deinit(); + (void)ats_adie_rtc_deinit(); + + // Deinitializes transport(s) + (void)ats_transport_deinit(); + + if (NULL != g_ats_reg_tbl) + { + if (g_ats_reg_tbl->p_head != NULL) + { + AtsServiceNode *cur_node = g_ats_reg_tbl->p_head->p_next; + while (cur_node) + { + g_ats_reg_tbl->p_head->p_next = cur_node->p_next; + ACDB_FREE(cur_node); + cur_node = g_ats_reg_tbl->p_head->p_next; + } + ACDB_FREE(g_ats_reg_tbl->p_head); + } + ACDB_FREE(g_ats_reg_tbl); + g_ats_reg_tbl = NULL; + } + ats_init_count = 0; + + return status; +} + +/*----------------------------------------------------------------------------- +* Private Functions +*----------------------------------------------------------------------------*/ + +/** + * \brief Interpret request and operate ACDB correspondingly, respond with + * the result. + * + * \depends ACDB needs to be initialized before this function is called + * + * \param[in/out] req_buf_ptr - pointer to request buffer + * \param[in/out] req_buf_length - length of the request buffer + * \param[in/out] resp_buf_ptr - pointer to response buffer + * \param[in/out] resp_buf_length - length of the response buffer + * + * \return none + */ +void ats_execute_command(uint8_t *req_buf_ptr, + uint32_t req_buf_length, + uint8_t **resp_buf_ptr, + uint32_t *resp_buf_length +) +{ + uint32_t data_length; + int32_t status = AR_EFAILED; + uint32_t service_id = 0; + uint32_t service_cmd_id = 0; + uint8_t *temp_resp_buf = NULL; + ATS_CALLBACK ats_cb_req_op = NULL; + uint32_t resp_buf_size = ATS_BUFFER_LENGTH + - ATS_ACDB_BUFFER_POSITION - sizeof(status); + + if (!ats_main_buffer.buffer) + { + *resp_buf_ptr = NULL; + *resp_buf_length = 0; + return; + } + + *resp_buf_ptr = ats_main_buffer.buffer; + temp_resp_buf = ats_main_buffer.buffer + ATS_ACDB_BUFFER_POSITION; + char svc_id_str[ATS_SEVICE_ID_STR_LEN] = { 0 }; + if (FALSE == get_command_length(req_buf_ptr, req_buf_length, &data_length)) + { + /**return error response: ERR_LENGTH_NOT_MATCH */ + ats_create_error_resp(AR_EBADPARAM, req_buf_ptr, *resp_buf_ptr, resp_buf_length); + return; + } + + //Copy 2byte service id + 2byte command id + ATS_MEM_CPY_SAFE((void*)&service_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH, + (void*)(req_buf_ptr + ATS_SERVICE_COMMAND_ID_POSITION), + ATS_SERVICE_COMMAND_ID_LENGTH); + + service_id = ATS_GET_SERVICE_ID(service_cmd_id); + ATS_SERVICE_ID_STR(svc_id_str, ATS_SEVICE_ID_STR_LEN, service_cmd_id); + + switch (service_id) + { + case ATS_RTC_SERVICE_ID: + case ATS_DLS_SERVICE_ID: + case ATS_FTS_SERVICE_ID: + case ATS_MCS_SERVICE_ID: + case ATS_CODEC_RTC_SERVICE_ID: + case ATS_ONLINE_SERVICE_ID: + break; + default: + ATS_ERR("The command id provided does not belong to any service category [%x]\n", service_cmd_id); + ats_create_error_resp(AR_EUNSUPPORTED, req_buf_ptr, *resp_buf_ptr, resp_buf_length); + return; + } + + if (g_ats_reg_tbl != NULL) + { + AtsServiceNode *pCur = g_ats_reg_tbl->p_head; + while (pCur) + { + if (pCur->service_id == service_id) + { + uint32_t temp_req_buf_len = req_buf_length - ATS_HEADER_LENGTH; + ats_cb_req_op = pCur->service_callback; + + // See note at top on Platform Agnostic Services + if (simulation_enabled && + (service_id != ATS_ONLINE_SERVICE_ID && + service_id != ATS_FTS_SERVICE_ID && + service_id != ATS_CODEC_RTC_SERVICE_ID)) + { + status = ats_simulation_callback(req_buf_length, req_buf_ptr, + resp_buf_length, ats_main_buffer.buffer); + + /* The recorded packet response already contains the status + * so there is no need to call ats_create_suc_resp. + * If the response buffer associated with the request buffer + * cannot be found call ats_create_suc_resp + */ + if(AR_SUCCEEDED(status)) return; + else break; + } + + if (temp_req_buf_len == 0) + { + status = ats_cb_req_op(service_cmd_id, + NULL, temp_req_buf_len, + temp_resp_buf, resp_buf_size, resp_buf_length); + } + else + { + status = ats_cb_req_op(service_cmd_id, + req_buf_ptr + ATS_HEADER_LENGTH, temp_req_buf_len, + temp_resp_buf, resp_buf_size, resp_buf_length); + } + break; + } + else + { + pCur = pCur->p_next; + } + } + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Error occured while executing Command[%s-%d]", status, svc_id_str, ATS_GET_COMMAND_ID(service_cmd_id)); + //ats_create_error_resp(status, req_buf_ptr, *resp_buf_ptr, resp_buf_length); + ats_create_suc_resp(status, *resp_buf_length, req_buf_ptr, *resp_buf_ptr, resp_buf_length); + } + else + { + ats_create_suc_resp(status, *resp_buf_length, req_buf_ptr, *resp_buf_ptr, resp_buf_length); + } + } + else + { + ATS_ERR("ATS registry table is not initialized. ats_init must be called prior to executing commands"); + status = AR_EFAILED; + } +} + +/** + * \brief + * register command id into ATS registry table + * + * \depends + * get_command_length is supposed to be called before this function, + * which will check the command length and ensures that the + * service + command id is present. + * + * \param[in] service_id - corresponding to command id to the function name, + * client must use this commandId to de-resiger the command + * \param[in] service_callback - a function callback + * + * \return AR_EOK if the register with function pointer success; + * AR_EFAILED otherwise. + */ +int32_t ats_register_service(uint32_t service_id, + ATS_CALLBACK service_callback +) +{ + int32_t result = AR_EOK; + + if ((service_id != ATS_RTC_SERVICE_ID) && + (service_id != ATS_DLS_SERVICE_ID) && + (service_id != ATS_FTS_SERVICE_ID) && + (service_id != ATS_MCS_SERVICE_ID) && + (service_id != ATS_CODEC_RTC_SERVICE_ID)&& + (service_id != ATS_ONLINE_SERVICE_ID)) + { + ATS_DBG("[ATS]->Invalid service id Received for ATS registration - %x\n", service_id); + return AR_EHANDLE; + } + + //ATS_DBG("[ATS]->registering the command - %x\n", nService_id); + + if (g_ats_reg_tbl == NULL) + { + ATS_DBG("[ATS ERROR]->ATS_execute_command->ATS registry table was not initialized\n"); + result = AR_EFAILED; + return result; + } + + if (is_service_registered(service_id)) + { + ATS_DBG("[ATS]->Requested service already registered - %x\n", service_id); + return AR_EFAILED; + } + + if (g_ats_reg_tbl->p_tail != NULL) + { + AtsServiceNode* pCur = g_ats_reg_tbl->p_tail; + pCur->p_next = (AtsServiceNode*)ACDB_MALLOC(AtsServiceNode, 1); + if (pCur->p_next != NULL) + { + pCur->p_next->service_id = service_id; + pCur->p_next->service_callback = service_callback; + pCur->p_next->p_next = NULL; + g_ats_reg_tbl->p_tail = pCur->p_next; + } + else + { + ATS_DBG("[ATS ERROR]->ATS_register_command->fail to ACDB_MALLOC memory\n"); + result = AR_EFAILED; + } + } + else + { + /* register with cmdId and function pointer */ + g_ats_reg_tbl->p_head = (AtsServiceNode*)ACDB_MALLOC(AtsServiceNode, 1); + if (g_ats_reg_tbl->p_head != NULL) + { + g_ats_reg_tbl->p_head->service_id = service_id; + g_ats_reg_tbl->p_head->service_callback = service_callback; + g_ats_reg_tbl->p_head->p_next = NULL; + g_ats_reg_tbl->p_tail = g_ats_reg_tbl->p_head; + } + else + { + ATS_DBG("[ATS ERROR]->ATS_register_command->fail to ACDB_MALLOC memory\n"); + result = AR_EFAILED; + } + } + + if (AR_SUCCEEDED(result)) + { + switch (service_id) + { + case ATS_ONLINE_SERVICE_ID: + ATS_INFO("Online service registered with ATS"); + break; + case ATS_CODEC_RTC_SERVICE_ID: + ATS_INFO("ADIE Realtime Calibration Service registered with ATS"); + break; + case ATS_MCS_SERVICE_ID: + ATS_INFO("Media Control Service registered with ATS"); + break; + case ATS_FTS_SERVICE_ID: + ATS_INFO("File Transfer Service registered with ATS"); + break; + case ATS_RTC_SERVICE_ID: + ATS_INFO("Realtime Calibration service registered with ATS"); + break; + case ATS_DLS_SERVICE_ID: + ATS_INFO("Data Logging service registered with ATS"); + break; + default: + ATS_INFO("Unknown service registered with ATS"); + break; + } + } + + return result; +} + +/** + * \brief deregister command into ATS registry table + * + * \depends + * get_command_length is supposed to be called before this function, + * which will check the command length and ensures that the + * service + command id is present. + * + * \param[in] service_id - corresponding to command id to the function + * name, it is dynamically created and client + must use this commandId to de-resiger the command + * + * \return AR_EOK if the register with function pointer success; + * AR_EFAILED otherwise. + * + * SIDE EFFECTS : None + */ +int32_t ats_deregister_service(uint32_t service_id +) +{ + int32_t result = AR_EFAILED; + + if (g_ats_reg_tbl != NULL && g_ats_reg_tbl->p_head != NULL) + { + AtsServiceNode* pCur = g_ats_reg_tbl->p_head; + AtsServiceNode* pPrev = g_ats_reg_tbl->p_head; + //first Node + if (pCur->service_id == service_id) + { + if (pCur == g_ats_reg_tbl->p_tail) + { + ACDB_FREE(pCur); + g_ats_reg_tbl->p_head = NULL; + g_ats_reg_tbl->p_tail = g_ats_reg_tbl->p_head; + } + else + { + g_ats_reg_tbl->p_head = pCur->p_next; + ATS_DBG("Free first node, p_head[%p],pCur[%p],p_next[%p]\n", + g_ats_reg_tbl->p_head, pCur, pCur->p_next); + ACDB_FREE(pCur); + } + + result = AR_EOK; + } + else + { + pCur = pCur->p_next; + + //2nd or ... Node + while (pCur) + { + if (pCur->service_id == service_id) + { + if (pCur == g_ats_reg_tbl->p_tail) + { + g_ats_reg_tbl->p_tail = pPrev; + } + pPrev->p_next = pCur->p_next; + ACDB_FREE(pCur); + result = AR_EOK; + break; + } + else + { + pPrev = pPrev->p_next; + pCur = pCur->p_next; + } + } + } + if (AR_FAILED(result)) + { + ATS_DBG("The provided Service ID was not found in the registry\n"); + } + } + else + { + ATS_DBG("ATS registry table was not initialized\n"); + result = AR_EFAILED; + } + + if (AR_SUCCEEDED(result)) + { + switch (service_id) + { + case ATS_ONLINE_SERVICE_ID: + ATS_DBG("Deregistering Online service"); + break; + case ATS_CODEC_RTC_SERVICE_ID: + ATS_DBG("Deregistering ADIE Realtime Calibration Service"); + break; + case ATS_MCS_SERVICE_ID: + ATS_DBG("Deregistering Media Control Service"); + break; + case ATS_FTS_SERVICE_ID: + ATS_DBG("Deregistering File Transfer Service"); + break; + case ATS_RTC_SERVICE_ID: + ATS_DBG("Deregistering Realtime Calibration service"); + break; + case ATS_DLS_SERVICE_ID: + ATS_DBG("Deregistering Data Logging service"); + break; + default: + ATS_DBG("Deregistering unknown service"); + break; + } + } + + return result; +} + +int32_t ats_get_service_info(AtsCmdGetServiceInfoRsp *svc_info_rsp, uint32_t rsp_buf_len) +{ + int32_t status = AR_EOK; + + if (rsp_buf_len < sizeof(AtsCmdGetServiceInfoRsp)) + { + ATS_ERR("Response buffer is too small") + return AR_EBADPARAM; + } + + //if (ACDB_SOFTWARE_VERSION_MAJOR == 1 && ACDB_SOFTWARE_VERSION_MINOR == 0) + //{ + + //} + AtsServiceInfo svc_info = { 0 }; + AtsServiceNode *cur_node = g_ats_reg_tbl->p_head; + uint32_t found = FALSE; + + while (!IsNull(cur_node)) + { + svc_info.service_id = cur_node->service_id; + + switch (cur_node->service_id) + { + case ATS_RTC_SERVICE_ID: + { + svc_info.major = ATS_RTC_MAJOR_VERSION; + svc_info.minor = ATS_RTC_MINOR_VERSION; + found = TRUE; + break; + } + case ATS_DLS_SERVICE_ID: + { + svc_info.major = ATS_DLS_MAJOR_VERSION; + svc_info.minor = ATS_DLS_MINOR_VERSION; + found = TRUE; + break; + } + case ATS_FTS_SERVICE_ID: + { + svc_info.major = ATS_FTS_MAJOR_VERSION; + svc_info.minor = ATS_FTS_MINOR_VERSION; + found = TRUE; + break; + } + case ATS_MCS_SERVICE_ID: + { + ats_mcs_get_version( + &svc_info.major, &svc_info.minor); + found = TRUE; + break; + } + case ATS_CODEC_RTC_SERVICE_ID: + { + ats_adie_rtc_get_version( + &svc_info.major, &svc_info.minor); + found = TRUE; + break; + } + case ATS_ONLINE_SERVICE_ID: + { + svc_info.major = ATS_ONC_MAJOR_VERSION; + svc_info.minor = ATS_ONC_MINOR_VERSION; + found = TRUE; + break; + } + default: + found = FALSE; + break; + } + + if (found) + { + ATS_MEM_CPY_SAFE(&svc_info_rsp->services_info[svc_info_rsp->service_count], + sizeof(AtsServiceInfo), &svc_info, sizeof(AtsServiceInfo)); + svc_info_rsp->service_count++; + } + + cur_node = cur_node->p_next; + } + + svc_info.service_id = 0xACDB0000; + svc_info.major = ACDB_SOFTWARE_VERSION_MAJOR << 16 | ACDB_SOFTWARE_VERSION_MINOR; + svc_info.minor = ACDB_SOFTWARE_VERSION_REVISION << 16 | ACDB_SOFTWARE_VERSION_CPLINFO; + + ATS_MEM_CPY_SAFE(&svc_info_rsp->services_info[svc_info_rsp->service_count], + sizeof(AtsServiceInfo), &svc_info, sizeof(AtsServiceInfo)); + svc_info_rsp->service_count++; + + if (0 == svc_info_rsp->service_count) + { + ATS_ERR("No registered services were found"); + status = AR_EFAILED; + } + + return status; +} + +/** +* \brief +* Get request data length from a request buffer +* +* \depends +* the address of a uint32_t variable need to be passed in to +* contain the data length +* +* \param[in] req_buf_ptr: pointer to request buffer +* \param[in] req_buf_length: length of the request buffer +* \param[in] data_length: pointer to the length of data +* +* \return +* Return false if the there is no data length information or the data length +* read from the request buffer is not consistent with the total buffer +* length. Return true otherwise and data length is returned in the last parameter. +*/ +static bool_t get_command_length(uint8_t *req_buf_ptr, + uint32_t req_buf_length, + uint32_t *data_length +) +{ + bool_t status = FALSE; + if (req_buf_length < ATS_HEADER_LENGTH) + { + /**there is no data length information*/ + status = FALSE; + } + else + { + /** copy data length*/ + ATS_MEM_CPY_SAFE(data_length, ATS_DATA_LENGTH_LENGTH, + req_buf_ptr + ATS_DATA_LENGTH_POSITION, + ATS_DATA_LENGTH_LENGTH); + + if (req_buf_length - ATS_HEADER_LENGTH == *data_length) + { + status = TRUE; + } + else + { + /**the data length read from the request buffer is not consistent + with the total buffer length.*/ + status = FALSE; + } + } + return status; +} + +/** +* \brief +* Create a response error buffer with the specified error code +* and request command id. +* +* \param[in] error_code - response error code +* \param[in/out] req_buf_ptr - pointer to request buffer +* \param[in/out] resp_buf_ptr - pointer to response buffer +* \param[in/out] resp_buf_length - length of the response buffer +* +* \return none +*/ +static void ats_create_error_resp(uint32_t error_code, + uint8_t *req_buf_ptr, + uint8_t *resp_buf_ptr, + uint32_t *resp_buf_length +) +{ + /* The format of the output is: + <-----------4bytes------------> + +-----------------------------+ + | service id | command id | + +-----------------------------+ + +-----------------------------+ + | data length | + +-----------------------------+ + +-----------------------------+ + | status | + +-----------------------------+ */ + uint32_t resp_data_length; + + if (IsNull(resp_buf_ptr)) + { + ATS_DBG("Response Buffer is not initialized"); + *resp_buf_length = 0; + return; + } + + *resp_buf_length = ATS_ERROR_FRAME_LENGTH; + resp_data_length = ATS_ERROR_FRAME_LENGTH - ATS_HEADER_LENGTH; + + //Service + Command ID + ATS_MEM_CPY_SAFE(resp_buf_ptr, ATS_SERVICE_COMMAND_ID_LENGTH, + req_buf_ptr, ATS_SERVICE_COMMAND_ID_LENGTH); + + //Data Length + ATS_MEM_CPY_SAFE(resp_buf_ptr + ATS_SERVICE_COMMAND_ID_LENGTH, ATS_DATA_LENGTH_LENGTH, + &resp_data_length, + ATS_DATA_LENGTH_LENGTH); + + //Status + ATS_MEM_CPY_SAFE(resp_buf_ptr + ATS_HEADER_LENGTH, ATS_ERROR_CODE_LENGTH, + &error_code, + ATS_ERROR_CODE_LENGTH); +} + +/** +* \brief +* Create a response buffer with the specified response data +* and request command id. +* +* \param[in] error_code - response error code +* \param[in/out] req_buf_ptr - pointer to request buffer +* \param[in/out] resp_buf_ptr - pointer to response buffer +* \param[in/out] resp_buf_length - length of the response buffer +* +* \return none +*/ +static void ats_create_suc_resp(uint32_t error_code, uint32_t data_length, + uint8_t *req_buf_ptr, + uint8_t *resp_buf_ptr, + uint32_t *resp_buf_length +) +{ + /* The format of the output is: + <-----------4bytes------------> + +-----------------------------+ + | service id | command id | + +-----------------------------+ + +-----------------------------+ + | data length | + +-----------------------------+ + +-----------------------------+ + | status | + +-----------------------------+ + +-----------------------------+ + | | + | data(response length) | + | | + +-.-.-.-.-.-.-.-.-.-.-.-.-.-.-+ */ + + uint32_t resp_data_length; + + if (IsNull(resp_buf_ptr)) + { + ATS_DBG("Response Buffer is not initialized"); + *resp_buf_length = 0; + return; + } + + *resp_buf_length = ATS_HEADER_LENGTH + data_length + sizeof(error_code); + resp_data_length = sizeof(error_code) + data_length; + + //Service + Command ID + ATS_MEM_CPY_SAFE(resp_buf_ptr, ATS_SERVICE_COMMAND_ID_LENGTH, req_buf_ptr, ATS_SERVICE_COMMAND_ID_LENGTH); + + //Data length + ATS_MEM_CPY_SAFE(resp_buf_ptr + ATS_SERVICE_COMMAND_ID_LENGTH, ATS_DATA_LENGTH_LENGTH, + &resp_data_length, ATS_DATA_LENGTH_LENGTH); + + //Status + ar_mem_move(resp_buf_ptr + ATS_HEADER_LENGTH + ATS_ERROR_CODE_LENGTH, data_length, + resp_buf_ptr + ATS_HEADER_LENGTH, data_length); + + ATS_MEM_CPY_SAFE(resp_buf_ptr + ATS_HEADER_LENGTH, sizeof(error_code), + &error_code, sizeof(error_code)); +} + +/** +* \brief +* Checks if the given service is already registered. +* +* PARAMS: +* \param[in] service_id - Service ID +* +* \return returns true or false. +*/ +static bool_t is_service_registered(uint32_t service_id) +{ + if (g_ats_reg_tbl != NULL) + { + AtsServiceNode *cur_node = g_ats_reg_tbl->p_head; + while (cur_node) + { + if (cur_node->service_id == service_id) + { + return TRUE; + } + + cur_node = cur_node->p_next; + } + } + + return FALSE; +} + +/** +* \brief +* Toggles simulation mode on/off depending on whether _DEVICE_SIM is defined +* +* \depends +* The _DEVICE_SIM preprocessor definition must be defined +*/ +void ats_simulation_switch() +{ +#if defined(_DEVICE_SIM) + simulation_enabled = TRUE; +#else + simulation_enabled = FALSE; +#endif +} + +void ats_register_simulation(ATS_SIM_CALLBACK sim_callback) +{ + __UNREFERENCED_PARAM(sim_callback); +#if defined(_DEVICE_SIM) + ats_simulation_callback = sim_callback; +#endif +} + diff --git a/acdb/ats/src/ats_command.c b/acdb/ats/src/ats_command.c new file mode 100644 index 0000000..41761cb --- /dev/null +++ b/acdb/ats/src/ats_command.c @@ -0,0 +1,498 @@ +/** +*============================================================================== +* \file ats_command.c +* \brief +* A T S C M D S O U R C E F I L E +* +* The ATS CMD source file defines the implementation for processessing +* requests from ATS clients and retrieves the response from ACDB. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +#include "ats_command.h" +#include "acdb_command.h" +#include "acdb_file_mgr.h" + +int32_t AtsCmdGetHostDatabaseFileSetInfo(AcdbFileManBlob *rsp) +{ + int32_t status = AR_EOK; + status = acdb_file_man_ioctl( + ACDB_FILE_MAN_GET_HOST_DATABASE_FILE_SET_INFO, + NULL, 0, + rsp, sizeof(AcdbFileManBlob)); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to retrieve loaded acdb " + "file set info for host database", status); + } + + return status; +} + +int32_t AtsCmdGetAllDatabasesFileSetInfo(AcdbFileManBlob* rsp) +{ + int32_t status = AR_EOK; + status = acdb_file_man_ioctl( + ACDB_FILE_MAN_GET_ALL_DATABASE_FILE_SETS, + NULL, 0, + rsp, sizeof(AcdbFileManBlob)); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to retrieve loaded acdb " + "file set info for one or more databases", status); + } + + return status; +} + +int32_t AtsCmdGetLoadedFileData( + AcdbFileManGetFileDataReq *req, AcdbFileManBlob *rsp) +{ + int32_t status = AR_EOK; + status = acdb_file_man_ioctl(ACDB_FILE_MAN_GET_DATABASE_FILE_SET, + req, sizeof(AcdbFileManGetFileDataReq), + rsp, sizeof(AcdbFileManBlob)); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to retrieve loaded acdb file info", status); + } + + return status; +} + +int32_t AtsCmdGetHeapEntryInfo( + acdb_handle_t acdb_handle, AcdbBufferContext *rsp) +{ + int32_t status = AR_EOK; + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE, + &acdb_handle, sizeof(acdb_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to set context handle. " + "Provided handle: %d", status, acdb_handle); + return status; + } + + status = DataProcGetHeapInfo(rsp); + + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Faild to get information from the ACDB heap", + status); + } + return status; +} + +int32_t AtsCmdGetHeapEntryData(acdb_handle_t acdb_handle, + AcdbGraphKeyVector *key_vector, AcdbBufferContext *rsp) +{ + int32_t status = AR_EOK; + uint32_t rsp_offset = rsp->bytes_filled; + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE, + &acdb_handle, sizeof(acdb_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to set context handle. " + "Provided handle: %d", status, acdb_handle); + return status; + } + + status = DataProcGetHeapData(key_vector, rsp, &rsp_offset); + if (AR_FAILED(status)) + { + ATS_ERR("Faild to get heap data for key vector"); + } + + rsp->bytes_filled = rsp_offset; + return status; +} + +int32_t AtsCmdGetCalDataNonPersist( + AtsGetSubgraphCalDataReq *req, AcdbBufferContext *rsp) +{ + int32_t status = AR_EOK; + uint32_t blob_offset = 0; + AcdbBlob blob = { 0 }; + AcdbUintList subgraph_list = { 0 }; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameteres are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + subgraph_list.count = 1; + subgraph_list.list = &req->subgraph_id; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + blob.buf = rsp->buf; + + status = GetSubgraphCalData(ACDB_DATA_NON_PERSISTENT, ACDB_DATA_ATS_CLIENT, + &req->cal_key_vector, req->subgraph_id, req->module_iid, req->param_id, + FALSE, &blob_offset, &blob); + + if(AR_FAILED(status)) + status = AcdbGetParameterCalData( + (AcdbParameterCalData*)(void*)req, &blob); + + switch (status) + { + case AR_EOK: + break; + case AR_ENOTEXIST: + ATS_ERR("No non-persistent calibration found in heap/file for Subgraph(%x) Module Instance(%x) Parameter(%x)", + req->subgraph_id, req->module_iid, req->param_id); + break; + default: + ATS_ERR_MSG_1("Failed to get non-persistent subgraph calibration from file/heap for Subgraph(%x) Module Instance(%x) Parameter(%x)", + status, req->subgraph_id, req->module_iid, req->param_id) + break; + } + + blob.buf = NULL; + rsp->bytes_filled = blob.buf_size; + + return status; +} + +int32_t AtsCmdSetCalDataNonPersist( + bool_t should_persist, + AcdbGraphKeyVector* cal_key_vector, + AcdbSubgraphParamData* subgraph_param_data) +{ + int32_t status = AR_EOK; + + if (IsNull(cal_key_vector) || IsNull(subgraph_param_data)) + { + ACDB_ERR("Error[%d]: One or more input parameteres are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_param_data->subgraph_id_list, sizeof(AcdbUintList), + NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + subgraph_param_data->ignore_error_code = TRUE; + status = DataProcSetCalData(cal_key_vector, subgraph_param_data); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to set non-persistent subgraph calibration to heap"); + return status; + } + + if (acdb_delta_data_is_persist_enabled() && should_persist) + { + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SAVE, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error(%d) Failed to save delta file", status); + } + } + + return status; +} + +int32_t AtsCmdGetCalDataPersist( + AtsGetSubgraphCalDataReq *req, AcdbBufferContext *rsp) +{ + int32_t status = AR_EOK; + uint32_t blob_offset = 0; + AcdbBlob blob = { 0 }; + AcdbUintList subgraph_list = { 0 }; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameteres are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + subgraph_list.count = 1; + subgraph_list.list = &req->subgraph_id; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + blob.buf = rsp->buf; + + status = GetSubgraphCalData(ACDB_DATA_PERSISTENT, ACDB_DATA_ATS_CLIENT, + &req->cal_key_vector, req->subgraph_id, req->module_iid, req->param_id, + FALSE, &blob_offset, &blob); + + if (AR_FAILED(status)) + status = AcdbGetParameterCalData( + (AcdbParameterCalData*)(void*)req, &blob); + + switch (status) + { + case AR_EOK: + break; + case AR_ENOTEXIST: + ATS_ERR("No persistent calibration found in heap/file for Subgraph(%x) Module Instance(%x) Parameter(%x)", + req->subgraph_id, req->module_iid, req->param_id); + break; + default: + ATS_ERR_MSG_1("Failed to get persistent subgraph calibration from file/heap for Subgraph(%x) Module Instance(%x) Parameter(%x)", + status, req->subgraph_id, req->module_iid, req->param_id) + break; + } + + blob.buf = NULL; + rsp->bytes_filled = blob.buf_size; + + return status; +} + +int32_t AtsCmdSetCalDataPersist( + bool_t should_persist, + AcdbGraphKeyVector* cal_key_vector, + AcdbSubgraphParamData* subgraph_param_data) +{ + int32_t status = AR_EOK; + + if (IsNull(cal_key_vector) || IsNull(subgraph_param_data)) + { + ACDB_ERR("Error[%d]: One or more input parameteres are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_param_data->subgraph_id_list, sizeof(AcdbUintList), + NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + subgraph_param_data->ignore_error_code = TRUE; + status = DataProcSetCalData(cal_key_vector, subgraph_param_data); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to set persistent subgraph calibration to heap"); + return status; + } + + if (acdb_delta_data_is_persist_enabled() && should_persist) + { + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SAVE, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error(%d) Failed to save delta file", status); + } + } + + return status; +} + +int32_t AtsCmdGetTagData( + AtsGetSubgraphTagDataReq* req, + AcdbBufferContext *rsp) +{ + int32_t status = AR_EOK; + uint32_t blob_offset = 0; + AcdbBlob blob = { 0 }; + AcdbDataPersistanceType persist_type = ACDB_DATA_UNKNOWN; + AcdbParameterTagData tag_req = { 0 }; + AcdbUintList subgraph_list = { 0 }; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameteres are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + subgraph_list.count = 1; + subgraph_list.list = &req->subgraph_id; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + status = DataProcGetPersistenceType(req->param_id, &persist_type); + if (AR_FAILED(status)) + { + ATS_ERR("Unable to determine persitence type for Parameter(0x%x)", req->param_id); + return status; + } + + blob.buf = rsp->buf; + + status = GetSubgraphCalData(ACDB_DATA_PERSISTENT, ACDB_DATA_ATS_CLIENT, + &req->tag_key_vector, req->subgraph_id, req->module_iid, req->param_id, + FALSE, &blob_offset, &blob); + + if (AR_FAILED(status)) + { + tag_req.subgraph_id = req->subgraph_id; + tag_req.module_tag.tag_id = req->tag_id; + tag_req.module_iid = req->module_iid; + tag_req.parameter_id = req->param_id; + tag_req.module_tag.tag_key_vector = req->tag_key_vector; + status = AcdbGetParameterTagData( + &tag_req, &blob); + } + + switch (status) + { + case AR_EOK: + break; + case AR_ENOTEXIST: + ATS_ERR("No heap tag data exists for Subgraph(%x) Module Instance(%x) Parameter(%x) Tag(%x)", + req->subgraph_id, req->module_iid, req->param_id, req->tag_id); + break; + default: + ATS_ERR_MSG_1("Failed to get tag data from heap for Subgraph(%x) Module Instance(%x) Parameter(%x) Tag(%x)", + status, req->subgraph_id, req->module_iid, req->param_id, req->tag_id) + break; + } + + blob.buf = NULL; + rsp->bytes_filled = blob.buf_size; + + return status; +} + +int32_t AtsCmdSetTagData( + bool_t should_persist, + AcdbModuleTag* module_tag, + AcdbSubgraphParamData* subgraph_param_data) +{ + int32_t status = AR_EOK; + + if (IsNull(module_tag) || IsNull(subgraph_param_data)) + { + ACDB_ERR("Error[%d]: One or more input parameteres are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_param_data->subgraph_id_list, sizeof(AcdbUintList), + NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + subgraph_param_data->ignore_error_code = TRUE; + status = DataProcSetTagData(module_tag, subgraph_param_data); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to set subgraph tag to heap"); + return status; + } + + if (acdb_delta_data_is_persist_enabled() && should_persist) + { + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SAVE, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error(%d) Failed to save delta file", status); + } + } + + return status; +} + +int32_t AtsCmdDeleteDeltaFiles(void) +{ + int32_t status = AR_EOK; + + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_DELETE_ALL_FILES, + NULL, 0, NULL, 0); + + return status; +} + +int32_t AtsCmdGetTempFilePath(uint32_t acdb_handle, AtsGetTempPath *path) +{ + int32_t status = AR_EOK; + acdb_file_man_writable_path_info_256_t tmp_path = { 0 }; + acdb_context_handle_t *ctx_handle = NULL; + + if (IsNull(path)) + { + ATS_ERR("Error[%d]: Input path parameter is null" + , AR_EBADPARAM); + return status; + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_GET_CONTEXT_HANDLE, + &acdb_handle, sizeof(uint32_t), + &ctx_handle, sizeof(acdb_context_handle_t)); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to get context handle", status); + return status; + } + + tmp_path.handle = ctx_handle->file_manager_handle; + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_GET_WRITABLE_PATH, + &tmp_path, sizeof(acdb_file_man_writable_path_info_256_t), + NULL, 0); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to retrieve temporary path " + "info", status); + return status; + } + + path->path_len = tmp_path.writable_path.path_len; + ATS_MEM_CPY_SAFE(path->path, path->path_len, + &tmp_path.writable_path.path[0], path->path_len); + + return status; +} diff --git a/acdb/ats/transports/common/api/ats_transport_api.h b/acdb/ats/transports/common/api/ats_transport_api.h new file mode 100644 index 0000000..c280403 --- /dev/null +++ b/acdb/ats/transports/common/api/ats_transport_api.h @@ -0,0 +1,66 @@ +#ifndef _ATS_TRANSPORT_API_H_ +#define _ATS_TRANSPORT_API_H_ +/** +*============================================================================= +* \file ats_transport_api.h +* \brief +* A T S T R A N S P O R T A P I +* +* This file defines APIs for initializing/deinitializing ATS transports. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ar_osal_types.h" + +/** +* \brief +* The command + response callback used to pass request to the +* application layer and return responses to the transport layer +* +* \param [in] req_buffer: The request buffer containing the command to execute +* \param [in] req_buffer_length: The length of the request buffer +* \param [in/out] resp_buffer: The response buffer returned after executing the command +* \param [out] resp_buffer_length: The length of the response buffer +* \return 0 on success, non-zero on failure +*/ +typedef void(*ats_cmd_rsp_callback_t)( + uint8_t *req_buffer, uint32_t req_buffer_length, + uint8_t **resp_buffer, uint32_t *resp_buffer_length); + +/** +* \brief ats_transport_init +* Initializes the transport layer. One or more transports can be initialized depending +* on the build configuration see implementation of ats_transport_init +* +* \param [in] cmd_rsp_callback: A callback to ats_exectue_command +* +* \return 0 on success, non-zero on failure +*/ +int32_t ats_transport_init(ats_cmd_rsp_callback_t cmd_rsp_callback); + +/** + * \brief ats_transport_deinit + * De-initializes the transport layer by realeasing resources aquired during ats_transport_init + * \return 0 on success, non-zero on failure + */ +int32_t ats_transport_deinit(void); + +/** + * \brief ats_transport_dls_send_callback + * Sends binary log data through the transport layer + * \param [in] buffer: the buffer containing the data to send + * \param [in] buffer_size: the size of the buffer + * \return 0 on success, non-zero on failure + */ +int32_t ats_transport_dls_send_callback(const uint8_t* buffer, uint32_t buffer_size); + +#endif /*_ATS_TRANSPORT_API_H_*/ + diff --git a/acdb/ats/transports/common/src/ats_transport.c b/acdb/ats/transports/common/src/ats_transport.c new file mode 100644 index 0000000..a958b3d --- /dev/null +++ b/acdb/ats/transports/common/src/ats_transport.c @@ -0,0 +1,110 @@ +/** +*============================================================================= +* \file ats_transport.c +* \brief +* A T S T R A N S P O R T A P I +* +* This file implements APIs for initializing/deinitializing ATS transports. +* +* \detdesc +* When adding a new transport, define a preprocessor macro for +* enabling/disabling the transport. Not every platform may support your +* transport. It is up to the platform to decide if a transport is supported +* by enabling the preprocessor macro associated with the transport. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ +#include "ats_transport_api.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" + +/* Transport includes */ +#include "tcpip_server_api.h" +#include "actp.h" + +#define LOG_TAG "ATS Transport" +#define ATS_TRANSPORT_ERR(...) AR_LOG_ERR(LOG_TAG, __VA_ARGS__) +#define ATS_TRANSPORT_DBG(...) AR_LOG_DEBUG(LOG_TAG, __VA_ARGS__) +#define ATS_TRANSPORT_INFO(...) AR_LOG_INFO(LOG_TAG, __VA_ARGS__) + +#if !defined(ATS_TRANSPORT_DIAG) && !defined(ATS_TRANSPORT_TCPIP) +/* The DIAG transport is the default transport. If no transports are + * specified in the build configuration then ATS_TRANSPORT_DIAG + * will be defined */ +#define ATS_TRANSPORT_DIAG +#endif + +int32_t ats_transport_init(ats_cmd_rsp_callback_t cmd_rsp_callback) +{ + int32_t status = AR_EOK; + + #if defined(ATS_TRANSPORT_TCPIP) + status = tcpip_cmd_server_init(cmd_rsp_callback); + if (AR_FAILED(status)) + { + ATS_TRANSPORT_ERR( + "Error[%d]: Failed to initialize " + "ATS TCP/IP Server", status); + } + #endif + + #if defined(ATS_TRANSPORT_DIAG) + status = actp_diag_init(cmd_rsp_callback); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to initialize Diag", status); + } + #endif + + //Init Other Transport + + return status; +} + +int32_t ats_transport_deinit(void) +{ + int32_t status = AR_EOK; + + //Init TCPIP Server + #if defined(ATS_TRANSPORT_TCPIP) + status = tcpip_cmd_server_deinit(); + if (AR_FAILED(status)) + { + ATS_TRANSPORT_ERR( + "Error[%d]: Failed to deinitialize " + "ATS TCP/IP Server", status); + } + #endif + + //Init Diag Transport + #if defined(ATS_TRANSPORT_DIAG) + status = actp_diag_deinit(); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to deinitialize Diag", status); + } + #endif + + return status; +} + +int32_t ats_transport_dls_send_callback(const uint8_t* buffer, uint32_t buffer_size) +{ + #if defined(ATS_TRANSPORT_TCPIP) + + ATS_TRANSPORT_DBG("Sending %d bytes", buffer_size); + return tcpip_cmd_server_send_dls_log_data(buffer, buffer_size); + + #else + __UNREFERENCED_PARAM(buffer); + __UNREFERENCED_PARAM(buffer_size); + /* We dont need to support diag since it already has support for pushing + * binary log packets to the ats realtime tuning client */ + + return AR_EUNSUPPORTED; + #endif +} diff --git a/acdb/ats/transports/diag/linux/actp/inc/actp.h b/acdb/ats/transports/diag/linux/actp/inc/actp.h new file mode 100644 index 0000000..18e732c --- /dev/null +++ b/acdb/ats/transports/diag/linux/actp/inc/actp.h @@ -0,0 +1,79 @@ +#ifndef ACTP_H +#define ACTP_H +/** +*============================================================================== +* \file actp.h +* \brief +* A C T P H E A D E R F I L E +* +* This header file contains all the definitions necessary for ACTP protocol +* layer to initialize ACTP diag dispatcher. +* This actp works in both ARM9 and ARM11 +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "acdb_utility.h" + +/*------------------------------------------ +* Macros +*------------------------------------------*/ +/*ACTP subsystem command ID Range (inclusive)*/ + +/**< ACTP subsystem command code range start ID */ +#define ACTP_CMD_ID_START 2051 +/**< ACTP subsystem command code range end ID */ +#define ACTP_CMD_ID_END 2100 +#define PACKED + + /*------------------------------------------ + * External Functions + *------------------------------------------*/ +/** +* \brief +* Registers the subsystem diag dispathcer with diag dispathcer. +* Initializes the actp session.and give it a call-back function. +* \depends +* actp_diag_table[] must be initialized and should have the proper +* sub-system command code range and pointer to the callback function. +* +* \param[in] request_callback: A callback that the dispatcher will use to +* send/recieve messages to/from ATS +* \param[in/out] rsp: A data blob containg tag data +* \return 0 on success, and non-zero on failure +*/ +extern int32_t actp_diag_init( + void (*callback_function)(uint8_t*, uint32_t, uint8_t**, uint32_t*)); + +/** +* \brief +* De-registers the subsystem diag dispathcer with diag dispathcer. +* +* \return n/a +*/ +extern int32_t actp_diag_deinit(void); + +/** +* \brief +* This is the entry point to ACTP when seen from the PC. It is the +* sub-system diag dispathcer for Audio Calibration manager. It receives +* a diag packet ment for ACTP, passes it to the protocol layer, and +* returns the response diag packet. In case of error, it returns diag +* packet with error code DIAG_BAD_CMD_F +* +* \param[in] request_callback: A callback that the dispatcher will use to +* send/recieve messages to/from ATS +* \param[in/out] rsp: A data blob containg tag data +* \return 0 on success, and non-zero on failure +*/ +extern PACKED void * avsACTP_diag_cmd (PACKED void *request, uint16_t length); + +#endif //ACTP_H + diff --git a/acdb/ats/transports/diag/linux/actp/src/actp.c b/acdb/ats/transports/diag/linux/actp/src/actp.c new file mode 100644 index 0000000..be20b98 --- /dev/null +++ b/acdb/ats/transports/diag/linux/actp/src/actp.c @@ -0,0 +1,193 @@ +/** +*============================================================================== +* \file actp.c +* \brief +* A U D I O C A L I B R A T I O N +* T R A N S P O R T E R P R O T O C O L +* S O U R C E F I L E +* +* This file contains the implementation of ACTP diag dispatcher. +* +* INITIALIZATION REQUIREMENTS: +* actp_diag_init must be called to initialise ACTP module. +* actp_diag_init must be called ~AFTER~ initialization of SOUND TASK +* A pointer to a call-back function with the following format needs +* to be passed in: +* func(char_t*, uint32_t, char_t**, uint32_t*) +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "audtp.h" +#include "actp.h" + +#ifdef __INTEGRITY +#include "Diag_LSM.h" +#else +#include "diag_lsm.h" +#endif + +#include "ats_common.h" + +//Defing diag functions for compilation on ottp +#if defined(ATS_OTTP) || defined(_DEVICE_SIM) || defined(ATS_USES_DUMMY_DIAG) +void diagpkt_commit(void *ptr) { __UNREFERENCED_PARAM(ptr); } +diagpkt_subsys_cmd_code_type diagpkt_subsys_get_cmd_code(void *ptr) { __UNREFERENCED_PARAM(ptr); return 0; } + +void *diagpkt_err_rsp(diagpkt_cmd_code_type code, + void *req_ptr, uint16_t req_len) +{ + __UNREFERENCED_PARAM(code); + __UNREFERENCED_PARAM(req_ptr); + __UNREFERENCED_PARAM(req_len); + return NULL; +} +void diagpkt_tbl_reg(const diagpkt_user_table_type * tbl_ptr) { __UNREFERENCED_PARAM(tbl_ptr); }; + +void *diagpkt_subsys_alloc(diagpkt_subsys_id_type id, + diagpkt_subsys_cmd_code_type code, unsigned int length) { + __UNREFERENCED_PARAM(id); + __UNREFERENCED_PARAM(code); + __UNREFERENCED_PARAM(length); + return NULL; +} +#endif + +/*------------------------------------------ +* Static Variable Definitions +*------------------------------------------*/ + +/**< The actp diag dispatch table that needs to be + * registered with the diag dispathcer to route the diag + * packets sent from PC to the actp diag dispatcher. + */ +static const diagpkt_user_table_entry_type actp_diag_table[] = +{ + { + ACTP_CMD_ID_START, + ACTP_CMD_ID_END, + avsACTP_diag_cmd + } +}; + + +/** ACTP session*/ +static atp_phone_context_struct actp_phone_context; + +/*------------------------------------------ +* External Functions +*------------------------------------------*/ + +int32_t actp_diag_init( + void (*request_callback)(uint8_t*, uint32_t, uint8_t**, uint32_t*) + ) +{ + if (Diag_LSM_Init(NULL)) + { + /**Register command range and diag subsystem dispatcher*/ + DIAGPKT_DISPATCH_TABLE_REGISTER(DIAG_SUBSYS_AUDIO_SETTINGS, + actp_diag_table); + memset(&actp_phone_context, 0, sizeof(atp_phone_context_struct)); + /** Set the pointer to the application callback function which receives the + request buffer and provides a response*/ + actp_phone_context.receive_req_buffer_ptr = request_callback; + return AR_EOK; + } + + ATS_INFO("Error[%d]: Failed to initialize DIAG", AR_EFAILED); + return AR_EFAILED; +} + +int32_t actp_diag_deinit(void) +{ + if (Diag_LSM_DeInit()) + { + return AR_EOK; + } + + ATS_INFO("Error[%d]: Failed to de-initialize DIAG", AR_EFAILED); + return AR_EFAILED; +} + +PACKED void * avsACTP_diag_cmd( + PACKED void *req_ptr, + uint16_t pkt_len + ) +{ + diag_pkt_resp_struct *rsp_diag_pkt_ptr = NULL; + diag_pkt_resp_struct *actp_rsp_ptr = NULL; + diag_pkt_req_struct request; + uint16_t actp_rsp_pkt_len = 0; + /** Initialize subsystem command code*/ + uint16_t command_code = ACTP_CMD_ID_START; + if (NULL != req_ptr) + { + /**Create an unpacked version of diag packet*/ + ATS_MEM_CPY_SAFE((void *)&request,sizeof(diag_pkt_req_struct), (void *)req_ptr,pkt_len); + /**Get command code*/ + command_code = (uint16_t) diagpkt_subsys_get_cmd_code((void *) &request); + /** Verify is the command code valid */ + if (command_code < ACTP_CMD_ID_START || command_code > ACTP_CMD_ID_END) + { + /**If not in the range return error*/ + rsp_diag_pkt_ptr = (diag_pkt_resp_struct*) diagpkt_err_rsp(DIAG_BAD_CMD_F, req_ptr, pkt_len); + } + else + { + /**Send diag packet to protocol layer*/ + + /**Call ATP to process the packet*/ + atp_receive_diag_pkt(&request, &actp_rsp_ptr, &actp_phone_context); + /**If we have not received response frame from protocol layer return error*/ + if(NULL == actp_rsp_ptr) + { + rsp_diag_pkt_ptr = (diag_pkt_resp_struct*) diagpkt_err_rsp(DIAG_BAD_CMD_F, req_ptr, pkt_len); + } + else + { + actp_rsp_pkt_len = DIAG_RES_PKT_SIZE + sizeof(diag_pkt_header_struct); + /** + Create a diag packet using diag api . It automatically delets the + packet after we commit the packet. + */ + rsp_diag_pkt_ptr = (diag_pkt_resp_struct*) diagpkt_subsys_alloc ( + DIAG_SUBSYS_AUDIO_SETTINGS,(uint16_t) command_code, actp_rsp_pkt_len); + //Klocwork fix: check rsp_diag_pkt_ptr if it is a null ptr. + if (rsp_diag_pkt_ptr == NULL) + { + rsp_diag_pkt_ptr = (diag_pkt_resp_struct*) diagpkt_err_rsp(DIAG_BAD_CMD_F, req_ptr, pkt_len); + if (actp_rsp_ptr != NULL) + { + ACDB_FREE(actp_rsp_ptr); + } + return (rsp_diag_pkt_ptr); + } + ATS_MEM_CPY_SAFE(rsp_diag_pkt_ptr,actp_rsp_pkt_len,actp_rsp_ptr,actp_rsp_pkt_len); + /**Send the diag packet .This will be received on PC side as response + packet*/ + if (rsp_diag_pkt_ptr == NULL) + //Klocwork fix: check rsp_diag_pkt_ptr if it is a null ptr. + { + rsp_diag_pkt_ptr = (diag_pkt_resp_struct*) diagpkt_err_rsp(DIAG_BAD_CMD_F, req_ptr, pkt_len); + return (rsp_diag_pkt_ptr); + } + diagpkt_commit(rsp_diag_pkt_ptr); + rsp_diag_pkt_ptr = NULL; + /**Free the response packet we received from protocol layer*/ + ACDB_FREE(actp_rsp_ptr); + } + } + } + else + { + rsp_diag_pkt_ptr = (diag_pkt_resp_struct*) diagpkt_err_rsp(DIAG_BAD_CMD_F, req_ptr, pkt_len); + } + return (rsp_diag_pkt_ptr); +} diff --git a/acdb/ats/transports/diag/linux/audtp/inc/audtp.h b/acdb/ats/transports/diag/linux/audtp/inc/audtp.h new file mode 100644 index 0000000..bc50bbb --- /dev/null +++ b/acdb/ats/transports/diag/linux/audtp/inc/audtp.h @@ -0,0 +1,214 @@ +#ifndef AUDTP_H +#define AUDTP_H +/** +*============================================================================== +* \file audtp.h +* \brief +* A T P H E A D E R F I L E +* +* This header file contains all the definitions necessary for other +* modules to interface and use the protocol(ATP protocol) which works +* on top of diag. +* This file is common to both protocol component on PC and protocol +* module on AMSS. PC only/phone only code is wrapped with in +* #ifdef WINPC +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ +/* + -------------------- + |include files | + -------------------- + */ + +#include "audtpi.h" +#include "diagcmd.h" +#include "diagpkt.h" + + +/* + -------------------- + | Macros and type defs | + -------------------- + */ +#define LOCAL_DIAG_MAX_RX_PKT_SIZ 15 * 1024 + +#define DIAG_MAX_PKT_HEADER_SIZ 0x20 +/**< Maximum Diag request packet size*/ +#define DIAG_REQ_PKT_SIZE (LOCAL_DIAG_MAX_RX_PKT_SIZ - DIAG_MAX_PKT_HEADER_SIZ) +/**< Maximum Diag response packet size*/ +#define DIAG_RES_PKT_SIZE (LOCAL_DIAG_MAX_RX_PKT_SIZ - DIAG_MAX_PKT_HEADER_SIZ) + +/** +* Structure definition for diag packet header +*/ +typedef struct diag_pkt_header_tag +{ + uint8_t cmdCode;/**< diag command code*/ + uint8_t subsysId;/**< subsystem ID*/ + uint16_t subsysCmdCode;/**< command code with in susbsystem*/ +} diag_pkt_header_struct; + +/** +* Structure definition for diag request packet
+*Packet size is fixed. +*/ +typedef struct diag_pkt_req_tag +{ + diag_pkt_header_struct header;/**< diag packet header*/ + char_t payload_req[DIAG_REQ_PKT_SIZE];/**< buffer to hold payload*/ +} diag_pkt_req_struct; + +/** +* Structure definition for diag response packet
+*Packet size is fixed. +*/ +typedef struct diag_pkt_resp_tag +{ + diag_pkt_header_struct header;/**< diag packet header*/ + char_t payload_resp[DIAG_RES_PKT_SIZE];/**< buffer to hold payload*/ +} diag_pkt_resp_struct; + +#ifdef WINPC +/** +* Structure definition to hold a whole context data related to a ATP session.on +*TX side +*/ +typedef struct atp_pc_context_tag +{ +/** +* Pointer to the head of a linked list, which holds the atp frames of a request +* buffer +*/ + atp_frame_dblnk_lst_struct *start_node_ptr; +/** +*pointer to the current frame in request buffer, which is being processed +*/ + atp_frame_dblnk_lst_struct *current_node_ptr; +/** +*Pointer to the response buffer context +*/ + buffer_context_struct resp_buf_cntxt; +/** +*pointer the call back function which sends request packet synchronusly and +*returns response packet. +*/ + bool_t (*send_atp_frame_ptr)(diag_pkt_req_struct *, diag_pkt_resp_struct *); +/** +*pointer the call back function in application layer which receives the +*response buffer +*/ + void (*receive_resp_buffer_ptr)(char_t *resp_buf_ptr, uint32_t buf_length); +} atp_pc_context_struct; +#else +/** +* Structure definition to hold a whole context data related to a ATP session.on +*RX side +*/ +typedef struct atp_phone_context_tag +{ +/** +* Pointer to the head of a linked list, which holds the atp frames of a response +* buffer +*/ + atp_frame_dblnk_lst_struct *resp_start_node_ptr; +/** +*pointer to the current frame in response buffer, which is being processed +*/ + atp_frame_dblnk_lst_struct *resp_current_node_ptr; +/** +*Pointer to the response buffer context +*/ + buffer_context_struct req_buf_cntxt; +/** +*pointer the response frame generated for request frame +*/ + atp_frame_struct* atp_current_resp_frame_ptr; +/** +*Inidicates whether the RX side is expecting a frame with GNF flag. +*/ + bool_t is_next_frame_gnf; +/** +*Pointer to a call back function in application layer, which takes the request +buffer and returns a response buffer +*/ + void (*receive_req_buffer_ptr) + ( + uint8_t *req_buf_ptr, uint32_t req_buf_length, + uint8_t **resp_buf_ptr, uint32_t *resp_buf_length + ); +} atp_phone_context_struct; +#endif + +/* + --------------------- + |Exported functions | + --------------------- + */ +#ifdef WINPC + +#ifdef __cplusplus +extern "C" +{ +#endif +/** +* FUNCTION : atp_send_buffer + +* DESCRIPTION : +* Send a request buffer to target. +* If buffer sent successfully, returns the response through the call back +*function: receive_resp_buffer_ptr of context_ptr. +* +* DEPENDENCIES : send_atp_frame_ptr memeber in context_ptr must be pointing to +* appropriate function. +* PARAMS: +* buffer_ptr - pointer to the input buffer +* buffer_length - bufer length +* atp_pc_context_ptr - ponter to ATP session(on PC side) +* +* RETURN VALUE : If sent successfully returns TRUE or FALSE + +* SIDE EFFECTS : Frees buffer_ptr and resets the pointer to NULL. + */ +extern bool_t atp_send_buffer ( + char_t* buffer_ptr, + uint32_t buffer_length, + atp_pc_context_struct *atp_pc_context_ptr + ); +#ifdef __cplusplus +} +#endif +#else +/** +* FUNCTION : atp_receive_diag_pkt + +* DESCRIPTION : +* Receive a request diag packet from acm diag dispatcher (avsACMdiag_cmd()) +*.and return a response diag packet. +* +* DEPENDENCIES : receive_req_buffer_ptr memeber in atp_phone_context_ptr must be +pointing to.appropriate function, which can process the request buffer and +provide a response buffer. + +* PARAMS: +* atp_diag_req_pkt_ptr - pointer to the diag packet which contains the atp frame from request buffer +* atp_diag_rsp_pkt_ptr - pointer to the diag packet which contains the atp frame from response buffer +* atp_phone_context_ptr - pointer to the phone context to whome request to be sent and resposne received +* +* RETURN VALUE : If sent successfully returns TRUE or FALSE + +* SIDE EFFECTS : Will NOT Free response buffer. + */ +extern void atp_receive_diag_pkt ( + diag_pkt_req_struct *atp_diag_req_pkt_ptr, + diag_pkt_resp_struct **atp_diag_rsp_pkt_ptr, + atp_phone_context_struct *atp_phone_context_ptr + ); +//extern void atp_diag_init(void); +#endif +#endif + diff --git a/acdb/ats/transports/diag/linux/audtp/inc/audtpi.h b/acdb/ats/transports/diag/linux/audtp/inc/audtpi.h new file mode 100644 index 0000000..7aa9f2d --- /dev/null +++ b/acdb/ats/transports/diag/linux/audtp/inc/audtpi.h @@ -0,0 +1,100 @@ +#ifndef AUDTPI_H +#define AUDTPI_H +/** +*============================================================================== +* \file actp.c +* \brief +* A T P I H E A D E R F I L E +* +* This header file contains all the definitions that are internal +* to ATP protocol module. +* This file is common to both PC and phone. PC only/phone only code +* is wrapped with in #ifdef WINPC +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ +/* + -------------------- + |include files | + -------------------- + */ + +/** Definitions for char_t, word, etc. */ + +#include "acdb_utility.h" +/* + -------------------- + | Macros and type defs | + -------------------- + */ + +/** Bit mask to identify ATP frame type */ +#define FLAG_HANDSHAKE_MASK 0x1 /**< Bit mask to identify Handshake frame */ +#define FLAG_LASTFRAME_MASK 0x2 /**< Bit mask to identify Last frame in the buffer */ +#define FLAG_GETNEXTFRAME_MASK 0x4 /**< Bit mask to identify Get Next Frame */ +#define FLAG_DATAFRAME_MASK 0x8 /**< Bit mask to identify that it is a data frame */ + +#define DIAG_EXTEND_CMDCODE 75 /**< Diag command code for extended mode*/ +#define AUDIO_SUBSYS_ID 17 /**< Audio subsystem ID */ +#if defined(IMAGE_MODEM_PROC) +#define SUBSYS_CMDCODE 2000 /**< Command code for ACM with in audio subsystem */ +#else +#define SUBSYS_CMDCODE 2051 /**< Command code for ACM with in audio subsystem */ +#endif +/** + * Structure definition for ATP frame Header + */ +typedef struct atp_frame_header_tag +{ + uint8_t version; /**< version of the protocol */ + uint8_t header_length; /**< ATP frame header length(i.e this structure length)*/ + uint8_t frame_number; /**< Identifies the number of the frame in a buffer*/ + /** + * Bit flags to identify frame type + * Bit0:HSK, Bit1:LAST, Bit2:GNF, Bit3:Data + */ + uint8_t flags; + uint32_t frame_offset;/**< offset position of the frame in buffer*/ + /** Length of the frame. + *Should not exceed DIAG_REQ_PKT_SIZE/DIAG_RES_PKT_SIZE + */ + uint16_t frame_length; + uint32_t buffer_length; /**< Total buffer size */ +} atp_frame_header_struct; + +/** + * Structure definition for ATP frame + */ +typedef struct atp_frame_tag +{ + atp_frame_header_struct header; /**< Frame header*/ + char_t *data_ptr; /**< Frame data*/ +}atp_frame_struct; + +/** + * Structure definition for doubly linked list node of type atp frame. + */ +typedef struct atp_frame_dblnk_lst_tag +{ + atp_frame_struct *frame_ptr;/**< pointer to hold atp frame*/ + struct atp_frame_dblnk_lst_tag *previous_node_ptr;/**< pointer to previous node */ + struct atp_frame_dblnk_lst_tag *next_node_ptr;/**< pointer to next node */ +}atp_frame_dblnk_lst_struct; + +/** + * Structure definition to hold a buffer context
+ * This buffer context is used at RX side to accumulate atp frames of a buffer + */ +typedef struct buffer_context_tag +{ + bool_t is_buffer_allocated;/**< Indicates if buffer is allocated*/ + uint8_t frame_count;/**< Keeps track of number of frames in the buffer*/ + char_t *buffer_ptr;/**< pointer to the buffer allocated*/ + uint32_t buffer_length;/**< size of the buffer*/ +}buffer_context_struct; + +#endif diff --git a/acdb/ats/transports/diag/linux/audtp/src/audtp.c b/acdb/ats/transports/diag/linux/audtp/src/audtp.c new file mode 100644 index 0000000..08620d9 --- /dev/null +++ b/acdb/ats/transports/diag/linux/audtp/src/audtp.c @@ -0,0 +1,1194 @@ + /** + *============================================================================== + * \file audtp.c + * \brief + * A T P P R O T O C O L L A Y E R + * S O U R C E F I L E + * + * This file contains implementation of ATP protocol layer + * + * INITIALIZATION REQUIREMENTS: + * atp_diag_init() must be called to initialise ATP protocol layer. + * atp_diag_init() must be called ~AFTER~ initialization of SOUND TASK + * + * This file is common to both protocol component on PC and protocol + * module on AMSS. PC only/phone only code is wrapped with in + * #ifdef WINPC + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + * + *============================================================================== + */ +/* + -------------------- + |include files | + -------------------- + */ +#include "audtp.h" +#include "ats_common.h" + +/* + -------------------- + |Constants | + -------------------- + */ +const uint8_t atp_protocol_version = 1; + +/* + -------------------- + |Function definitions | + -------------------- + */ + +void print_atp_frame(atp_frame_struct* atp_frame) +{ + if (atp_frame == NULL) + { + ATS_ERR("ATS FRAME: frame is null"); + return; + } + + ATS_ERR("ATS FRAME: version: %d", atp_frame->header.version); + ATS_ERR("ATS FRAME: header length: %d", atp_frame->header.header_length); + ATS_ERR("ATS FRAME: frame#: %d", atp_frame->header.frame_number); + ATS_ERR("ATS FRAME: flags: %d", atp_frame->header.flags); + ATS_ERR("ATS FRAME: frame offset: %d", atp_frame->header.frame_offset); + ATS_ERR("ATS FRAME: frame length: %d", atp_frame->header.frame_length); + ATS_ERR("ATS FRAME: buffer length: %d", atp_frame->header.buffer_length); + + if (atp_frame->data_ptr == NULL) + { + ATS_ERR("ATS FRAME: frame data is null"); + } +} + +/** + * FUNCTION init_atp_header + * + * DESCRIPTION : Initializes ATP frame headr with default values + * + * DEPENDENCIES: atp_frame_ptr should be a valid pointer + * + * PARAMS: + * atp_frame_ptr - atp_frame pointer which requires initialization + * + * RETURN VALUE: None + * + * SIDE EFFECTS: Sets the atp_frame to default values which is pointed to by atp_frame_ptr . + */ +void init_atp_header ( + atp_frame_struct *atp_frame_ptr + ) +{ + if ( atp_frame_ptr == NULL ) + return; + /** Set protocol Version */ + atp_frame_ptr->header.version = atp_protocol_version; + + /** Set header length , which is of fixed size*/ + atp_frame_ptr->header.header_length = sizeof(atp_frame_header_struct); + + /** Turn off all flags */ + atp_frame_ptr->header.flags = 0; + /** Reset frame number to zero */ + atp_frame_ptr->header.frame_number = 0; + /** Reset frame offset to zero */ + atp_frame_ptr->header.frame_offset = 0; + /** Reset frame length to zero */ + atp_frame_ptr->header.frame_length = 0; + /** Reset buffer length to zero */ + atp_frame_ptr->header.buffer_length = 0; +} /* init_atp_header */ + +/** + * FUNCTION free_atp_frame + * + * DESCRIPTION : Deallocates memory for atp frame data pointer and sets pointers to NULL. + * Then deallocates memory for this frame and sets pointer to NULL + * + * DEPENDENCIES: atp_frame_ptr should be a valid pointer + * + * PARAMS: + * atp_frame_ptr - atp_frame pointer which needs to be deallocated + * + * RETURN VALUE: None + * + * SIDE EFFECTS: None + * + */ +void free_atp_frame ( + atp_frame_struct* atp_frame_ptr + ) +{ + if(NULL==atp_frame_ptr) + { + return; + } + /** deallocate data part and set to NULL*/ + if ( atp_frame_ptr->data_ptr != NULL ) + { + ACDB_FREE(atp_frame_ptr->data_ptr); + atp_frame_ptr->data_ptr = NULL; + } + /** ACDB_FREE frame */ + if( atp_frame_ptr != NULL ) + { + ACDB_FREE(atp_frame_ptr); + atp_frame_ptr = NULL; + } +}/* free_atp_frame */ + +/** + * FUNCTION : break_buffer_into_frames + * + * DESCRIPTION : Breaks a given buffer into frames and sets their header info. + * Creates a doubly linked list of created frames. + * Input buffer can be deallocated. + * + * DEPENDENCIES: None. + * + * PARAMS: + * buffer_ptr - pointer to the input buffer + * buffer_length - bufer length + * start_node_ptr - linked list of frames start pointer + * + * RETURN VALUE: Pointer to the first node of the linked list + * + * SIDE EFFECTS: None. + */ +void break_buffer_into_frames ( + char_t* buffer_ptr, + uint32_t buffer_length, + atp_frame_dblnk_lst_struct** start_node_ptr + ) +{ + /** variable to hold the starting point of the dbl lnk lst.*/ + atp_frame_dblnk_lst_struct *start_ptr = NULL; + uint32_t frame_byte_offset = 0; + /** initialize frame count to zero */ + uint8_t frame_count = 0; + /** calculate max payload size */ +#ifdef WINPC + uint16_t atp_data_size = DIAG_REQ_PKT_SIZE - sizeof(atp_frame_header_struct); +#else + uint16_t atp_data_size = DIAG_RES_PKT_SIZE - sizeof(atp_frame_header_struct); +#endif + uint16_t frame_length = atp_data_size; + /** Variable to hold the length of the buffer to be processed to break into frames*/ + uint32_t remaining_buffer_length = buffer_length; + /** pointer to hold the previous node in the linked list */ + atp_frame_dblnk_lst_struct *prev_node_ptr = NULL; + /** pointer to hold the current node in the linked list */ + atp_frame_dblnk_lst_struct *current_node_ptr = NULL; + /** Initialize the frame count to zero*/ + frame_count = 0; + /**loop while we have some buffer to break*/ + while(remaining_buffer_length > 0 ) + { + atp_frame_struct* atp_frame_ptr = NULL; + + /** Create a atp_frame*/ + atp_frame_ptr = ACDB_MALLOC(atp_frame_struct, 1); + if(NULL==atp_frame_ptr) + { + //Klocwork fix: memory leak, return without ACDB_FREE memory allocation + if (current_node_ptr != NULL) + { + ACDB_FREE(current_node_ptr); + } + return; + } + /** Initialize the header*/ + init_atp_header(atp_frame_ptr); + /** allocate memory for frame data */ + atp_frame_ptr->data_ptr = ACDB_MALLOC(char_t, atp_data_size); + /*klocwork fix*/ + if(atp_frame_ptr->data_ptr==NULL) + { + if (current_node_ptr != NULL) + { + ACDB_FREE(current_node_ptr); + } + ACDB_FREE(atp_frame_ptr); + return; + } + /**Calculate the current frame size + *if this is last frame then frame length can be smalled than max frame length*/ + frame_length = (uint16_t) ((remaining_buffer_length >= atp_data_size) ? + atp_data_size : remaining_buffer_length ); + /** Set it data flag for this frame*/ + atp_frame_ptr->header.flags |= FLAG_DATAFRAME_MASK; + /** If this is the last frame in the buffer, set LAST frame flag also*/ + if( frame_length == remaining_buffer_length ) + { + //Set LAST frame FLAG + atp_frame_ptr->header.flags |= FLAG_LASTFRAME_MASK; + } + /**Increment frame count*/ + frame_count++; + /** Set header info for current frame*/ + atp_frame_ptr->header.buffer_length = buffer_length; + atp_frame_ptr->header.frame_offset = frame_byte_offset; + atp_frame_ptr->header.frame_number = frame_count; + atp_frame_ptr->header.frame_length = frame_length; + + /** copy data into frame*/ + ATS_MEM_CPY_SAFE(atp_frame_ptr->data_ptr,atp_data_size,buffer_ptr,frame_length); + + /** increment buffer pointer by the amount of data we copied*/ + buffer_ptr += frame_length; + + /** increment offset */ + frame_byte_offset +=frame_length; + /**Calculate remaining buffer length*/ + remaining_buffer_length -=frame_length; + current_node_ptr = ACDB_MALLOC(atp_frame_dblnk_lst_struct, 1); + if(NULL==current_node_ptr) + { + ACDB_FREE(atp_frame_ptr->data_ptr); + ACDB_FREE(atp_frame_ptr); + // ACDB_FREE(atp_frame_ptr->data_ptr); //duplicate ACDB_FREE atp_frame_ptr + return; + } + /**If this is first node in the linked list, save it as start_ptr*/ + if ( start_ptr == NULL ) + { + start_ptr = current_node_ptr; + } + /**Initialize previous node pointer and next node pointer of current node*/ + current_node_ptr->previous_node_ptr = current_node_ptr->next_node_ptr = NULL; + /**set the frame pointer of the current node to the atp frame we created just + *now + */ + current_node_ptr->frame_ptr = atp_frame_ptr; + /**Set the previous node pointer of the current node */ + current_node_ptr->previous_node_ptr = prev_node_ptr; + /**set the next node pointer of the previous node */ + if ( prev_node_ptr != NULL ) + { + prev_node_ptr->next_node_ptr = current_node_ptr; + } + /**Save the current node as previous node . Required to set for next node*/ + prev_node_ptr = current_node_ptr; + } + + *start_node_ptr = start_ptr; +} /* break_buffer_into_frames */ + +/** + * FUNCTION : initialize_buffer_context + + * DESCRIPTION : Initializes buffer context. + * his should be called once before using the buffer for transmission + * + * DEPENDENCIES: None. + * + * PARAMS: + * buf_cntxt_ptr - pointer to the buffer context which requires initialization + * + * RETURN VALUE: None + * + * SIDE EFFECTS: None. + */ +void initialize_buffer_context ( + buffer_context_struct *buf_cntxt_ptr + ) +{ + buf_cntxt_ptr->buffer_length = 0; + buf_cntxt_ptr->buffer_ptr = NULL; + buf_cntxt_ptr->is_buffer_allocated = FALSE; + buf_cntxt_ptr->frame_count = 0 ; +} /* initialize_buffer_context */ + +/** + * FUNCTION : copy_frame_to_buffer + * DESCRIPTION : copies a frame on to buffer. + * Takes the offset info from header to find the location to which frame data should copy. + * + * DEPENDENCIES: None. + * + * PARAMS: + * buf_cntxt_ptr - pointer to the address of buffer context + * frame_ptr - pointer to the frame which needs to be copied + * + * RETURN VALUE: bool_t. TRUE indicates this frame is last frame in the buffer. FALSE indicates + * this is NOT last frame. + * + * SIDE EFFECTS: None. + */ +bool_t copy_frame_to_buffer ( + buffer_context_struct *buf_cntxt_ptr, + atp_frame_struct *frame_ptr + ) +{ + char_t *dest_loc_ptr = NULL; + /**If buffer is not created yet, create and initialize */ + if ( buf_cntxt_ptr->is_buffer_allocated == FALSE ) + { + buf_cntxt_ptr->buffer_ptr = ACDB_MALLOC(char_t, frame_ptr->header.buffer_length); + //Klocwork fix: check input ptr if it is a NULL ptr before memset + if (buf_cntxt_ptr->buffer_ptr == NULL) + { + return FALSE; + } + memset(buf_cntxt_ptr->buffer_ptr, 0, frame_ptr->header.buffer_length); + buf_cntxt_ptr->is_buffer_allocated = TRUE ; + /** assign buffer length*/ + buf_cntxt_ptr->buffer_length = frame_ptr->header.buffer_length; + } + + /** Calculate destination loaction where to copy the frame*/ + dest_loc_ptr = buf_cntxt_ptr->buffer_ptr + frame_ptr->header.frame_offset; + /** copy frame on to buffer */ + ATS_MEM_CPY_SAFE( dest_loc_ptr,(buf_cntxt_ptr->buffer_length-frame_ptr->header.frame_offset), frame_ptr->data_ptr, frame_ptr->header.frame_length ); + /** Note the frame count */ + if( buf_cntxt_ptr->frame_count < frame_ptr->header.frame_number ) + buf_cntxt_ptr->frame_count = frame_ptr->header.frame_number; + + /** return TRUE if this is last frame else FALSE*/ + if ( frame_ptr->header.flags & FLAG_LASTFRAME_MASK ) + return TRUE; + else + return FALSE; +} /* copy_frame_to_buffer */ + +/** + * FUNCTION : free_linked_list + + * DESCRIPTION : traverse the linked list and ACDB_FREE all (frame data, + frame and linked list node )the memory. + * + * DEPENDENCIES: None. + * + * PARAMS: + * start_ptr - start node of the linked list + * + * RETURN VALUE: None + * + * SIDE EFFECTS: None. + */ +void free_linked_list ( + atp_frame_dblnk_lst_struct *start_ptr + ) +{ + /**declare and initalise all required pointer for traversing the linked list*/ + atp_frame_dblnk_lst_struct *current_node_ptr=NULL; + atp_frame_dblnk_lst_struct *prev_node_ptr=NULL; + atp_frame_struct *frame_ptr = NULL ; + /** If there are no nodes just return*/ + if ( start_ptr == NULL ) + return; + /**Initislise the current node to start node*/ + current_node_ptr = start_ptr; + do + { + /** ACDB_FREE the atp frame*/ + frame_ptr = current_node_ptr->frame_ptr; + free_atp_frame(frame_ptr); + /**Save the current node as previous node to ACDB_FREE it later*/ + prev_node_ptr = current_node_ptr; + /**Get the next node*/ + current_node_ptr = current_node_ptr->next_node_ptr; + /**ACDB_FREE the previous node*/ + if ( prev_node_ptr != NULL ) + ACDB_FREE(prev_node_ptr); + } + while(current_node_ptr); +} /* free_linked_list */ + + +#ifdef WINPC +/** + * FUNCTION : atp_create_diag_req_pkt + * + * DESCRIPTION : creates diag request packet and puts the given atp frame into payload + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_frame_ptr - pointer to atp frame which needs to be put in as pay load + * atp_diag_pkt - pointer to pointer of diag request pakect to be created + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +void atp_create_diag_req_pkt ( + atp_frame_struct* atp_frame_ptr, + diag_pkt_req_struct** atp_diag_pkt + ) +{ + //atp frame header size + uint8_t headersize = sizeof(atp_frame_header_struct); + /**create a diag packet*/ + *atp_diag_pkt = (diag_pkt_req_struct* )malloc(sizeof(diag_pkt_req_struct)); + if(NULL==(*atp_diag_pkt)) + { + return; + } + /**initialize the diag packet memory to zero*/ + memset(*atp_diag_pkt,0,sizeof(diag_pkt_req_struct)); + /**Set diag packet header*/ + /**Set diag command code*/ + (*atp_diag_pkt)->header.cmdCode = DIAG_EXTEND_CMDCODE; + /**set susbsystem ID as audio subsystem*/ + (*atp_diag_pkt)->header.subsysId = AUDIO_SUBSYS_ID; + /**set the sub system command code */ + (*atp_diag_pkt)->header.subsysCmdCode = SUBSYS_CMDCODE; + + //copy atp frame header to payload + ATS_MEM_CPY_SAFE((*atp_diag_pkt)->payload_req,sizeof((*atp_diag_pkt)->payload_req),&atp_frame_ptr->header,headersize); + + //copy frame data to payload + ATS_MEM_CPY_SAFE((*atp_diag_pkt)->payload_req+headersize,(sizeof((*atp_diag_pkt)->payload_req)-headersize),atp_frame_ptr->data_ptr, + atp_frame_ptr->header.frame_length); + return; +} + +/** + * FUNCTION : atp_create_frame_from_diag_resp + * + * DESCRIPTION : extracts atp frame from diag resp packet + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_diag_pkt - pointer to diag response packet from which to extract atp fraem + * atp_frame_ptr - pointer to pinter where to extrat the atp frame + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +void atp_create_frame_from_diag_resp ( + diag_pkt_resp_struct* atp_diag_pkt, + atp_frame_struct** atp_frame_ptr + ) +{ + uint8_t headersize = sizeof(atp_frame_header_struct); + /**create atp frame*/ + *atp_frame_ptr = (atp_frame_struct* )malloc(sizeof(atp_frame_struct)); + if(NULL==*atp_frame_ptr) + { + return; + } + /**copy header to atp_frame*/ + ATS_MEM_CPY_SAFE(&(*atp_frame_ptr)->header,headersize,atp_diag_pkt->payload_resp,headersize); + /**allocate required memory to hold data*/ + (*atp_frame_ptr)->data_ptr = (char_t *) malloc((*atp_frame_ptr)->header.frame_length); + + //Klocwork fix: check ptr if it is NULL + if ((*atp_frame_ptr)->data_ptr == NULL) + { + ACDB_FREE((*atp_frame_ptr)); + return; + } + /**copy frame data*/ + ATS_MEM_CPY_SAFE((*atp_frame_ptr)->data_ptr,(*atp_frame_ptr)->header.frame_length, atp_diag_pkt->payload_resp+headersize, + (*atp_frame_ptr)->header.frame_length); + return; +} +#endif + +/** + * FUNCTION : atp_create_frame_from_diag_req + * + * DESCRIPTION : creates atp frame from diag request packet + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_diag_pkt - pointer to diag request packet from which to extract atp fraem + * atp_frame_ptr - pointer to pinter where to extrat the atp frame + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +void atp_create_frame_from_diag_req ( + diag_pkt_req_struct* atp_diag_pkt, + atp_frame_struct** atp_frame_ptr + ) +{ + uint8_t headersize = sizeof(atp_frame_header_struct); + /**create atp frame*/ + *atp_frame_ptr = ACDB_MALLOC(atp_frame_struct, 1); + if(NULL==(*atp_frame_ptr)) + { + return; + } + /**copy header part to atp_frame*/ + ATS_MEM_CPY_SAFE(&(*atp_frame_ptr)->header,headersize,atp_diag_pkt->payload_req,headersize); + (*atp_frame_ptr)->data_ptr = NULL ; + if ( (*atp_frame_ptr)->header.frame_length > 0 ) + { + /**allocate required memory to hold data*/ + (*atp_frame_ptr)->data_ptr = ACDB_MALLOC(char_t, (*atp_frame_ptr)->header.frame_length); + if(NULL==((*atp_frame_ptr)->data_ptr)) + { + return; + } + /**copy frame data*/ + ATS_MEM_CPY_SAFE((*atp_frame_ptr)->data_ptr,(*atp_frame_ptr)->header.frame_length, atp_diag_pkt->payload_req+headersize, + (*atp_frame_ptr)->header.frame_length); + } + return; +} + +/** + * FUNCTION : create_atp_frame + * + * DESCRIPTION : creates atp frame and initializes + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_frame_ptr - pointer of pointer of atp_frame_struct + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +void create_atp_frame ( + atp_frame_struct** atp_frame_ptr + ) +{ + /**create atp frame*/ + *atp_frame_ptr = ACDB_MALLOC(atp_frame_struct, 1); + if(NULL==(*atp_frame_ptr)) + { + return; + } + /**initialize its header*/ + init_atp_header(*atp_frame_ptr); + /**Set data pointer to null*/ + (*atp_frame_ptr)->data_ptr = NULL; + return; +}/*create_atp_frame*/ + +#ifdef WINPC + +/** + * FUNCTION : atp_perform_handshake + * + * DESCRIPTION : Performs hand shake with RX. + * Should be called each time before sending a buffer from PC. + * + * DEPENDENCIES: None. + * + * PARAMS: + * context_ptr - pointer to the atp session + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +bool_t atp_perform_handshake ( + atp_pc_context_struct *context_ptr + ) +{ + //Cariable to hold the diag request packet, which is wraper of hand shake frame + diag_pkt_req_struct* atp_diag_req_pkt = NULL; + //Received diag response in response to hand shake + diag_pkt_resp_struct atp_diag_resp_pkt; + //pointer to hand shake frame + atp_frame_struct *atp_hsk_frame_ptr = NULL; + //pointer to response frame for hand shake frame + atp_frame_struct *atp_resp_frame_ptr=NULL; + //flag to indicate if packet is sent successfully + bool_t is_pkt_sent = TRUE; + //flag to indicate is hand shake is success + bool_t is_hsk_success = TRUE; + /**Create a ATP frame*/ + create_atp_frame(&atp_hsk_frame_ptr); + /**Set hand shake frame*/ + atp_hsk_frame_ptr->header.flags |= FLAG_HANDSHAKE_MASK; + /**Create a diag request paket*/ + atp_create_diag_req_pkt(atp_hsk_frame_ptr, &atp_diag_req_pkt); + /**ACDB_FREE the hand shake frame, as we have copied it to diag request packet*/ + free_atp_frame(atp_hsk_frame_ptr); + if( atp_diag_req_pkt != NULL ) + { + /**Send the diag request packet*/ + is_pkt_sent = context_ptr->send_atp_frame_ptr(atp_diag_req_pkt,&atp_diag_resp_pkt); + ACDB_FREE(atp_diag_req_pkt); + } + + if ( FALSE == is_pkt_sent ) + { + /**if failed to send the packet, return error */ + return FALSE; + } + else + { + /**Extract atp frame from diag response packet*/ + atp_create_frame_from_diag_resp(&atp_diag_resp_pkt,&atp_resp_frame_ptr); + /**if RX acknowleded the hand shake it send a frame GetNextFrame flag set*/ + if( (atp_resp_frame_ptr->header.flags & FLAG_GETNEXTFRAME_MASK) == 0 ) + is_hsk_success = FALSE; + else + is_hsk_success = TRUE; + free_atp_frame(atp_resp_frame_ptr); + return is_hsk_success; + } +} + +/** + * FUNCTION : atp_send_buffer + + * DESCRIPTION : + * Send a request buffer to target. + * If buffer sent successfully, returns the response through the call back + *function: receive_resp_buffer_ptr of context_ptr. + * + * DEPENDENCIES : send_atp_frame_ptr memeber in context_ptr must be pointing to + * appropriate function. + * + * PARAMS: + * buffer_ptr - pointer to the input buffer + * buffer_length - bufer length + * atp_pc_context_ptr - pointer to ATP session(on PC side) + * + * RETURN VALUE : If sent successfully returns TRUE or FALSE + + * SIDE EFFECTS : Frees buffer_ptr and resets the pointer to NULL. + */ +bool_t atp_send_buffer ( + char_t* buffer_ptr, + uint32_t buffer_length, + atp_pc_context_struct *atp_pc_context_ptr + ) +{ + diag_pkt_req_struct* atp_current_diag_req_pkt_ptr = NULL; + diag_pkt_resp_struct atp_diag_resp_pkt; + bool_t is_pkt_sent = TRUE; + bool_t is_last_frame_received = FALSE; + atp_frame_struct *atp_resp_frame_ptr=NULL; + atp_frame_struct *atp_gnf_frame_ptr=NULL; + /** Initialize response buffer context */ + initialize_buffer_context(&atp_pc_context_ptr->resp_buf_cntxt); + /** + *Break the request buffer into atp frames and create a linked list. + *Get the start node of the created linked list. + */ + break_buffer_into_frames(buffer_ptr, buffer_length, + &atp_pc_context_ptr->start_node_ptr); + /** Free the request buffer */ + if(buffer_ptr) + { + ACDB_FREE(buffer_ptr); + buffer_ptr = NULL; + } + /** We are going to start sending the frames from linked list. + *So assign the start node as current node + */ + atp_pc_context_ptr->current_node_ptr = atp_pc_context_ptr->start_node_ptr; + /** If there are no nodes in linked list just return FALSE (error)*/ + if ( atp_pc_context_ptr->current_node_ptr == NULL ) + return FALSE; + /** Perform hand shake with RX to inform that we are going to start + transmission + of fresh request buffer*/ + if ( FALSE == atp_perform_handshake(atp_pc_context_ptr) ) + return FALSE; + /** Wrap the first atp_frame into a diag packet */ + atp_create_diag_req_pkt(atp_pc_context_ptr->current_node_ptr->frame_ptr, + &atp_current_diag_req_pkt_ptr); + /** Start traversing the linked list to send all atp_frames one by one*/ + while( 1 ) + { + /** Send atp frame through the call back function of application layer*/ + /** If the packet is send successfully, we receive response atp frame + wrapped in diag packet*/ + is_pkt_sent = atp_pc_context_ptr->send_atp_frame_ptr(atp_current_diag_req_pkt_ptr, + &atp_diag_resp_pkt); + /** ACDB_FREE the diag packet*/ + ACDB_FREE(atp_current_diag_req_pkt_ptr); + /** Check the return code of send_atp_frame_ptr(). + *If failed to send the packet, return FALSE (error) + */ + if ( FALSE == is_pkt_sent ) + return FALSE; + /** No error? unwrap the diag packet to get response atp frame*/ + atp_create_frame_from_diag_resp(&atp_diag_resp_pkt,&atp_resp_frame_ptr); + /** If the current frame is not the last frame... */ + if( atp_pc_context_ptr->current_node_ptr->next_node_ptr != NULL ) + { + /** Expect a atp frame with GNF(Gent Next Frame) flag set*/ + if( !(atp_resp_frame_ptr->header.flags & FLAG_GETNEXTFRAME_MASK) ) + { + /**.If we havn't received a GNF frame, its an error return FALSE(erro)*/ + free_atp_frame(atp_resp_frame_ptr); + return FALSE; + } + /** If we received a frame with GNF flag set, send next frame and + *increment the current node pointer to next node in the lined list + */ + atp_pc_context_ptr->current_node_ptr = + atp_pc_context_ptr->current_node_ptr->next_node_ptr; + /** wrap the next atp frame into diag packet*/ + atp_create_diag_req_pkt(atp_pc_context_ptr->current_node_ptr->frame_ptr, + &atp_current_diag_req_pkt_ptr); + } + else + { + /** If we have sent all frames from request buffer, expect a frame from + response buffer. i.e a frame with Data flag set.*/ + if( !(atp_resp_frame_ptr->header.flags & FLAG_DATAFRAME_MASK) ) + { + /** If we hav not received a Data frame, return FALSE (error) */ + free_atp_frame(atp_resp_frame_ptr); + return FALSE; + } + /** If yes, copy frame to response buffer */ + is_last_frame_received = copy_frame_to_buffer( + &atp_pc_context_ptr->resp_buf_cntxt, + atp_resp_frame_ptr); + free_atp_frame(atp_resp_frame_ptr); + /** If we received a data frame.with LAST flag set, give the response + buffer to application layer*/ + if( is_last_frame_received == TRUE ) + { + atp_pc_context_ptr->receive_resp_buffer_ptr( + atp_pc_context_ptr->resp_buf_cntxt.buffer_ptr, + atp_pc_context_ptr->resp_buf_cntxt.buffer_length); + /** clear the request buffer and reinitialize the response buffer context*/ + ACDB_FREE(atp_pc_context_ptr->resp_buf_cntxt.buffer_ptr); + initialize_buffer_context(&atp_pc_context_ptr->resp_buf_cntxt); + return TRUE; + } + else + { + /** Else request next frame from RX */ + /** create GNF frame */ + create_atp_frame(&atp_gnf_frame_ptr); + /** Set GNF flag*/ + atp_gnf_frame_ptr->header.flags |= FLAG_GETNEXTFRAME_MASK; + /** Prepare the diag packet with the next frame we need to send*/ + atp_create_diag_req_pkt(atp_gnf_frame_ptr, + &atp_current_diag_req_pkt_ptr); + /** ACDB_FREE the atp frame*/ + free_atp_frame( atp_gnf_frame_ptr ); + } + } + }/*while*/ + return FALSE; +}/*atp_send_buffer*/ + +#else +/** + * FUNCTION : atp_receive_atp_frame + + * DESCRIPTION : + *This is the main part of RX algorithm + * Receives an atp frame and copies on to buffer. + *If all frame are received calls the callback function of the application layer + *to give the request buffer and to recive the response buffer. Then sends the + *response buffer to TX. + * + * DEPENDENCIES : receive_req_buffer_ptr memeber in context_ptr must be pointing to + * appropriate function, which can process the request buffer and can provide response buffer + * + * PARAMS: + * context_ptr - pointer to the atp session + * atp_frame_ptr - pointer to the atp frame. which needs to be processed in the give atp context + * + * RETURN VALUE : If sent successfully returns TRUE or FALSE + + * SIDE EFFECTS : None + */ +bool_t atp_receive_atp_frame ( + atp_phone_context_struct *context_ptr, + atp_frame_struct *atp_frame_ptr + ) +{ + /*flag to indicate whether the received frame is last frame in the request + buffer*/ + bool_t is_last_frame = FALSE; + /*pointer to the response buffer*/ + char_t* resp_buf_ptr = NULL ; + /*variable to hold response buffer length*/ + uint32_t resp_buf_length=0; + /*pointer to the response frame created inresponse to the atp_frame-ptr*/ + atp_frame_struct *atp_resp_frame_ptr=NULL; + uint8_t atp_frame_header_length = sizeof(atp_frame_header_struct); + /**We received a handshake frame, so drop all the frames from previous session + *and get ready for new session. + */ + if( (atp_frame_ptr->header.flags & FLAG_HANDSHAKE_MASK) != 0 ) + { + ATS_ERR("ATS FRAME: handshake"); + /** we are expecting a frame with GNF flag */ + if ( context_ptr->is_next_frame_gnf == TRUE ) + { + ATS_ERR("ATS FRAME: handshake GNF = TRUE"); + context_ptr->is_next_frame_gnf = FALSE; + /**we have some response frames left in previous session ACDB_FREE them*/ + free_linked_list(context_ptr->resp_start_node_ptr); + } + else + { + ATS_ERR("ATS FRAME: recieving frames from previous sessions req buffer"); + /**We were receiving frames from previous session request buffer, so ACDB_FREE + *the request buffer*/ + if ( context_ptr->req_buf_cntxt.buffer_ptr != NULL ) + ACDB_FREE(context_ptr->req_buf_cntxt.buffer_ptr); + /**initialise the response buffer context*/ + initialize_buffer_context(&context_ptr->req_buf_cntxt); + }/*hand shake if*/ + /** inform TX that we are ready to receive new request buffer */ + /**create GNF frame and it is our response frame for hand shake frame*/ + create_atp_frame(&context_ptr->atp_current_resp_frame_ptr); + //Klocwork fix: check input if it is a NULL ptr + if (context_ptr->atp_current_resp_frame_ptr == NULL) + { + ATS_ERR("ATS FRAME: current resp frame ptr is null"); + return FALSE; + } + + ATS_ERR("ATS FRAME: setting GNF mask"); + /**Set GNF flag*/ + context_ptr->atp_current_resp_frame_ptr->header.flags |=FLAG_GETNEXTFRAME_MASK ; + return TRUE; + } + /**If we have not received a hand shake frame. + * we have left some frames in response buffer so we are expecting a GNF frame + */ + if ( context_ptr->is_next_frame_gnf == TRUE ) + { + ATS_ERR("ATS FRAME: in GNF condition"); + /**If we have not received a GNF frame so its an error because still we have + *some frame is response buffer*/ + if( (atp_frame_ptr->header.flags & FLAG_GETNEXTFRAME_MASK) == 0 ) + { + ATS_ERR("ATS FRAME: error condition if we are expecting a GNF but have frames in response buffer"); + return FALSE; + } + /** move to next node pointer to send + *If we don't have frames means some unexpected error*/ + if( context_ptr->resp_current_node_ptr == NULL ) + { + ATS_ERR("ATS FRAME: resp curr node ptr is null BEFORE setting to next node ptr"); + return FALSE; + } + context_ptr->resp_current_node_ptr = context_ptr->resp_current_node_ptr->next_node_ptr; + + if (context_ptr->resp_current_node_ptr == NULL) + { + ATS_ERR("ATS FRAME: resp curr node ptr is null AFTER setting to next node ptr"); + return FALSE; + } + /** if this is the last frame in response, note that we are not expecting a GNF + *frame + */ + if ( context_ptr->resp_current_node_ptr->next_node_ptr == NULL ) + { + ATS_ERR("ATS FRAME: last frame! not expecting a GNF"); + context_ptr->is_next_frame_gnf = FALSE; + } + else + { + /**current node is not the last node in response buffer linked list so + *next frame should be GNF frame + */ + context_ptr->is_next_frame_gnf = TRUE; + ATS_ERR("ATS FRAME: still more frames! expecting a GNF"); + } + + ATS_ERR("ATS FRAME: creating fresponse frame"); + /**create response frame*/ + create_atp_frame(&atp_resp_frame_ptr); + //Klocwork fix: check input if it is NULL ptr before perform memcpy + if (atp_resp_frame_ptr == NULL || context_ptr->resp_current_node_ptr == NULL) + { + if(atp_resp_frame_ptr == NULL) + ATS_ERR("ATS FRAME: atp_resp_frame_ptr is null. returning false"); + if (context_ptr->resp_current_node_ptr == NULL) + ATS_ERR("ATS FRAME: context_ptr->resp_current_node_ptr is null. returning false"); + return FALSE; + } + + ATS_ERR("ATS FRAME: copy header info into response frame"); + /**copy header info to response frame*/ + ATS_MEM_CPY_SAFE(atp_resp_frame_ptr,atp_frame_header_length, + &context_ptr->resp_current_node_ptr->frame_ptr->header, + atp_frame_header_length); + + ATS_ERR("ATS FRAME: create mem for data"); + + /**create memory for data */ + atp_resp_frame_ptr->data_ptr = + ACDB_MALLOC(char_t, atp_resp_frame_ptr->header.frame_length); + + + /**copy data to response frame*/ + if (atp_resp_frame_ptr->data_ptr == NULL) + { + ATS_ERR("ATS FRAME: unable to allocate memory for ats response frame data ptr"); + + ACDB_FREE(atp_resp_frame_ptr); + return FALSE; + } + + ATS_ERR("ATS FRAME: copy data into response frame"); + ATS_MEM_CPY_SAFE(atp_resp_frame_ptr->data_ptr,atp_resp_frame_ptr->header.frame_length, + context_ptr->resp_current_node_ptr->frame_ptr->data_ptr, + atp_resp_frame_ptr->header.frame_length + ); + + ATS_ERR("ATS FRAME: set resp frame ptr to current node"); + + /** set response frame pointer as current node frame pointer*/ + context_ptr->atp_current_resp_frame_ptr= atp_resp_frame_ptr; + + if ( context_ptr->resp_current_node_ptr->next_node_ptr == NULL ) + { + //Since this is the last frame we can ACDB_FREE the response buffer linked list + free_linked_list(context_ptr->resp_start_node_ptr); + } + return TRUE; + } + else + { + ATS_ERR("ATS FRAME: data frame"); + + /**we are expecting a data frame + *we have not received a data frame so its an error*/ + if ((atp_frame_ptr->header.flags & FLAG_DATAFRAME_MASK) == 0) + { + ATS_ERR("ATS FRAME: not a data frame! return false"); + + return FALSE; + } + ATS_ERR("ATS FRAME: copy frame to our buffer"); + + /**copy frame to our buffer*/ + is_last_frame = copy_frame_to_buffer(&context_ptr->req_buf_cntxt,atp_frame_ptr); + + if ( is_last_frame ) + { + ATS_ERR("ATS FRAME: this is the last frame"); + + /**we received last frame*/ + /**send request buffer to ACM*/ + if ( context_ptr->receive_req_buffer_ptr == NULL ) + //CR: coding format fix + { + ATS_ERR("ATS FRAME: context_ptr->receive_req_buffer_ptr is null"); + + return FALSE; + } + context_ptr->receive_req_buffer_ptr((uint8_t*)context_ptr->req_buf_cntxt.buffer_ptr, + context_ptr->req_buf_cntxt.buffer_length, + (uint8_t**)&resp_buf_ptr,&resp_buf_length); + + /**ACDB_FREE the request buffer*/ + ACDB_FREE(context_ptr->req_buf_cntxt.buffer_ptr); + if(resp_buf_ptr == NULL) + { + ATS_ERR("ATS FRAME: resp_buf_ptr is null"); + + return FALSE; + } + + ATS_ERR("ATS FRAME: create response buffer START"); + + initialize_buffer_context(&context_ptr->req_buf_cntxt); + /**break the response buffer into frames*/ + break_buffer_into_frames(resp_buf_ptr,resp_buf_length, + &context_ptr->resp_start_node_ptr); + /**ACDB_FREE the response buffer*/ + //ACDB_FREE(resp_buf_ptr); + //Klocwork fix: check if src ptr is a NULL ptr + if (context_ptr->resp_start_node_ptr == NULL) + { + ATS_ERR("context_ptr->resp_start_node_ptr is null"); + return FALSE; + } + /**set current node pointer to start pointer*/ + context_ptr->resp_current_node_ptr = context_ptr->resp_start_node_ptr; + if ( context_ptr->resp_current_node_ptr->next_node_ptr == NULL ) + { + context_ptr->is_next_frame_gnf = FALSE; + } + else + { + context_ptr->is_next_frame_gnf = TRUE; + } + create_atp_frame(&atp_resp_frame_ptr); + //Klocwork fix: check if input it is a NULL ptr + if (atp_resp_frame_ptr == NULL) + { + ATS_ERR("unable to create atp response frame"); + return FALSE; + } + /**copy header info to response frame*/ + ATS_MEM_CPY_SAFE(atp_resp_frame_ptr,atp_frame_header_length, + &context_ptr->resp_current_node_ptr->frame_ptr->header, + atp_frame_header_length); + /**create memory for data */ + atp_resp_frame_ptr->data_ptr = + ACDB_MALLOC(char_t, atp_resp_frame_ptr->header.frame_length); + /**copy data to response frame*/ + //Klocwork fix: check input if it is a NULL ptr before perform memcpy + if (atp_resp_frame_ptr->data_ptr == NULL) + { + ATS_ERR("unable to allocate mem for atp_resp_frame_ptr->data_ptr"); + ACDB_FREE(atp_resp_frame_ptr); + return FALSE; + } + ATS_MEM_CPY_SAFE(atp_resp_frame_ptr->data_ptr,atp_resp_frame_ptr->header.frame_length, + context_ptr->resp_current_node_ptr->frame_ptr->data_ptr, + atp_resp_frame_ptr->header.frame_length + ); + /** set response frame pointer as current node frame pointer*/ + context_ptr->atp_current_resp_frame_ptr= atp_resp_frame_ptr; + if ( context_ptr->resp_current_node_ptr->next_node_ptr == NULL ) + { + //Since this is the last frame we can ACDB_FREE the response buffer linked list + free_linked_list(context_ptr->resp_start_node_ptr); + } + + ATS_ERR("ATS FRAME: create response buffer END"); + return TRUE; + } + else + { + ATS_ERR("ATS FRAME: not the last data frame! requeset next frame "); + /**this is not last frame so request next frame*/ + /**create GNF frame and it is our response frame*/ + create_atp_frame(&context_ptr->atp_current_resp_frame_ptr); + //Klocwork fix: if input is a NULL ptr + if (context_ptr->atp_current_resp_frame_ptr == NULL) + { + return FALSE; + } + context_ptr->atp_current_resp_frame_ptr->header.flags |=FLAG_GETNEXTFRAME_MASK ; + return TRUE; + } + }/*else if( context_ptr->is_next_frame_gnf == TRUE )*/ + /*return FALSE; This is not reachable*/ +}/*atp_receive_atp_frame*/ +#endif + +/** + * FUNCTION : atp_create_diag_resp_pkt + * + * DESCRIPTION : creates a diag resp packet from atp frame + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_frame_ptr - frame to be wrapped in response diag packet + * atp_diag_pkt - created diag response packet + * + * RETURN VALUE: None + * + * SIDE EFFECTS: None. + */ +void atp_create_diag_resp_pkt ( + atp_frame_struct* atp_frame_ptr, + diag_pkt_resp_struct** atp_diag_pkt + ) +{ + ATS_ERR("DIAG PKT: Creating diag response packet"); + print_atp_frame(atp_frame_ptr); + uint8_t headersize = sizeof(atp_frame_header_struct); + /** Create diag response packet*/ + (*atp_diag_pkt) = ACDB_MALLOC(diag_pkt_resp_struct, 1); + if(NULL==(*atp_diag_pkt)) + { + return; + } + /**Initialise the memeory*/ + memset(*atp_diag_pkt,0,sizeof(diag_pkt_resp_struct)); + /**set diag response packet header info*/ + (*atp_diag_pkt)->header.cmdCode = DIAG_EXTEND_CMDCODE; + (*atp_diag_pkt)->header.subsysId = AUDIO_SUBSYS_ID; + (*atp_diag_pkt)->header.subsysCmdCode = SUBSYS_CMDCODE; + + /** copy atp header info*/ + ATS_MEM_CPY_SAFE(&(*atp_diag_pkt)->payload_resp[0], headersize, &atp_frame_ptr->header, headersize); + + /**copy frame data*/ + if (atp_frame_ptr->data_ptr != NULL) + { + ATS_MEM_CPY_SAFE( + &(*atp_diag_pkt)->payload_resp[headersize], atp_frame_ptr->header.frame_length, + atp_frame_ptr->data_ptr, atp_frame_ptr->header.frame_length); + } + return; +} + +#ifndef WINPC + + + +/** + * FUNCTION : atp_receive_diag_pkt + * + * DESCRIPTION : + * Receive a request diag packet from acm diag dispatcher (avsACMdiag_cmd()) + *.and return a response diag packet. + * + * DEPENDENCIES : receive_req_buffer_ptr memeber in atp_phone_context_ptr must be + *pointing to.appropriate function, which can process the request buffer and + *provide a response buffer. + * + * PARAMS: + * atp_diag_req_pkt_ptr - pointer to the diag packet which contains the atp frame from request buffer + * atp_diag_rsp_pkt_ptr - pointer to the diag packet which contains the atp frame from response buffer + * atp_phone_context_ptr - pointer to the phone context to whome request to be sent and resposne received + * + * RETURN VALUE : If sent successfully returns TRUE or FALSE + * + * SIDE EFFECTS : Will NOT Free response buffer. + */ +void atp_receive_diag_pkt ( + diag_pkt_req_struct *atp_diag_req_pkt_ptr, + diag_pkt_resp_struct **atp_diag_rsp_pkt_ptr, + atp_phone_context_struct *atp_phone_context_ptr + ) +{ + //Klocwork fix: //A temporary NULL ptr to hold atp frame extracted from request diag packet + atp_frame_struct* atp_frame_ptr = NULL; + /** Create a atp frame from diag request packet */ + atp_create_frame_from_diag_req(atp_diag_req_pkt_ptr, &atp_frame_ptr); + + print_atp_frame(atp_frame_ptr); + + /** Send extracted atp frame to RX algorithm, which accumulates all the + request frames to construct a request buffer.*/ + //Klocwork fix: Null pointer check before calling atp_receive_atp_frame command + if (atp_frame_ptr != NULL) + { + (void)atp_receive_atp_frame(atp_phone_context_ptr, atp_frame_ptr); + } + /** ACDB_FREE the extracted atp frame*/ + //Klocwork fix: Null pointer check before calling atp_receive_atp_frame command + if (atp_frame_ptr != NULL) + { + free_atp_frame(atp_frame_ptr); + } + /** if response atp frame is ready...*/ + if ( atp_phone_context_ptr->atp_current_resp_frame_ptr != NULL ) + { + /** create a diag packet which wraps the response frame*/ + atp_create_diag_resp_pkt( + atp_phone_context_ptr->atp_current_resp_frame_ptr, + atp_diag_rsp_pkt_ptr + ); + /**ACDB_FREE the response frame*/ + free_atp_frame(atp_phone_context_ptr->atp_current_resp_frame_ptr); + } + else + { + /**else return NULL as response diag packet*/ + *atp_diag_rsp_pkt_ptr = NULL; + } +} +#endif + +//#endif /*FEATURE_AVS_AUDIO_TRANSPORT_PROTOCOL || WINPC*/ diff --git a/acdb/ats/transports/diag/linux/audtp/src/audtp_debug.c b/acdb/ats/transports/diag/linux/audtp/src/audtp_debug.c new file mode 100644 index 0000000..2e90305 --- /dev/null +++ b/acdb/ats/transports/diag/linux/audtp/src/audtp_debug.c @@ -0,0 +1,1193 @@ + /** + *============================================================================== + * \file audtp.c + * \brief + * A T P P R O T O C O L L A Y E R + * S O U R C E F I L E + * + * This file contains implementation of ATP protocol layer + * + * INITIALIZATION REQUIREMENTS: + * atp_diag_init() must be called to initialise ATP protocol layer. + * atp_diag_init() must be called ~AFTER~ initialization of SOUND TASK + * + * This file is common to both protocol component on PC and protocol + * module on AMSS. PC only/phone only code is wrapped with in + * #ifdef WINPC + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + *============================================================================== + */ +/* + -------------------- + |include files | + -------------------- + */ +#include "audtp.h" +#include "ats_common.h" + +/* + -------------------- + |Constants | + -------------------- + */ +const uint8_t atp_protocol_version = 1; + +/* + -------------------- + |Function definitions | + -------------------- + */ + +void print_atp_frame(atp_frame_struct* atp_frame) +{ + if (atp_frame == NULL) + { + ATS_ERR("ATS FRAME: frame is null"); + return; + } + + ATS_ERR("ATS FRAME: version: %d", atp_frame->header.version); + ATS_ERR("ATS FRAME: header length: %d", atp_frame->header.header_length); + ATS_ERR("ATS FRAME: frame#: %d", atp_frame->header.frame_number); + ATS_ERR("ATS FRAME: flags: %d", atp_frame->header.flags); + ATS_ERR("ATS FRAME: frame offset: %d", atp_frame->header.frame_offset); + ATS_ERR("ATS FRAME: frame length: %d", atp_frame->header.frame_length); + ATS_ERR("ATS FRAME: buffer length: %d", atp_frame->header.buffer_length); + + if (atp_frame->data_ptr == NULL) + { + ATS_ERR("ATS FRAME: frame data is null"); + } +} + +/** + * FUNCTION init_atp_header + * + * DESCRIPTION : Initializes ATP frame headr with default values + * + * DEPENDENCIES: atp_frame_ptr should be a valid pointer + * + * PARAMS: + * atp_frame_ptr - atp_frame pointer which requires initialization + * + * RETURN VALUE: None + * + * SIDE EFFECTS: Sets the atp_frame to default values which is pointed to by atp_frame_ptr . + */ +void init_atp_header ( + atp_frame_struct *atp_frame_ptr + ) +{ + if ( atp_frame_ptr == NULL ) + return; + /** Set protocol Version */ + atp_frame_ptr->header.version = atp_protocol_version; + + /** Set header length , which is of fixed size*/ + atp_frame_ptr->header.header_length = sizeof(atp_frame_header_struct); + + /** Turn off all flags */ + atp_frame_ptr->header.flags = 0; + /** Reset frame number to zero */ + atp_frame_ptr->header.frame_number = 0; + /** Reset frame offset to zero */ + atp_frame_ptr->header.frame_offset = 0; + /** Reset frame length to zero */ + atp_frame_ptr->header.frame_length = 0; + /** Reset buffer length to zero */ + atp_frame_ptr->header.buffer_length = 0; +} /* init_atp_header */ + +/** + * FUNCTION free_atp_frame + * + * DESCRIPTION : Deallocates memory for atp frame data pointer and sets pointers to NULL. + * Then deallocates memory for this frame and sets pointer to NULL + * + * DEPENDENCIES: atp_frame_ptr should be a valid pointer + * + * PARAMS: + * atp_frame_ptr - atp_frame pointer which needs to be deallocated + * + * RETURN VALUE: None + * + * SIDE EFFECTS: None + * + */ +void free_atp_frame ( + atp_frame_struct* atp_frame_ptr + ) +{ + if(NULL==atp_frame_ptr) + { + return; + } + /** deallocate data part and set to NULL*/ + if ( atp_frame_ptr->data_ptr != NULL ) + { + ACDB_FREE(atp_frame_ptr->data_ptr); + atp_frame_ptr->data_ptr = NULL; + } + /** ACDB_FREE frame */ + if( atp_frame_ptr != NULL ) + { + ACDB_FREE(atp_frame_ptr); + atp_frame_ptr = NULL; + } +}/* free_atp_frame */ + +/** + * FUNCTION : break_buffer_into_frames + * + * DESCRIPTION : Breaks a given buffer into frames and sets their header info. + * Creates a doubly linked list of created frames. + * Input buffer can be deallocated. + * + * DEPENDENCIES: None. + * + * PARAMS: + * buffer_ptr - pointer to the input buffer + * buffer_length - bufer length + * start_node_ptr - linked list of frames start pointer + * + * RETURN VALUE: Pointer to the first node of the linked list + * + * SIDE EFFECTS: None. + */ +void break_buffer_into_frames ( + char_t* buffer_ptr, + uint32_t buffer_length, + atp_frame_dblnk_lst_struct** start_node_ptr + ) +{ + /** variable to hold the starting point of the dbl lnk lst.*/ + atp_frame_dblnk_lst_struct *start_ptr = NULL; + uint32_t frame_byte_offset = 0; + /** initialize frame count to zero */ + uint8_t frame_count = 0; + /** calculate max payload size */ +#ifdef WINPC + uint16_t atp_data_size = DIAG_REQ_PKT_SIZE - sizeof(atp_frame_header_struct); +#else + uint16_t atp_data_size = DIAG_RES_PKT_SIZE - sizeof(atp_frame_header_struct); +#endif + uint16_t frame_length = atp_data_size; + /** Variable to hold the length of the buffer to be processed to break into frames*/ + uint32_t remaining_buffer_length = buffer_length; + /** pointer to hold the previous node in the linked list */ + atp_frame_dblnk_lst_struct *prev_node_ptr = NULL; + /** pointer to hold the current node in the linked list */ + atp_frame_dblnk_lst_struct *current_node_ptr = NULL; + /** Initialize the frame count to zero*/ + frame_count = 0; + /**loop while we have some buffer to break*/ + while(remaining_buffer_length > 0 ) + { + atp_frame_struct* atp_frame_ptr = NULL; + + /** Create a atp_frame*/ + atp_frame_ptr = ACDB_MALLOC(atp_frame_struct, 1); + if(NULL==atp_frame_ptr) + { + //Klocwork fix: memory leak, return without ACDB_FREE memory allocation + if (current_node_ptr != NULL) + { + ACDB_FREE(current_node_ptr); + } + return; + } + /** Initialize the header*/ + init_atp_header(atp_frame_ptr); + /** allocate memory for frame data */ + atp_frame_ptr->data_ptr = ACDB_MALLOC(char_t, atp_data_size); + /*klocwork fix*/ + if(atp_frame_ptr->data_ptr==NULL) + { + if (current_node_ptr != NULL) + { + ACDB_FREE(current_node_ptr); + } + ACDB_FREE(atp_frame_ptr); + return; + } + /**Calculate the current frame size + *if this is last frame then frame length can be smalled than max frame length*/ + frame_length = (uint16_t) ((remaining_buffer_length >= atp_data_size) ? + atp_data_size : remaining_buffer_length ); + /** Set it data flag for this frame*/ + atp_frame_ptr->header.flags |= FLAG_DATAFRAME_MASK; + /** If this is the last frame in the buffer, set LAST frame flag also*/ + if( frame_length == remaining_buffer_length ) + { + //Set LAST frame FLAG + atp_frame_ptr->header.flags |= FLAG_LASTFRAME_MASK; + } + /**Increment frame count*/ + frame_count++; + /** Set header info for current frame*/ + atp_frame_ptr->header.buffer_length = buffer_length; + atp_frame_ptr->header.frame_offset = frame_byte_offset; + atp_frame_ptr->header.frame_number = frame_count; + atp_frame_ptr->header.frame_length = frame_length; + + /** copy data into frame*/ + ATS_MEM_CPY_SAFE(atp_frame_ptr->data_ptr,atp_data_size,buffer_ptr,frame_length); + + /** increment buffer pointer by the amount of data we copied*/ + buffer_ptr += frame_length; + + /** increment offset */ + frame_byte_offset +=frame_length; + /**Calculate remaining buffer length*/ + remaining_buffer_length -=frame_length; + current_node_ptr = ACDB_MALLOC(atp_frame_dblnk_lst_struct, 1); + if(NULL==current_node_ptr) + { + ACDB_FREE(atp_frame_ptr->data_ptr); + ACDB_FREE(atp_frame_ptr); + // ACDB_FREE(atp_frame_ptr->data_ptr); //duplicate ACDB_FREE atp_frame_ptr + return; + } + /**If this is first node in the linked list, save it as start_ptr*/ + if ( start_ptr == NULL ) + { + start_ptr = current_node_ptr; + } + /**Initialize previous node pointer and next node pointer of current node*/ + current_node_ptr->previous_node_ptr = current_node_ptr->next_node_ptr = NULL; + /**set the frame pointer of the current node to the atp frame we created just + *now + */ + current_node_ptr->frame_ptr = atp_frame_ptr; + /**Set the previous node pointer of the current node */ + current_node_ptr->previous_node_ptr = prev_node_ptr; + /**set the next node pointer of the previous node */ + if ( prev_node_ptr != NULL ) + { + prev_node_ptr->next_node_ptr = current_node_ptr; + } + /**Save the current node as previous node . Required to set for next node*/ + prev_node_ptr = current_node_ptr; + } + + *start_node_ptr = start_ptr; +} /* break_buffer_into_frames */ + +/** + * FUNCTION : initialize_buffer_context + + * DESCRIPTION : Initializes buffer context. + * his should be called once before using the buffer for transmission + * + * DEPENDENCIES: None. + * + * PARAMS: + * buf_cntxt_ptr - pointer to the buffer context which requires initialization + * + * RETURN VALUE: None + * + * SIDE EFFECTS: None. + */ +void initialize_buffer_context ( + buffer_context_struct *buf_cntxt_ptr + ) +{ + buf_cntxt_ptr->buffer_length = 0; + buf_cntxt_ptr->buffer_ptr = NULL; + buf_cntxt_ptr->is_buffer_allocated = FALSE; + buf_cntxt_ptr->frame_count = 0 ; +} /* initialize_buffer_context */ + +/** + * FUNCTION : copy_frame_to_buffer + * DESCRIPTION : copies a frame on to buffer. + * Takes the offset info from header to find the location to which frame data should copy. + * + * DEPENDENCIES: None. + * + * PARAMS: + * buf_cntxt_ptr - pointer to the address of buffer context + * frame_ptr - pointer to the frame which needs to be copied + * + * RETURN VALUE: bool_t. TRUE indicates this frame is last frame in the buffer. FALSE indicates + * this is NOT last frame. + * + * SIDE EFFECTS: None. + */ +bool_t copy_frame_to_buffer ( + buffer_context_struct *buf_cntxt_ptr, + atp_frame_struct *frame_ptr + ) +{ + char_t *dest_loc_ptr = NULL; + /**If buffer is not created yet, create and initialize */ + if ( buf_cntxt_ptr->is_buffer_allocated == FALSE ) + { + buf_cntxt_ptr->buffer_ptr = ACDB_MALLOC(char_t, frame_ptr->header.buffer_length); + //Klocwork fix: check input ptr if it is a NULL ptr before memset + if (buf_cntxt_ptr->buffer_ptr == NULL) + { + return FALSE; + } + memset(buf_cntxt_ptr->buffer_ptr, 0, frame_ptr->header.buffer_length); + buf_cntxt_ptr->is_buffer_allocated = TRUE ; + /** assign buffer length*/ + buf_cntxt_ptr->buffer_length = frame_ptr->header.buffer_length; + } + + /** Calculate destination loaction where to copy the frame*/ + dest_loc_ptr = buf_cntxt_ptr->buffer_ptr + frame_ptr->header.frame_offset; + /** copy frame on to buffer */ + ATS_MEM_CPY_SAFE( dest_loc_ptr,(buf_cntxt_ptr->buffer_length-frame_ptr->header.frame_offset), frame_ptr->data_ptr, frame_ptr->header.frame_length ); + /** Note the frame count */ + if( buf_cntxt_ptr->frame_count < frame_ptr->header.frame_number ) + buf_cntxt_ptr->frame_count = frame_ptr->header.frame_number; + + /** return TRUE if this is last frame else FALSE*/ + if ( frame_ptr->header.flags & FLAG_LASTFRAME_MASK ) + return TRUE; + else + return FALSE; +} /* copy_frame_to_buffer */ + +/** + * FUNCTION : free_linked_list + + * DESCRIPTION : traverse the linked list and ACDB_FREE all (frame data, + frame and linked list node )the memory. + * + * DEPENDENCIES: None. + * + * PARAMS: + * start_ptr - start node of the linked list + * + * RETURN VALUE: None + * + * SIDE EFFECTS: None. + */ +void free_linked_list ( + atp_frame_dblnk_lst_struct *start_ptr + ) +{ + /**declare and initalise all required pointer for traversing the linked list*/ + atp_frame_dblnk_lst_struct *current_node_ptr=NULL; + atp_frame_dblnk_lst_struct *prev_node_ptr=NULL; + atp_frame_struct *frame_ptr = NULL ; + /** If there are no nodes just return*/ + if ( start_ptr == NULL ) + return; + /**Initislise the current node to start node*/ + current_node_ptr = start_ptr; + do + { + /** ACDB_FREE the atp frame*/ + frame_ptr = current_node_ptr->frame_ptr; + free_atp_frame(frame_ptr); + /**Save the current node as previous node to ACDB_FREE it later*/ + prev_node_ptr = current_node_ptr; + /**Get the next node*/ + current_node_ptr = current_node_ptr->next_node_ptr; + /**ACDB_FREE the previous node*/ + if ( prev_node_ptr != NULL ) + ACDB_FREE(prev_node_ptr); + } + while(current_node_ptr); +} /* free_linked_list */ + + +#ifdef WINPC +/** + * FUNCTION : atp_create_diag_req_pkt + * + * DESCRIPTION : creates diag request packet and puts the given atp frame into payload + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_frame_ptr - pointer to atp frame which needs to be put in as pay load + * atp_diag_pkt - pointer to pointer of diag request pakect to be created + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +void atp_create_diag_req_pkt ( + atp_frame_struct* atp_frame_ptr, + diag_pkt_req_struct** atp_diag_pkt + ) +{ + //atp frame header size + uint8_t headersize = sizeof(atp_frame_header_struct); + /**create a diag packet*/ + *atp_diag_pkt = (diag_pkt_req_struct* )malloc(sizeof(diag_pkt_req_struct)); + if(NULL==(*atp_diag_pkt)) + { + return; + } + /**initialize the diag packet memory to zero*/ + memset(*atp_diag_pkt,0,sizeof(diag_pkt_req_struct)); + /**Set diag packet header*/ + /**Set diag command code*/ + (*atp_diag_pkt)->header.cmdCode = DIAG_EXTEND_CMDCODE; + /**set susbsystem ID as audio subsystem*/ + (*atp_diag_pkt)->header.subsysId = AUDIO_SUBSYS_ID; + /**set the sub system command code */ + (*atp_diag_pkt)->header.subsysCmdCode = SUBSYS_CMDCODE; + + //copy atp frame header to payload + ATS_MEM_CPY_SAFE((*atp_diag_pkt)->payload_req,sizeof((*atp_diag_pkt)->payload_req),&atp_frame_ptr->header,headersize); + + //copy frame data to payload + ATS_MEM_CPY_SAFE((*atp_diag_pkt)->payload_req+headersize,(sizeof((*atp_diag_pkt)->payload_req)-headersize),atp_frame_ptr->data_ptr, + atp_frame_ptr->header.frame_length); + return; +} + +/** + * FUNCTION : atp_create_frame_from_diag_resp + * + * DESCRIPTION : extracts atp frame from diag resp packet + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_diag_pkt - pointer to diag response packet from which to extract atp fraem + * atp_frame_ptr - pointer to pinter where to extrat the atp frame + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +void atp_create_frame_from_diag_resp ( + diag_pkt_resp_struct* atp_diag_pkt, + atp_frame_struct** atp_frame_ptr + ) +{ + uint8_t headersize = sizeof(atp_frame_header_struct); + /**create atp frame*/ + *atp_frame_ptr = (atp_frame_struct* )malloc(sizeof(atp_frame_struct)); + if(NULL==*atp_frame_ptr) + { + return; + } + /**copy header to atp_frame*/ + ATS_MEM_CPY_SAFE(&(*atp_frame_ptr)->header,headersize,atp_diag_pkt->payload_resp,headersize); + /**allocate required memory to hold data*/ + (*atp_frame_ptr)->data_ptr = (char_t *) malloc((*atp_frame_ptr)->header.frame_length); + + //Klocwork fix: check ptr if it is NULL + if ((*atp_frame_ptr)->data_ptr == NULL) + { + ACDB_FREE((*atp_frame_ptr)); + return; + } + /**copy frame data*/ + ATS_MEM_CPY_SAFE((*atp_frame_ptr)->data_ptr,(*atp_frame_ptr)->header.frame_length, atp_diag_pkt->payload_resp+headersize, + (*atp_frame_ptr)->header.frame_length); + return; +} +#endif + +/** + * FUNCTION : atp_create_frame_from_diag_req + * + * DESCRIPTION : creates atp frame from diag request packet + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_diag_pkt - pointer to diag request packet from which to extract atp fraem + * atp_frame_ptr - pointer to pinter where to extrat the atp frame + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +void atp_create_frame_from_diag_req ( + diag_pkt_req_struct* atp_diag_pkt, + atp_frame_struct** atp_frame_ptr + ) +{ + uint8_t headersize = sizeof(atp_frame_header_struct); + /**create atp frame*/ + *atp_frame_ptr = ACDB_MALLOC(atp_frame_struct, 1); + if(NULL==(*atp_frame_ptr)) + { + return; + } + /**copy header part to atp_frame*/ + ATS_MEM_CPY_SAFE(&(*atp_frame_ptr)->header,headersize,atp_diag_pkt->payload_req,headersize); + (*atp_frame_ptr)->data_ptr = NULL ; + if ( (*atp_frame_ptr)->header.frame_length > 0 ) + { + /**allocate required memory to hold data*/ + (*atp_frame_ptr)->data_ptr = ACDB_MALLOC(char_t, (*atp_frame_ptr)->header.frame_length); + if(NULL==((*atp_frame_ptr)->data_ptr)) + { + return; + } + /**copy frame data*/ + ATS_MEM_CPY_SAFE((*atp_frame_ptr)->data_ptr,(*atp_frame_ptr)->header.frame_length, atp_diag_pkt->payload_req+headersize, + (*atp_frame_ptr)->header.frame_length); + } + return; +} + +/** + * FUNCTION : create_atp_frame + * + * DESCRIPTION : creates atp frame and initializes + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_frame_ptr - pointer of pointer of atp_frame_struct + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +void create_atp_frame ( + atp_frame_struct** atp_frame_ptr + ) +{ + /**create atp frame*/ + *atp_frame_ptr = ACDB_MALLOC(atp_frame_struct, 1); + if(NULL==(*atp_frame_ptr)) + { + return; + } + /**initialize its header*/ + init_atp_header(*atp_frame_ptr); + /**Set data pointer to null*/ + (*atp_frame_ptr)->data_ptr = NULL; + return; +}/*create_atp_frame*/ + +#ifdef WINPC + +/** + * FUNCTION : atp_perform_handshake + * + * DESCRIPTION : Performs hand shake with RX. + * Should be called each time before sending a buffer from PC. + * + * DEPENDENCIES: None. + * + * PARAMS: + * context_ptr - pointer to the atp session + * + * RETURN VALUE: void + * + * SIDE EFFECTS: None. + */ +bool_t atp_perform_handshake ( + atp_pc_context_struct *context_ptr + ) +{ + //Cariable to hold the diag request packet, which is wraper of hand shake frame + diag_pkt_req_struct* atp_diag_req_pkt = NULL; + //Received diag response in response to hand shake + diag_pkt_resp_struct atp_diag_resp_pkt; + //pointer to hand shake frame + atp_frame_struct *atp_hsk_frame_ptr = NULL; + //pointer to response frame for hand shake frame + atp_frame_struct *atp_resp_frame_ptr=NULL; + //flag to indicate if packet is sent successfully + bool_t is_pkt_sent = TRUE; + //flag to indicate is hand shake is success + bool_t is_hsk_success = TRUE; + /**Create a ATP frame*/ + create_atp_frame(&atp_hsk_frame_ptr); + /**Set hand shake frame*/ + atp_hsk_frame_ptr->header.flags |= FLAG_HANDSHAKE_MASK; + /**Create a diag request paket*/ + atp_create_diag_req_pkt(atp_hsk_frame_ptr, &atp_diag_req_pkt); + /**ACDB_FREE the hand shake frame, as we have copied it to diag request packet*/ + free_atp_frame(atp_hsk_frame_ptr); + if( atp_diag_req_pkt != NULL ) + { + /**Send the diag request packet*/ + is_pkt_sent = context_ptr->send_atp_frame_ptr(atp_diag_req_pkt,&atp_diag_resp_pkt); + ACDB_FREE(atp_diag_req_pkt); + } + + if ( FALSE == is_pkt_sent ) + { + /**if failed to send the packet, return error */ + return FALSE; + } + else + { + /**Extract atp frame from diag response packet*/ + atp_create_frame_from_diag_resp(&atp_diag_resp_pkt,&atp_resp_frame_ptr); + /**if RX acknowleded the hand shake it send a frame GetNextFrame flag set*/ + if( (atp_resp_frame_ptr->header.flags & FLAG_GETNEXTFRAME_MASK) == 0 ) + is_hsk_success = FALSE; + else + is_hsk_success = TRUE; + free_atp_frame(atp_resp_frame_ptr); + return is_hsk_success; + } +} + +/** + * FUNCTION : atp_send_buffer + + * DESCRIPTION : + * Send a request buffer to target. + * If buffer sent successfully, returns the response through the call back + *function: receive_resp_buffer_ptr of context_ptr. + * + * DEPENDENCIES : send_atp_frame_ptr memeber in context_ptr must be pointing to + * appropriate function. + * + * PARAMS: + * buffer_ptr - pointer to the input buffer + * buffer_length - bufer length + * atp_pc_context_ptr - pointer to ATP session(on PC side) + * + * RETURN VALUE : If sent successfully returns TRUE or FALSE + + * SIDE EFFECTS : Frees buffer_ptr and resets the pointer to NULL. + */ +bool_t atp_send_buffer ( + char_t* buffer_ptr, + uint32_t buffer_length, + atp_pc_context_struct *atp_pc_context_ptr + ) +{ + diag_pkt_req_struct* atp_current_diag_req_pkt_ptr = NULL; + diag_pkt_resp_struct atp_diag_resp_pkt; + bool_t is_pkt_sent = TRUE; + bool_t is_last_frame_received = FALSE; + atp_frame_struct *atp_resp_frame_ptr=NULL; + atp_frame_struct *atp_gnf_frame_ptr=NULL; + /** Initialize response buffer context */ + initialize_buffer_context(&atp_pc_context_ptr->resp_buf_cntxt); + /** + *Break the request buffer into atp frames and create a linked list. + *Get the start node of the created linked list. + */ + break_buffer_into_frames(buffer_ptr, buffer_length, + &atp_pc_context_ptr->start_node_ptr); + /** Free the request buffer */ + if(buffer_ptr) + { + ACDB_FREE(buffer_ptr); + buffer_ptr = NULL; + } + /** We are going to start sending the frames from linked list. + *So assign the start node as current node + */ + atp_pc_context_ptr->current_node_ptr = atp_pc_context_ptr->start_node_ptr; + /** If there are no nodes in linked list just return FALSE (error)*/ + if ( atp_pc_context_ptr->current_node_ptr == NULL ) + return FALSE; + /** Perform hand shake with RX to inform that we are going to start + transmission + of fresh request buffer*/ + if ( FALSE == atp_perform_handshake(atp_pc_context_ptr) ) + return FALSE; + /** Wrap the first atp_frame into a diag packet */ + atp_create_diag_req_pkt(atp_pc_context_ptr->current_node_ptr->frame_ptr, + &atp_current_diag_req_pkt_ptr); + /** Start traversing the linked list to send all atp_frames one by one*/ + while( 1 ) + { + /** Send atp frame through the call back function of application layer*/ + /** If the packet is send successfully, we receive response atp frame + wrapped in diag packet*/ + is_pkt_sent = atp_pc_context_ptr->send_atp_frame_ptr(atp_current_diag_req_pkt_ptr, + &atp_diag_resp_pkt); + /** ACDB_FREE the diag packet*/ + ACDB_FREE(atp_current_diag_req_pkt_ptr); + /** Check the return code of send_atp_frame_ptr(). + *If failed to send the packet, return FALSE (error) + */ + if ( FALSE == is_pkt_sent ) + return FALSE; + /** No error? unwrap the diag packet to get response atp frame*/ + atp_create_frame_from_diag_resp(&atp_diag_resp_pkt,&atp_resp_frame_ptr); + /** If the current frame is not the last frame... */ + if( atp_pc_context_ptr->current_node_ptr->next_node_ptr != NULL ) + { + /** Expect a atp frame with GNF(Gent Next Frame) flag set*/ + if( !(atp_resp_frame_ptr->header.flags & FLAG_GETNEXTFRAME_MASK) ) + { + /**.If we havn't received a GNF frame, its an error return FALSE(erro)*/ + free_atp_frame(atp_resp_frame_ptr); + return FALSE; + } + /** If we received a frame with GNF flag set, send next frame and + *increment the current node pointer to next node in the lined list + */ + atp_pc_context_ptr->current_node_ptr = + atp_pc_context_ptr->current_node_ptr->next_node_ptr; + /** wrap the next atp frame into diag packet*/ + atp_create_diag_req_pkt(atp_pc_context_ptr->current_node_ptr->frame_ptr, + &atp_current_diag_req_pkt_ptr); + } + else + { + /** If we have sent all frames from request buffer, expect a frame from + response buffer. i.e a frame with Data flag set.*/ + if( !(atp_resp_frame_ptr->header.flags & FLAG_DATAFRAME_MASK) ) + { + /** If we hav not received a Data frame, return FALSE (error) */ + free_atp_frame(atp_resp_frame_ptr); + return FALSE; + } + /** If yes, copy frame to response buffer */ + is_last_frame_received = copy_frame_to_buffer( + &atp_pc_context_ptr->resp_buf_cntxt, + atp_resp_frame_ptr); + free_atp_frame(atp_resp_frame_ptr); + /** If we received a data frame.with LAST flag set, give the response + buffer to application layer*/ + if( is_last_frame_received == TRUE ) + { + atp_pc_context_ptr->receive_resp_buffer_ptr( + atp_pc_context_ptr->resp_buf_cntxt.buffer_ptr, + atp_pc_context_ptr->resp_buf_cntxt.buffer_length); + /** clear the request buffer and reinitialize the response buffer context*/ + ACDB_FREE(atp_pc_context_ptr->resp_buf_cntxt.buffer_ptr); + initialize_buffer_context(&atp_pc_context_ptr->resp_buf_cntxt); + return TRUE; + } + else + { + /** Else request next frame from RX */ + /** create GNF frame */ + create_atp_frame(&atp_gnf_frame_ptr); + /** Set GNF flag*/ + atp_gnf_frame_ptr->header.flags |= FLAG_GETNEXTFRAME_MASK; + /** Prepare the diag packet with the next frame we need to send*/ + atp_create_diag_req_pkt(atp_gnf_frame_ptr, + &atp_current_diag_req_pkt_ptr); + /** ACDB_FREE the atp frame*/ + free_atp_frame( atp_gnf_frame_ptr ); + } + } + }/*while*/ + return FALSE; +}/*atp_send_buffer*/ + +#else +/** + * FUNCTION : atp_receive_atp_frame + + * DESCRIPTION : + *This is the main part of RX algorithm + * Receives an atp frame and copies on to buffer. + *If all frame are received calls the callback function of the application layer + *to give the request buffer and to recive the response buffer. Then sends the + *response buffer to TX. + * + * DEPENDENCIES : receive_req_buffer_ptr memeber in context_ptr must be pointing to + * appropriate function, which can process the request buffer and can provide response buffer + * + * PARAMS: + * context_ptr - pointer to the atp session + * atp_frame_ptr - pointer to the atp frame. which needs to be processed in the give atp context + * + * RETURN VALUE : If sent successfully returns TRUE or FALSE + + * SIDE EFFECTS : None + */ +bool_t atp_receive_atp_frame ( + atp_phone_context_struct *context_ptr, + atp_frame_struct *atp_frame_ptr + ) +{ + /*flag to indicate whether the received frame is last frame in the request + buffer*/ + bool_t is_last_frame = FALSE; + /*pointer to the response buffer*/ + char_t* resp_buf_ptr = NULL ; + /*variable to hold response buffer length*/ + uint32_t resp_buf_length=0; + /*pointer to the response frame created inresponse to the atp_frame-ptr*/ + atp_frame_struct *atp_resp_frame_ptr=NULL; + uint8_t atp_frame_header_length = sizeof(atp_frame_header_struct); + /**We received a handshake frame, so drop all the frames from previous session + *and get ready for new session. + */ + if( (atp_frame_ptr->header.flags & FLAG_HANDSHAKE_MASK) != 0 ) + { + ATS_ERR("ATS FRAME: handshake"); + /** we are expecting a frame with GNF flag */ + if ( context_ptr->is_next_frame_gnf == TRUE ) + { + ATS_ERR("ATS FRAME: handshake GNF = TRUE"); + context_ptr->is_next_frame_gnf = FALSE; + /**we have some response frames left in previous session ACDB_FREE them*/ + free_linked_list(context_ptr->resp_start_node_ptr); + } + else + { + ATS_ERR("ATS FRAME: recieving frames from previous sessions req buffer"); + /**We were receiving frames from previous session request buffer, so ACDB_FREE + *the request buffer*/ + if ( context_ptr->req_buf_cntxt.buffer_ptr != NULL ) + ACDB_FREE(context_ptr->req_buf_cntxt.buffer_ptr); + /**initialise the response buffer context*/ + initialize_buffer_context(&context_ptr->req_buf_cntxt); + }/*hand shake if*/ + /** inform TX that we are ready to receive new request buffer */ + /**create GNF frame and it is our response frame for hand shake frame*/ + create_atp_frame(&context_ptr->atp_current_resp_frame_ptr); + //Klocwork fix: check input if it is a NULL ptr + if (context_ptr->atp_current_resp_frame_ptr == NULL) + { + ATS_ERR("ATS FRAME: current resp frame ptr is null"); + return FALSE; + } + + ATS_ERR("ATS FRAME: setting GNF mask"); + /**Set GNF flag*/ + context_ptr->atp_current_resp_frame_ptr->header.flags |=FLAG_GETNEXTFRAME_MASK ; + return TRUE; + } + /**If we have not received a hand shake frame. + * we have left some frames in response buffer so we are expecting a GNF frame + */ + if ( context_ptr->is_next_frame_gnf == TRUE ) + { + ATS_ERR("ATS FRAME: in GNF condition"); + /**If we have not received a GNF frame so its an error because still we have + *some frame is response buffer*/ + if( (atp_frame_ptr->header.flags & FLAG_GETNEXTFRAME_MASK) == 0 ) + { + ATS_ERR("ATS FRAME: error condition if we are expecting a GNF but have frames in response buffer"); + return FALSE; + } + /** move to next node pointer to send + *If we don't have frames means some unexpected error*/ + if( context_ptr->resp_current_node_ptr == NULL ) + { + ATS_ERR("ATS FRAME: resp curr node ptr is null BEFORE setting to next node ptr"); + return FALSE; + } + context_ptr->resp_current_node_ptr = context_ptr->resp_current_node_ptr->next_node_ptr; + + if (context_ptr->resp_current_node_ptr == NULL) + { + ATS_ERR("ATS FRAME: resp curr node ptr is null AFTER setting to next node ptr"); + return FALSE; + } + /** if this is the last frame in response, note that we are not expecting a GNF + *frame + */ + if ( context_ptr->resp_current_node_ptr->next_node_ptr == NULL ) + { + ATS_ERR("ATS FRAME: last frame! not expecting a GNF"); + context_ptr->is_next_frame_gnf = FALSE; + } + else + { + /**current node is not the last node in response buffer linked list so + *next frame should be GNF frame + */ + context_ptr->is_next_frame_gnf = TRUE; + ATS_ERR("ATS FRAME: still more frames! expecting a GNF"); + } + + ATS_ERR("ATS FRAME: creating fresponse frame"); + /**create response frame*/ + create_atp_frame(&atp_resp_frame_ptr); + //Klocwork fix: check input if it is NULL ptr before perform memcpy + if (atp_resp_frame_ptr == NULL || context_ptr->resp_current_node_ptr == NULL) + { + if(atp_resp_frame_ptr == NULL) + ATS_ERR("ATS FRAME: atp_resp_frame_ptr is null. returning false"); + if (context_ptr->resp_current_node_ptr == NULL) + ATS_ERR("ATS FRAME: context_ptr->resp_current_node_ptr is null. returning false"); + return FALSE; + } + + ATS_ERR("ATS FRAME: copy header info into response frame"); + /**copy header info to response frame*/ + ATS_MEM_CPY_SAFE(atp_resp_frame_ptr,atp_frame_header_length, + &context_ptr->resp_current_node_ptr->frame_ptr->header, + atp_frame_header_length); + + ATS_ERR("ATS FRAME: create mem for data"); + + /**create memory for data */ + atp_resp_frame_ptr->data_ptr = + ACDB_MALLOC(char_t, atp_resp_frame_ptr->header.frame_length); + + + /**copy data to response frame*/ + if (atp_resp_frame_ptr->data_ptr == NULL) + { + ATS_ERR("ATS FRAME: unable to allocate memory for ats response frame data ptr"); + + ACDB_FREE(atp_resp_frame_ptr); + return FALSE; + } + + ATS_ERR("ATS FRAME: copy data into response frame"); + ATS_MEM_CPY_SAFE(atp_resp_frame_ptr->data_ptr,atp_resp_frame_ptr->header.frame_length, + context_ptr->resp_current_node_ptr->frame_ptr->data_ptr, + atp_resp_frame_ptr->header.frame_length + ); + + ATS_ERR("ATS FRAME: set resp frame ptr to current node"); + + /** set response frame pointer as current node frame pointer*/ + context_ptr->atp_current_resp_frame_ptr= atp_resp_frame_ptr; + + if ( context_ptr->resp_current_node_ptr->next_node_ptr == NULL ) + { + //Since this is the last frame we can ACDB_FREE the response buffer linked list + free_linked_list(context_ptr->resp_start_node_ptr); + } + return TRUE; + } + else + { + ATS_ERR("ATS FRAME: data frame"); + + /**we are expecting a data frame + *we have not received a data frame so its an error*/ + if ((atp_frame_ptr->header.flags & FLAG_DATAFRAME_MASK) == 0) + { + ATS_ERR("ATS FRAME: not a data frame! return false"); + + return FALSE; + } + ATS_ERR("ATS FRAME: copy frame to our buffer"); + + /**copy frame to our buffer*/ + is_last_frame = copy_frame_to_buffer(&context_ptr->req_buf_cntxt,atp_frame_ptr); + + if ( is_last_frame ) + { + ATS_ERR("ATS FRAME: this is the last frame"); + + /**we received last frame*/ + /**send request buffer to ACM*/ + if ( context_ptr->receive_req_buffer_ptr == NULL ) + //CR: coding format fix + { + ATS_ERR("ATS FRAME: context_ptr->receive_req_buffer_ptr is null"); + + return FALSE; + } + context_ptr->receive_req_buffer_ptr((uint8_t*)context_ptr->req_buf_cntxt.buffer_ptr, + context_ptr->req_buf_cntxt.buffer_length, + (uint8_t**)&resp_buf_ptr,&resp_buf_length); + + /**ACDB_FREE the request buffer*/ + ACDB_FREE(context_ptr->req_buf_cntxt.buffer_ptr); + if(resp_buf_ptr == NULL) + { + ATS_ERR("ATS FRAME: resp_buf_ptr is null"); + + return FALSE; + } + + ATS_ERR("ATS FRAME: create response buffer START"); + + initialize_buffer_context(&context_ptr->req_buf_cntxt); + /**break the response buffer into frames*/ + break_buffer_into_frames(resp_buf_ptr,resp_buf_length, + &context_ptr->resp_start_node_ptr); + /**ACDB_FREE the response buffer*/ + //ACDB_FREE(resp_buf_ptr); + //Klocwork fix: check if src ptr is a NULL ptr + if (context_ptr->resp_start_node_ptr == NULL) + { + ATS_ERR("context_ptr->resp_start_node_ptr is null"); + return FALSE; + } + /**set current node pointer to start pointer*/ + context_ptr->resp_current_node_ptr = context_ptr->resp_start_node_ptr; + if ( context_ptr->resp_current_node_ptr->next_node_ptr == NULL ) + { + context_ptr->is_next_frame_gnf = FALSE; + } + else + { + context_ptr->is_next_frame_gnf = TRUE; + } + create_atp_frame(&atp_resp_frame_ptr); + //Klocwork fix: check if input it is a NULL ptr + if (atp_resp_frame_ptr == NULL) + { + ATS_ERR("unable to create atp response frame"); + return FALSE; + } + /**copy header info to response frame*/ + ATS_MEM_CPY_SAFE(atp_resp_frame_ptr,atp_frame_header_length, + &context_ptr->resp_current_node_ptr->frame_ptr->header, + atp_frame_header_length); + /**create memory for data */ + atp_resp_frame_ptr->data_ptr = + ACDB_MALLOC(char_t, atp_resp_frame_ptr->header.frame_length); + /**copy data to response frame*/ + //Klocwork fix: check input if it is a NULL ptr before perform memcpy + if (atp_resp_frame_ptr->data_ptr == NULL) + { + ATS_ERR("unable to allocate mem for atp_resp_frame_ptr->data_ptr"); + ACDB_FREE(atp_resp_frame_ptr); + return FALSE; + } + ATS_MEM_CPY_SAFE(atp_resp_frame_ptr->data_ptr,atp_resp_frame_ptr->header.frame_length, + context_ptr->resp_current_node_ptr->frame_ptr->data_ptr, + atp_resp_frame_ptr->header.frame_length + ); + /** set response frame pointer as current node frame pointer*/ + context_ptr->atp_current_resp_frame_ptr= atp_resp_frame_ptr; + if ( context_ptr->resp_current_node_ptr->next_node_ptr == NULL ) + { + //Since this is the last frame we can ACDB_FREE the response buffer linked list + free_linked_list(context_ptr->resp_start_node_ptr); + } + + ATS_ERR("ATS FRAME: create response buffer END"); + return TRUE; + } + else + { + ATS_ERR("ATS FRAME: not the last data frame! requeset next frame "); + /**this is not last frame so request next frame*/ + /**create GNF frame and it is our response frame*/ + create_atp_frame(&context_ptr->atp_current_resp_frame_ptr); + //Klocwork fix: if input is a NULL ptr + if (context_ptr->atp_current_resp_frame_ptr == NULL) + { + return FALSE; + } + context_ptr->atp_current_resp_frame_ptr->header.flags |=FLAG_GETNEXTFRAME_MASK ; + return TRUE; + } + }/*else if( context_ptr->is_next_frame_gnf == TRUE )*/ + /*return FALSE; This is not reachable*/ +}/*atp_receive_atp_frame*/ +#endif + +/** + * FUNCTION : atp_create_diag_resp_pkt + * + * DESCRIPTION : creates a diag resp packet from atp frame + * + * DEPENDENCIES: None. + * + * PARAMS: + * atp_frame_ptr - frame to be wrapped in response diag packet + * atp_diag_pkt - created diag response packet + * + * RETURN VALUE: None + * + * SIDE EFFECTS: None. + */ +void atp_create_diag_resp_pkt ( + atp_frame_struct* atp_frame_ptr, + diag_pkt_resp_struct** atp_diag_pkt + ) +{ + ATS_ERR("DIAG PKT: Creating diag response packet"); + print_atp_frame(atp_frame_ptr); + uint8_t headersize = sizeof(atp_frame_header_struct); + /** Create diag response packet*/ + (*atp_diag_pkt) = ACDB_MALLOC(diag_pkt_resp_struct, 1); + if(NULL==(*atp_diag_pkt)) + { + return; + } + /**Initialise the memeory*/ + memset(*atp_diag_pkt,0,sizeof(diag_pkt_resp_struct)); + /**set diag response packet header info*/ + (*atp_diag_pkt)->header.cmdCode = DIAG_EXTEND_CMDCODE; + (*atp_diag_pkt)->header.subsysId = AUDIO_SUBSYS_ID; + (*atp_diag_pkt)->header.subsysCmdCode = SUBSYS_CMDCODE; + + /** copy atp header info*/ + ATS_MEM_CPY_SAFE(&(*atp_diag_pkt)->payload_resp[0], headersize, &atp_frame_ptr->header, headersize); + + /**copy frame data*/ + if (atp_frame_ptr->data_ptr != NULL) + { + ATS_MEM_CPY_SAFE( + &(*atp_diag_pkt)->payload_resp[headersize], atp_frame_ptr->header.frame_length, + atp_frame_ptr->data_ptr, atp_frame_ptr->header.frame_length); + } + return; +} + +#ifndef WINPC + + + +/** + * FUNCTION : atp_receive_diag_pkt + * + * DESCRIPTION : + * Receive a request diag packet from acm diag dispatcher (avsACMdiag_cmd()) + *.and return a response diag packet. + * + * DEPENDENCIES : receive_req_buffer_ptr memeber in atp_phone_context_ptr must be + *pointing to.appropriate function, which can process the request buffer and + *provide a response buffer. + * + * PARAMS: + * atp_diag_req_pkt_ptr - pointer to the diag packet which contains the atp frame from request buffer + * atp_diag_rsp_pkt_ptr - pointer to the diag packet which contains the atp frame from response buffer + * atp_phone_context_ptr - pointer to the phone context to whome request to be sent and resposne received + * + * RETURN VALUE : If sent successfully returns TRUE or FALSE + * + * SIDE EFFECTS : Will NOT Free response buffer. + */ +void atp_receive_diag_pkt ( + diag_pkt_req_struct *atp_diag_req_pkt_ptr, + diag_pkt_resp_struct **atp_diag_rsp_pkt_ptr, + atp_phone_context_struct *atp_phone_context_ptr + ) +{ + //Klocwork fix: //A temporary NULL ptr to hold atp frame extracted from request diag packet + atp_frame_struct* atp_frame_ptr = NULL; + /** Create a atp frame from diag request packet */ + atp_create_frame_from_diag_req(atp_diag_req_pkt_ptr, &atp_frame_ptr); + + print_atp_frame(atp_frame_ptr); + + /** Send extracted atp frame to RX algorithm, which accumulates all the + request frames to construct a request buffer.*/ + //Klocwork fix: Null pointer check before calling atp_receive_atp_frame command + if (atp_frame_ptr != NULL) + { + (void)atp_receive_atp_frame(atp_phone_context_ptr, atp_frame_ptr); + } + /** ACDB_FREE the extracted atp frame*/ + //Klocwork fix: Null pointer check before calling atp_receive_atp_frame command + if (atp_frame_ptr != NULL) + { + free_atp_frame(atp_frame_ptr); + } + /** if response atp frame is ready...*/ + if ( atp_phone_context_ptr->atp_current_resp_frame_ptr != NULL ) + { + /** create a diag packet which wraps the response frame*/ + atp_create_diag_resp_pkt( + atp_phone_context_ptr->atp_current_resp_frame_ptr, + atp_diag_rsp_pkt_ptr + ); + /**ACDB_FREE the response frame*/ + free_atp_frame(atp_phone_context_ptr->atp_current_resp_frame_ptr); + } + else + { + /**else return NULL as response diag packet*/ + *atp_diag_rsp_pkt_ptr = NULL; + } +} +#endif + +//#endif /*FEATURE_AVS_AUDIO_TRANSPORT_PROTOCOL || WINPC*/ diff --git a/acdb/ats/transports/diag/linux/inc/diag_lsm.h b/acdb/ats/transports/diag/linux/inc/diag_lsm.h new file mode 100644 index 0000000..7c282ce --- /dev/null +++ b/acdb/ats/transports/diag/linux/inc/diag_lsm.h @@ -0,0 +1,38 @@ +#ifndef DIAG_LSM_H +#define DIAG_LSM_H +/** +*============================================================================= +* \file diag_lsm.h +* \brief +* Diag Mapping Layer DLL declarations +* +* This file is a stub version of the Diag Mapping Layer Interface +* header. This file is used for compilation with the +* Off-target Test Platform(OTTP). +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#include "ar_osal_types.h" + +/** +* \brief +* Initializes the Diag Legacy Mapping Layer. This should be called only once +* per process. This is a stub used for compilation on OTTP +* +* \depends +* Successful initialization requires Diag CS component files to be present +* and accessible in the file system. +* +* \return FALSE = failure, else TRUE +*/ +bool_t Diag_LSM_Init(uint8_t* pIEnv) { __UNREFERENCED_PARAM(pIEnv); return TRUE; } + +bool_t Diag_LSM_DeInit(void) { return TRUE; } + +#endif /* DIAG_LSM_H */ + diff --git a/acdb/ats/transports/diag/linux/inc/diagcmd.h b/acdb/ats/transports/diag/linux/inc/diagcmd.h new file mode 100644 index 0000000..8b08d25 --- /dev/null +++ b/acdb/ats/transports/diag/linux/inc/diagcmd.h @@ -0,0 +1,31 @@ +#ifndef DIAGCMD_H +#define DIAGCMD_H +/** +*============================================================================== +* \file diagcmd.h +* \brief +* D I A G N O S T I C C O M M A N D +* I N T E R F A C E S T U B +* +* This file is a stub version of the Diagnostic System Command +* Interface header. This file is used for compilation with the +* Off-target Test Platform(OTTP). +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +/* Invalid Command Response */ +#define DIAG_BAD_CMD_F 19 + +typedef enum { + DIAG_SUBSYS_AUDIO_SETTINGS = 17, /* Audio Settings */ +} diagpkt_subsys_cmd_enum_type; + +#endif /* DIAGCMD_H */ + + + diff --git a/acdb/ats/transports/diag/linux/inc/diagpkt.h b/acdb/ats/transports/diag/linux/inc/diagpkt.h new file mode 100644 index 0000000..7ddcb58 --- /dev/null +++ b/acdb/ats/transports/diag/linux/inc/diagpkt.h @@ -0,0 +1,87 @@ +#ifndef DIAGPKT_H +#define DIAGPKT_H +/** +*============================================================================== +* \file diagpkt.h +* \brief +* D I A G N O S T I C S Y S T E M P A C K E T +* I N T E R F A C E S T U B +* +* This file is a stub version of the Diagnostic System Packet +* Interface header. This file is used for compilation with the +* Off-target Test Platform(OTTP). +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ +#include "ar_osal_types.h" +#define word uint32_t + +/*-------------------------------------------------------------------------- +* Type and Packet Definition Macros +*-------------------------------------------------------------------------*/ +typedef uint8_t diagpkt_cmd_code_type; +typedef uint8_t diagpkt_subsys_id_type; +typedef uint16_t diagpkt_subsys_cmd_code_type; + +/*-------------------------------------------------------------------------- +* Function Definitions +*-------------------------------------------------------------------------*/ +/* Packet Handler Types */ + +/* An array of this type is created by the client and registered with this + service. It must be declared 'const' (preferrably 'static const'). + The function is called when an inbound packet matches subsystem ID and + is within the command code range specified in the table. */ +typedef struct +{ +word cmd_code_lo; +word cmd_code_hi; +void *(*func_ptr) (void *req_pkt_ptr, uint16_t pkt_len); +} +diagpkt_user_table_entry_type; + +/* Note: the following 2 items are used internally via the macro below. */ + +/* User table type */ +typedef struct +{ uint16_t delay_flag; /* 0 means no delay and 1 means with delay */ +uint16_t cmd_code; +word subsysid; +word count; +uint16_t proc_id; +const diagpkt_user_table_entry_type *user_table; +} diagpkt_user_table_type; + +void diagpkt_tbl_reg (const diagpkt_user_table_type * tbl_ptr); + +/* Single processor or modem proc*/ +#define DIAGPKT_DISPATCH_TABLE_REGISTER(xx_subsysid, xx_entry) \ +do { \ + static const diagpkt_user_table_type xx_entry##_table = { \ + 0, 0xFF, xx_subsysid, sizeof (xx_entry) / sizeof (xx_entry[0]), 0, xx_entry \ + }; \ + /*lint -save -e717 */ \ + diagpkt_tbl_reg (&xx_entry##_table); \ +} while (0) + /*lint -restore */ + +/*-------------------------------------------------------------------------- +* Functions +*-------------------------------------------------------------------------*/ + +void *diagpkt_subsys_alloc (diagpkt_subsys_id_type id, +diagpkt_subsys_cmd_code_type code, unsigned int length); + +void diagpkt_commit (void *ptr); + +diagpkt_subsys_cmd_code_type diagpkt_subsys_get_cmd_code (void *ptr); + +void *diagpkt_err_rsp (diagpkt_cmd_code_type code, +void *req_ptr, uint16_t req_len); + + +#endif /* DIAGPKT_H */ diff --git a/acdb/ats/transports/tcpip/linux/inc/ats_server.h b/acdb/ats/transports/tcpip/linux/inc/ats_server.h new file mode 100644 index 0000000..e4fdc6e --- /dev/null +++ b/acdb/ats/transports/tcpip/linux/inc/ats_server.h @@ -0,0 +1,137 @@ +#ifndef _ATS_SERVER_H_ +#define _ATS_SERVER_H_ +/** +*============================================================================= +* \file ats_server.h +* \brief +* A T S S E R V E R H E A D E R F I L E +* +* This file contains the TCP/IP server API definitions used to host +* connections to QACT. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ar_osal_mutex.h" +#include "ar_osal_error.h" +#include "ar_osal_thread.h" +#include "ats_common.h" +#include "acdb_utility.h" + +//constants used by the server +#define SOCK_PATH "/vendor/app/GatewayServer/ats_sockets"; +#define SOCK_PATH_SERVER "/vendor/app/GatewayServer/ats_sockets/unix_sock.server"; +#define MAX_LENGTH_IP_ADDRESS 16 +#define MAX_ATS_CLIENTS_ALLOWED 1 +#define ATS_THREAD_LISTENER "ATS_THD_LISTENER" +#define ATS_THREAD_TRANSMIT "ATS_THD_TRANSMIT" +#define ATS_THD_STACK_SIZE 0xF4240 //1mb stack size + +#define ATS_SERVER_ADDRESS "127.0.0.1" //local host +#define ATS_GATEWAY_PORT 5559 + +#define ATS_THREAD_PRIORITY_HIGH 0 +#define ATS_THREAD_PRIORITY_LOW 1 + +/**< Read in sizes of 1024 to avoid allocating too much memory*/ +#define ATS_RECIEVE_BUF_SIZE 1024 + +#define ATS_SERVER_CMD_QUIT "QUIT" + +//const uint32_t maxsize = 0x200000; +//const uint32_t bufsize = 1024; + +#ifdef __cplusplus +extern "C"{ +#endif + + typedef struct ats_server_context { + void(*ats_cb)(uint8_t* req, uint32_t req_len, uint8_t** resp, uint32_t* resp_len); + } ats_server_context; + +/** +* \brief +* Initializes the ATS TCP/IP server +* +* \detdesc +* Entry function to start ats_server threads +* ats_server will start a listening thread on a local IP address on the +* designated port. +* ats communicates with the Gateway Server for any connection to external clients +* +* Note: Only one client can be connected to this target at a time. The use of a mutex +* ensures this. +* +* \param [in] ats_cb: A callback to ats_exectue_command +* +* \return +* 0 on success, non-zero on failure +*/ +int32_t ats_server_init(void(*ats_cb)(uint8_t *buf, uint32_t buf_len, uint8_t **resp, uint32_t *resp_len)); + +/** +* \brief +* De-initializes the ATS TCP/IP server +* +* \detdesc +* Releases threading and memory resources aquired during ats_server_init +* +* Note: Only one client can be connected to this target at a time. The use of a mutex +* ensures this. +* +* \return +* 0 on success, non-zero on failure +*/ + +/** +* \brief ats_server_deinit +* Stops ats_server threads. +* +* \return 0 on success, non-zero on failure +*/ +int32_t ats_server_deinit(void); + +/** + \brief + Initializes the ATS TCP/IP server + + \detdesc + Startup the server. + Creates the listening socket on 5559 and accepts incoming connections. + Upon accepting a new connection, a thread called recv_thread_proc is + created to handle transmitting(send/recieve) data to client. + + \dependencies + None + + \param [in] thread_param: Parameters to be used within the thread routine +*/ +void* ats_server_start_routine(void* thread_param); + +/** + \brief + Thread for transmitting data between ATS and its client(s) + + \detdesc + Thread process that is created to handle 2 way message sending between server and client + + \dependencies + There must be a socket already accepted that is passed into this function. + + \param [in] client_socket_ptr: is a SOCKET pointer returned by the accept() + function in ats_svr_start_routine +*/ +void* ats_server_transmit_routine(void* client_socket_ptr); + +#ifdef __cplusplus +} +#endif +#endif /*_ATS_SERVER_H_*/ + diff --git a/acdb/ats/transports/tcpip/linux/src/ats_server.cpp b/acdb/ats/transports/tcpip/linux/src/ats_server.cpp new file mode 100644 index 0000000..8bd5a92 --- /dev/null +++ b/acdb/ats/transports/tcpip/linux/src/ats_server.cpp @@ -0,0 +1,788 @@ +/** +*============================================================================= +* \file ats_server.cpp +* \brief +* A T S S E R V E R S O U R C E F I L E +* +* This file contains the TCP/IP server implementation to host connections +* to QACT. +* This file first sets up a listening socket on port 5558. Upon accepting +* new connections, the server creates new receiving threads that handles +* all ATS upcalls. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* +------------------------------- +|Include Files | +------------------------------- +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#if defined(__linux__) +#include +#include +#include +#include +#include +#include +#include +#ifdef AR_ATS_USE_CUTILS +#include +#endif +#elif defined(_WIN32) +//Windows +#include +#include + +// Need to link with Ws2_32.lib +#pragma comment (lib, "Ws2_32.lib") +#endif + +extern "C" +{ +#include "ats.h" +#include "ats_i.h" +#include "ats_server.h" +#include "ar_osal_types.h" +} + +#if defined(__linux__) +#define ADDRESS_FAMILY AF_UNIX +#define PROTOCOL 0 +typedef int SOCKET; + +#define ATS_INVALID_SOCKET(s) ((s) < 0) +#define atsclosesocket close +#elif defined(_WIN32) +#define ADDRESS_FAMILY AF_INET +#define PROTOCOL IPPROTO_TCP + +#define ATS_INVALID_SOCKET(s) (s == INVALID_SOCKET) +#define atsclosesocket closesocket +#endif + +/* --------------------------------------------------------------------------- +* Global Variables +*--------------------------------------------------------------------------- */ +ar_osal_thread_t g_thd_ats_listener; +ar_osal_thread_t g_transmit_thread_holder[MAX_ATS_CLIENTS_ALLOWED]; + +ar_osal_mutex_t g_connected_mutex;//rename to connection lock +uint8_t g_is_connected; //used to ensure only one QACT client will be connected at one time + +ats_server_context g_ats_server_context = { 0 }; + +AtsBufferManager *ats_buffer_manager = NULL; +bool_t g_should_close_server = FALSE; +SOCKET g_server_socket = NULL; + +/* --------------------------------------------------------------------------- +* Helper Functions +*--------------------------------------------------------------------------- */ +/** + \brief + Helper function that retrieves the expected message length from the message header + + \detdesc + Passed in buffer must be in the following format: + *-----------------------------------------------------* + | SERVICE ID | CMD ID | CMD Size | CMD Payload | + | 2 bytes | 2 bytes | 4 bytes | n byteS | + *-----------------------------------------------------* + Note: the size referes to the n bytes of the payload (not including header + size of 6 bytes) + + \dependencies + None + + \param [in] rec_buf_ptr: Parameters to be used within the thread routine + \param [in] req_buf_length: Parameters to be used within the thread routine + \param [in] data_length: Parameters to be used within the thread routine + + \return + TRUE if successfully parsed and FALSE otherwise +*/ +static bool_t get_command_length_s(char_t* rec_buf_ptr, uint32_t req_buf_length, uint32_t* data_length); + +#if defined(_WIN32) + +/** +* \brief +* Initializes the Windsock DLL +* +* \param [in] socket_descriptor: a pointer to an allocated socket object that +* will be filled in +* \return +* 0 on success, non-zero on failure +*/ +int32_t init_winsock(void) +{ + int result = 0; + WSADATA wsaData = { 0 }; + + result = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (result != NO_ERROR) + { + ATS_ERR("Failed to initialize winsock. WSAStartup Error(%d)", result); + return AR_EFAILED; + } + return result; +} + +/** +* \brief +* Creates a windows based socket +* +* \param [in] socket_descriptor: a pointer to an allocated socket object that +* will be filled in +* \return +* 0 on success, non-zero on failure +*/ +int32_t create_socket_win(SOCKET *socket_descriptor) +{ + int32_t status = AR_EOK; + SOCKET socketfd = NULL; + + status = init_winsock(); + if (AR_FAILED(status)) + { + return status; + } + + ATS_DBG("Setting up sockets..."); + //creates socket and references the socket using a file descriptor + socketfd = socket(ADDRESS_FAMILY, SOCK_STREAM, PROTOCOL); + ATS_DBG("sockfd: %d\n", socketfd); + + //Checks for errors from socket function + if (ATS_INVALID_SOCKET(socketfd)) + { + ATS_ERR("Error opening socket"); + perror("Error opening socket"); + + //Prints out specific error in ADBLogcat + ATS_ERR("socket error: %d - %s", errno, strerror(errno)); + return status; + } + + //AtsSockAddr addr = { 0 }; + sockaddr_in addr = {0}; + addr.sin_family = ADDRESS_FAMILY; + inet_pton(ADDRESS_FAMILY, ATS_SERVER_ADDRESS, &addr.sin_addr.s_addr); + addr.sin_port = htons(ATS_GATEWAY_PORT); + + //binds socket to socket path + status = bind(socketfd, (struct sockaddr*)&addr, sizeof(addr)); + //checks for errors when binding address and prints to ADBLogcat + if (status < 0) { + ATS_ERR("bind socket error: %d - %s", errno, strerror(errno)); + ATS_ERR("Bind to %s:%d", ATS_SERVER_ADDRESS, ATS_GATEWAY_PORT); + status = AR_EFAILED; + atsclosesocket(socketfd); + return status; + } + else { + ATS_ERR("Bind successful"); + } + + *socket_descriptor = socketfd; + + return status; +} +#endif +#if defined(__linux__) +/** +* \brief +* Creates a unix based socket +* +* \param [in] socket_descriptor: a pointer to an allocated socket object that +* will be filled in +* \return +* 0 on success, non-zero on failure +*/ +int32_t create_socket_unix(SOCKET *socket_descriptor) +{ + __UNREFERENCED_PARAM(socket_descriptor); + + int32_t status = AR_EOK; + + return status; + /* + ATS_DBG("Setting up sockets..."); + + //creates socket and references the socket using a file descriptor + SOCKET socketfd = socket(ADDRESS_FAMILY, SOCK_STREAM, PROTOCOL); + ATS_DBG("sockfd: %d", socketfd); + + //Checks for errors from socket function + if (ATS_INVALID_SOCKET(socketfd)) + { + ATS_ERR("Error opening socket"); + perror("Error opening socket"); + + //Prints out specific error in ADBLogcat + ATS_ERR("socket error: %d - %s", errno, strerror(errno)); + return status; + } + + //mode_t process_mask = umask(0); + //700 is permission for -rwx------ (read/write/execute for only owner) + char socket_path[] = SOCK_PATH; + mode_t permissions = S_IRUSR | S_IWUSR | S_IXUSR; + status = mkdir(socket_path, permissions); + chmod(socket_path, permissions); //if already exists + + //umask(process_mask); + struct sockaddr_un addr; + ATS_DBG("Mode for directory and file is: %o", permissions); + char socket_path_file[] = SOCK_PATH_SERVER; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = ADDRESS_FAMILY; + AcdbStrCpy(addr.sun_path, sizeof(addr.sun_path), socket_path_file, strlen(socket_path_file)); + unlink(socket_path_file); + + //binds socket to socket path + status = bind(socketfd, (struct sockaddr*)&addr, sizeof(addr)); + //checks for errors when binding address and prints to ADBLogcat + if (status < 0) { + ATS_ERR("bind socket error: %d - %s", errno, strerror(errno)); + ATS_ERR("Bind to %s:%d", ATS_SERVER_ADDRESS, ATS_GATEWAY_PORT); + status = AR_EFAILED; + return status; + } + else { + ATS_ERR("Bind successful"); + } + + *socket_descriptor = socketfd; + + return status; + */ +} +#endif + +/** +* \brief +* Creates a socket depending on the platform. Currently supports Unix and +* windows based sockets +* +* \param [in] socket_descriptor: a pointer to an allocated socket object that +* will be filled in +* \return +* 0 on success, non-zero on failure +*/ +int32_t create_socket(SOCKET *sd) +{ + SOCKET socket_descriptor = 0; + int32_t status = AR_EOK; + +#if defined(__linux__) + status = create_socket_unix(&socket_descriptor); +#elif defined(_WIN32) + status = create_socket_win(&socket_descriptor); +#endif + + *sd = socket_descriptor; + return status; +} + +/** +* \brief +* Creates a server socket and listens for clients. +* +* \detdesc +* Once a client is connected, a transmission thread is created +* for processing commands. Only client can be connected at a +* time to perform operations on the ACDB and DSP. +* +* \param [in] arg: This input parameter is unused +* +* \return +* 0 on success, non-zero on failure +*/ +void* ats_server_start_routine(void* arg) +{ + __UNREFERENCED_PARAM(arg); + ATS_DBG("Starting TCP/IP server thread."); + + int32_t status = AR_EOK; + char str_addr[MAX_LENGTH_IP_ADDRESS] = { 0 }; + SOCKET sockfd; + status = create_socket(&sockfd); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to create and bind to socket"); + } + + g_server_socket = sockfd; + + //fd_set socket_set; + //socket_set.fd_count = 1; + //socket_set.fd_array = &sockfd; + //timeval tv; + //tv.tv_sec = 1; + //tv.tv_usec = 0; + + //int num_ready_sockets = select(0, NULL, &socket_set, NULL, &tv); + + ATS_ERR("Listening for connections..."); + + //listen queue is of size 5 + status = listen(sockfd, 5); + if (status < 0) { + ATS_ERR("Error on listening"); + perror("Error on listen"); + } + else { + ATS_ERR("Listening successful"); + } + + //initializing mutex and setting up environment for threading + ar_osal_mutex_init(g_connected_mutex); + ar_osal_mutex_lock(g_connected_mutex); + g_is_connected = 0; + ar_osal_mutex_unlock(g_connected_mutex); + + int i = 0; + + + //uint8_t connected = 0; + + while (true) + { + struct sockaddr_in client_addr; + socklen_t addr_size = sizeof(client_addr); + SOCKET *gateway_socket_ptr = (SOCKET*)malloc(sizeof(SOCKET)); + if (IsNull(gateway_socket_ptr)) + { + ATS_ERR("Insufficient memory to create socket"); + g_server_socket = NULL; + atsclosesocket(sockfd); + return 0; + } + memset(&client_addr, 0, addr_size); + + *gateway_socket_ptr = accept(sockfd, (struct sockaddr*)&client_addr, &addr_size); + + if (g_should_close_server) + { + atsclosesocket(*gateway_socket_ptr); + ACDB_FREE(gateway_socket_ptr); + break; + } + + if (ATS_INVALID_SOCKET(*gateway_socket_ptr)) + { + atsclosesocket(*gateway_socket_ptr); + ACDB_FREE(gateway_socket_ptr); + + if (errno == EINTR) continue; + + inet_ntop(ADDRESS_FAMILY, &client_addr.sin_addr, str_addr, MAX_LENGTH_IP_ADDRESS); + ATS_ERR("Accept error: %s", strerror(errno)); + ATS_ERR("Attempted Connection from: %s", str_addr); + } + else + { + if (g_is_connected) { + ATS_ERR("New connection request. Refusing..."); + atsclosesocket(*gateway_socket_ptr); + ACDB_FREE(gateway_socket_ptr); + continue; + } + + //Lock - Do not create more threads if already connected. + ar_osal_mutex_lock(g_connected_mutex); + + inet_ntop(ADDRESS_FAMILY, &client_addr.sin_addr, str_addr, MAX_LENGTH_IP_ADDRESS); + ATS_INFO("Accept successful to Gateway Service"); + ATS_INFO("Connection from: %s", str_addr); + ATS_INFO("Starting transmission thread..."); + + ar_osal_thread_t thd_ats_transmit; + ar_osal_thread_start_routine routine = \ + (ar_osal_thread_start_routine)ats_server_transmit_routine; + + char threadName[32]; + ACDB_STR_CPY_SAFE(threadName, 32, ATS_THREAD_TRANSMIT, strlen(ATS_THREAD_TRANSMIT)); + ar_osal_thread_attr_t thd_attr = \ + { + threadName, + ATS_THD_STACK_SIZE, + ATS_THREAD_PRIORITY_HIGH + }; + + status = ar_osal_thread_create(&thd_ats_transmit, &thd_attr, + routine, gateway_socket_ptr); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]: Failed to create transmission thread #%d.\n", status, i); + } + else + { + ATS_INFO("Created transmission thread #%d...", i); + g_transmit_thread_holder[i] = thd_ats_transmit; + g_is_connected = 1; + i++; + i %= MAX_ATS_CLIENTS_ALLOWED; + } + + //Unlock + ar_osal_mutex_unlock(g_connected_mutex); + + //TODO: move this cleanup work to a separate thread so that we can still refuse + //new connection requests + for (int thd = 0; thd < MAX_ATS_CLIENTS_ALLOWED; thd++) + { + ar_osal_thread_join_destroy(g_transmit_thread_holder[thd]); + ACDB_FREE(gateway_socket_ptr); + } + } + } + + atsclosesocket(sockfd); + g_server_socket = NULL; + + return 0; +} + +/** +* \brief +* Handles processing commands sent by clients and returns the +* appropriate response. +* +* \detdesc +* This function allocates a message and recieve buffer that are +* each ATS_BUFFER_LENGTH bytes. The message buffer holds the +* request sent by the client and is read from the recieve buffer. +* The recieve buffer is the socket buffer and holds data sent by clients. +* +* \param [in] client_socket_ptr: the client socket used for +* sending/recieving messages +* +* \return +* 0 on success, non-zero on failure +*/ +void* ats_server_transmit_routine(void* client_socket_ptr) +{ + SOCKET client_socket = *((SOCKET*)client_socket_ptr); + //current maxsize of any expected message is 'ATS_BUFFER_LENGTH' + const uint32_t maxsize = ATS_BUFFER_LENGTH; + char svc_id_str[ATS_SEVICE_ID_STR_LEN] = { 0 }; + + //Service Command ID 2 Byte Service ID + 2 Byte Command ID + uint32_t svc_cmd_id = 0; + + //Stores one message + char* msgBuf = (char*)ACDB_MALLOC(char, maxsize); + if (NULL == msgBuf) { + return 0; + } + char* recvbuf = (char*)ACDB_MALLOC(char, maxsize); + if (NULL == recvbuf) { + ACDB_FREE(msgBuf); + return 0; + } + + char* outbuf = (char*)ACDB_MALLOC(char, 1); // An array of 5 haracters (including terminator) + if (NULL == outbuf) { + ACDB_FREE(msgBuf); + ACDB_FREE(recvbuf); + return 0; + } + char* holder = outbuf; + memset(outbuf, 0, 1); + + /* + This loop will run once per ENTIRE message received. + Conditions that will exit this loop: + 1. An unexpected error occured that requires the thread to close + 2. A 'QUIT' command is sent by the client + */ + while (true) + { + //keep listening for whole incoming messages + int32_t bytes_recieved = 0; + uint32_t headerBytesRead = 0; + uint32_t msg_len = 0; + //--------------------------- + memset(msgBuf, 0, maxsize); + memset(recvbuf, 0, ATS_RECIEVE_BUF_SIZE); + //memset(outbuf, 0, maxsize); + + //This loop will run as many times as to receive full message header (should be just once) + while (true) + { + //receive full message header + ATS_ERR("Waiting to recieve message..."); + bytes_recieved = recv(client_socket, recvbuf, ATS_HEADER_LENGTH - headerBytesRead, 0); + + //client sends "QUIT" to signal end of connection. At that point, close socket and return. + if (strncmp(recvbuf, ATS_SERVER_CMD_QUIT, 4) == 0) + { + ATS_DBG("Quitting..."); + + atsclosesocket(client_socket); + goto threaddone; + } + + if (bytes_recieved > 0) + { + ATS_DBG("Recieved %d bytes", bytes_recieved); + ACDB_MEM_CPY_SAFE(msgBuf + headerBytesRead, bytes_recieved, recvbuf, bytes_recieved); + headerBytesRead += bytes_recieved; + + //this determines how many bytes to expect (thus determining how many times to loop). + if (get_command_length_s(msgBuf, bytes_recieved, &msg_len)) + { + svc_cmd_id = 0; + ACDB_MEM_CPY_SAFE(&svc_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH, + msgBuf + ATS_SERVICE_COMMAND_ID_POSITION, ATS_SERVICE_COMMAND_ID_LENGTH); + + ATS_SERVICE_ID_STR(svc_id_str, ATS_SEVICE_ID_STR_LEN, svc_cmd_id); + ATS_ERR("Recieved Command[%s-%d] with length %d bytes", svc_id_str, ATS_GET_COMMAND_ID(svc_cmd_id), msg_len); + break; + } + } + else if (bytes_recieved <= 0) + { + if (errno == EINTR) continue; + + ATS_ERR("Receive failed with error: %s\n", strerror(errno)); + atsclosesocket(client_socket); + goto threaddone; + } + } + + uint32_t payload_bytes_read = 0; + + //this loop will receive maxbufsize bytes each iteration, looping until it receives a full message + while (msg_len != 0) + { + //receive rest of message + if (payload_bytes_read > msg_len) { + ATS_ERR("Read more than message length...corruption\n"); + atsclosesocket(client_socket); + goto threaddone; + } + + uint32_t remaining_recv_len = msg_len - payload_bytes_read; + uint32_t recv_len = remaining_recv_len > ATS_RECIEVE_BUF_SIZE ? remaining_recv_len : ATS_RECIEVE_BUF_SIZE; + + //will receive min(ATS_RECIEVE_BUF_SIZE, bytes left to receive to complete message) + bytes_recieved = recv(client_socket, recvbuf, recv_len, 0); + + if (bytes_recieved > 0) { + ATS_ERR("Recieved %d bytes", bytes_recieved); + ACDB_MEM_CPY_SAFE(msgBuf + ATS_HEADER_LENGTH + payload_bytes_read, bytes_recieved, recvbuf, bytes_recieved); + payload_bytes_read += bytes_recieved; + if (payload_bytes_read == msg_len) { + break; + } + } + else if (bytes_recieved <= 0) { + if (errno == EINTR) { + ATS_ERR("Signal interrupt. Continuing..."); + continue; + } + ATS_ERR("Receive failed with error: %s", strerror(errno)); + atsclosesocket(client_socket); + goto threaddone; + } + } + + ATS_ERR("Full message received from client"); + //handle message handling - calls to ATS/ACDB + uint32_t* recvlen_ptr = (uint32_t*)ACDB_MALLOC(uint32_t, 1); + if (recvlen_ptr == NULL) { + atsclosesocket(client_socket); + goto threaddone; + } + + memset(recvlen_ptr, 0, sizeof(uint32_t)); + msg_len += ATS_HEADER_LENGTH; + svc_cmd_id = 0; + ACDB_MEM_CPY_SAFE(&svc_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH, + msgBuf + ATS_SERVICE_COMMAND_ID_POSITION, ATS_SERVICE_COMMAND_ID_LENGTH); + + uint32_t msgBufCheck = 11;//TODO: Why is this hardcoded to 11? + get_command_length_s(msgBuf, msg_len, &msgBufCheck); + ATS_ERR("Command[%s-%d]: Request data length is %d bytes", svc_id_str, ATS_GET_COMMAND_ID(svc_cmd_id), msgBufCheck); + + //passing received data and blank output buffer to ats upcall + g_ats_server_context.ats_cb((uint8_t *)msgBuf, (uint32_t)msg_len, (uint8_t**)&outbuf, recvlen_ptr); + + ATS_ERR("Outbound message of length %d bytes", *recvlen_ptr); + uint32_t outlen = 0; + svc_cmd_id = 0; + get_command_length_s(outbuf, *recvlen_ptr, &outlen); + + ACDB_MEM_CPY_SAFE(&svc_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH, + outbuf + ATS_SERVICE_COMMAND_ID_POSITION, ATS_SERVICE_COMMAND_ID_LENGTH); + + ATS_ERR("Command[%s-%d]: Sending response of %d bytes", svc_id_str, ATS_GET_COMMAND_ID(svc_cmd_id), outlen); + + int32_t send_result = 0; + + /* GATEWAY HEADER + Only send accros the bytes nessesary (not MAX_SIZE bytes) + <-----------4bytes------------> + +-----------------------------+ + | msg length | + +-----------------------------+ + +-----------------------------+ + | | + | msg(msg length) | + | | + +-.-.-.-.-.-.-.-.-.-.-.-.-.-.-+ */ + + //char* gatewayMessage = (char*)malloc(sizeof(uint32_t) + *recvlen_ptr); + //memcpy(gatewayMessage, recvlen_ptr, sizeof(uint32_t)); + //memcpy(gatewayMessage + sizeof(uint32_t), outbuf, *recvlen_ptr); + // + //send_result = ::send(client_socket, gatewayMessage, sizeof(uint32_t) + *recvlen_ptr, 0); + //ACDB_FREE(gatewayMessage); + + //No Gateway Header (for debugging purposes) + send_result = ::send(client_socket, outbuf, *recvlen_ptr, 0); + ACDB_FREE(recvlen_ptr); + + if (send_result < 0) { + ATS_ERR("Send failed with error: %s\n", strerror(errno)); + atsclosesocket(client_socket); + goto threaddone; + } + ATS_ERR("Message sent\n"); + } + +threaddone: + ACDB_FREE(msgBuf); + ACDB_FREE(recvbuf); + ACDB_FREE(holder); + //ACDB_FREE(outbuf); + + ATS_INFO("Transmission thread closed...\n"); + + ar_osal_mutex_lock(g_connected_mutex); + g_is_connected = 0; + ar_osal_mutex_unlock(g_connected_mutex); + ACDB_FREE(client_socket_ptr); + return 0; +} + +static bool_t get_command_length_s(char_t* rec_buf_ptr, uint32_t req_buf_length, uint32_t* data_length) { + bool_t result = FALSE; + if (IsNull(rec_buf_ptr) || IsNull(data_length)) + { + ATS_ERR("Input parameter is null"); + return FALSE; + } + if (req_buf_length < ATS_HEADER_LENGTH) + { + ATS_ERR("There is no data length information"); + result = FALSE; + } + else + { + /** copy data length*/ + ACDB_MEM_CPY_SAFE(data_length, ATS_DATA_LENGTH_LENGTH, + rec_buf_ptr + ATS_DATA_LENGTH_POSITION, ATS_DATA_LENGTH_LENGTH); + + result = TRUE; + } + return result; +} + +int32_t ats_server_init(void(*ats_cb)(uint8_t *buf, uint32_t buf_len, uint8_t **resp, uint32_t *resp_len)) { + int32_t status = AR_EOK; + +//#ifdef _WIN32 +// status = init_winsock(); +// if (AR_FAILED(status)) +// { +// return status; +// } +//#endif + + status = ar_osal_mutex_create(&g_connected_mutex); + if (AR_FAILED(status)) + { + ATS_ERR("Failed to create mutex.\n"); + return status; + } + + ATS_DBG("Creating server thread."); + g_ats_server_context.ats_cb = ats_cb; + + char threadName[32]; + ACDB_STR_CPY_SAFE(threadName, 32, ATS_THREAD_LISTENER, strlen(ATS_THREAD_LISTENER)); + + ar_osal_thread_attr_t thd_attr = + { + threadName, + ATS_THD_STACK_SIZE, + ATS_THREAD_PRIORITY_HIGH + }; + + ar_osal_thread_start_routine routine = \ + (ar_osal_thread_start_routine)ats_server_start_routine; + + status = ar_osal_thread_create(&g_thd_ats_listener, &thd_attr, routine, NULL); + + if (AR_FAILED(status)) + { + ATS_ERR("Failed to create server thread.\n"); + return status; + } + + return status; +} + +int32_t ats_server_deinit() +{ + ATS_INFO("Shutting down server..."); + + int32_t status = AR_EOK; + + g_should_close_server = TRUE; + + if (!IsNull(g_server_socket)) + atsclosesocket(g_server_socket); + + status = ar_osal_thread_join_destroy(g_thd_ats_listener); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]:An error occured when waiting to " + "close the listener thread.", status); + return status; + } + + status = ar_osal_mutex_destroy(g_connected_mutex); + if (AR_FAILED(status)) + { + ATS_ERR("Error[%d]:An error occured while " + "destroying the mutex.", status); + return status; + } + + ATS_INFO("Status[%d]: ATS server shut down successfully.", status); + return status; +} + diff --git a/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_cmd_server.h b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_cmd_server.h new file mode 100644 index 0000000..30c2fd8 --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_cmd_server.h @@ -0,0 +1,154 @@ +#ifndef _TCPIP_GATEWAY_CMD_SERVER_H_ +#define _TCPIP_GATEWAY_CMD_SERVER_H_ +/** +*============================================================================== +* \file tcpip_gateway_cmd_server.h +* \brief +* T C P I P G A T E W A Y C M D S E R V E R +* H E A D E R F I L E +* +* This file defines the class for the TCPIP Gateway Server as +* well as types and defines used by the server. This server is +* a proxy server that forwards request from server clients to the +* TCPIP CMD Server. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ + +/*------------------------------------- + * Includes + *-----------------------------------*/ +#include +#include "ar_osal_mutex.h" +#include "ar_osal_error.h" +#include "ar_osal_thread.h" +#include "ar_osal_string.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_heap.h" +#include "ar_sockets_api.h" +#include "tcpip_gateway_cmds.h" +#include "tcpip_gateway_common.h" +#include "tcpip_gateway_dls_server.h" + +#define TGWS_START_ROUTINE_THREAD "GWS_THD_START" +#define TGWS_TRANSMIT_THREAD "GWS_THD_TRANSMIT" + /**< 1MB stack size used when creating threads */ +#define TGWS_THD_STACK_SIZE 0xF4240 // +#define TGWS_THREAD_PRIORITY_HIGH 0 +#define TGWS_THREAD_PRIORITY_LOW 1 + +#define TGWS_1_KB 1024UL +#define TGWS_RECIEVE_BUFFER_SIZE (TGWS_1_KB * 32UL) +#define TGWS_MIN_MESSAGE_BUFFER_SIZE (TGWS_1_KB * 32UL) +#define TGWS_MAX_MESSAGE_BUFFER_SIZE 0x200000ul + + /**< The ATS Layers TCPIP CMD Server TCP/IP Port */ +#define TCPIP_CMD_SERVER_PORT 5559 + /**< The TCPIP Gateway Servers default TCP/IP port when no port is specified at startup */ +#define TGWS_DEFAULT_PORT 5558 + /**< Timeout in seconds */ +#define TGWS_CONNECTION_TIMEOUT 30 + /**< The localhost address */ +#define TGWS_DEFAULT_IP_ADDRESS "127.0.0.1" + /**< 000.000.000.000 - 15 characteres plus null terminator */ +#define MAX_LENGTH_IP_ADDRESS 16 + +class TcpipGatewayServer { +private: + buffer_t message_buffer; + buffer_t recieve_buffer; + uint16_t pc_port; + std::string str_ip_addr; + std::string str_pc_port; + tgws_config_t *config; + ar_socket_t* server_socket_ptr; + ar_socket_t *client_socket_ptr; + ar_socket_t listen_socket; + ar_osal_thread_t start_routine_thread; + ar_osal_mutex_t connected_mutex; + uint8_t is_connected; + uint32_t option; + + #ifdef ATS_DATA_LOGGING + TcpipGatewayDlsServer dls_server; + #endif + +public: + TcpipGatewayServer(std::string ip_addr, std::string port, uint32_t option); + ~TcpipGatewayServer(); + + /** + * \brief + * Allocates recources and starts the gateway servers connection routine thread. + */ + int32_t run(); + + /** + * \brief + * Starts the TCP/IP connection routine and waits to accept clients. + * \detdesc + * Waits to accept clients. When clients connect the Gateway Server establishes a connection to the TCPIP CMD Server + */ + void* connect_routine(void* arg); + + /** + * \brief + * Recieves messages from the Gateway Server Client and forwads messages to the TCPIP CMD Server + */ + void* transmit_routine(void* client_socket); + +private: + //We need to define these static fuinction in order to use the ar_osal_create_thread(...) API + + void static start(void* arg); + void static transmit(void* arg); + + /** + * \brief + * Forwards messages between the socket established between QACT and the Gateway Server + * and the socket established between the Gateway Server and TCPIP CMD Server + * + * \param [in] sender_socket_ptr: A pointer to the client socket. This is either the socket established with QACT or with the TCPIP CMD server + * \param [in] receiver_socket_ptr: A pointer to the client socket. This is either the socket established with QACT or with the TCPIP CMD server + * \param [in/out] gateway_message_buf: The buffer where the incomming message is written + * \param [in/out] gateway_recv_buf: The buffer used for message boundry processing + * \param [in] is_cmd_request: Indicates if a command request came from QACT + * \param [out] status_code: A gateway status code that the caller can use to handle gateway server specific errors + */ + void tcp_forward( + ar_socket_t* sender_socket_ptr, ar_socket_t* receiver_socket_ptr, + buffer_t* gateway_message_buf, buffer_t* gateway_recv_buf, + bool_t is_cmd_request, tgws_status_codes_t &status_code); + + /** + * \brief + * Connects the Gateway Server to the TCPIP CMD Server + */ + int32_t connect_to_target_server( + ar_socket_t* server_socket); + + /** + * \brief + * Handles gateway server commands detected in the inbound message + * + * \param [in] service_cmd_id: The ATS Service + Command ID used to identify the service the command is part of and the command to execute + * \param [in] sender_socket: The socket to send messages to + * \param [in] service_cmd_id: The lemgth of the inbound message + * \param [out] status_code: A gateway status code that the caller can use to handle gateway server specific errors + * + * \return AR_EOK on success, otherwise non-zero on failure + */ + int32_t execute_server_command( + uint32_t service_cmd_id, ar_socket_t sender_socket, uint32_t message_length, tgws_status_codes_t &status_code); + + /** + * \brief + * Starts the dls gateway server which alows gateway clients to recieve logging data from the ats dls server + */ + void start_dls_server(void); +}; + +#endif /*_TCPIP_GATEWAY_CMD_SERVER_H_*/ diff --git a/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_cmds.h b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_cmds.h new file mode 100644 index 0000000..7421bf3 --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_cmds.h @@ -0,0 +1,106 @@ +#ifndef _TCPIP_GATEWAY_CMD_H_ +#define _TCPIP_GATEWAY_CMD_H_ +/** +*============================================================================== +* \file tcpip_gateway_cmd.h +* \brief +* T C P I P G A T E W A Y C M D +* H E A D E R F I L E +* +* This file contains definitions for server commands +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ +#include "ar_osal_types.h" + +/* NOTE: + * The commands in this file originate from ats_i.h. We cannot include + * ats_i.h b/c it contains acdb.h which will require that you compile the AML + * library. The ATS gateway server has no dependencies on ATS or AML libraries. + */ + + /*----------------------------------------------------------------------------- + ** flag, page size, and buffer length definition for ats_main_buffer + *----------------------------------------------------------------------------*/ +#define ATS_BUFFER_LENGTH 0x200000 +#define ATS_HEADER_LENGTH 8 + + + /* ATS Message formats + * Request Format (for incoming messages) + * + * <--------- 4 bytes -----------> + * +-----------------------------+ + * | service id | command id | + * +-----------------------------+ + * | data length | + * +_____________________________+ + * | | + * | data | + * | ... | + * +~.-~.-~.-~.-~.-~.-~.-~.-~.-~.+ + * + * + * Response Format (outgoing messages) + * + * <-----------4bytes------------> + * +-----------------------------+ + * | service id | command id | + * +-----------------------------+ + * | data length | + * +-----------------------------+ + * | status | + * +_____________________________+ + * | | + * | data | + * | ... | + * +~.-~.-~.-~.-~.-~.-~.-~.-~.-~.+ + */ + +#define ATS_SERVICE_COMMAND_ID_LENGTH 4 +#define ATS_DATA_LENGTH_LENGTH 4 +#define ATS_ERROR_CODE_LENGTH 4 +#define ATS_ERROR_FRAME_LENGTH 12 + +#define ATS_SERVICE_COMMAND_ID_POSITION 0 +#define ATS_DATA_LENGTH_POSITION 4 +#define ATS_ACDB_BUFFER_POSITION 8 + + /**< Extract the service id from the MSW of the 4byte service command id x*/ +#define ATS_GET_SERVICE_ID(x) ((0xFFFF0000 & x)) + +/**< Defines command IDs for the Online Calibration service */ +#define ATS_ONLINE_CMD_ID(x) ((0x4F4Eul << 16) | (0xFFFFul & x)) +#define ATS_ONLINE_SERVICE_ID (0x4F4Eul << 16) + +/** \addtogroup ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH +\{ */ + +/** + Set the maximum buffer size to be used by ATS + + \param[in] cmd_id + Command ID is ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH. + \param[in] cmd + There is no input structure; set this to NULL. + \param[in] cmd_size + There is no input structure; set this to 0. + \param[out] rsp + There is no output structure; set this to NULL. + \param[in] rsp_size + There is no output structure; set this to 0. + + \return + - AR_EOK -- Command executed successfully. + - AR_EBADPARAM -- Invalid input parameters were provided. + - AR_EFAILED -- Command execution failed. + + \sa ats_online_ioctl +*/ +#define ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH ATS_ONLINE_CMD_ID(4) +/** \} */ /* end_addtogroup ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH */ + +#endif /*_TCPIP_GATEWAY_CMD_H_*/ diff --git a/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_common.h b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_common.h new file mode 100644 index 0000000..293430f --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_common.h @@ -0,0 +1,78 @@ +#ifndef _TCPIP_GATEWAY_COMMON_H_ +#define _TCPIP_GATEWAY_COMMON_H_ +/** +*============================================================================= +* \file tcpip_gateway_common.h +* +* T C P I P G A T E W A Y C O M M O N +* H E A D E R F I L E +* +* \brief +* Common header file used by GATEWAY modules. +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================= +*/ + +#include "ar_osal_types.h" +#include "ar_osal_log.h" +#include "ar_osal_mem_op.h" +#include +#include +#include + +#define GATEWAY_LOG_TAG "GATEWAY" +#define GATEWAY_ERR(...) AR_LOG_ERR(GATEWAY_LOG_TAG, __VA_ARGS__) +#define GATEWAY_DBG(...) AR_LOG_DEBUG(GATEWAY_LOG_TAG, __VA_ARGS__) +#define GATEWAY_INFO(...) AR_LOG_INFO(GATEWAY_LOG_TAG, __VA_ARGS__) + +struct tgws_config_t +{ + uint16_t option; + uint16_t port; + char port_str[5]; +}; + +struct buffer_t{ + uint32_t buffer_size; + char_t* buffer; +}; + +/**< Defines options for connecting to the gateway server */ +typedef enum tgws_connection_options_t +{ + TGWS_CONNECTION_OPTION_USB = 0, + TGWS_CONNECTION_OPTION_WIFI = 1 +}tgws_connection_options_t; + +/**< Defines error codes specific to the gateway server */ +typedef enum tgws_status_codes_t +{ + /**< General Success */ + TGWS_E_SUCCESS = 0, + /**< End message forwarding */ + TGWS_E_END_MSG_FWD = 1, + /**< Ignore message forwarding */ + TGWS_E_IGNORE_MSG_FWD = 2 +}tgws_status_codes_t; + +inline int32_t tgws_mem_cpy(void* dest, size_t sz_dest, void* src, size_t sz_src) +{ + int32_t result = AR_EOK; + + if (dest == NULL || src == NULL) return result; + if (sz_src <= sz_dest) + { + ar_mem_cpy((int8_t*)dest, sz_dest, (int8_t*)src, sz_src); + + if (sz_dest - sz_src != 0) + { + ar_mem_set((int8_t*)dest + sz_src, 0, sz_dest - sz_src); + } + result = 0; + } + + return result; +} +#endif /*_TCPIP_GATEWAY_COMMON_H_*/ diff --git a/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_dls_server.h b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_dls_server.h new file mode 100644 index 0000000..3ded39a --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_dls_server.h @@ -0,0 +1,123 @@ +#ifndef _TCPIP_GATEWAY_DSL_SERVER_H_ +#define _TCPIP_GATEWAY_DSL_SERVER_H_ +/** +*============================================================================== +* \file tcpip_gateway_dls_server.h +* \brief +* T C P I P G A T E W A Y D L S S E R V E R +* H E A D E R F I L E +* +* This file defines the class for the TCPIP Gateway Server as +* well as types and defines used by the server. This server is +* a proxy server that forwards request from server clients to the +* TCPIP CMD Server. +* +* ATS_DATA_LOGGING must be defined in the build configuration to use +* this feature +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ + +#if defined(ATS_DATA_LOGGING) + +/*------------------------------------- + * Includes + *-----------------------------------*/ +#include +#include "ar_osal_mutex.h" +#include "ar_osal_error.h" +#include "ar_osal_thread.h" +#include "ar_osal_string.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_heap.h" +#include "ar_sockets_api.h" +#include "tcpip_gateway_cmds.h" +#include "tcpip_gateway_common.h" + +#define TGWS_START_ROUTINE_THREAD "GWS_THD_START" +#define TGWS_TRANSMIT_THREAD "GWS_THD_TRANSMIT" + /**< 1MB stack size used when creating threads */ +#define TGWS_THD_STACK_SIZE 0xF4240 // +#define TGWS_THREAD_PRIORITY_HIGH 0 +#define TGWS_THREAD_PRIORITY_LOW 1 + +#define TGWS_1_KB 1024UL +#define TGWS_RECIEVE_BUFFER_SIZE (TGWS_1_KB * 32UL) +#define TGWS_MIN_MESSAGE_BUFFER_SIZE (TGWS_1_KB * 32UL) +#define TGWS_MAX_MESSAGE_BUFFER_SIZE 0x200000ul + + /**< The TCPIP Gateway DLS Servers default TCP/IP port when no port is specified at startup */ +#define TCPIP_DEFAULT_DLS_SERVER_PORT 5560 + /**< Timeout in seconds */ +#define TGWS_CONNECTION_TIMEOUT 30 + /**< The localhost address */ + +#define TCPIP_THREAD_PRIORITY_HIGH 0 +#define TCPIP_THREAD_PRIORITY_LOW 1 +#define TCPIP_THD_STACK_SIZE 0xF4240 //1mb stack size + +#define TCPIP_DLS_SERVER_PORT 5560 + +class TcpipGatewayDlsServer +{ +public: + std::string address; + std::string str_pc_port;//todo: might need this? + uint16_t port; +private: + buffer_t message_buffer; + buffer_t recieve_buffer; + bool_t is_connected; + bool_t should_close_server; + ar_socket_t accept_socket; + ar_osal_mutex_t connection_lock; + ar_osal_thread_t thread; + ar_socket_t* server_socket_ptr; + ar_socket_t *client_socket_ptr; + ar_socket_t listen_socket; + std::string str_ip_addr; + ar_osal_mutex_t connected_mutex; +public: + TcpipGatewayDlsServer(); + // TcpipGatewayDlsServer(std::string thd_name); + int32_t start(); + int32_t stop(); + + void* connect_routine(void* args); + void* transmit_routine(void* args); + void set_ip_address(std::string address); +private: + int32_t set_connected_lock(bool_t is_conn); + + static void connect(void* arg); + void static transmit(void* arg); + + /** + * \brief + * Forwards messages from the socket established between the ATS TCPIP CMD Server and the Gateway Server + * to the socket established between the Gateway Server and QACT + * + * \param [in] sender_socket_ptr: A pointer to the client socket. This is either the socket established with QACT or with the TCPIP CMD server + * \param [in] receiver_socket_ptr: A pointer to the client socket. This is either the socket established with QACT or with the TCPIP CMD server + * \param [in/out] gateway_message_buf: The buffer where the incomming message is written + * \param [in/out] gateway_recv_buf: The buffer used for message boundry processing + * \param [in] is_cmd_request: Indicates if a command request came from QACT + * \param [out] status_code: A gateway status code that the caller can use to handle gateway server specific errors + */ + void tcp_forward( + ar_socket_t* sender_socket_ptr, ar_socket_t* receiver_socket_ptr, + buffer_t* gateway_message_buf, buffer_t* gateway_recv_buf, + bool_t is_cmd_request, tgws_status_codes_t &status_code); + + /** + * \brief + * Connects the Gateway DLS Server to the ATS TCPIP DLS Server + */ + int32_t connect_to_target_server( + ar_socket_t* server_socket); +}; + +#endif /*ATS_DATA_LOGGING*/ +#endif /*_TCPIP_GATEWAY_DSL_SERVER_H_*/ diff --git a/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_socket_util.h b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_socket_util.h new file mode 100644 index 0000000..64b9a2b --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/inc/tcpip_gateway_socket_util.h @@ -0,0 +1,37 @@ +#ifndef _TCPIP_GATEWAY_SOCKET_UTIL_H_ +#define _TCPIP_GATEWAY_SOCKET_UTIL_H_ +/** +*============================================================================== +* \file tcpip_gateway_socket_util.h +* \brief +* T C P I P G A T E W A Y S O C K E T U T I L I T Y +* H E A D E R F I L E +* +* Contains utility functions to simplify socket creation in the +* server sources files +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ +#include "ar_osal_types.h" +#include "ar_osal_log.h" +#include "ar_osal_string.h" +#include "ar_sockets_api.h" +#include + +typedef enum tgws_util_address_type_t{ + TGWS_ADDRESS_TCPIP = 0, + TGWS_ADDRESS_UNIX_ABSTRACT_DOMAIN = 1, +}tgws_util_address_type_t; + +tgws_util_address_type_t tgws_get_address_type(); + +uint32_t tgws_util_get_socket_address_length(tgws_util_address_type_t address_type, std::string address); + +uint32_t tgws_util_create_socket(ar_socket_t* socket); + +void tgws_util_get_socket_address(tgws_util_address_type_t address_type, std::string address, uint16_t port, ar_socket_addr_storage_t* socket_address); + +#endif /*_TCPIP_GATEWAY_SOCKET_UTIL_H_*/ diff --git a/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_cmd_server.cpp b/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_cmd_server.cpp new file mode 100644 index 0000000..8d6ed25 --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_cmd_server.cpp @@ -0,0 +1,952 @@ +/** +*============================================================================== +* \file tcpip_gateway_cmd_server.cpp +* \brief +* T C P I P G A T E W A Y C M D S E R V E R +* S O U R C E F I L E +* +* Contains the implementation for the ATS TCPIP Gateway Command Server. +* This Command server is the middle man between ATS TCPIP Command +* Server and QACT and handles forwarding messages between the two. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ + +/** +* Preprocessor Macro Notes +*------------------------------------------------------------------------------ +* ATS_DATA_LOGGING | define this macro in your build configuration to enable +* | recieving log packet data from SPF +*/ + +#include "tcpip_gateway_cmd_server.h" +#include "tcpip_gateway_socket_util.h" +#include +#include + +#define IS_NULL(ptr) (ptr == NULL) + +/* The name of the unix abstract domain socket used by the + * ATS Server to communicate with the gateway server */ +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_CMD "#AtsCmdServer" +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_DLS "#AtsDlsServer" +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_CMD "#AtsGwCmdServer" +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_DLS "#AtsGwDlsServer" + + /* The character length of the unix domain socket string + * including the null-terminating character */ +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_CMD_LENGTH 13 +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_CMD_LENGTH 16 + +typedef enum ats_server_id_t +{ + ATS_CMD_SERVER = 0, + ATS_DLS_SERVER = 1 +}ats_server_id_t; +/* +============================================================================ + Prototypes / Typedefs / Callbacks +============================================================================ +*/ + +typedef void* (TcpipGatewayServer::* thread_callback)(void* args); +thread_callback thd_cb_start_routine = &TcpipGatewayServer::connect_routine; +thread_callback thd_cb_transmit_routine = &TcpipGatewayServer::transmit_routine; + +/** +* \brief +* Helper function that retrieves the expected message length from the command request header +* +* \detdesc +* The message_buffer must be in the following format: +* <--------- 4 bytes -----------> +* +-----------------------------+ +* | service id | command id | +* +-----------------------------+ +* | data length | +* +_____________________________+ +* | | +* | data | +* | ... | +* +~.-~.-~.-~.-~.-~.-~.-~.-~.-~.+ +* +* Note: the data length referes to the size of the data section (not including header +* size of 6 bytes) +* +* \dependencies +* None +* +* \param [in] message_buffer: The buffer containing the command request sent by the client +* \param [in] message_buffer_size: The length of the message buffer +* \param [in] data_length: The data length field in the command request header +* +* \return +* TRUE if successfully parsed and FALSE otherwise +*/ +static bool_t tgws_get_ats_command_length( + char_t* message_buffer, uint32_t message_buffer_size, uint32_t* data_length); + +/** +* \brief +* Create a response error buffer with the specified error code +* and request command id. +* +* \detdesc +* The response +* <-----------4bytes------------> +* +-----------------------------+ +* | service id | command id | +* +-----------------------------+ +* +-----------------------------+ +* | data length | +* +-----------------------------+ +* +-----------------------------+ +* | status | +* +-----------------------------+ +* +* \param[in] ar_status_code: The AR status code indicating the error +* \param[in/out] message_buffer: The message buffer where the message is written to +* \param[in] message_buffer_size: The size of the message buffer +* \param[out] message_length: The length of the message written to the message buffer +* +* \return none +*/ +static void tgws_create_error_resp( + uint32_t service_cmd_id, uint32_t ar_status_code, + char_t* rsp_msg_buffer, uint32_t rsp_msg_buffer_size, + uint32_t& rsp_msg_legnth +); + +/* +============================================================================ + TCPIP Gateway Server Implementation +============================================================================ +*/ + +TcpipGatewayServer::TcpipGatewayServer(std::string ip_addr, std::string port, uint32_t option) + : str_ip_addr { ip_addr }, str_pc_port{ port }, + option{ option } +{ + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + size_t index = 0; + pc_port = (uint16_t)std::stoi(port, &index); + + server_socket_ptr = (ar_socket_t*)ar_heap_malloc(sizeof(ar_socket_t), &heap_inf); + client_socket_ptr = (ar_socket_t*)ar_heap_malloc(sizeof(ar_socket_t), &heap_inf); + ar_mem_set(server_socket_ptr, 0, sizeof(ar_socket_t)); + ar_mem_set(client_socket_ptr, 0, sizeof(ar_socket_t)); + + int32_t status = ar_osal_mutex_create(&connected_mutex); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Error[%d]: Failed to create mutex.", status); + } +} + +TcpipGatewayServer::~TcpipGatewayServer() +{ + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + //Cleanup resources + ar_heap_free(server_socket_ptr, &heap_inf); + ar_heap_free(client_socket_ptr, &heap_inf); + + int32_t status = ar_osal_mutex_destroy(connected_mutex); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Error[%d]:An error occured while destroying the mutex.", status); + } +} + +int32_t TcpipGatewayServer::connect_to_target_server(ar_socket_t* server_socket) +{ + int32_t status = AR_EOK; + uint32_t client_addr_length = 0; + uint32_t server_addr_length = 0; + ar_socket_addr_storage_t client_sockaddr = { 0 }; + ar_socket_addr_storage_t server_sockaddr = { 0 }; + +// #if defined (__linux__) +// if (AR_FAILED(ar_socket_unix(server_socket))) +// return AR_EFAILED; +// client_addr_length = ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_CMD_LENGTH +// + sizeof(uint16_t); +// server_addr_length = ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_CMD_LENGTH +// + sizeof(uint16_t); +// #elif defined (_WIN32) +// if (AR_FAILED(ar_socket_tcp(server_socket))) +// return AR_EFAILED; +// /*client_addr_length = sizeof(ar_socket_addr_storage_t);*/ +// client_addr_length = sizeof(ar_socket_addr_in_t); +// server_addr_length = sizeof(ar_socket_addr_in_t); +// #endif + +// ar_socket_addr_storage_t client_sockaddr = { 0 }; +// tgws_get_client_address(pc_port, &client_sockaddr); +// ar_socket_addr_storage_t server_sockaddr = { 0 }; +// tgws_get_server_address(TCPIP_CMD_SERVER_PORT, &server_sockaddr); + + tgws_util_create_socket(server_socket); + + //Get Client address and address length (this gateway dls server) + tgws_util_get_socket_address(tgws_get_address_type(), ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_CMD, pc_port, &client_sockaddr); + client_addr_length = tgws_util_get_socket_address_length(tgws_get_address_type(), ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_CMD); + + //Get ATS Service address and address length + server_addr_length = tgws_util_get_socket_address_length(tgws_get_address_type(), ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_CMD); + tgws_util_get_socket_address(tgws_get_address_type(), ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_CMD, TCPIP_CMD_SERVER_PORT, &server_sockaddr); + + /* Bind to client address to the Gateway Server socket */ + client_addr_length = sizeof(ar_socket_addr_in_t); + status = ar_socket_bind( + *server_socket, + (ar_socket_addr_t*)&client_sockaddr, + client_addr_length);// This is size of ar_socket_addr_un_t::sun_family + if (AR_FAILED(status)) + { + GATEWAY_DBG("Unable to bind client address to gateway cmd server socket"); + ar_socket_close(*server_socket); + return AR_EFAILED; + } + + GATEWAY_DBG("Attempting to connect to ats command server socket..."); + client_addr_length = sizeof(server_sockaddr); + /* Connect Gateway to the CMD Server socket */ + status = ar_socket_connect( + *server_socket, + (ar_socket_addr_t*)&server_sockaddr, + server_addr_length); // This is size of ar_socket_addr_un_t::sun_family + if (AR_FAILED(status)) + { + GATEWAY_ERR("Error[%d]: Failed to connect to ats command server."); + ar_socket_close(*server_socket); + return AR_EFAILED; + } + + GATEWAY_INFO("Connected to ats command server."); + return status; +} + +void* TcpipGatewayServer::connect_routine(void* arg) +{ + __UNREFERENCED_PARAM(arg); + + GATEWAY_DBG("Starting gateway command server thread."); + int status = 0; + int32_t thd_index = 0; + struct timeval timeout = { 0 }; + struct addrinfo socket_hints; + struct addrinfo* connected_devices_addr_info = NULL; + + // getaddrinfo() requires all fields in the addrinfo struct to be zeroed out + ar_mem_set(&socket_hints, 0, sizeof(socket_hints)); + + //sets hints to look for addresses that IPv4 and used for TCP/IP + socket_hints.ai_family = AF_INET; // IPv4 + socket_hints.ai_socktype = SOCK_STREAM; // TCP + socket_hints.ai_flags = AI_PASSIVE; //IP Wildcard + + //gets addrinfo structure for devices on port 5558 + + //set up USB listening thread on localhost + switch (option) + { + case TGWS_CONNECTION_OPTION_USB: + GATEWAY_INFO("Connecting to gateway over usb"); + + status = ar_socket_get_addr_info(str_ip_addr.c_str(), + config->port_str, + &socket_hints, + &connected_devices_addr_info); + break; + case TGWS_CONNECTION_OPTION_WIFI: + { + GATEWAY_INFO("Connecting to gateway over wifi"); + //int fd; + //struct ifreq ifr; + //fd = socket(AF_INET, SOCK_DGRAM, 0); + //ifr.ifr_addr.sa_family = AF_INET; + //strncpy(ifr.ifr_name, "wlan0", IFNAMSIZ-1); + //ioctl(fd, SIOCGIFADDR, &ifr); + //ar_socket_close(fd); + //GATEWAY_ERR("IP Addr.: %s", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr)); + //status = getaddrinfo(inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), PORT_NUMBER_PC.c_str(), &hints, &results); + status = ar_socket_get_addr_info(NULL, str_pc_port.c_str(), &socket_hints, &connected_devices_addr_info); + } + break; + default: + break; + } + + //checks for errors getting the IP address + if (AR_FAILED(status) || connected_devices_addr_info == NULL) + { + return NULL; + } + + GATEWAY_DBG("Host Info AI_FLAGS: %d", connected_devices_addr_info->ai_flags); + GATEWAY_DBG("Host Info AI_FAMILY: %d", connected_devices_addr_info->ai_family); + GATEWAY_DBG("Host Info AI_SOCKTYPE: %d", connected_devices_addr_info->ai_socktype); + GATEWAY_DBG("Host Info AI_PROTOCOL: %d", connected_devices_addr_info->ai_protocol); + GATEWAY_DBG("Host Info ADDRLEM: %u", connected_devices_addr_info->ai_addrlen); + GATEWAY_DBG("Host Info AI_CANONNAME: %s", connected_devices_addr_info->ai_canonname); + + GATEWAY_ERR("Setting up sockets..."); + //ar_socket_t listen_socket; + + //creates socket and references the socket using a file descriptor + status = ar_socket_tcp(&listen_socket); + + //Sets socket options allowing sockets to bind to a certain address + int32_t yes = 1; + status = ar_socket_set_options(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char_t*)&yes, sizeof(int32_t)); + if (status < 0) + { + GATEWAY_ERR("Error[%d]: Unable to set socket options", status); + return 0; + } + + // timeout.tv_sec = TGWS_CONNECTION_TIMEOUT; + // ar_socket_set_options(listen_socket, SOL_SOCKET, SO_RCVTIMEO, (char_t*)&timeout, sizeof(struct timeval)); + + //binds IP address to socket + status = ar_socket_bind(listen_socket, + connected_devices_addr_info->ai_addr, + (int)connected_devices_addr_info->ai_addrlen); + + GATEWAY_INFO("Listening for connections..."); + + //listens queue is of size 1 + status = ar_socket_listen(listen_socket, 1); + + //initializing mutex and setting up environment for threading + ar_osal_mutex_init(connected_mutex); + ar_osal_mutex_lock(connected_mutex); + is_connected = 0; + ar_osal_mutex_unlock(connected_mutex); + + while (TRUE) + { + ar_socket_addr_storage_t their_addr; + socklen_t addr_size = sizeof(their_addr); + ar_socket_t client_socket_temp; + + //GATEWAY_ERR("Waiting to accept connections..."); + status = ar_socket_accept(listen_socket, (struct sockaddr*)&their_addr, &addr_size, &client_socket_temp); + + if (AR_FAILED(status)) + { + if (errno == EINTR) continue; + + ar_socket_addr_in_t* sin = (ar_socket_addr_in_t*)&their_addr; + //Converts binary to IPv4 string + char_t ip_addr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sin->sin_addr), ip_addr, INET_ADDRSTRLEN); + //GATEWAY_ERR("Attempted Connection from: %s", ip_addr); + } + else + { + //do not create more threads if already connected. + //ar_osal_mutex_lock(connected_mutex); + //if (is_connected) + //{ + // ar_osal_mutex_unlock(connected_mutex); + // GATEWAY_ERR("Detected a new connection request. Refusing..."); + // ar_socket_close(client_socket_temp); + // continue; + //} + + GATEWAY_DBG("Accept successful to gateway command server: Client Socket %d", client_socket_temp); + ar_osal_mutex_unlock(connected_mutex); + + timeout.tv_sec = TGWS_CONNECTION_TIMEOUT; + ar_socket_set_options(client_socket_temp, SOL_SOCKET, SO_RCVTIMEO, (char_t*)&timeout, sizeof(struct timeval)); + + *client_socket_ptr = client_socket_temp; + ar_socket_addr_in_t* sin = (ar_socket_addr_in_t*)&their_addr; + + //Converts binary to IPv4 string + char_t str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sin->sin_addr), str, INET_ADDRSTRLEN); + GATEWAY_INFO("Connection from: %s:%d", str, pc_port); + + //ar_socket_close(listen_socket); + status = connect_to_target_server(server_socket_ptr); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Unable to connect to intended server. Refusing client..."); + ar_socket_close(client_socket_temp); + continue; + } + + ar_osal_thread_t thd_transmit; + ar_osal_thread_start_routine routine = \ + (ar_osal_thread_start_routine)(transmit); + + std::string thd_name_tmp = "GW_THD_" + std::to_string(thd_index); + char_t thd_name[20]; + ar_strcpy(thd_name, 20, thd_name_tmp.c_str(), thd_name_tmp.length() + 1); + ar_osal_thread_attr_t thd_attr = \ + { + thd_name, + TGWS_THD_STACK_SIZE, + TGWS_THREAD_PRIORITY_HIGH + }; + + status = ar_osal_thread_create(&thd_transmit, &thd_attr, routine, this); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Failed to create data transmission thread."); + break; + } + + start_dls_server(); + + /* Only one client is allowed to connect to the server for now. + * Block until client calls QUIT on transmission thread. + * Allow 200 msec sleep for thd_transmit to aquire connection_lock*/ + //Sleep(200); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + ar_osal_mutex_lock(connected_mutex); + + GATEWAY_DBG("Error[%d]: Waiting for thread %s to complete", status, thd_name); + status = ar_osal_thread_join_destroy(thd_transmit); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Error[%d]: Failed to join usb thread", status); + } + GATEWAY_DBG("Error[%d]: Thread %s destroyed", status, thd_name); + } + } + + GATEWAY_INFO("Ending connect routine."); + ar_socket_close(*client_socket_ptr); + ar_socket_close(*server_socket_ptr); + return 0; +} + +void* TcpipGatewayServer::transmit_routine(void* arg) +{ + __UNREFERENCED_PARAM(arg); + ar_osal_mutex_lock(connected_mutex); + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + GATEWAY_DBG("Begin message forwarding"); + + //todo: If we decide to support multiple device connections, the buffers need to be added to an array and each thread needs to pick its associated buffer we can do this after testing with 1 connection + message_buffer.buffer_size = TGWS_MAX_MESSAGE_BUFFER_SIZE; + recieve_buffer.buffer_size = TGWS_RECIEVE_BUFFER_SIZE; + + message_buffer.buffer = (char_t*)ar_heap_malloc(message_buffer.buffer_size, &heap_inf); + if (NULL == message_buffer.buffer) + { + GATEWAY_ERR("Error[%d]: Failed to allocate memory for message buffer", AR_ENOMEMORY); + return NULL; + } + + recieve_buffer.buffer = (char_t*)ar_heap_malloc(recieve_buffer.buffer_size, &heap_inf); + if (NULL == recieve_buffer.buffer) + { + ar_heap_free(message_buffer.buffer, &heap_inf); + GATEWAY_ERR("Error[%d]: Failed to allocate memory for recieve buffer", AR_ENOMEMORY); + return NULL; + } + + /* this loop will run once per ENTIRE message received. + * keep listening for whole incoming messages + */ + while (true) + { + tgws_status_codes_t status_code = TGWS_E_SUCCESS; + + /* Forward requests from Gateway Client to CMD Server */ + tcp_forward( + /* from client */ client_socket_ptr, + /* to server */ server_socket_ptr,//server_socket_ptr, + &message_buffer, &recieve_buffer, true, status_code); + + switch (status_code) + { + case TGWS_E_END_MSG_FWD: + goto threaddone; + case TGWS_E_IGNORE_MSG_FWD: + /* Return error response was returned to Gateway + * Client so dont forward messages to CMD Server*/ + continue; + default: + break; + } + + /* Forward responses from CMD Server to Gateway Client */ + tcp_forward( + /* from server */ server_socket_ptr, + /* to client */ client_socket_ptr, + &message_buffer, &recieve_buffer, false, status_code); + if (TGWS_E_END_MSG_FWD == status_code) + break; + } +threaddone: + ar_socket_close(*client_socket_ptr); + ar_socket_close(*server_socket_ptr); + ar_heap_free(message_buffer.buffer, &heap_inf); + ar_heap_free(recieve_buffer.buffer, &heap_inf); + + GATEWAY_DBG("End message forwarding"); + + is_connected = 0; + ar_osal_mutex_unlock(connected_mutex); + return NULL; +} + +int32_t TcpipGatewayServer::execute_server_command( + uint32_t service_cmd_id, ar_socket_t sender_socket, uint32_t message_length, + tgws_status_codes_t& status_code) +{ + switch (service_cmd_id) + { + case ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH: + { + uint32_t new_buffer_size = 0; + uint32_t data_length = 0; + uint32_t offset = 0; + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + ar_mem_cpy(&new_buffer_size, sizeof(uint32_t), this->message_buffer.buffer, message_length); + + GATEWAY_DBG("Setting max buffer length to %d bytes", new_buffer_size); + + //The new buffer size needs to be between the required range to resize the message buffer: + //range: AGWS_RECV_BUF_SIZE * 4 < new buffer size < GWS_MAX_BUFFER_SIZE + //Largest buffer size is 2mb the GWS_MAX_BUFFER_SIZE + //Smalleset buffer size is 4 * 1024 the recieve buffer size + if ((new_buffer_size > this->message_buffer.buffer_size && new_buffer_size < TGWS_MIN_MESSAGE_BUFFER_SIZE) || + (new_buffer_size < this->message_buffer.buffer_size && new_buffer_size > TGWS_MAX_MESSAGE_BUFFER_SIZE) + ) + { + ar_heap_free(message_buffer.buffer, &heap_inf); + + message_buffer.buffer_size = new_buffer_size; + message_buffer.buffer = (char_t*)ar_heap_malloc(message_buffer.buffer_size, &heap_inf); + if (NULL == message_buffer.buffer) + { + GATEWAY_ERR("Error[%d]: Failed to resize gateway message buffer", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + ar_mem_set(message_buffer.buffer, 0, message_buffer.buffer_size); + + /* Write the ATS command back to the resized message buffer so that the ATS Command + * layer can resize its buffer.*/ + ar_mem_cpy(message_buffer.buffer, sizeof(uint32_t), &service_cmd_id, sizeof(uint32_t)); + offset += sizeof(uint32_t); + ar_mem_cpy(message_buffer.buffer + offset, sizeof(uint32_t), &data_length, sizeof(uint32_t)); + offset += sizeof(uint32_t); + ar_mem_cpy(message_buffer.buffer + offset, sizeof(uint32_t), &new_buffer_size, sizeof(uint32_t)); + } + } + break; + default: + break; + } + + return TGWS_E_SUCCESS; +} + +void TcpipGatewayServer::tcp_forward( + ar_socket_t* sender_socket_ptr, ar_socket_t* receiver_socket_ptr, + buffer_t* gateway_message_buf, buffer_t* gateway_recv_buf, + bool_t is_cmd_request, tgws_status_codes_t& agws_status_code) +{ + int32_t status = AR_EOK; + ar_socket_t sender_socket = *sender_socket_ptr; + ar_socket_t receiver_socket = *receiver_socket_ptr; + uint32_t header_bytes_read = 0; + uint32_t message_length = 0; + uint32_t msg_offset = 0; + int32_t bytes_sent = 0; + int32_t bytes_read = 0; + uint32_t svc_cmd_id = 0; + + ar_mem_set(gateway_message_buf->buffer, 0, gateway_message_buf->buffer_size); + ar_mem_set(gateway_recv_buf->buffer, 0, gateway_recv_buf->buffer_size); + + //This loop will run as many times as to receive full message header (should be just once) + while (TRUE) + { + bytes_read = 0; + bytes_sent = 0; + status = AR_EOK; + + GATEWAY_DBG("Receiving..."); + + status = ar_socket_recv( + sender_socket, + gateway_recv_buf->buffer, + ATS_HEADER_LENGTH - header_bytes_read, + 0, &bytes_read); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Recieve failed. Data of %d bytes received.", bytes_read); + } + + //client sends "QUIT" to signal end of connection. At that point, close socket and return. + if (ar_strcmp(gateway_recv_buf->buffer, "QUIT", 4) == 0) + { + ar_socket_send(receiver_socket, "QUIT", 4, 0, &bytes_sent); + GATEWAY_ERR("Quitting"); + ar_socket_close(receiver_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + + if (bytes_read <= 0) + { + /*recv(...) returned -1 or 0 + * -1 - indicates an error so we need to check errno (error number) + * 0 - the client sent 0 or the connection was closed. Check + * recv(...) documentation for addition info + */ + if (AR_SOCKET_LAST_ERROR == EINTR) continue; + + GATEWAY_INFO("Failed to recieve data from client"); + ar_socket_close(sender_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + else if (bytes_read == 0) + { + GATEWAY_INFO("Client shutdown socket. Closing connection..."); + ar_socket_close(sender_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + + GATEWAY_ERR("Data of %d bytes received.", bytes_read); + header_bytes_read += bytes_read; + + //this determines how many bytes to expect (thus determining how many times to loop). + if (tgws_get_ats_command_length(gateway_recv_buf->buffer, header_bytes_read, &message_length)) + { + GATEWAY_DBG("Message with length: %d received.", message_length); + ar_mem_cpy( + gateway_message_buf->buffer, ATS_HEADER_LENGTH, + gateway_recv_buf->buffer, ATS_HEADER_LENGTH); + msg_offset += ATS_HEADER_LENGTH; + break; + } + } + + + if (message_length > message_buffer.buffer_size) + { + /* We reject messages that are larger that what we can store in our message buffer */ + GATEWAY_DBG("Error[%d]: Not enough memory to store incoming message of %d bytes. " + "Use resize buffer command update the max buffer size", AR_ENEEDMORE, message_length); + status = AR_ENEEDMORE; + agws_status_code = TGWS_E_IGNORE_MSG_FWD; + goto tcp_forward_end; + } + + //this loop will receive max bufsize bytes each iteration, looping until it receives full message + msg_offset = 0; + while (message_length != 0) + { + if (msg_offset > message_length) + { + GATEWAY_ERR("read more than message length...corruption"); + ar_socket_close(sender_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + + //will receive min(bufsize, bytes left to receive to complete message) + uint32_t recv_buf_size = gateway_recv_buf->buffer_size;//AGWS_RECV_BUF_SIZE; + int32_t bytes_read = 0; + + int32_t bytes_remaining = message_length - msg_offset < recv_buf_size ? message_length - msg_offset : recv_buf_size; + ar_socket_recv( + sender_socket, + gateway_recv_buf->buffer, + bytes_remaining, + 0, &bytes_read); + + if (bytes_read <= 0) + { + if (AR_SOCKET_LAST_ERROR == EINTR) + { + GATEWAY_ERR("Signal Interrupt. Continuing..."); + continue; + } + GATEWAY_ERR("failed to recieve data from client"); + ar_socket_close(sender_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + + GATEWAY_ERR("msg offset: %d bytes", msg_offset); + ar_mem_cpy( + gateway_message_buf->buffer + ATS_HEADER_LENGTH + msg_offset, bytes_read, + gateway_recv_buf->buffer, bytes_read); + msg_offset += bytes_read; + + if (msg_offset == message_length) + break; + } + + //The total message length is ATS Header + CMD Length + message_length += ATS_HEADER_LENGTH; + GATEWAY_DBG("*** Full message received [%d bytes]***", message_length); + + + GATEWAY_DBG("message offset = %d", msg_offset); + GATEWAY_DBG("message buffer [0-8] = \n%08x %08x %08x %08x\n%08x %08x %08x %08x", + *((uint32_t*)gateway_message_buf->buffer + 0), + *((uint32_t*)gateway_message_buf->buffer + 1), + *((uint32_t*)gateway_message_buf->buffer + 2), + *((uint32_t*)gateway_message_buf->buffer + 3), + *((uint32_t*)gateway_message_buf->buffer + 4), + *((uint32_t*)gateway_message_buf->buffer + 5), + *((uint32_t*)gateway_message_buf->buffer + 6), + *((uint32_t*)gateway_message_buf->buffer + 7) + ); + +tcp_forward_end: + + ar_mem_cpy(&svc_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH, + gateway_message_buf->buffer + ATS_SERVICE_COMMAND_ID_POSITION, ATS_SERVICE_COMMAND_ID_LENGTH); + GATEWAY_DBG("Service Command ID: 0x%x", svc_cmd_id); + + if (ATS_ONLINE_SERVICE_ID == ATS_GET_SERVICE_ID(svc_cmd_id) && is_cmd_request) + { + //process gateway command + status = execute_server_command(svc_cmd_id, sender_socket, message_length, agws_status_code); + } + + if (agws_status_code == TGWS_E_IGNORE_MSG_FWD) + { + //create error response + tgws_create_error_resp(svc_cmd_id, status, + gateway_message_buf->buffer, gateway_message_buf->buffer_size, message_length); + receiver_socket = sender_socket; + + if (message_length == 0) + { + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + GATEWAY_DBG("Returning err message of length: %d to client", message_length); + } + + status = ar_socket_send( + receiver_socket, + gateway_message_buf->buffer, + message_length, 0, &bytes_sent); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Error[%d]: Failed to send data to client"); + ar_socket_close(receiver_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + } +} + +void TcpipGatewayServer::start(void* arg) +{ + GATEWAY_ERR("Start routine callback..."); + TcpipGatewayServer* gws = (TcpipGatewayServer*)arg; + (gws->*thd_cb_start_routine)(NULL); +} + +void TcpipGatewayServer::transmit(void* arg) +{ + GATEWAY_ERR("Transmit routine callback..."); + TcpipGatewayServer* gws = (TcpipGatewayServer*)arg; + (gws->*thd_cb_transmit_routine)(NULL); +} + +int32_t TcpipGatewayServer::run() +{ + int32_t status = AR_EOK; + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + status = ar_socket_init(); + if (AR_FAILED(status)) + { + return status; + } + + config = (tgws_config_t*)ar_heap_malloc(sizeof(tgws_config_t), &heap_inf); + config->option = this->option;// TGWS_CONNECTION_OPTION_USB; + config->port = pc_port; + // config->port_str = str_pc_port.c_str(); + + str_pc_port.copy(config->port_str, str_pc_port.size() + 1, 0); + config->port_str[4] = 0; + GATEWAY_DBG("Port Str: %s | Port: %d", config->port_str, config->port); + + char thd_name_usb[] = TGWS_START_ROUTINE_THREAD; + ar_osal_thread_attr_t thd_attr_usb = \ + { + thd_name_usb, + TGWS_THD_STACK_SIZE, + TGWS_THREAD_PRIORITY_HIGH + }; + + ar_osal_thread_start_routine routine = \ + (ar_osal_thread_start_routine)(start); + status = ar_osal_thread_create(&start_routine_thread, &thd_attr_usb, routine, this); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Error[%d]: Failed to create USB listening thread", status); + goto main_cleanup; + } + + GATEWAY_ERR("waiting for usb thread to end..."); + status = ar_osal_thread_join_destroy(start_routine_thread); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Failed to join usb thread"); + goto main_cleanup; + } + +main_cleanup: + GATEWAY_ERR("END.."); + ar_heap_free(server_socket_ptr, &heap_inf); + ar_heap_free(client_socket_ptr, &heap_inf); + return status; +} + +void TcpipGatewayServer::start_dls_server() +{ + #if defined(ATS_DATA_LOGGING) + + GATEWAY_INFO("starting gateway dls server"); + //Start the DLS client server after successfully connecting to the CMD server + dls_server.set_ip_address(str_ip_addr); + dls_server.stop(); + + //wait for arts tcpip dls server to be ready + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + + uint32_t status = dls_server.start(); + if (AR_FAILED(status)) + { + GATEWAY_ERR("Error[%d]: Unable to start gateway dls server. Client won't be able to recieve log packets. Skipping..."); + } + + #endif +} + +/* +============================================================================ + Helper Functions +============================================================================ +*/ + +static bool_t tgws_get_ats_command_length( + char_t* message_buffer, uint32_t message_buffer_size, uint32_t* data_length) +{ + bool_t result = FALSE; + if (IS_NULL(message_buffer) || IS_NULL(data_length)) + { + GATEWAY_ERR("Error[%d]: Input parameter is null", AR_EBADPARAM); + return FALSE; + } + if (message_buffer_size < ATS_HEADER_LENGTH) + { + GATEWAY_ERR("Error[%d]: Message buffer is smaller than request header format length", AR_ENEEDMORE); + result = FALSE; + } + else + { + /** copy data length*/ + tgws_mem_cpy(data_length, ATS_DATA_LENGTH_LENGTH, + message_buffer + ATS_DATA_LENGTH_POSITION, ATS_DATA_LENGTH_LENGTH); + + result = TRUE; + } + return result; +} + +static void tgws_create_error_resp( + uint32_t service_cmd_id, uint32_t ar_status_code, + char_t* message_buffer, uint32_t message_buffer_size, + uint32_t& message_length +) +{ + /* The format of the command response message is: + * <-----------4bytes------------> + * +-----------------------------+ + * | service id | command id | + * +-----------------------------+ + * +-----------------------------+ + * | data length | + * +-----------------------------+ + * +-----------------------------+ + * | status | + * +-----------------------------+ */ + uint32_t resp_data_length; + + if (NULL == message_buffer) + { + GATEWAY_ERR("Error[%d]: Response Buffer is not initialized", AR_EBADPARAM); + message_length = 0; + return; + } + + if (message_buffer_size < ATS_ERROR_FRAME_LENGTH) + { + GATEWAY_ERR("Error[%d]: TUnable to create error response. " + "The response buffer is less than %d bytes", + AR_EBADPARAM, ATS_ERROR_FRAME_LENGTH); + return; + } + + message_length = ATS_ERROR_FRAME_LENGTH; + resp_data_length = ATS_ERROR_FRAME_LENGTH - ATS_HEADER_LENGTH; + + //Service + Command ID + ar_mem_cpy(message_buffer, ATS_SERVICE_COMMAND_ID_LENGTH, + &service_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH); + + //Data Length + ar_mem_cpy(message_buffer + ATS_SERVICE_COMMAND_ID_LENGTH, ATS_DATA_LENGTH_LENGTH, + &resp_data_length, + ATS_DATA_LENGTH_LENGTH); + + //Status + ar_mem_cpy(message_buffer + ATS_HEADER_LENGTH, ATS_ERROR_CODE_LENGTH, + &ar_status_code, + ATS_ERROR_CODE_LENGTH); +} \ No newline at end of file diff --git a/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_dls_server.cpp b/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_dls_server.cpp new file mode 100644 index 0000000..aa71549 --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_dls_server.cpp @@ -0,0 +1,767 @@ +/** +*============================================================================= +* \file tcpip_gateway_dls_server.cpp +* \brief +* T C P I P G A T E W A Y D L S S E R V E R +* S O U R C E F I L E +* +* This file contains the TCPIP Gateway DLS Server implementation. +* +* This server listens for clients on on port 5560 and allows one +* connection per session. After establishing a connection the server will +* send dls messages containing log data to the client. The client must +* register log codeds to recievce log data. +* +* ATS_DATA_LOGGING must be defined in the build configuration to use +* this feature +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================= +*/ +#if defined(ATS_DATA_LOGGING) + +#include "tcpip_gateway_dls_server.h" +#include "tcpip_gateway_socket_util.h" +#include +#include + +#define IS_NULL(ptr) (ptr == NULL) + +#define TCPIP_THREAD_PRIORITY_HIGH 0 +#define TCPIP_THREAD_PRIORITY_LOW 1 +#define TCPIP_THD_STACK_SIZE 0xF4240 //1mb stack size + +#define TCPIP_DLS_SERVER_PORT 5560 +#define TCPIP_ATS_DLS_SERVER_PORT 5561 +#define MAX_TCPIP_CLIENTS_ALLOWED 1 + +/**< ATS TCPIP DLS Server(TRS) Log Tag */ +#define TCPIP_DLS_SRV_LOG_TAG "ATS-GTD" +#define TCPIP_DLS_ERR(...) AR_LOG_ERR(TCPIP_DLS_SRV_LOG_TAG, __VA_ARGS__) +#define TCPIP_DLS_DBG(...) AR_LOG_INFO(TCPIP_DLS_SRV_LOG_TAG, __VA_ARGS__)//AR_LOG_DEBUG +#define TCPIP_DLS_INFO(...) AR_LOG_INFO(TCPIP_DLS_SRV_LOG_TAG, __VA_ARGS__) + + +/* The name of the unix abstract domain socket used by the + * ATS Server to communicate with the gateway server */ +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_DLS "#AtsDlsServer" +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_DLS "#AtsGwDlsServer" + + /* The character length of the unix domain socket string + * including the null-terminating character */ +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_DLS_LENGTH 13 +#define ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_DLS_LENGTH 16 + +/* The byte position of the total log data size field in the DLS log data message packet */ +#define DLS_LOG_DATA_FIELD_TOTAL_SIZE_POSITION 8 +/* The byte size of the total log data size field in the DLS log data message packet */ +#define DLS_LOG_DATA_FIELD_TOTAL_SIZE_LENGTH 4 + +#define DLS_LOG_DATA_HEADER_LENGTH 12 + +typedef void* (TcpipGatewayDlsServer::* tcpip_dls_server_thread_callback)(void* args); +static tcpip_dls_server_thread_callback thd_cb_gw_dls_connect_routine = &TcpipGatewayDlsServer::connect_routine; +static tcpip_dls_server_thread_callback thd_cb_gw_dls_transmit_routine = &TcpipGatewayDlsServer::transmit_routine; + +/** +* \brief +* Helper function that retrieves the expected message length from the command request header +* +* \detdesc +* The message_buffer must be in the following format: +* The DLS log buffers are bundled to gether and sent to the ATS client in the format below: +* +* .+-- +================================+ +* | | 'A''R''T''M' | bytes: 4 +* | | ---------------------------- | +* Header-->| | Version | bytes: 2 +* | | # Log Packets | bytes: 2 +* .+-- | Log Data Size | bytes: 4 +* .+-- .--------------------------------. +* | | Log Packet #1 | +* | | ---------------------------- | +* | | Packet Size | bytes: 4 +* | | Packet Data [packet size] | bytes: Packet Size bytes +* | |--------------------------------| +* Log Data--> | : ... : +* | |--------------------------------| +* | | Log Packet #n | +* | | ---------------------------- | +* | | Packet Size | bytes: 4 +* | | Packet Data [packet size] | bytes: Packet Size bytes +* .+-- +.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~+ +* +* Note: the Log Data Size referes to the size of the data section (not including header +* size of 12 bytes) +* +* \dependencies +* None +* +* \param [in] message_buffer: The buffer containing the command request sent by the client +* \param [in] message_buffer_size: The length of the message buffer +* \param [in] data_length: The data length field in the command request header +* +* \return +* TRUE if successfully parsed and FALSE otherwise +*/ +static bool_t tgws_get_dls_log_data_length( + char_t* message_buffer, uint32_t message_buffer_size, uint32_t* data_length); + +void tgws_dls_get_client_address(uint16_t port, ar_socket_addr_storage_t* client_sock_addr); +void tgws_dls_get_server_address(uint16_t port, ar_socket_addr_storage_t* server_sock_addr); + +/* +============================================================================ + DLS TCPIP Server Implementation +============================================================================ +*/ + +TcpipGatewayDlsServer::TcpipGatewayDlsServer() + :is_connected{FALSE} +{ + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + //todo: do we want to set this as part of the gateway config? + str_pc_port = "5560"; + // ats_gateway IP CMD_PORT DLS_PORT + + server_socket_ptr = (ar_socket_t*)ar_heap_malloc(sizeof(ar_socket_t), &heap_inf); + client_socket_ptr = (ar_socket_t*)ar_heap_malloc(sizeof(ar_socket_t), &heap_inf); + ar_mem_set(server_socket_ptr, 0, sizeof(ar_socket_t)); + ar_mem_set(client_socket_ptr, 0, sizeof(ar_socket_t)); + + int32_t status = ar_osal_mutex_create(&connected_mutex); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to create mutex.", status); + } +} + +void TcpipGatewayDlsServer::set_ip_address(std::string address) +{ + str_ip_addr = address; +} + +int32_t TcpipGatewayDlsServer::start() +{ + int32_t status = AR_EOK; + std::string thd_name = "DLS_TCPIP_SVR"; + is_connected = FALSE; + TCPIP_DLS_INFO("Starting gateway dls tcpip server"); + + status = ar_osal_mutex_create(&connection_lock); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to create mutex for %s thread", status, thd_name.c_str()); + return status; + } + + ar_osal_thread_attr_t thd_attr = + { + (char_t*)thd_name.c_str(), + TCPIP_THD_STACK_SIZE, + TCPIP_THREAD_PRIORITY_HIGH, + }; + + ar_osal_thread_start_routine r = \ + (ar_osal_thread_start_routine)(connect); + + status = ar_osal_thread_create(&thread, &thd_attr, r, this); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to create thread %s", status, thd_name.c_str()); + return status; + } + + return status; +} + +int32_t TcpipGatewayDlsServer::stop() +{ + TCPIP_DLS_INFO("Is connected? value:%d 1= true, 0 = false", is_connected); + if (!is_connected) + return AR_EOK; + + //todo: add ar_socket_shutdown and call it here + //ar_socket_shutdown(accept_socket); + + TCPIP_DLS_INFO("Closing DLS TCPIP Server ..."); + int32_t status = ar_osal_thread_join_destroy(thread); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to destroy connection thread", status); + } + + is_connected = FALSE; + should_close_server = true; + ar_socket_close(accept_socket); + ar_osal_mutex_destroy(connection_lock); + + return AR_EOK; +} + +int32_t TcpipGatewayDlsServer::set_connected_lock(bool_t value) +{ + int32_t status = AR_EOK; + + status = ar_osal_mutex_lock(connection_lock); + if (AR_FAILED(status)) + { + return status; + } + + is_connected = value; + + status = ar_osal_mutex_lock(connection_lock); + if (AR_FAILED(status)) + { + return status; + } + + return status; +} + +void TcpipGatewayDlsServer::transmit(void* arg) +{ + TCPIP_DLS_ERR("Transmit routine callback..."); + TcpipGatewayDlsServer* gws = (TcpipGatewayDlsServer*)arg; + (gws->*thd_cb_gw_dls_transmit_routine)(NULL); +} + +void TcpipGatewayDlsServer::connect(void* arg) +{ + TcpipGatewayDlsServer* thread = (TcpipGatewayDlsServer*)arg; + (thread->*thd_cb_gw_dls_connect_routine)(NULL); +} + +void* TcpipGatewayDlsServer::connect_routine(void* arg) +{ + __UNREFERENCED_PARAM(arg); + + TCPIP_DLS_INFO("Starting gateway dls tcpip server"); + int status = 0; + int32_t thd_index = 0; + struct timeval timeout = { 0 }; + struct addrinfo socket_hints; + struct addrinfo* connected_devices_addr_info = NULL; + + // getaddrinfo() requires all fields in the addrinfo struct to be zeroed out + ar_mem_set(&socket_hints, 0, sizeof(socket_hints)); + + //sets hints to look for addresses that IPv4 and used for TCP/IP + socket_hints.ai_family = AF_INET; // IPv4 + socket_hints.ai_socktype = SOCK_STREAM; // TCP + socket_hints.ai_flags = AI_PASSIVE; //IP Wildcard + + //gets addrinfo structure for devices on port 5560 + + TCPIP_DLS_INFO("my address:%s:%s",str_ip_addr.c_str(), str_pc_port.c_str()); + + //set up USB listening thread on localhost + status = ar_socket_get_addr_info(str_ip_addr.c_str(), + str_pc_port.c_str(), + &socket_hints, + &connected_devices_addr_info); + + + //checks for errors getting the IP address + if (AR_FAILED(status) || connected_devices_addr_info == NULL) + { + return NULL; + } + + TCPIP_DLS_DBG("Host Info AI_FLAGS: %d", connected_devices_addr_info->ai_flags); + TCPIP_DLS_DBG("Host Info AI_FAMILY: %d", connected_devices_addr_info->ai_family); + TCPIP_DLS_DBG("Host Info AI_SOCKTYPE: %d", connected_devices_addr_info->ai_socktype); + TCPIP_DLS_DBG("Host Info AI_PROTOCOL: %d", connected_devices_addr_info->ai_protocol); + TCPIP_DLS_DBG("Host Info ADDRLEM: %u", connected_devices_addr_info->ai_addrlen); + TCPIP_DLS_DBG("Host Info AI_CANONNAME: %s", connected_devices_addr_info->ai_canonname); + + TCPIP_DLS_INFO("Setting up server..."); + //ar_socket_t listen_socket; + + //creates socket and references the socket using a file descriptor + status = ar_socket_tcp(&listen_socket); + + //Sets socket options allowing sockets to bind to a certain address + int32_t yes = 1; + status = ar_socket_set_options(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char_t*)&yes, sizeof(int32_t)); + if (status < 0) + { + TCPIP_DLS_ERR("Error[%d]: Unable to set socket options", status); + return 0; + } + + // timeout.tv_sec = TGWS_CONNECTION_TIMEOUT; + // ar_socket_set_options(listen_socket, SOL_SOCKET, SO_RCVTIMEO, (char_t*)&timeout, sizeof(struct timeval)); + + //binds IP address to socket + status = ar_socket_bind(listen_socket, + connected_devices_addr_info->ai_addr, + (int)connected_devices_addr_info->ai_addrlen); + + TCPIP_DLS_ERR("Listening for connections..."); + + //listens queue is of size 1 + status = ar_socket_listen(listen_socket, 1); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Listen failed. Closing server..."); + ar_socket_close(listen_socket); + return NULL; + } + TCPIP_DLS_ERR("after invoking ar_socket_listen"); + + //initializing mutex and setting up environment for threading + ar_osal_mutex_init(connected_mutex); + // set_connected_lock(FALSE); + + TCPIP_DLS_ERR("after invoking ar_osal_mutex_init"); + while (TRUE) + { + ar_socket_addr_storage_t their_addr; + socklen_t addr_size = sizeof(their_addr); + ar_socket_t client_socket_temp; + + TCPIP_DLS_ERR("Waiting to accept connections..."); + status = ar_socket_accept(listen_socket, (struct sockaddr*)&their_addr, &addr_size, &client_socket_temp); + + if (AR_FAILED(status)) + { + if (errno == EINTR) continue; + + ar_socket_addr_in_t* sin = (ar_socket_addr_in_t*)&their_addr; + //Converts binary to IPv4 string + char_t ip_addr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sin->sin_addr), ip_addr, INET_ADDRSTRLEN); + //TCPIP_DLS_ERR("Attempted Connection from: %s", ip_addr); + } + else + { + //do not create more threads if already connected. + ar_osal_mutex_lock(connected_mutex); + if (is_connected) + { + ar_osal_mutex_unlock(connected_mutex); + TCPIP_DLS_ERR("Detected a new connection request. Refusing..."); + ar_socket_close(client_socket_temp); + continue; + } + + is_connected = TRUE; + TCPIP_DLS_INFO("Accept successful to Gateway DLS Service: Client Socket %d", client_socket_temp); + // ar_osal_mutex_unlock(connected_mutex); + + timeout.tv_sec = TGWS_CONNECTION_TIMEOUT; + ar_socket_set_options(client_socket_temp, SOL_SOCKET, SO_RCVTIMEO, (char_t*)&timeout, sizeof(struct timeval)); + + *client_socket_ptr = client_socket_temp; + ar_socket_addr_in_t* sin = (ar_socket_addr_in_t*)&their_addr; + + //Converts binary to IPv4 string + char_t str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sin->sin_addr), str, INET_ADDRSTRLEN); + // TCPIP_DLS_INFO("Connection from: %s:%d", str, pc_port); + + //ar_socket_close(listen_socket); + status = connect_to_target_server(server_socket_ptr); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Unable to connect to intended server. Refusing client..."); + ar_socket_close(client_socket_temp); + continue; + } + + ar_osal_thread_t thd_transmit; + ar_osal_thread_start_routine routine = \ + (ar_osal_thread_start_routine)(transmit); + + std::string thd_name_tmp = "GWD_THD_" + std::to_string(thd_index); + char_t thd_name[21]; + ar_strcpy(thd_name, 21, thd_name_tmp.c_str(), thd_name_tmp.length() + 1); + ar_osal_thread_attr_t thd_attr = \ + { + thd_name, + TGWS_THD_STACK_SIZE, + TGWS_THREAD_PRIORITY_HIGH + }; + + status = ar_osal_thread_create(&thd_transmit, &thd_attr, routine, this); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Failed to create data transmission thread."); + break; + } + + + /* Only one client is allowed to connect to the server for now. + * Block until client calls QUIT on transmission thread. + * Allow 200 msec sleep for thd_transmit to aquire connection_lock*/ + //Sleep(200); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + ar_osal_mutex_lock(connected_mutex); + + TCPIP_DLS_DBG("Error[%d]: Waiting for thread %s to complete", status, thd_name); + status = ar_osal_thread_join_destroy(thd_transmit); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to join usb thread", status); + } + TCPIP_DLS_DBG("Error[%d]: Thread %s destroyed", status, thd_name); + } + } + + TCPIP_DLS_INFO("Ending connect routine."); + ar_socket_close(*client_socket_ptr); + ar_socket_close(*server_socket_ptr); + return 0; +} + +void* TcpipGatewayDlsServer::transmit_routine(void* arg) +{ + __UNREFERENCED_PARAM(arg); + // ar_osal_mutex_lock(connected_mutex); + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + TCPIP_DLS_DBG("Begin message forwarding"); + + /*todo: Note on Supporting multiple connections + * If we decide to support multiple device connections, the buffers need to be added + * to an array and each thread needs to pick its associated buffer we can do this + * after testing with 1 connection + */ + message_buffer.buffer_size = TGWS_MAX_MESSAGE_BUFFER_SIZE; + recieve_buffer.buffer_size = TGWS_RECIEVE_BUFFER_SIZE; + + message_buffer.buffer = (char_t*)ar_heap_malloc(message_buffer.buffer_size, &heap_inf); + if (NULL == message_buffer.buffer) + { + TCPIP_DLS_ERR("Error[%d]: Failed to allocate memory for message buffer", AR_ENOMEMORY); + return NULL; + } + + recieve_buffer.buffer = (char_t*)ar_heap_malloc(recieve_buffer.buffer_size, &heap_inf); + if (NULL == recieve_buffer.buffer) + { + ar_heap_free(message_buffer.buffer, &heap_inf); + TCPIP_DLS_ERR("Error[%d]: Failed to allocate memory for recieve buffer", AR_ENOMEMORY); + return NULL; + } + + /* this loop will run once per ENTIRE message received. + * keep listening for whole incoming messages + */ + while (true) + { + tgws_status_codes_t status_code = TGWS_E_SUCCESS; + + /* Forward responses from CMD Server to Gateway Client */ + tcp_forward( + /* from server */ server_socket_ptr, + /* to client */ client_socket_ptr, + &message_buffer, &recieve_buffer, false, status_code); + if (TGWS_E_END_MSG_FWD == status_code) + break; + } + + ar_socket_close(*client_socket_ptr); + ar_socket_close(*server_socket_ptr); + ar_heap_free(message_buffer.buffer, &heap_inf); + ar_heap_free(recieve_buffer.buffer, &heap_inf); + + TCPIP_DLS_DBG("End message forwarding"); + + is_connected = FALSE; + // ar_osal_mutex_unlock(connected_mutex); + return NULL; +} + +void TcpipGatewayDlsServer::tcp_forward( + ar_socket_t* sender_socket_ptr, ar_socket_t* receiver_socket_ptr, + buffer_t* gateway_message_buf, buffer_t* gateway_recv_buf, + bool_t is_cmd_request, tgws_status_codes_t& agws_status_code) +{ + int32_t status = AR_EOK; + ar_socket_t sender_socket = *sender_socket_ptr; + ar_socket_t receiver_socket = *receiver_socket_ptr; + uint32_t header_bytes_read = 0; + uint32_t message_length = 0; + uint32_t msg_offset = 0; + int32_t bytes_sent = 0; + int32_t bytes_read = 0; + + ar_mem_set(gateway_message_buf->buffer, 0, gateway_message_buf->buffer_size); + ar_mem_set(gateway_recv_buf->buffer, 0, gateway_recv_buf->buffer_size); + + //This loop will run as many times as to receive full message header (should be just once) + while (TRUE) + { + bytes_read = 0; + bytes_sent = 0; + status = AR_EOK; + + TCPIP_DLS_DBG("Receiving..."); + + status = ar_socket_recv( + sender_socket, + gateway_recv_buf->buffer, + DLS_LOG_DATA_HEADER_LENGTH - header_bytes_read, + 0, &bytes_read); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Recieve failed. Data of %d bytes received.", bytes_read); + } + + //client sends "QUIT" to signal end of connection. At that point, close socket and return. + if (ar_strcmp(gateway_recv_buf->buffer, "QUIT", 4) == 0) + { + ar_socket_send(receiver_socket, "QUIT", 4, 0, &bytes_sent); + TCPIP_DLS_ERR("Quitting"); + ar_socket_close(receiver_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + + if (bytes_read <= 0) + { + /*recv(...) returned -1 or 0 + * -1 - indicates an error so we need to check errno (error number) + * 0 - the client sent 0 or the connection was closed. Check + * recv(...) documentation for addition info + */ + if (AR_SOCKET_LAST_ERROR == EINTR) continue; + + TCPIP_DLS_INFO("Failed to recieve data from client"); + ar_socket_close(sender_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + else if (bytes_read == 0) + { + TCPIP_DLS_INFO("Client shutdown socket. Closing connection..."); + ar_socket_close(sender_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + + TCPIP_DLS_ERR("Data of %d bytes received.", bytes_read); + header_bytes_read += bytes_read; + + //this determines how many bytes to expect (thus determining how many times to loop). + if (tgws_get_dls_log_data_length(gateway_recv_buf->buffer, header_bytes_read, &message_length)) + { + TCPIP_DLS_DBG("Message with length: %d received.", message_length); + ar_mem_cpy( + gateway_message_buf->buffer, DLS_LOG_DATA_HEADER_LENGTH, + gateway_recv_buf->buffer, DLS_LOG_DATA_HEADER_LENGTH); + msg_offset += DLS_LOG_DATA_HEADER_LENGTH; + break; + } + } + + if (message_length > message_buffer.buffer_size) + { + /* We reject messages that are larger that what we can store in our message buffer */ + TCPIP_DLS_DBG("Error[%d]: Not enough memory to store incoming message of %d bytes. " + "Use resize buffer command update the max buffer size", AR_ENEEDMORE, message_length); + status = AR_ENEEDMORE; + agws_status_code = TGWS_E_IGNORE_MSG_FWD; + goto tcp_forward_end; + } + + //this loop will receive max bufsize bytes each iteration, looping until it receives full message + msg_offset = 0; + while (message_length != 0) + { + if (msg_offset > message_length) + { + TCPIP_DLS_ERR("read more than message length...corruption"); + ar_socket_close(sender_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + + //will receive min(bufsize, bytes left to receive to complete message) + uint32_t recv_buf_size = gateway_recv_buf->buffer_size;//AGWS_RECV_BUF_SIZE; + int32_t bytes_read = 0; + + int32_t bytes_remaining = message_length - msg_offset < recv_buf_size ? message_length - msg_offset : recv_buf_size; + ar_socket_recv( + sender_socket, + gateway_recv_buf->buffer, + bytes_remaining, + 0, &bytes_read); + + if (bytes_read <= 0) + { + if (AR_SOCKET_LAST_ERROR == EINTR) + { + TCPIP_DLS_ERR("Signal Interrupt. Continuing..."); + continue; + } + TCPIP_DLS_ERR("failed to recieve data from client"); + ar_socket_close(sender_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + + TCPIP_DLS_ERR("msg offset: %d bytes", msg_offset); + ar_mem_cpy( + gateway_message_buf->buffer + DLS_LOG_DATA_HEADER_LENGTH + msg_offset, bytes_read, + gateway_recv_buf->buffer, bytes_read); + msg_offset += bytes_read; + + if (msg_offset == message_length) + break; + } + + //The total message length is DLS Log Data Header + Total Log Data Size + message_length += DLS_LOG_DATA_HEADER_LENGTH; + TCPIP_DLS_DBG("*** Full message received [%d bytes]***", message_length); + TCPIP_DLS_DBG("message offset = %d", msg_offset); + TCPIP_DLS_DBG("message buffer [0-8] = \n%08x %08x %08x %08x\n%08x %08x %08x %08x", + *((uint32_t*)gateway_message_buf->buffer + 0), + *((uint32_t*)gateway_message_buf->buffer + 1), + *((uint32_t*)gateway_message_buf->buffer + 2), + *((uint32_t*)gateway_message_buf->buffer + 3), + *((uint32_t*)gateway_message_buf->buffer + 4), + *((uint32_t*)gateway_message_buf->buffer + 5), + *((uint32_t*)gateway_message_buf->buffer + 6), + *((uint32_t*)gateway_message_buf->buffer + 7) + ); + +tcp_forward_end: + + if (agws_status_code == TGWS_E_IGNORE_MSG_FWD) + { + if (message_length == 0) + { + agws_status_code = TGWS_E_END_MSG_FWD; + return; + } + TCPIP_DLS_DBG("Returning err message of length: %d to client", message_length); + } + + status = ar_socket_send( + receiver_socket, + gateway_message_buf->buffer, + message_length, 0, &bytes_sent); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to send message to client"); + ar_socket_close(receiver_socket); + agws_status_code = TGWS_E_END_MSG_FWD; + } +} + + +int32_t TcpipGatewayDlsServer::connect_to_target_server(ar_socket_t* server_socket) +{ + int32_t status = AR_EOK; + uint32_t client_addr_length = 0; + uint32_t server_addr_length = 0; + ar_socket_addr_storage_t client_sockaddr = { 0 }; + ar_socket_addr_storage_t server_sockaddr = { 0 }; + +// #if defined (__linux__) +// if (AR_FAILED(ar_socket_unix(server_socket))) +// return AR_EFAILED; +// client_addr_length = ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_DLS_LENGTH +// + sizeof(uint16_t); +// server_addr_length = ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_DLS_LENGTH +// + sizeof(uint16_t); +// #elif defined (_WIN32) +// if (AR_FAILED(ar_socket_tcp(server_socket))) +// return AR_EFAILED; +// client_addr_length = sizeof(ar_socket_addr_in_t); +// server_addr_length = sizeof(ar_socket_addr_in_t); +// #endif + // ar_socket_addr_storage_t client_sockaddr = { 0 }; + // ar_socket_addr_storage_t server_sockaddr = { 0 }; + // tgws_dls_get_client_address(TCPIP_DLS_SERVER_PORT /*pc_port*/, &client_sockaddr); + // tgws_dls_get_server_address(TCPIP_ATS_DLS_SERVER_PORT, &server_sockaddr); + + tgws_util_create_socket(server_socket); + + //Get Client address and address length (this gateway dls server) + tgws_util_get_socket_address(TGWS_ADDRESS_UNIX_ABSTRACT_DOMAIN, ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_DLS, TCPIP_DLS_SERVER_PORT, &client_sockaddr); + client_addr_length = tgws_util_get_socket_address_length(tgws_get_address_type(), ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_GATEWAY_DLS); + + //Get ATS Service address and address length + server_addr_length = tgws_util_get_socket_address_length(tgws_get_address_type(), ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_DLS); + tgws_util_get_socket_address(TGWS_ADDRESS_UNIX_ABSTRACT_DOMAIN, ATS_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_ATS_DLS, TCPIP_ATS_DLS_SERVER_PORT, &server_sockaddr); + + /* Bind to client address to the Gateway Server socket */ + client_addr_length = sizeof(ar_socket_addr_in_t); + status = ar_socket_bind( + *server_socket, + (ar_socket_addr_t*)&client_sockaddr, + client_addr_length);// This is size of ar_socket_addr_un_t::sun_family + if (AR_FAILED(status)) + { + TCPIP_DLS_DBG("Unable to bind client address to gateway dls server socket"); + ar_socket_close(*server_socket); + return AR_EFAILED; + } + + /* Connect dls gateway server to dls server socket */ + TCPIP_DLS_DBG("Attempting to connect to dls gateway server..."); + client_addr_length = sizeof(server_sockaddr); + status = ar_socket_connect( + *server_socket, + (ar_socket_addr_t*)&server_sockaddr, + server_addr_length); // This is size of ar_socket_addr_un_t::sun_family + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to connect to dls server"); + ar_socket_close(*server_socket); + return AR_EFAILED; + } + + TCPIP_DLS_INFO("Connected to dls server"); + return status; +} + +/* +============================================================================ + Helper Functions +============================================================================ +*/ + +static bool_t tgws_get_dls_log_data_length( + char_t* message_buffer, uint32_t message_buffer_size, uint32_t* data_length) +{ + if (IS_NULL(message_buffer) || IS_NULL(data_length)) + { + TCPIP_DLS_ERR("Error[%d]: Input parameter is null", AR_EBADPARAM); + return FALSE; + } + + if (message_buffer_size < DLS_LOG_DATA_HEADER_LENGTH) + { + TCPIP_DLS_ERR("Error[%d]: Message buffer is smaller than request header format length", AR_ENEEDMORE); + return FALSE; + } + + /** copy data length*/ + tgws_mem_cpy( + data_length, DLS_LOG_DATA_FIELD_TOTAL_SIZE_LENGTH, + message_buffer + DLS_LOG_DATA_FIELD_TOTAL_SIZE_POSITION, DLS_LOG_DATA_FIELD_TOTAL_SIZE_LENGTH); + + return TRUE; +} + +#endif /*ATS_DATA_LOGGING*/ diff --git a/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_main.cpp b/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_main.cpp new file mode 100644 index 0000000..3a30189 --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_main.cpp @@ -0,0 +1,61 @@ +/** +*============================================================================= +* \file tcpip_gateway_main.cpp +* +* T C P I P G A T E W A Y M A I N +* S O U R C E F I L E +* +* \brief +* The main entry point for the Gateway Server application +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================= +*/ +#include +#include "tcpip_gateway_cmd_server.h" + +int32_t g_pc_port = TGWS_DEFAULT_PORT; + +/** +* \brief +* Only one client can be connected to this target at a time. The use of a mutex +* ensures this. This includes both types of Listening Threads (WiFi and USB). +* +* \depends +* Intended server on Target must already be started +* +* \param[in] argc: 2 input arguments. Arg1 =?? Arg2 = PC Port +* \param[in] argv: list of input arguments. +* +* \return 0 on successful completion, or negative number on failure +* negative number refers to type of failure +*/ +int main(int argc, char *argv[]) +{ + int32_t status = AR_EOK; + std::string pc_port = ""; + std::string ip_addr = TGWS_DEFAULT_IP_ADDRESS; + + GATEWAY_ERR("Inside gateway main");//DEBUG + if (argc == 2) + { + pc_port = argv[1]; + GATEWAY_INFO("Specified IP: %s, Port: %s", ip_addr.c_str(), pc_port.c_str()); + size_t index = 0; + g_pc_port = std::stoi(pc_port, &index); + } else if (argc == 3) + { + ip_addr = argv[1]; + pc_port = argv[2]; + GATEWAY_INFO("Specified IP: %s, Port: %s", ip_addr.c_str(), pc_port.c_str()); + } + + /* TODO: For now only gateway over USB is supported until we can make + * WIFI support cross-platform friendly */ + TcpipGatewayServer gs{ ip_addr, pc_port , TGWS_CONNECTION_OPTION_USB }; + status = gs.run(); + + return status; +} diff --git a/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_socket_util.cpp b/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_socket_util.cpp new file mode 100644 index 0000000..8e884da --- /dev/null +++ b/acdb/ats/transports/tcpip_gateway/src/tcpip_gateway_socket_util.cpp @@ -0,0 +1,87 @@ +/** +*============================================================================== +* \file tcpip_gateway_socket_util.cpp +* \brief +* T C P I P G A T E W A Y S O C K E T U T I L I T Y +* H E A D E R F I L E +* +* Contains utility functions to simplify socket creation in the +* server sources files +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================== +*/ +#include "ar_osal_mem_op.h" +#include "tcpip_gateway_socket_util.h" + +tgws_util_address_type_t tgws_get_address_type() +{ +#if defined (__linux__) + return TGWS_ADDRESS_UNIX_ABSTRACT_DOMAIN; +#elif defined (_WIN32) + return TGWS_ADDRESS_TCPIP; +#endif +} + +uint32_t tgws_util_get_socket_address_length(tgws_util_address_type_t address_type, std::string address) +{ + uint32_t address_length = 0; + switch(address_type) + { + case TGWS_ADDRESS_UNIX_ABSTRACT_DOMAIN: + { + //see ar_sockaddr_un_t + address_length = sizeof(uint16_t) + address.length(); + break; + } + case TGWS_ADDRESS_TCPIP: + { + address_length = sizeof(ar_socket_addr_in_t); + break; + } + } + + return address_length; +} + +uint32_t tgws_util_create_socket(ar_socket_t* socket) +{ +#if defined (__linux__) + if (AR_FAILED(ar_socket_unix(socket))) + return AR_EFAILED; +#elif defined (_WIN32) + if (AR_FAILED(ar_socket_tcp(socket))) + return AR_EFAILED; +#endif + return AR_EOK; +} + +void tgws_util_get_socket_address(tgws_util_address_type_t address_type, std::string address, uint16_t port, ar_socket_addr_storage_t* socket_address) +{ + switch(address_type) + { + case TGWS_ADDRESS_UNIX_ABSTRACT_DOMAIN: + { + #if defined(__linux__) + //Create Abstract Domain Address + ar_socket_addr_un_t* un_abstract_sock_addr = + (ar_socket_addr_un_t*)socket_address; + ar_strcpy(un_abstract_sock_addr->sun_path, AR_UNIX_PATH_MAX, address.c_str(), address.length()); + un_abstract_sock_addr->sun_family = AF_UNIX; + un_abstract_sock_addr->sun_path[0] = 0; + #endif + break; + } + case TGWS_ADDRESS_TCPIP: + { + ar_socket_addr_in_t ip_sock_addr = { 0 }; + ip_sock_addr.sin_family = AF_INET; + ip_sock_addr.sin_port = htons(port); + inet_pton(AF_INET, address.c_str(), &ip_sock_addr.sin_addr.s_addr); + ar_mem_cpy(socket_address, sizeof(ar_socket_addr_storage_t), &ip_sock_addr, sizeof(ar_socket_addr_in_t)); + break; + } + } +} diff --git a/acdb/ats/transports/tcpip_server/api/tcpip_server_api.h b/acdb/ats/transports/tcpip_server/api/tcpip_server_api.h new file mode 100644 index 0000000..5fbfd9c --- /dev/null +++ b/acdb/ats/transports/tcpip_server/api/tcpip_server_api.h @@ -0,0 +1,104 @@ +#ifndef _TCPIP_SERVER_API_H_ +#define _TCPIP_SERVER_API_H_ +/** +*============================================================================= +* \file tcpip_server_api.h +* \brief +* T C P I P S E R V E R A P I +* H E A D E R F I L E +* +* This file contains the TCP/IP server API definitions used to host +* connections to QACT. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ar_osal_mutex.h" +#include "ar_osal_error.h" +#include "ar_osal_thread.h" +#include "ats_common.h" +#include "acdb_utility.h" + +#ifdef __cplusplus +extern "C"{ +#endif /*__cplusplus*/ + +#ifdef ATS_TRANSPORT_TCPIP + typedef struct tcpip_cmd_server_context { + void(*ats_cb)(uint8_t* req, uint32_t req_len, uint8_t** resp, uint32_t* resp_len); + } tcpip_cmd_server_context; + +/** +* \brief +* Initializes the ATS TCP/IP Command server +* +* \detdesc +* Entry function to start ats_server threads +* ats_server will start a listening thread on a local IP address on the +* designated port. +* ats communicates with the Gateway Server for any connection to external clients +* +* Note: Only one client can be connected to this target at a time. The use of a mutex +* ensures this. +* +* \param [in] ats_cb: A callback to ats_exectue_command +* +* \return +* 0 on success, non-zero on failure +*/ +int32_t tcpip_cmd_server_init(void(*ats_cb)(uint8_t *buf, uint32_t buf_len, uint8_t **resp, uint32_t *resp_len)); + +/** +* \brief +* De-initializes the ATS TCP/IP server +* +* \detdesc +* Releases threading and memory resources aquired during tcpip_cmd_server_init +* +* Note: Only one client can be connected to this target at a time. The use of a mutex +* ensures this. +* +* \return +* 0 on success, non-zero on failure +*/ + +/** +* \brief tcpip_cmd_server_deinit +* Stops ats_server threads. +* +* \return 0 on success, non-zero on failure +*/ +int32_t tcpip_cmd_server_deinit(void); + + +/** + \brief + Sends log buffers from the ATS DLS service to ATS Tcpip clients that are connected to the DLS server + + \detdesc + Log packet data is sent on a port separate from the command/response packets. + + \dependencies + DLS support must be enabled in the build to successfully forward log data to clients + + \param [in] buffer: logging buffer populated by ats dls service layer + \param [in] buffer_size: size of the log data buffer in bytes +*/ +int32_t tcpip_cmd_server_send_dls_log_data(const uint8_t* buffer, uint32_t buffer_size); + + +#endif /*ATS_TRANSPORT_TCPIP*/ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*_TCPIP_SERVER_API_H_*/ + diff --git a/acdb/ats/transports/tcpip_server/inc/tcpip_cmd_server.h b/acdb/ats/transports/tcpip_server/inc/tcpip_cmd_server.h new file mode 100644 index 0000000..16797d7 --- /dev/null +++ b/acdb/ats/transports/tcpip_server/inc/tcpip_cmd_server.h @@ -0,0 +1,199 @@ +#ifndef _TCPIP_CMD_SERVER_H_ +#define _TCPIP_CMD_SERVER_H_ +/** +*============================================================================= +* \file tcpip_cmd_server.h +* \brief +* T C P I P C M D S E R V E R +* H E A D E R F I L E +* +* This file contains the TCP/IP server implementation to host connections +* to QACT. +* This file first sets up a listening socket on port 5558. Upon accepting +* new connections, the server creates new receiving threads that handles +* all ATS upcalls. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================= +*/ + +#ifdef ATS_TRANSPORT_TCPIP + +#include +#include "ar_osal_mutex.h" +#include "ar_osal_error.h" +#include "ar_osal_thread.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" + +#include "ats_i.h" +#include "tcpip_dls_server.h" + +//#if defined(__linux__) +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#endif + +#define TCPIP_CMD_SERVER_RECV_BUFFER_SIZE (ATS_1_KB * 32UL) +#define TCPIP_CMD_SERVER_MIN_MSG_BUFFER_SIZE (ATS_1_KB * 32UL) +#define TCPIP_CMD_SERVER_MAX_MSG_BUFFER_SIZE 0x200000ul //2MB max size +#define TCPIP_CMD_SERVER_ADDRESS "127.0.0.1" //local host +#define TCPIP_CMD_SERVER_PORT 5559 + +typedef void(*ATS_EXECUTE_CALLBACK) ( + uint8_t* req, uint32_t req_len, + uint8_t** resp, uint32_t* resp_len); + +struct buffer_t { + uint32_t buffer_size; + char_t* buffer; +}; + +class TcpipServer; + +class TcpipCmdServer +{ +public: + std::string thd_name; + ar_osal_thread_t thd_connection_routine; + ar_osal_thread_start_routine routine; + uint16_t port; + std::string address; + ar_socket_t listen_socket; + ar_socket_t accept_socket; + ATS_EXECUTE_CALLBACK execute_command; + +private: + uint8_t is_connected; + bool_t is_aborted; + bool_t should_close_server; + ar_osal_mutex_t connection_lock; + buffer_t message_buffer; + buffer_t recieve_buffer; + + /*------------------------- Server Commands -------------------------*/ + + const std::string ATS_SERVER_CMD_QUIT = "QUIT"; + + +#ifdef ATS_DATA_LOGGING +private: + + TcpipDlsServer _dls_server; +#endif + +public: + + int32_t send_dls_log_buffers(const char_t* buffer, uint32_t buffer_size); + +public: + + TcpipCmdServer(std::string thd_name); + + /** + * \brief + * Starts the server by initializing locks and launches the connection routine thread + * + * \param [in] args: Optional arguments. Unused for now. + * + * \return Returns AR_EOK on success and non-zero on failure + */ + int32_t start(void *args); + + /** + * \brief + * Stops the server and releases all resources. This API is blocking since + * it needs to wait until the connection routine thread exists + * \return Returns AR_EOK on success and non-zero on failure + */ + int32_t stop(); + + /** + * \brief + * Listens for incoming clients and starts the data transmission thread after a client connects + * + * \detdesc + * Creates the listening socket on 5559 and accepts incoming connections. + * Upon accepting a new connection, a thread called recv_thread_proc is + * created to handle transmitting(send/recieve) data to client. + * + * \dependencies + * None + * + * \param [in] thread_param: Parameters to be used within the thread routine + */ + void *connect_routine(void *args); + + /** + * \brief + * Routine for transmitting data between ATS and its client(s) + * + * \detdesc + * Thread process that is created to handle 2 way message sending between server and client + * + * \param [in] args: This is unused + */ + void *transmit_routine(void *args); + +private: + + int32_t set_connected_lock(uint8_t is_conn); + + static void connect(void* arg); + + static void transmit(void* arg); + + int32_t recv_message_header(char_t *msgBuf, uint32_t msgbuflen, + char_t *recvbuf, uint32_t recvbuflen, uint32_t &msg_len); + + int32_t recv_message(char_t *msgBuf, uint32_t msgbuflen, + char_t *recvbuf, uint32_t recvbuflen, uint32_t msg_len); + + int32_t process_message( + char_t *msgBuf, uint32_t msgbuflen, uint32_t msg_len, + char_t **out_buf, uint32_t out_buf_len, uint32_t &resp_len); + + int32_t send_message(char_t *buf, uint32_t buf_len, uint32_t msg_len); + + int32_t execute_server_command(uint32_t service_cmd_id, uint32_t message_length); + + void start_dls_server(); + + void stop_dls_server(); +}; + +class TcpipServer +{ +private: + //Server Thread Properties + + const std::string THREAD_NAME_ATS_LISTENER = "ATS_THD_LISTENER"; + const std::string THREAD_NAME_ATS_DLS_LISTENER = "ATS_DLS_THD_LISTENER"; + const std::string THREAD_NAME_ATS_TRANSMIT = "ATS_THD_TRANSMIT"; + + TcpipCmdServer cmd_server; + +public: + TcpipServer(); + + ~TcpipServer(); + + int32_t start(ATS_EXECUTE_CALLBACK cb); + + int32_t stop(); + + int32_t send_dls_log_buffers(const uint8_t* buffer, uint32_t buffer_size); +}; + +#endif /*ATS_TRANSPORT_TCPIP*/ + +#endif /*_TCPIP_CMD_SERVER_H_*/ + diff --git a/acdb/ats/transports/tcpip_server/inc/tcpip_dls_server.h b/acdb/ats/transports/tcpip_server/inc/tcpip_dls_server.h new file mode 100644 index 0000000..61844dd --- /dev/null +++ b/acdb/ats/transports/tcpip_server/inc/tcpip_dls_server.h @@ -0,0 +1,75 @@ +#ifndef _TCPIP_DLS_SERVER_H_ +#define _TCPIP_DLS_SERVER_H_ +/** +*============================================================================= +* \file tcpip_dls_server.h +* \brief +* T C P I P D L S S E R V E R +* H E A D E R F I L E +* +* This file contains the TCP/IP server implementation to host connections +* to QACT. +* This file first sets up a listening socket on port 5558. Upon accepting +* new connections, the server creates new receiving threads that handles +* all ATS upcalls. +* +* ATS_DATA_LOGGING must be defined in the build configuration to use +* this feature +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================= +*/ +#ifdef ATS_TRANSPORT_TCPIP +#ifdef ATS_DATA_LOGGING + +#include +#include "ar_osal_types.h" +#include "ar_osal_error.h" +#include "ar_osal_thread.h" +#include "ar_osal_mutex.h" +#include "ar_osal_log.h" +#include "ar_sockets_api.h" +#include "tcpip_socket_util.h" + +#define TCPIP_THREAD_PRIORITY_HIGH 0 +#define TCPIP_THREAD_PRIORITY_LOW 1 +#define TCPIP_THD_STACK_SIZE 0xF4240 //1mb stack size + +#define TCPIP_DLS_SERVER_PORT 5561 + +class TcpipDlsServer +{ +public: + std::string address; + uint16_t port; +private: + uint8_t is_connected; + bool_t should_close_server; + ar_socket_t accept_socket; + ar_osal_mutex_t connection_lock; + ar_osal_thread_t thread; +public: + TcpipDlsServer() = default; + TcpipDlsServer(std::string thd_name); + int32_t start(); + int32_t stop(); + + void* connect_routine(void* args); + + /* \brief + * Sends DLS log buffers to the client + * param[in] buffer: a data buffer containing the DLS packet data + * param[in] buffer: The size of the buffer containing the DLS packet data + */ + int32_t send_dls_log_buffers(const char_t* buffer, uint32_t buffer_size); + +private: + int32_t set_connected_lock(uint8_t is_conn); + + static void connect(void* arg); +}; + +#endif /*ATS_DATA_LOGGING*/ +#endif /*ATS_TRANSPORT_TCPIP*/ +#endif /* _TCPIP_DLS_SERVER_H_ */ diff --git a/acdb/ats/transports/tcpip_server/inc/tcpip_socket_util.h b/acdb/ats/transports/tcpip_server/inc/tcpip_socket_util.h new file mode 100644 index 0000000..538698a --- /dev/null +++ b/acdb/ats/transports/tcpip_server/inc/tcpip_socket_util.h @@ -0,0 +1,100 @@ +#ifndef _TCPIP_SOCKET_UTIL_H_ +#define _TCPIP_SOCKET_UTIL_H_ +/** +*============================================================================= +* \file tcpip_socket_util.h +* \brief +* T C P I P S O C K E T U T I L I T Y +* H E A D E R F I L E +* +* This a utility class that encapsulates socket creation and socket connection +* for the ATS tcpip server +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#ifdef ATS_TRANSPORT_TCPIP +/*------------------------------------------ +* Includes +*------------------------------------------*/ +#include "ar_osal_error.h" +#include "ats_common.h" +#include "ar_sockets_api.h" +#include + +/**< The path containing the socket file on a linux file system */ +//#define SOCK_PATH "/vendor/app/GatewayServer/ats_sockets"; +/**< The socket file used for restricting access to the socket. Permissions + * must be enabled for the socket file to allow the TCPIP Gateway to establish + * a connection with the Tcpip CMD/RSP Server. + * Commented out for now if required later. + */ +//#define SOCK_PATH_SERVER "/vendor/app/GatewayServer/ats_sockets/unix_sock.server"; + +#ifdef __cplusplus +extern "C"{ +#endif + +typedef enum tcpip_server_type_t +{ + /**< Command Response Server Type */ + TCPIP_SERVER_TYPE_CMD = 0, + /**< Data Logging Service Server Type */ + TCPIP_SERVER_TYPE_DLS = 1, +}tcpip_server_type_t; + +/** +* \brief +* Creates a server listening socket based on the address family. +* +* \detdesc +* Setting the address familty to AF_INET will create a TCPIP socket using an IP address +* Setting the address family to AF_UNIX will create and abstract domain socket to communicate with the Gateway Server (only on linux) +* +* \param [in] server_type: The type of server to create a socket for +* \param [in] address_family: AF_INET or AF_UNIX +* \param [in] address_string: an IP string when using AF_INET or a Unix Domain Socket name starting with # when using AF_UNIX +* \param [in] gateway_port: The port to connect to. Only used with AF_INET +* \param [out] listen_socket: The socket used to listen for clients +* +* \return +* 0 on success and populates listen_socket, non-zero on failure +*/ +int32_t tcpip_socket_util_create_socket( + tcpip_server_type_t server_type, + ar_address_family_t address_family, + std::string address, + uint16_t gateway_port, + ar_socket_t* listen_socket); + +/** +* \brief +* Creates an accept socket after successfully listening and accepting a new client connection +* +* \detdesc +* Setting the address familty to AF_INET will create a TCPIP socket using an IP address +* Setting the address family to AF_UNIX will create and abstract domain socket to communicate with the Gateway Server (only on linux) +* +* \param [in] address_family: AF_INET or AF_UNIX +* \param [in] listen_socket: The socket used to listen for clients +* \param [out] accept_socket: The a socket used to listen for clients +* +* \return +* 0 on success and populates accept_socket, non-zero on failure +*/ +int32_t tcpip_socket_util_accept_connections( + ar_address_family_t address_family, + ar_socket_t listen_socket, + ar_socket_t* accept_socket); + +#ifdef __cplusplus +} +#endif + +#endif /*ATS_TRANSPORT_TCPIP*/ +#endif /*_TCPIP_SOCKET_UTIL_H_*/ + diff --git a/acdb/ats/transports/tcpip_server/src/tcpip_cmd_server.cpp b/acdb/ats/transports/tcpip_server/src/tcpip_cmd_server.cpp new file mode 100644 index 0000000..44d6614 --- /dev/null +++ b/acdb/ats/transports/tcpip_server/src/tcpip_cmd_server.cpp @@ -0,0 +1,947 @@ +/** +*============================================================================= +* \file tcpip_cmd_server.cpp +* \brief +* A T S T C P I P C M D S E R V E R +* S O U R C E F I L E +* +* This file contains the TCP/IP server implementation to host connections +* to QACT. +* This file first sets up a listening socket on port 5558. Upon accepting +* new connections, the server creates new receiving threads that handles +* all ATS upcalls. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================= +*/ +#ifdef ATS_TRANSPORT_TCPIP +#include +#include +#include "tcpip_socket_util.h" +#include "tcpip_dls_server.h" +#include "tcpip_server_api.h" +#include "tcpip_cmd_server.h" +#include "ar_osal_log.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_string.h" +#include "ar_osal_heap.h" +#include "ar_sockets_api.h" + +/**< ATS TCPIP CMD Server(TCS) Log Tag */ +#define TCPIP_CMD_SRV_LOG_TAG "ATS-TCS" +#define TCPIP_CMD_SVR_ERR(...) AR_LOG_ERR(TCPIP_CMD_SRV_LOG_TAG, __VA_ARGS__) +#define TCPIP_CMD_SVR_DBG(...) AR_LOG_DEBUG(TCPIP_CMD_SRV_LOG_TAG, __VA_ARGS__) +#define TCPIP_CMD_SVR_INFO(...) AR_LOG_INFO(TCPIP_CMD_SRV_LOG_TAG, __VA_ARGS__) + +/**< The maximum number of clients that can connect to the command server*/ +#define MAX_TCPIP_CLIENTS_ALLOWED 1 +/**< The name of the listening thread */ +#define TCPIP_THREAD_LISTENER "ATS_THD_LISTENER" +/**< The name of the data transmission thread */ +#define TCPIP_THREAD_TRANSMIT "ATS_THD_TRANSMIT" +/**< The size of the stack used by the threads created by the server */ +#define TCPIP_THD_STACK_SIZE 0xF4240 //1mb stack size +/**< Indicates a high thread priority when creating a thread */ +#define TCPIP_THREAD_PRIORITY_HIGH 0 +/**< Indicates a low thread priority when creating a thread */ +#define TCPIP_THREAD_PRIORITY_LOW 1 + +typedef void *(TcpipCmdServer::*cmd_server_thread_callback)(void* args); +static cmd_server_thread_callback thd_cb_connect_routine = &TcpipCmdServer::connect_routine; +static cmd_server_thread_callback thd_cb_transmit_routine = &TcpipCmdServer::transmit_routine; + +/**< Instantiate a global static instance of the server for the duration of the appliation */ +static TcpipServer server; + +/* +============================================================================ + Forward Declarations +============================================================================ +*/ + +/** +* \brief +* Helper function that retrieves the expected message length from the command request header +* +* \detdesc +* The message_buffer must be in the following format: +* <--------- 4 bytes -----------> +* +-----------------------------+ +* | service id | command id | +* +-----------------------------+ +* | data length | +* +_____________________________+ +* | | +* | data | +* | ... | +* +~.-~.-~.-~.-~.-~.-~.-~.-~.-~.+ +* +* Note: the data length referes to the size of the data section (not including header +* size of 6 bytes) +* +* \dependencies +* None +* +* \param [in] message_buffer: The buffer containing the command request sent by the client +* \param [in] msg_buffer_size: The length of the message buffer +* \param [in] data_length: The data length field in the command request header +* +* \return +* TRUE if successfully parsed and FALSE otherwise +*/ +static bool_t tcpip_cmd_server_get_ats_command_length( + char_t* message_buffer, uint32_t message_buffer_size, uint32_t* data_length); + +/** +* \brief +* Create a response error buffer with the specified error code +* and request command id. +* +* \detdesc +* The response +* <-----------4bytes------------> +* +-----------------------------+ +* | service id | command id | +* +-----------------------------+ +* +-----------------------------+ +* | data length | +* +-----------------------------+ +* +-----------------------------+ +* | status | +* +-----------------------------+ +* +* \param[in] ar_status_code: The AR status code indicating the error +* \param[in/out] message_buffer: The message buffer where the message is written to +* \param[in] msg_buffer_size: The size of the message buffer +* \param[out] msg_length: The length of the message written to the message buffer +* +* \return none +*/ +static void tcpip_cmd_server_create_error_resp( + uint32_t service_cmd_id, uint32_t ar_status_code, + char_t* message_buffer, uint32_t message_buffer_size, + uint32_t& message_length); + +/* +============================================================================ + Public APIs +============================================================================ +*/ +int32_t tcpip_cmd_server_init(void(*ats_exec_callback)(uint8_t* req, uint32_t req_len, + uint8_t** resp, uint32_t* resp_len)) +{ + int32_t status = AR_EOK; + + status = server.start(ats_exec_callback); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to initialize ATS TCP/IP Server", + status); + } + return status; +} + +int32_t tcpip_cmd_server_deinit() +{ + int32_t status = AR_EOK; + status = server.stop(); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to deinitialize ATS Tcpip Server", + status); + } + return status; +} + +int32_t tcpip_cmd_server_send_dls_log_data(const uint8_t * sendbuf, uint32_t payload_size) +{ + return server.send_dls_log_buffers(sendbuf, payload_size); +} +/* +============================================================================ + TCPIP Server Implementation +============================================================================ +*/ +TcpipServer::TcpipServer() + : cmd_server("CMD Thread") +{ +} + +TcpipServer::~TcpipServer() +{ +} + +int32_t TcpipServer::start(ATS_EXECUTE_CALLBACK cb) +{ + int32_t status = AR_EOK; + TCPIP_CMD_SVR_INFO("Starting ATS server.."); + + status = ar_socket_init(); + if (AR_FAILED(status)) + return status; + + cmd_server.execute_command = cb; + cmd_server.start(NULL); + return status; +} + +int32_t TcpipServer::stop() +{ + int32_t status = AR_EOK; + TCPIP_CMD_SVR_INFO("Stopping ATS server.."); + cmd_server.stop(); + + status = ar_socket_deinit(); + return status; +} + +int32_t TcpipServer::send_dls_log_buffers(const uint8_t* buffer, uint32_t buffer_size) +{ + return cmd_server.send_dls_log_buffers((const char_t*)buffer, buffer_size); +} + +/* +============================================================================ + TCPIP CMD/RSP Server Implementation +============================================================================ +*/ +TcpipCmdServer::TcpipCmdServer(std::string thd_name) + : thd_name(thd_name) +{ +} + +int32_t TcpipCmdServer::start(void *args) +{ + __UNREFERENCED_PARAM(args); + int32_t status = AR_EOK; + + this->address = TCPIP_CMD_SERVER_ADDRESS; + this->port = TCPIP_CMD_SERVER_PORT; + + status = ar_osal_mutex_create(&connection_lock); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to create mutex for %s thread", status, thd_name.c_str()); + return status; + } + + ar_osal_thread_attr_t thd_attr = + { + (char_t*)thd_name.c_str(), + TCPIP_THD_STACK_SIZE, + TCPIP_THREAD_PRIORITY_HIGH, + }; + + ar_osal_thread_start_routine r = \ + (ar_osal_thread_start_routine)(connect); + + status = ar_osal_thread_create(&thd_connection_routine, &thd_attr, r, this); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to create thread %s", status, thd_name.c_str()); + return status; + } + + return status; +} + +int32_t TcpipCmdServer::stop() +{ + int32_t status = AR_EOK; + + TCPIP_CMD_SVR_INFO("Closing ATS CMD/RSP Server ..."); + is_aborted = true; + should_close_server = true; + + stop_dls_server(); + + ar_socket_close(listen_socket); + ar_socket_close(accept_socket); + ar_osal_mutex_unlock(connection_lock); + + TCPIP_CMD_SVR_DBG("Destroying listening thread..."); + status = ar_osal_thread_join_destroy(thd_connection_routine); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]:An error occured when waiting to close the listener thread.", status); + } + + TCPIP_CMD_SVR_DBG("Destroying mutexes thread..."); + ar_osal_mutex_destroy(connection_lock); + + is_aborted = false; + should_close_server = false; + return status; +} + + +int32_t TcpipCmdServer::send_dls_log_buffers(const char_t* buffer, uint32_t buffer_size) +{ +#ifdef ATS_DATA_LOGGING + return _dls_server.send_dls_log_buffers(buffer, buffer_size); +#else + __UNREFERENCED_PARAM(buffer); + __UNREFERENCED_PARAM(buffer_size); + return AR_EUNSUPPORTED; +#endif +} + + +int32_t TcpipCmdServer::set_connected_lock(uint8_t value) +{ + int32_t status = AR_EOK; + + status = ar_osal_mutex_lock(connection_lock); + if (AR_FAILED(status)) + { + return status; + } + + is_connected = value; + + status = ar_osal_mutex_lock(connection_lock); + if (AR_FAILED(status)) + { + return status; + } + + return status; +} + +void TcpipCmdServer::connect(void* arg) +{ + TcpipCmdServer *thread = (TcpipCmdServer*)arg; + (thread->*thd_cb_connect_routine)(NULL); +} + +void TcpipCmdServer::transmit(void* arg) +{ + TcpipCmdServer * thread = (TcpipCmdServer*)arg; + (thread->*thd_cb_transmit_routine)(NULL); +} + +void *TcpipCmdServer::connect_routine(void *args) +{ + __UNREFERENCED_PARAM(args); + + TCPIP_CMD_SVR_INFO("Starting TCP/IP server thread."); + int32_t status = AR_EOK; + ar_osal_thread_t thd_transmit = NULL; + + status = tcpip_socket_util_create_socket(TCPIP_SERVER_TYPE_CMD, AR_SOCKET_ADDRESS_FAMILY, address, port, &listen_socket); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to create and bind to socket", status); + return NULL; + } + + TCPIP_CMD_SVR_INFO("%s: Listening for connections...", thd_name.c_str()); + + /* Clients will recieve a 'connection refused' error if the the + * listening queue is full. The size of the queue is + * MAX_TCPIP_CLIENTS_ALLOWED */ + status = ar_socket_listen(listen_socket, MAX_TCPIP_CLIENTS_ALLOWED); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_INFO("Error[%d]: Listen failed. Closing server..."); + ar_socket_close(listen_socket); + return NULL; + } + + TCPIP_CMD_SVR_INFO("Waiting to accept ATS TCP/IP Command-Response clients..."); + while (true) + { + if (should_close_server) break; + + status = tcpip_socket_util_accept_connections(AR_SOCKET_ADDRESS_FAMILY, listen_socket, &accept_socket); + if (AR_FAILED(status)) + { + ar_socket_close(accept_socket); + + if (AR_SOCKET_LAST_ERROR == EINTR) continue; + + continue; + } + + //Start dls Server only after connecting to command server + start_dls_server(); + + TCPIP_CMD_SVR_INFO("Client connected to ATS TCPIP Command-Response Server"); + ar_osal_mutex_unlock(connection_lock); + is_connected = true; + + //ar_osal_thread_t thd_transmit; + ar_osal_thread_start_routine r = \ + (ar_osal_thread_start_routine)(transmit); + + std::string thd_transmit_name = ""; + ar_osal_thread_attr_t thd_attr = \ + { + (char_t*)thd_transmit_name.c_str(), + TCPIP_THD_STACK_SIZE, + TCPIP_THREAD_PRIORITY_HIGH + }; + + status = ar_osal_thread_create(&thd_transmit, &thd_attr, r, this); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to create transmission thread", status); + } + + + /* Only one client is allowed to connect to the server for now. + * Block until client calls QUIT on transmission thread. + * Allow 200 msec sleep for thd_transmit to aquire connection_lock*/ + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + ar_osal_mutex_lock(connection_lock); + + status = ar_osal_thread_join_destroy(thd_transmit); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to destroy connection thread", status); + } + } + + ar_socket_close(listen_socket); + ar_socket_close(accept_socket); + //for (int j = 0; j < MAX_TCPIP_CLIENTS_ALLOWED; j++) + //{ + // status = ar_osal_thread_join_destroy(thd_transmit); + // if (AR_FAILED(status)) + // { + // TCPIP_CMD_SVR_ERR("Error[%d]: Failed to destroy connection thread", status); + // } + //} + + return 0; +} + +void TcpipCmdServer::start_dls_server() +{ +#ifdef ATS_DATA_LOGGING + + _dls_server.address = TCPIP_CMD_SERVER_ADDRESS; + // _dls_server.port = TCPIP_DLS_SERVER_PORT; + _dls_server.stop(); + if (AR_FAILED(_dls_server.start())) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Unable to start the tcpip dls server. Skipping..."); + } + +#endif +} + +void TcpipCmdServer::stop_dls_server() +{ +#ifdef ATS_DATA_LOGGING + + _dls_server.stop(); + +#endif +} + +void *TcpipCmdServer::transmit_routine(void *args) +{ + __UNREFERENCED_PARAM(args); + + int32_t status = AR_EOK; + const uint32_t maxsize = ATS_BUFFER_LENGTH;//TODO: We need to introduce a command to change this size. 2mb is too high + char_t* outbuf = NULL; + + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + ar_osal_mutex_lock(connection_lock); + + message_buffer.buffer_size = ATS_BUFFER_LENGTH; + recieve_buffer.buffer_size = TCPIP_CMD_SERVER_RECV_BUFFER_SIZE; + //Stores one message + message_buffer.buffer = (char_t*)ar_heap_malloc(message_buffer.buffer_size, &heap_inf); + if (NULL == message_buffer.buffer) + return 0; + + recieve_buffer.buffer = (char_t*)ar_heap_malloc(recieve_buffer.buffer_size, &heap_inf); + if (NULL == recieve_buffer.buffer) { + ar_heap_free(message_buffer.buffer, &heap_inf); + return 0; + } + + outbuf = (char_t*)ar_heap_malloc(maxsize, &heap_inf); + if (NULL == outbuf) { + ar_heap_free(message_buffer.buffer, &heap_inf); + ar_heap_free(recieve_buffer.buffer, &heap_inf); + return 0; + } + ar_mem_set(outbuf, 0, 1); + + while (true) + { + uint32_t request_message_length = 0; + uint32_t response_message_length = 0; + + /* This is for readability when analyzing the logs.We want to separate each command + * sent by the client with a new line to understand all the operations that occur + * during one command */ + TCPIP_CMD_SVR_DBG("\n"); + + status = recv_message_header( + message_buffer.buffer, message_buffer.buffer_size, + recieve_buffer.buffer, recieve_buffer.buffer_size, + request_message_length); + if (AR_FAILED(status)) + { + if (AR_ETERMINATED == status) + { + TCPIP_CMD_SVR_INFO("Ending data transmission...") + } + else + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to read message header", + status); + } + break; + } + + status = recv_message( + message_buffer.buffer, message_buffer.buffer_size, + recieve_buffer.buffer, recieve_buffer.buffer_size, + request_message_length); + if (AR_FAILED(status) && status != AR_ENEEDMORE) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to read message data", status); + break; + } + + status = process_message( + message_buffer.buffer, message_buffer.buffer_size, request_message_length, + (char_t**)&outbuf, + maxsize, response_message_length); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to read message data", status); + break; + } + + status = send_message(outbuf, maxsize, response_message_length); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to send message", status); + break; + } + } + + //Cleanup + TCPIP_CMD_SVR_DBG("%s: closing thread", thd_name.c_str()); + + ar_heap_free(message_buffer.buffer, &heap_inf); + ar_heap_free(recieve_buffer.buffer, &heap_inf); + + is_connected = false; + ar_osal_mutex_unlock(connection_lock); + return 0; +} + +int32_t TcpipCmdServer::recv_message_header(char_t *msgBuf, uint32_t msgbuflen, + char_t *recvbuf, uint32_t recvbuflen, uint32_t &msg_len) +{ + int32_t status = AR_EOK; + int32_t bytes_recieved = 0; + int32_t headerBytesRead = 0; + char svc_id_str[ATS_SEVICE_ID_STR_LEN] = { 0 }; + uint32_t svc_cmd_id = 0; + + while (true) + { + //receive full message header + TCPIP_CMD_SVR_DBG("Waiting to recieve message..."); + + if (ATS_HEADER_LENGTH - headerBytesRead > (int32_t)recvbuflen) + { + return AR_EBADPARAM; + } + status = ar_socket_recv(accept_socket, recvbuf, ATS_HEADER_LENGTH - headerBytesRead, 0, &bytes_recieved); + + if (bytes_recieved < 0) + { + if (AR_SOCKET_LAST_ERROR == EINTR) continue; + + TCPIP_CMD_SVR_ERR("Receive failed with error: %d\n", AR_SOCKET_LAST_ERROR); + ar_socket_close(accept_socket); + return AR_EFAILED; + } + else if (bytes_recieved == 0) + { + TCPIP_CMD_SVR_INFO("Client shutdown socket. Closing connection..."); + ar_socket_close(accept_socket); + return AR_ETERMINATED; + } + + TCPIP_CMD_SVR_DBG("Recieved %d bytes", bytes_recieved); + + /* The client sends "QUIT" to signal end of connection. The server will close + * the socket and return */ + if (ar_strcmp(recvbuf, ATS_SERVER_CMD_QUIT.c_str(), 4) == 0) + { + TCPIP_CMD_SVR_INFO("Quitting..."); + ar_socket_close(accept_socket); + return AR_ETERMINATED; + } + + if (headerBytesRead > (int32_t)msgbuflen) + { + return AR_EBADPARAM; + } + ar_mem_cpy(msgBuf + headerBytesRead, bytes_recieved, recvbuf, bytes_recieved); + headerBytesRead += bytes_recieved; + + //this determines how many bytes to expect (thus determining how many times to loop). + if (tcpip_cmd_server_get_ats_command_length(msgBuf, bytes_recieved, &msg_len)) + { + svc_cmd_id = 0; + ar_mem_cpy(&svc_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH, + msgBuf + ATS_SERVICE_COMMAND_ID_POSITION, ATS_SERVICE_COMMAND_ID_LENGTH); + + ATS_SERVICE_ID_STR(svc_id_str, ATS_SEVICE_ID_STR_LEN, svc_cmd_id); + TCPIP_CMD_SVR_DBG("Recieved Command[%s-%d] with length %d bytes", svc_id_str, ATS_GET_COMMAND_ID(svc_cmd_id), msg_len); + break; + } + } + + msg_len += ATS_HEADER_LENGTH; + + return status; +} + +int32_t TcpipCmdServer::recv_message(char_t *msgBuf, uint32_t msgbuflen, + char_t *recvbuf, uint32_t recvbuflen, uint32_t msg_len) +{ + __UNREFERENCED_PARAM(recvbuflen); + int32_t status = AR_EOK; + int32_t bytes_recieved = 0; + uint32_t message_bytes_read = 0; + uint32_t remaining_message_length = 0; + uint32_t recv_len = 0; + uint32_t data_length = msg_len; + bool_t should_write_msg = TRUE; + + if (msg_len > msgbuflen) + { + /* We reject messages that are larger that what we can store in our message buffer */ + TCPIP_CMD_SVR_ERR("Error[%d]: Not enough memory to store incoming message of %d bytes. " + "Use resize buffer command to update the max buffer size", AR_ENEEDMORE, msg_len); + + should_write_msg = FALSE; + status = AR_ENEEDMORE; + } + + data_length -= ATS_HEADER_LENGTH; + while (data_length > 0) + { + //receive rest of message + if (message_bytes_read > data_length) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Read more than message length. Exiting..", + AR_ENEEDMORE); + ar_socket_close(accept_socket); + + return AR_ENEEDMORE; + } + + remaining_message_length = data_length - message_bytes_read; + recv_len = remaining_message_length < TCPIP_CMD_SERVER_RECV_BUFFER_SIZE ? + remaining_message_length : TCPIP_CMD_SERVER_RECV_BUFFER_SIZE; + + //will receive min(TCPIP_CMD_SERVER_RECV_BUFFER_SIZE, bytes left to receive to complete message) + bytes_recieved = recv(accept_socket, recvbuf, recv_len, 0); + + if (bytes_recieved > 0) + { + TCPIP_CMD_SVR_DBG("Recieved %d bytes", bytes_recieved); + + if (should_write_msg) + { + if (ATS_HEADER_LENGTH + message_bytes_read > msgbuflen) + { + TCPIP_CMD_SVR_ERR("Message bytes read + ATS Header %d bytes is greater " + "than message buffer length %d bytes", + ATS_HEADER_LENGTH + message_bytes_read, msgbuflen); + return AR_ENEEDMORE; + } + + ar_mem_cpy(msgBuf + ATS_HEADER_LENGTH + message_bytes_read, bytes_recieved, + recvbuf, bytes_recieved); + } + + message_bytes_read += bytes_recieved; + if (message_bytes_read == data_length) + { + break; + } + } + else if (bytes_recieved <= 0) + { + if (AR_SOCKET_LAST_ERROR == EINTR) + { + //TCPIP_CMD_SVR_DBG("Signal interruption detected. Continuing.."); + continue; + } + + TCPIP_CMD_SVR_ERR("Receive failed with error: %d", AR_SOCKET_LAST_ERROR); + ar_socket_close(accept_socket); + return AR_EFAILED; + } + } + + return status; +} + +int32_t TcpipCmdServer::process_message( + char_t* msg_buffer, uint32_t msg_buffer_size, uint32_t msg_length, + char_t** out_buf, uint32_t out_buf_len, uint32_t& resp_len) +{ + __UNREFERENCED_PARAM(out_buf_len); + int32_t status = AR_EOK; + //uint32_t recvlen_ptr = 0; + uint32_t svc_cmd_id = 0; + uint32_t data_length = 11;//TODO: Why is this hardcoded to 11? + char svc_id_str[ATS_SEVICE_ID_STR_LEN] = { 0 }; + if (msg_length > msg_buffer_size) + { + /* We reject messages that are larger that what we can store in our message buffer */ + tcpip_cmd_server_create_error_resp(svc_cmd_id, AR_ENEEDMORE, + *out_buf, out_buf_len, resp_len); + goto process_message_end; + } + + svc_cmd_id = 0; + ar_mem_cpy(&svc_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH, + msg_buffer + ATS_SERVICE_COMMAND_ID_POSITION, ATS_SERVICE_COMMAND_ID_LENGTH); + + tcpip_cmd_server_get_ats_command_length(msg_buffer, msg_length, &data_length); + ATS_SERVICE_ID_STR(svc_id_str, ATS_SEVICE_ID_STR_LEN, svc_cmd_id); + TCPIP_CMD_SVR_DBG("Command[%s-%d]: Request data length is %d bytes", svc_id_str, ATS_GET_COMMAND_ID(svc_cmd_id), data_length); + + //Handle server commands like RESIZE_BUFFER, etc.. + if (ATS_ONLINE_SERVICE_ID == ATS_GET_SERVICE_ID(svc_cmd_id)) + { + status = execute_server_command(svc_cmd_id, msg_length); + + if (AR_FAILED(status)) + { + tcpip_cmd_server_create_error_resp(svc_cmd_id, status, + *out_buf, out_buf_len, resp_len); + status = AR_EOK; + goto process_message_end; + } + } + + //passing received data and blank output buffer to ats upcall + execute_command((uint8_t *)message_buffer.buffer, (uint32_t)msg_length, + (uint8_t**)out_buf, &resp_len); + + //resp_len = recvlen_ptr; + +process_message_end: + TCPIP_CMD_SVR_DBG("Outbound message of length %d bytes", resp_len); + + return status; +} + +int32_t TcpipCmdServer::send_message(char_t* buf, uint32_t buf_len, uint32_t msg_len) +{ + int32_t status = AR_EOK; + int32_t bytes_sent = 0; + uint32_t data_length = 0; + uint32_t svc_cmd_id = 0; + char svc_id_str[ATS_SEVICE_ID_STR_LEN] = { 0 }; + + if (buf == NULL) + { + TCPIP_CMD_SVR_ERR("Error[%d]: The send buffer is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (msg_len > buf_len) + { + TCPIP_CMD_SVR_ERR("Error[%d]: The message length %d bytes is >" + " the send buffer length %d", AR_EBADPARAM, msg_len, buf_len); + return AR_EBADPARAM; + } + + tcpip_cmd_server_get_ats_command_length(buf, msg_len, &data_length); + + ar_mem_cpy(&svc_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH, + buf + ATS_SERVICE_COMMAND_ID_POSITION, ATS_SERVICE_COMMAND_ID_LENGTH); + ATS_SERVICE_ID_STR(svc_id_str, ATS_SEVICE_ID_STR_LEN, svc_cmd_id); + TCPIP_CMD_SVR_DBG("Command[%s-%d]: Sending response of %d bytes", svc_id_str, ATS_GET_COMMAND_ID(svc_cmd_id), data_length); + + //Send response to client + status = ar_socket_send(accept_socket, buf, msg_len, 0, &bytes_sent); + if (AR_FAILED(status)) + { + TCPIP_CMD_SVR_ERR("Unable to send message. Socket error: %d", AR_SOCKET_LAST_ERROR); + ar_socket_close(accept_socket); + } + else + { + TCPIP_CMD_SVR_DBG("Message sent"); + } + + return status; +} + +int32_t TcpipCmdServer::execute_server_command(uint32_t service_cmd_id, uint32_t message_length) +{ + switch (service_cmd_id) + { + case ATS_CMD_ONC_SET_MAX_BUFFER_LENGTH: + { + uint32_t new_buffer_size = 0; + uint32_t data_length = 0; + uint32_t offset = 0; + struct ar_heap_info_t heap_inf = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + if (message_length < sizeof(uint32_t)) + { + return AR_ENEEDMORE; + } + + ar_mem_cpy(&data_length, sizeof(uint32_t), + this->message_buffer.buffer + ATS_DATA_LENGTH_POSITION, sizeof(uint32_t)); + ar_mem_cpy(&new_buffer_size, sizeof(uint32_t), + this->message_buffer.buffer + ATS_ACDB_BUFFER_POSITION, sizeof(uint32_t)); + + //The new buffer size needs to be between the required range to resize the message buffer: + //range: AGWS_RECV_BUF_SIZE * 4 < new buffer size < GWS_MAX_BUFFER_SIZE + //Largest buffer size is 2mb the GWS_MAX_BUFFER_SIZE + //Smalleset buffer size is 4 * 1024 the recieve buffer size + if ((new_buffer_size > this->message_buffer.buffer_size && new_buffer_size < TCPIP_CMD_SERVER_MAX_MSG_BUFFER_SIZE) || + (new_buffer_size < this->message_buffer.buffer_size && new_buffer_size > TCPIP_CMD_SERVER_MIN_MSG_BUFFER_SIZE) + ) + { + ar_heap_free(message_buffer.buffer, &heap_inf); + + message_buffer.buffer_size = new_buffer_size; + message_buffer.buffer = (char_t*)ar_heap_malloc(message_buffer.buffer_size, &heap_inf); + if (NULL == message_buffer.buffer) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Failed to resize gateway message buffer", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + ar_mem_set(message_buffer.buffer, 0, message_buffer.buffer_size); + + /* Write the ATS command back to the resized message buffer so that the ATS Command + * layer can resize its buffer.*/ + ar_mem_cpy(message_buffer.buffer, sizeof(uint32_t), &service_cmd_id, sizeof(uint32_t)); + offset += sizeof(uint32_t); + ar_mem_cpy(message_buffer.buffer + offset, sizeof(uint32_t), &data_length, sizeof(uint32_t)); + offset += sizeof(uint32_t); + ar_mem_cpy(message_buffer.buffer + offset, sizeof(uint32_t), &new_buffer_size, sizeof(uint32_t)); + } + } + break; + default: + break; + } + + return AR_EOK; +} + +/* +============================================================================ + Helper Functions +============================================================================ +*/ + +static bool_t tcpip_cmd_server_get_ats_command_length( + char_t* message_buffer, uint32_t message_buffer_size, uint32_t* data_length) +{ + bool_t result = FALSE; + if (NULL == message_buffer || NULL == data_length) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Input parameter is null", AR_EBADPARAM); + return FALSE; + } + if (message_buffer_size < ATS_HEADER_LENGTH) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Message buffer is smaller than request header format length", AR_ENEEDMORE); + result = FALSE; + } + else + { + /** copy data length*/ + ar_mem_cpy(data_length, ATS_DATA_LENGTH_LENGTH, + message_buffer + ATS_DATA_LENGTH_POSITION, ATS_DATA_LENGTH_LENGTH); + + result = TRUE; + } + return result; +} + +static void tcpip_cmd_server_create_error_resp( + uint32_t service_cmd_id, uint32_t ar_status_code, + char_t* message_buffer, uint32_t message_buffer_size, + uint32_t& message_length +) +{ + /* The format of the command response message is: + * <-----------4bytes------------> + * +-----------------------------+ + * | service id | command id | + * +-----------------------------+ + * +-----------------------------+ + * | data length | + * +-----------------------------+ + * +-----------------------------+ + * | status | + * +-----------------------------+ */ + uint32_t resp_data_length; + + if (NULL == message_buffer) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Response Buffer is not initialized", AR_EBADPARAM); + message_length = 0; + return; + } + + if (message_buffer_size < ATS_ERROR_FRAME_LENGTH) + { + TCPIP_CMD_SVR_ERR("Error[%d]: Unable to create error response. " + "The response buffer is less than %d bytes", + AR_EBADPARAM, ATS_ERROR_FRAME_LENGTH); + return; + } + + message_length = ATS_ERROR_FRAME_LENGTH; + resp_data_length = ATS_ERROR_FRAME_LENGTH - ATS_HEADER_LENGTH; + + //Service + Command ID + ar_mem_cpy(message_buffer, ATS_SERVICE_COMMAND_ID_LENGTH, + &service_cmd_id, ATS_SERVICE_COMMAND_ID_LENGTH); + + //Data Length + ar_mem_cpy(message_buffer + ATS_SERVICE_COMMAND_ID_LENGTH, ATS_DATA_LENGTH_LENGTH, + &resp_data_length, + ATS_DATA_LENGTH_LENGTH); + + //Status + ar_mem_cpy(message_buffer + ATS_HEADER_LENGTH, ATS_ERROR_CODE_LENGTH, + &ar_status_code, + ATS_ERROR_CODE_LENGTH); +} + +#endif /*ATS_TRANSPORT_TCPIP*/ diff --git a/acdb/ats/transports/tcpip_server/src/tcpip_dls_server.cpp b/acdb/ats/transports/tcpip_server/src/tcpip_dls_server.cpp new file mode 100644 index 0000000..b24dffc --- /dev/null +++ b/acdb/ats/transports/tcpip_server/src/tcpip_dls_server.cpp @@ -0,0 +1,223 @@ +/** +*============================================================================= +* \file tcpip_dls_server.cpp +* \brief +* T C P I P D L S S E R V E R +* S O U R C E F I L E +* +* This file contains the DLS TCPIP server implementation to host connections +* to QACT. +* This file first sets up a listening socket on port 5561. Upon accepting +* new connections, the server sends DLS log packets to the connected client. +* +* ATS_DATA_LOGGING must be defined in the build configuration to use +* this feature +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================= +*/ +#ifdef ATS_TRANSPORT_TCPIP +#ifdef ATS_DATA_LOGGING + +#include "tcpip_dls_server.h" + +#define TCPIP_THREAD_PRIORITY_HIGH 0 +#define TCPIP_THREAD_PRIORITY_LOW 1 +#define TCPIP_THD_STACK_SIZE 0xF4240 //1mb stack size + +// #define TCPIP_DLS_SERVER_PORT 5561 +#define MAX_TCPIP_CLIENTS_ALLOWED 1 + +/**< ATS TCPIP DLS Server(TDS) Log Tag */ +#define TCPIP_DLS_SRV_LOG_TAG "ATS-TDS" +#define TCPIP_DLS_ERR(...) AR_LOG_ERR(TCPIP_DLS_SRV_LOG_TAG, __VA_ARGS__) +#define TCPIP_DLS_DBG(...) AR_LOG_DEBUG(TCPIP_DLS_SRV_LOG_TAG, __VA_ARGS__) +#define TCPIP_DLS_INFO(...) AR_LOG_INFO(TCPIP_DLS_SRV_LOG_TAG, __VA_ARGS__) + +typedef void* (TcpipDlsServer::* tcpip_dls_server_thread_callback)(void* args); +static tcpip_dls_server_thread_callback thd_cb_connect_routine = &TcpipDlsServer::connect_routine; + +/* +============================================================================ + DLS TCPIP Server Implementation +============================================================================ +*/ + +TcpipDlsServer::TcpipDlsServer(std::string thd_name) +{ + port = TCPIP_DLS_SERVER_PORT; +} + +int32_t TcpipDlsServer::start() +{ + int32_t status = AR_EOK; + std::string thd_name = "DLS_TCPIP_SVR"; + + status = ar_osal_mutex_create(&connection_lock); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to create mutex for %s thread", status, thd_name.c_str()); + return status; + } + + ar_osal_thread_attr_t thd_attr = + { + (char_t*)thd_name.c_str(), + TCPIP_THD_STACK_SIZE, + TCPIP_THREAD_PRIORITY_HIGH, + }; + + ar_osal_thread_start_routine r = \ + (ar_osal_thread_start_routine)(connect); + + status = ar_osal_thread_create(&thread, &thd_attr, r, this); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to create thread %s", status, thd_name.c_str()); + return status; + } + + return status; +} + +int32_t TcpipDlsServer::stop() +{ + if (!is_connected) + return AR_EOK; + + TCPIP_DLS_INFO("Closing tcpip dls server ..."); + int32_t status = ar_osal_thread_join_destroy(thread); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to destroy connection thread", status); + } + + should_close_server = true; + ar_socket_close(accept_socket); + ar_osal_mutex_destroy(connection_lock); + + return AR_EOK; +} + +int32_t TcpipDlsServer::set_connected_lock(uint8_t value) +{ + int32_t status = AR_EOK; + + status = ar_osal_mutex_lock(connection_lock); + if (AR_FAILED(status)) + { + return status; + } + + is_connected = value; + + status = ar_osal_mutex_lock(connection_lock); + if (AR_FAILED(status)) + { + return status; + } + + return status; +} + +void TcpipDlsServer::connect(void* arg) +{ + TcpipDlsServer* thread = (TcpipDlsServer*)arg; + (thread->*thd_cb_connect_routine)(NULL); +} + +void* TcpipDlsServer::connect_routine(void* args) +{ + __UNREFERENCED_PARAM(args); + + TCPIP_DLS_INFO("Starting tcpip dls server thread."); + int32_t status = AR_EOK; + char_t* str_addr = (char_t*)address.c_str(); + ar_socket_t listen_socket; + + status = tcpip_socket_util_create_socket(TCPIP_SERVER_TYPE_DLS, AR_SOCKET_ADDRESS_FAMILY, str_addr, port, &listen_socket); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to create and bind to socket", status); + return NULL; + } + + //TCPIP_DLS_INFO("%s: Listening for connections...", thd_name.c_str()); + + /* Clients will recieve a 'connection refused' error if the the + * listening queue is full. The size of the queue is + * MAX_TCPIP_CLIENTS_ALLOWED */ + status = ar_socket_listen(listen_socket, MAX_TCPIP_CLIENTS_ALLOWED); + if (AR_SUCCEEDED(status)) + { + TCPIP_DLS_INFO("Listening successful"); + } + else + return NULL; + + ar_osal_mutex_init(connection_lock); + // status = set_connected_lock(false); + if (AR_FAILED(status)) + { + TCPIP_DLS_ERR("Error[%d]: Failed to set 'connected' lock", status); + return 0; + } + + while (true) + { + TCPIP_DLS_INFO("Waiting to accept clients for tcpip dls server..."); + + status = tcpip_socket_util_accept_connections(AR_SOCKET_ADDRESS_FAMILY, listen_socket, &accept_socket); + if (AR_FAILED(status)) + { + ar_socket_close(accept_socket); + if (AR_SOCKET_LAST_ERROR == EINTR) continue; + + continue; + } + + ar_osal_mutex_lock(connection_lock); + if (is_connected) + { + TCPIP_DLS_ERR("New connection request. Refusing..."); + ar_socket_close(accept_socket); + ar_osal_mutex_unlock(connection_lock); + continue; + } + ar_osal_mutex_unlock(connection_lock); + + TCPIP_DLS_INFO("Client connected to tcpip dls server..."); + break; + } + + ar_socket_close(listen_socket); + + return 0; +} + +int32_t TcpipDlsServer::send_dls_log_buffers(const char_t* buffer, uint32_t buffer_size) +{ + int32_t status = AR_EOK; + int32_t bytes_sent = 0; + + if(ar_socket_is_invalid(accept_socket)) + { + TCPIP_DLS_ERR("Unable to send log data. tcpip dls server isn't connected"); + return AR_EFAILED; + } + + TCPIP_DLS_DBG("Preparing to send %d bytes", buffer_size); + status = ar_socket_send(accept_socket, buffer, buffer_size, 0, &bytes_sent); + if (AR_SUCCEEDED(status) && bytes_sent >= 0) + { + TCPIP_DLS_DBG("Successfully Sent %d bytes:", bytes_sent); + return status; + } + + return AR_EOK; +} + +#endif /*ATS_DATA_LOGGING*/ +#endif /*ATS_TRANSPORT_TCPIP*/ diff --git a/acdb/ats/transports/tcpip_server/src/tcpip_socket_util.cpp b/acdb/ats/transports/tcpip_server/src/tcpip_socket_util.cpp new file mode 100644 index 0000000..7a60560 --- /dev/null +++ b/acdb/ats/transports/tcpip_server/src/tcpip_socket_util.cpp @@ -0,0 +1,265 @@ +/** +*============================================================================= +* \file tcpip_socket_util.cpp +* \brief +* S O C K E T U T I L I T Y +* S O U R C E F I L E +* +* Contains socket creation functions to simplify socket creation in the +* server sources files +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*============================================================================= +*/ +#ifdef ATS_TRANSPORT_TCPIP + +#include "tcpip_socket_util.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_heap.h" +#include "ar_osal_string.h" + +/**< TCPIP Socket Utility(TSU) Log Tag */ +#define LOG_TAG "ATS-TSU" +#define TCPIP_SOCKET_UTIL_ERR(...) AR_LOG_ERR(LOG_TAG, __VA_ARGS__) +#define TCPIP_SOCKET_UTIL_DBG(...) AR_LOG_DEBUG(LOG_TAG, __VA_ARGS__) +#define TCPIP_SOCKET_UTIL_INFO(...) AR_LOG_INFO(LOG_TAG, __VA_ARGS__) + +/* The name of the unix abstract domain socket used by the + * ATS Server to communicate with the gateway server */ +#define CMD_SERVER_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME "#AtsCmdServer" + +/* The character length of the unix domain socket string + * including the null-terminating character */ +#define CMD_SERVER_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_LENGTH 13 + +/* The name of the unix abstract domain socket used by the + * ATS Server to communicate with the gateway server */ +#define DLS_SERVER_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME "#AtsDlsServer" + +int32_t create_socket_inet( + ar_address_family_t address_family, + std::string address, + uint16_t gateway_port, + ar_socket_t* listen_socket) +{ + int32_t status = AR_EOK; + char_t* address_string = (char_t*)address.c_str(); + TCPIP_SOCKET_UTIL_DBG("Setting up sockets..."); + //creates socket and references the socket using a file descriptor + status = ar_socket_tcp(listen_socket); + + //Checks for errors from socket function + if (ar_socket_is_invalid(*listen_socket)) + { + TCPIP_SOCKET_UTIL_ERR("Error opening socket"); + return status; + } + + ar_socket_addr_in_t addr = { 0 }; + addr.sin_family = address_family; + ar_socket_inet_pton(address_family, address_string, &addr.sin_addr.s_addr); + addr.sin_port = ar_socket_htons(gateway_port); + + //binds socket to socket path + status = ar_socket_bind(*listen_socket, (struct sockaddr*)&addr, sizeof(addr)); + if (AR_FAILED(status)) + { + return status; + } + + TCPIP_SOCKET_UTIL_DBG("Bind successful"); + + return status; +} + +// void create_unix_socket_path() +// { +// #if defined(__linux__) +// //Create the sockets path and give full permisions to the path +// char_t socket_path[] = SOCK_PATH; +// //700 is permission for -rwx------ (read/write/execute for only owner) +// mode_t permissions = S_IRWXU;//S_IRWXU +// status = mkdir(socket_path, permissions); +// chmod(socket_path, permissions); //if already exists +// #endif +// } + +int32_t create_socket_unix( + std::string address, + ar_socket_t* listen_socket) +{ + int32_t status = AR_EOK; + char_t* address_string = NULL; + size_t address_string_length = 0; + //creates socket and references the socket using a file descriptor + status = ar_socket_unix(listen_socket); + + //Checks for errors from socket function + if (ar_socket_is_invalid(*listen_socket)) + { + TCPIP_SOCKET_UTIL_ERR("Error opening socket"); + return status; + } + + //Create Abstract domain socket + ar_socket_addr_un_t addr = { 0 }; + ar_mem_set(&addr, 0, sizeof(ar_socket_addr_un_t)); + addr.sun_family = AF_UNIX; + + address_string = (char_t*)address.c_str(); + address_string_length = address.length(); + + TCPIP_SOCKET_UTIL_ERR("address:%s str len:%d", address_string, address_string_length); + // ar_strcpy(addr.sun_path, + // AR_UNIX_PATH_MAX, + // SERVER_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME, + // SERVER_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME_LENGTH); + ar_strcpy(addr.sun_path, + AR_UNIX_PATH_MAX, + address_string, + address_string_length); + addr.sun_path[0] = 0; + + size_t length = address_string_length + + sizeof(addr.sun_family); + + //binds socket to socket path + TCPIP_SOCKET_UTIL_DBG("Binding Abstract Domain Socket. Socket Path: %s Length: %d", + &addr.sun_path[0], + address_string_length); + + status = ar_socket_bind(*listen_socket, (struct sockaddr*)&addr, (uint32_t)length); + if (AR_FAILED(status)) + { + return status; + } + + TCPIP_SOCKET_UTIL_DBG("Bind successful"); + + return status; +} + +int32_t tcpip_socket_util_create_socket( + tcpip_server_type_t server_type, + ar_address_family_t address_family, + std::string address, + uint16_t gateway_port, + ar_socket_t* listen_socket) +{ + int32_t status = AR_EOK; + std::string abstrat_domain = ""; + + switch (address_family) + { + case AF_UNIX: + if(server_type == TCPIP_SERVER_TYPE_CMD) + abstrat_domain = CMD_SERVER_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME; + else if(server_type == TCPIP_SERVER_TYPE_DLS) + abstrat_domain = DLS_SERVER_UNIX_SOCKET_ABSTRACT_DOMAIN_NAME; + + status = create_socket_unix(abstrat_domain, listen_socket); + break; + case AF_INET: + case AF_INET6: + status = create_socket_inet( + address_family, address, gateway_port, listen_socket); + break; + + default: + break; + } + + return status; +} + +int32_t tcpip_socket_util_accept_unix_socket_connection( + ar_socket_t listen_socket, + ar_socket_t* accept_socket) +{ + int32_t status = AR_EOK; + ar_sockaddr_un_t client_addr; + socklen_t addr_size = sizeof(client_addr); + ar_mem_set(&client_addr, 0, addr_size); + + TCPIP_SOCKET_UTIL_DBG("Waiting to accept clients..."); + status = ar_socket_accept( + listen_socket, (struct sockaddr*)&client_addr, &addr_size, accept_socket); + + return status; +} + +int32_t tcpip_socket_util_accept_inet_socket_connection( + ar_socket_t listen_socket, + ar_socket_t *accept_socket) +{ + int32_t status = AR_EOK; + ar_socket_addr_in_t client_addr; + ar_socketlen_t addr_size = sizeof(client_addr); + ar_mem_set(&client_addr, 0, addr_size); + + TCPIP_SOCKET_UTIL_DBG("Waiting to accept clients..."); + status = ar_socket_accept( + listen_socket, (struct sockaddr*)&client_addr, &addr_size, accept_socket); + + return status; +} + +int32_t tcpip_socket_util_accept_connections( + ar_address_family_t address_family, + ar_socket_t listen_socket, + ar_socket_t* accept_socket) +{ + int32_t status = AR_EOK; + + switch (address_family) + { + case AF_UNIX: + status = tcpip_socket_util_accept_unix_socket_connection(listen_socket, accept_socket); + break; + case AF_INET: + case AF_INET6: + status = tcpip_socket_util_accept_inet_socket_connection(listen_socket, accept_socket); + break; + + default: + status = AR_EUNSUPPORTED; + break; + } + + return status; +} + +int32_t tcpip_socket_util_get_client_name( + ar_address_family_t address_family, + ar_socket_t accept_socket) +{ + int32_t status = AR_EOK; + ar_socketlen_t addr_length = 0; + switch (address_family) + { + case AF_UNIX: + { + ar_sockaddr_un_t client_addr; + status = ar_socket_get_peer_name(accept_socket, (ar_socket_addr_t*)&client_addr, &addr_length); + } + break; + case AF_INET: + case AF_INET6: + { + ar_socket_addr_in_t client_addr; + status = ar_socket_get_peer_name(accept_socket, (ar_socket_addr_t*)&client_addr, &addr_length); + + //client_addr.sin_addr + } + break; + default: + status = AR_EUNSUPPORTED; + break; + } + + return status; +} + +#endif /*ATS_TRANSPORT_TCPIP*/ diff --git a/acdb/inc/acdb_command.h b/acdb/inc/acdb_command.h new file mode 100644 index 0000000..5ef3dcc --- /dev/null +++ b/acdb/inc/acdb_command.h @@ -0,0 +1,157 @@ +#ifndef __ACDB_COMMAND_H__ +#define __ACDB_COMMAND_H__ +/** +*============================================================================= +* \file acdb_command.h +* +* \brief +* Contains the definition of the commands exposed by the +* ACDB public interface. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- + * Include Files + *--------------------------------------------------------------------------- */ +#include "acdb.h" +#include "acdb_file_mgr.h" +#include "acdb_delta_file_mgr.h" +#include "acdb_utility.h" + +/* --------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + *--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- + * Type Declarations + *--------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- +* Class Definitions +*--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- + * Function Declarations and Documentation + *--------------------------------------------------------------------------- */ + +int32_t AcdbCmdGetGraph( + AcdbGraphKeyVector *gkv, AcdbGetGraphRsp *getGraphRsp, + uint32_t rsp_struct_size); + +int32_t AcdbCmdGetSubgraphData( + AcdbSgIdGraphKeyVector *pInput, + AcdbGetSubgraphDataRsp *pOutput); + +int32_t AcdbCmdGetSubgraphConnections( + AcdbSubGraphList* req, AcdbBlob* rsp); + +int32_t AcdbCmdGetSubgraphCalDataNonPersist( + AcdbSgIdCalKeyVector *pInput, + AcdbBlob *pOutput, uint32_t rsp_struct_size); + +int32_t AcdbCmdGetSubgraphCalDataPersist( + AcdbSgIdCalKeyVector *pInput, + AcdbSgIdPersistCalData *pOutput); + +//int32_t AcdbCmdGetSubgraphGlbPersistIds( +// AcdbSgIdCalKeyVector *pInput, +// AcdbGlbPsistIdentifierList *pOutput, uint32_t rsp_struct_size); +// +//int32_t AcdbCmdGetSubgraphGlbPersistCalData( +// AcdbGlbPersistCalDataCmdType *pInput, AcdbBlob *pOutput, +// uint32_t rsp_struct_size); + +int32_t AcdbCmdGetModuleTagData( + AcdbSgIdModuleTag* sg_mod_tag, AcdbBlob* rsp, + uint32_t rsp_size); + +int32_t AcdbCmdGetTaggedModules( + AcdbGetTaggedModulesReq* req, + AcdbGetTaggedModulesRsp* rsp, uint32_t rsp_size); + +int32_t AcdbCmdGetProcTaggedModules( + AcdbGetProcTaggedModulesReq* req, + AcdbGetProcTaggedModulesRsp* rsp, uint32_t rsp_size); + +int32_t AcdbCmdGetDriverData( + AcdbDriverData *driver_data, AcdbBlob* rsp, + uint32_t rsp_size ); + +int32_t AcdbCmdSetCalData( + AcdbSetCalDataReq *req); + +int32_t AcdbCmdGetAmdbRegData( + AcdbAmdbProcID *req, AcdbBlob* rsp); + +int32_t AcdbCmdGetAmdbDeregData( + AcdbAmdbProcID *req, AcdbBlob* rsp); + +int32_t AcdbCmdGetSubgraphProcIds( + AcdbCmdGetSubgraphProcIdsReq *req, + AcdbCmdGetSubgraphProcIdsRsp* rsp, uint32_t rsp_size); + +int32_t AcdbCmdGetAmdbBootupLoadModules( + AcdbAmdbProcID *req, AcdbBlob* rsp); + +int32_t AcdbCmdGetTagsFromGkv( + AcdbCmdGetTagsFromGkvReq *req, AcdbCmdGetTagsFromGkvRsp* rsp, + uint32_t rsp_size); + +int32_t AcdbCmdGetGraphCalKeyVectors( + AcdbGraphKeyVector *gkv, AcdbKeyVectorList *rsp, + uint32_t rsp_size); + +int32_t AcdbCmdGetSupportedGraphKeyVectors( + AcdbUintList *key_id_list, AcdbKeyVectorList *rsp, + uint32_t rsp_size); + +int32_t AcdbCmdGetDriverModuleKeyVectors( + uint32_t module_id, AcdbKeyVectorList *rsp, + uint32_t rsp_size); + +int32_t AcdbCmdGetGraphTagKeyVectors( + AcdbGraphKeyVector *gkv, AcdbTagKeyVectorList *rsp, + uint32_t rsp_size); + +int32_t AcdbCmdGetCalData( + AcdbGetCalDataReq *req, AcdbBlob *rsp); + +int32_t AcdbCmdGetTagData( + AcdbGetTagDataReq *req, AcdbBlob *rsp); + +int32_t AcdbCmdSetTagData(AcdbSetTagDataReq *req); + +int32_t AcdbCmdGetHwAccelInfo( + AcdbHwAccelSubgraphInfoReq* req, + AcdbHwAccelSubgraphInfoRsp* rsp); + +int32_t AcdbCmdGetProcSubgraphCalDataPersist( + AcdbProcSubgraphPersistCalReq* req, + AcdbSgIdPersistCalData* rsp); + +int32_t AcdbCmdGetAmdbRegDataV2( + AcdbAmdbDbHandle* req, AcdbBlob* rsp); + +int32_t AcdbCmdGetAmdbDeregDataV2( + AcdbAmdbDbHandle* req, AcdbBlob* rsp); + +int32_t AcdbCmdGetAmdbBootupLoadModulesV2( + AcdbAmdbDbHandle* req, AcdbBlob* rsp); + +int32_t AcdbCmdGetGraphAlias( + AcdbGraphKeyVector *req, AcdbString *rsp); +/****************************************************************************** +* Functions Only Used by ATS +******************************************************************************* +*/ + +int32_t AcdbGetParameterCalData( + AcdbParameterCalData *req, AcdbBlob* rsp); + +int32_t AcdbGetParameterTagData( + AcdbParameterTagData *req, AcdbBlob* rsp); +#endif /* __ACDB_COMMAND_H__ */ diff --git a/acdb/inc/acdb_common.h b/acdb/inc/acdb_common.h new file mode 100644 index 0000000..9ec604c --- /dev/null +++ b/acdb/inc/acdb_common.h @@ -0,0 +1,118 @@ +#ifndef ACDB_COMMON_H +#define ACDB_COMMON_H +/** +*============================================================================= +* \file acdb_common.h +* +* \brief +* Common header file used by ACDB modules. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#include "ar_osal_types.h" +#include "ar_osal_log.h" +#include +#include +#include + +#define LOG_TAG "ACDB" +#define ACDB_ERR(...) AR_LOG_ERR(LOG_TAG, __VA_ARGS__) +#define ACDB_DBG(...) AR_LOG_DEBUG(LOG_TAG, __VA_ARGS__) +#define ACDB_INFO(...) AR_LOG_INFO(LOG_TAG, __VA_ARGS__) +#define ACDB_VERBOSE(...) AR_LOG_VERBOSE(LOG_TAG, __VA_ARGS__) + +/* Error/Debug Message Format 2 +* @param msg: Brief message describing the error +* @param err_code: Error code to be logged +* @param variadic: any parameter to fill in %d %x %s characters in msg +*/ +#define ACDB_ERR_MSG_2(status, msg, ...) \ +ACDB_ERR("Status[%d]:"##msg, status, __VA_ARGS__) +#define ACDB_DBG_MSG_2(status, msg, ...) \ +ACDB_DBG("Status[%d]:"##msg, status, __VA_ARGS__) + +/* Error/Debug Message Format 1 +* @param msg: Brief message describing the error +* @param err_code: Error code to be logged +*/ +#define ACDB_ERR_MSG_1(msg, err_code) ACDB_ERR("Error[%d]: %s", err_code, msg) +#define ACDB_DBG_MSG_1(msg, err_code) ACDB_DBG("Error[%d]: %s", err_code, msg) + +/**< Macro for obtaining a mutex. The lock must already be initialized + * through ar_osal_mutex_create before calling this macro. */ +#define ACDB_MUTEX_LOCK(lock)\ +do{\ + if (lock){\ + uint32_t __status = ar_osal_mutex_lock(lock);\ + if (AR_FAILED(__status)){\ + ACDB_DBG("Error[%d]: Failed to obtain lock", __status);\ + }\ + }\ + break;\ +} while (1); + + /**< Macro for releasing a mutex. The lock must already be initialized + * through ar_osal_mutex_create before calling this macro. */ +#define ACDB_MUTEX_UNLOCK(lock)\ +do{\ + if (lock){\ + uint32_t __status = ar_osal_mutex_unlock(lock);\ + if (AR_FAILED(__status)){\ + ACDB_DBG("Error[%d]: Failed to release lock", __status);\ + }\ + }\ + break;\ +} while (1); + +//#define ACDB_DEBUG_ENABLE + +#ifdef ACDB_DEBUG_ENABLE +extern ar_fhandle *acdb_pkt_log_fd; + +#define ACDB_PKT_LOG_INIT() \ +do {\ +if (acdb_pkt_log_fd == NULL)\ +acdb_pkt_log_fd = (ar_fhandle*)malloc(sizeof(ar_fhandle));\ +ar_fopen(acdb_pkt_log_fd, "acdb_log.bin", AR_FOPEN_READ_WRITE);\ +} while (0) + +#define ACDB_PKT_LOG_DEINIT() \ +do{\ +ar_fclose(*acdb_pkt_log_fd);\ +ACDB_FREE(acdb_pkt_log_fd); \ +acdb_pkt_log_fd = NULL;\ +} while (0) + +/* +* @param DST_FD File descriptor where logs will be logged to +* @param ID_STR MUST be exactly 8 chars, string that will be placed in the log +* before BUFF to help in parsing +* +*/ +#define ACDB_PKT_LOG_TO_FILE(DST_FD, ID_STR, BUFF, SIZE)\ +do {\ +char *acdb_log_str = "acdb_log_";\ +size_t bytes_written = 0;\ +ar_fwrite(*DST_FD, acdb_log_str, strlen(acdb_log_str), &bytes_written);\ +ar_fwrite(*DST_FD, __FUNCTION__, strlen(__FUNCTION__), &bytes_written);\ +ar_fwrite(*DST_FD, "_", strlen("_"), &bytes_written);\ +ar_fwrite(*DST_FD, ID_STR, strlen(ID_STR), &bytes_written);\ +ar_fwrite(*DST_FD, BUFF, SIZE, &bytes_written);\ +ar_fwrite(*DST_FD, "\n", sizeof(char), &bytes_written);\ +} while (0) + +#define ACDB_PKT_LOG_DATA(ID_STR, BUFF, SIZE)\ +ACDB_PKT_LOG_TO_FILE(acdb_pkt_log_fd, ID_STR, BUFF, SIZE) + +#else +#define ACDB_PKT_LOG_INIT() +#define ACDB_PKT_LOG_DEINIT() +#define ACDB_PKT_LOG_DATA(ID_STR, BUFF, SIZE) +#endif // ACDB_DEBUG_ENABLE + +#endif diff --git a/acdb/inc/acdb_context_mgr.h b/acdb/inc/acdb_context_mgr.h new file mode 100644 index 0000000..160deb4 --- /dev/null +++ b/acdb/inc/acdb_context_mgr.h @@ -0,0 +1,157 @@ +#ifndef __ACDB_CONTEXT_MGR_H__ +#define __ACDB_CONTEXT_MGR_H__ + +/** +*============================================================================= +* \file acdb_context_mgr.h +* +* \brief +* Manages the active database context for an acdb_ioctl command. The +* context can only be changed per command since acdb_ioctl commands +* are guarded by a lock. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#include "ar_osal_types.h" +#include "ar_osal_mutex.h" +#include "acdb_common.h" + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ + +#define ACDB_CTX_MAN_DEFAULT_DB_HANDLE 0 + +/**< A Pointer to the active context manager database handle */ +#define ACDB_CTX_MAN_ACTIVE_HANDLE acdb_man_get_active_handle() + +/**< The total number of databases being managed */ +#define ACDB_CTX_MAN_DATABASE_COUNT acdb_ctx_man_get_database_count() + +/**< The lock for incoming ACDB client commands.(e.g ATS online +commands from QACT and acdb_ioctl commands from GSL */ +#define ACDB_CTX_MAN_CLIENT_CMD_LOCK acdb_ctx_man_get_client_lock() + +#define ACDB_MAGIC_WORD 0x00ACDB00 +#define ACDB_HANDLE_MASK 0xF +/**< Casts a pointer to a acdb_handle_t to a uint */ +#define ACDB_HANDLE_TO_UINT(handle) \ +(ACDB_HANDLE_MASK & (uint32_t)(uintptr_t)*handle) + +/**< Casts a uint handle to a acdb_handle_t */ +#define ACDB_UINT_TO_HANDLE(handle) \ +(acdb_handle_t)(uintptr_t)(ACDB_MAGIC_WORD |(handle & ACDB_HANDLE_MASK)); + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ + +/**< A handle to a heap object */ +typedef void *acdb_heap_handle_t; + +/**< A handle to a file manager object */ +typedef void *acdb_file_man_handle_t; + +/**< A handle to a delta file manager object */ +typedef void *acdb_delta_file_man_handle_t; + +/**< A context handle that holds references to the file manager, +delta file manager, and heap objects for a database */ +typedef struct acdb_context_handle_t acdb_context_handle_t; +struct acdb_context_handle_t { + uint32_t vm_id; + uint32_t database_index; + /**< A handle to a file manager object */ + acdb_file_man_handle_t file_manager_handle; + /**< A handle to a delta file manager object*/ + acdb_delta_file_man_handle_t delta_manager_handle; + /**< A handle to heap object*/ + acdb_heap_handle_t heap_handle; +}; + +typedef enum acdb_ctx_manager_command_t +{ + /**< Initializes the context manager */ + ACDB_CTX_MAN_CMD_INIT = 0, + /**< Adds a data to the manager */ + ACDB_CTX_MAN_CMD_ADD_DATABASE, + /**< Removes a database from the manager using the clients acdb_handle_t */ + ACDB_CTX_MAN_CMD_REMOVE_DATABASE, + /**< De-initializes the context manager and frees resources */ + ACDB_CTX_MAN_CMD_RESET, + /**< Get the number of remaining file slots */ + ACDB_CTX_MAN_CMD_GET_AVAILABLE_FILE_SLOTS, + /**< Get the acdb client handle */ + ACDB_CTX_MAN_CMD_GET_ACDB_CLIENT_HANDLE, + /**< Get the context handle associated with the database using + the virtual machine identifier */ + ACDB_CTX_MAN_CMD_GET_CONTEXT_HANDLE, + /**< Get the context handle associated with the database using + the an index */ + ACDB_CTX_MAN_CMD_GET_CONTEXT_HANDLE_USING_INDEX, + /**< Set the active context handle using the acdb handle */ + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE, + /**< Set the active context handle using a database index */ + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_INDEX, + /**< Set the active context handle using a Graph Key Vector */ + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_GKV, + /**< Set the active context handle using one or more subgraphs */ + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + /**< Set the active context handle using a driver module id */ + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_DRIVER_MODULE, +}acdb_ctx_manager_command_t; + +/* --------------------------------------------------------------------------- +* Funcions +*--------------------------------------------------------------------------- */ + +/** +* \brief +* Retrieves the active context handle +* +* \return a pointer to the active context handle, or +* NULL if the context manager is not initialized +*/ +acdb_context_handle_t *acdb_ctx_man_get_active_handle(void); + +/** +* \brief +* Retrieves the active context handle +* +* \return a pointer to the active context handle, or +* NULL if the context manager is not initialized +*/ +ar_osal_mutex_t acdb_ctx_man_get_client_lock(void); + +/** +* \brief +* Retrieves the total number of databases being managed +* +* \return the number of databases +*/ +uint32_t acdb_ctx_man_get_database_count(void); + +/** +* \brief +* The context manager ioctl used to execute the commands +* defined under acdb_ctx_manager_command_t +* +* \param[in] cmd_id: The command to execute. See acdb_ctx_manager_command_t +* \param[in/out] req: The command request structure +* \param[in] sz_req: The size of the request structure +* \param[in/out] rsp: The command response structure +* \param[in] sz_rsp: The size of the response structure +* +* \sa acdb_ctx_manager_command_t +* \return 0 on success, non-zero on failure +*/ +int32_t acdb_ctx_man_ioctl(uint32_t cmd_id, + void *req, uint32_t sz_req, + void *rsp, uint32_t sz_rsp); + +#endif /*__ACDB_CONTEXT_MGR_H__*/ diff --git a/acdb/inc/acdb_data_proc.h b/acdb/inc/acdb_data_proc.h new file mode 100644 index 0000000..ad08b20 --- /dev/null +++ b/acdb/inc/acdb_data_proc.h @@ -0,0 +1,660 @@ +#ifndef __ACDB_DATA_PROC_H__ +#define __ACDB_DATA_PROC_H__ +/** +*============================================================================= +* \file acdb_data_proc.h +* +* \brief +* Processes data for the ACDB SW commands. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#include "acdb.h" +#include "acdb_types.h" +#include "acdb_parser.h" + +/* --------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + *--------------------------------------------------------------------------- */ + + /* --------------------------------------------------------------------------- + * Global Definitions + *--------------------------------------------------------------------------- */ + +extern uint32_t glb_buf_1[GLB_BUF_1_LENGTH]; +extern uint32_t glb_buf_2[GLB_BUF_2_LENGTH]; +extern uint32_t glb_buf_3[GLB_BUF_3_LENGTH]; + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ + +typedef enum _acdb_data_persistance_type_t { + ACDB_DATA_UNKNOWN, + ACDB_DATA_NON_PERSISTENT = 0x0, + ACDB_DATA_PERSISTENT, + ACDB_DATA_GLOBALY_PERSISTENT, + ACDB_DATA_DONT_CARE, +} AcdbDataPersistanceType; + +/**< Specifies the clients that make requests to ACDB SW*/ +typedef enum _acdb_data_client_t { + ACDB_DATA_ACDB_CLIENT = 0x0, /**< A client of ACDB SW (e.g GSL)*/ + ACDB_DATA_ATS_CLIENT /**< A client of ATS (e.g ARCT)*/ +}AcdbDataClient; + +typedef struct _acdb_property_t AcdbProperty; +struct _acdb_property_t +{ + /**< Determines which handle to use to retrieve data in the file manager. + By default the context manager handle is used */ + AcdbHandleOverride handle_override; + /**< Identifies the property */ + uint32_t property_id; + /**< Size of the property data */ + uint32_t size; + /**< The property data */ + uint8_t* property_data; +}; + +typedef struct _acdb_blob_module_info_t AcdbBlobModuleInfo; +#include "acdb_begin_pack.h" +struct _acdb_blob_module_info_t { + //Offset of the module data within the AcdbBlob + uint32_t blob_offset; + + //Subgraph that the module belongs to + uint32_t subgraph_id; +} +#include "acdb_end_pack.h" +; + +/**< Stores information about an Acdb File table*/ +typedef struct _acdb_table_info_t AcdbTableInfo; +struct _acdb_table_info_t +{ + /**< Determines which handle to use to retrieve data in the file manager. + By default the context manager handle is used */ + AcdbHandleOverride handle_override; + /**< Offset of the table in the ACDB file */ + uint32_t table_offset; + /**< Size of the entire table */ + uint32_t table_size; + /**< Size of the table entry */ + uint32_t table_entry_size; +}; + +/**< Contains infomation used to partitions and search in a sractch buffer*/ +typedef struct _acdb_partition_search_info_t AcdbPartitionSearchInfo; +struct _acdb_partition_search_info_t +{ + /**< Number of Keys to use in the search */ + uint32_t num_search_keys; + /**< Number of elements within the structure */ + uint32_t num_structure_elements; + /**< Index of the entry within the table + returned by the algorithm */ + uint32_t entry_index; + /**< Offset of the entry within the table + returned by the algorithm (In bytes)*/ + uint32_t entry_offset; + /**< Buffer used to store and search partitions */ + AcdbBlob scratch_space; + /**< Pointer to the structure containing the search keys */ + void *table_entry_struct; +}; + +/**< Contains infomation used to search a table for an item */ +typedef struct _acdb_table_search_info_t AcdbTableSearchInfo; +struct _acdb_table_search_info_t +{ + /**< Number of Keys to use in the search */ + uint32_t num_search_keys; + /**< Number of elements within the structure */ + uint32_t num_structure_elements; + /**< Index of the entry within the table + returned by the algorithm */ + uint32_t entry_index; + /**< Offset of the entry within the table + returned by the algorithm (In bytes)*/ + uint32_t entry_offset; + /**< Pointer to the structure containing the search keys */ + void *table_entry_struct; +}; + +typedef struct _acdb_payload_t AcdbPayload; +struct _acdb_payload_t +{ + /**< Size of the payload */ + uint32_t size; + /**< The payload */ + uint8_t *payload; +}; + +typedef struct acdb_hw_accel_subgraph_into_t AcdbHwAccelSubgraphInfo; +struct acdb_hw_accel_subgraph_into_t +{ + /**< The ID of the the subgraph that contains HW Accel data */ + uint32_t subgraph_id; + /**< The type of memory used by the subgraphs calibration */ + uint32_t mem_type; + /**< Offset of the module instance id list that also contains an offset + to the list of parameters */ + uint32_t module_list_offset; +}; + +typedef struct _acdb_heap_request_t +{ + AcdbDataClient client; + AcdbDataPersistanceType persist_type; + AcdbGraphKeyVector* key_vector; + uint32_t subgraph_id; + uint32_t module_iid; + uint32_t param_id; + uint32_t blob_offset; + AcdbBlob* blob; + bool_t is_offloaded_param; + bool_t should_write_iid_pid; +}acdb_heap_request_t; + +/* --------------------------------------------------------------------------- +* Function Prototypes +*--------------------------------------------------------------------------- */ + +/** +* \brief +* Determines the persistence type of a Parameter. Persistence types are +* Persist, Non-persist, and shared(aka global) +* \param[in] pid: Parameter ID to check the persistence type for. +* \param[in/out] persistence_type: Pointer to persistence type +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcGetPersistenceType(uint32_t pid, AcdbDataPersistanceType *persistence_type); + +/** +* \brief +* Retrieves calibration from the heap for a subgraph +* \param[in] persist_type: Get subgraph data for non-persistent, persistent, or globally persistent calibration +* \param[in] client: Indicates where the request originates from (GSL, ARCT, etc...). +* This is used by the heap to determine what type of nodes can be saved to the delta file +* \param[in] key_vector: key vector used to retrieve data from the heap. Can be CKV/TKV. +* \param[in] subgraph_id: The subgraph to retrieve data for +* \param[in] module_iid: The module to retrieve data for +* \param[in] param_id: The parameter to retrieve data for +* \param[in] is_offloaded_param: Indicates whether the parameter is offloaded +* \param[in] blob_offset: Offset of where to start writing data within the blob +* \param[in] blob: Calibration blob in the format MID, PID, ParamSize, Error Code, Payload +* \return 0 on success, non-zero on failure +*/ +int32_t GetSubgraphCalData( + AcdbDataPersistanceType persist_type, AcdbDataClient client, + AcdbGraphKeyVector *key_vector, + uint32_t subgraph_id, uint32_t module_iid, uint32_t param_id, + bool_t is_offloaded_param, uint32_t *blob_offset, AcdbBlob *blob); + +int32_t DataProcGetHeapSubgraphCalData(acdb_heap_request_t* request); + +//TODO: Are these two functions needed? Remove if not +//int32_t DataProcGetCalData(); +//int32_t DataProcGetTagData(); + +/** +* \brief +* Sets calibration data to the heap based on the Key Vector and Subgraphs +* \param[in] cal_key_vector: The cal key vector that the subgraph data is based on +* \param[in] subgraph_param_data: The subgraphs and param data to set to the heap +* \sa AcdbSetCalDataReq +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcSetCalData(AcdbGraphKeyVector *cal_key_vector, AcdbSubgraphParamData* subgraph_param_data); + +/** +* \brief +* Sets tag data to the heap based on the Key Vector and Subgraphs +* \param[in] module_tag: Tag and Tag Key Vector and Subgraph data to set to the heap. +* \param[in] subgraph_param_data: The subgraphs and param data to set to the heap +* \sa AcdbSetTagDataReq +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcSetTagData(AcdbModuleTag *module_tag, AcdbSubgraphParamData* subgraph_param_data); + +bool_t DoesSubgraphContainModule(uint32_t subgraph_id, uint32_t module_iid, int32_t* status); + +/** +* \brief +* Retrieves the processor domain ID that a module is associated with. +* The caller should already know that the module instance belongs to the subgraph. +* \param[in] subgraph_proc_domain_map: a map containing associations between a subgraphs, the +* modules in the subgraph and the processors domains that the +* modules run under +* \param[in] module_iid: the instance id of the module +* \param[out] proc_domain_id: the processor domain id returned +* \sa DoesSubgraphContainModule +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcGetProcDomainForModule(AcdbSubgraphPdmMap* subgraph_proc_domain_map, uint32_t module_iid, uint32_t* proc_domain_id); + +/** +* \brief +* Retrieve a map containing associations between: +* 1. a subgraph, +* 2. the modules in the subgraph and +* 3. the processors domains that the modules run under +* +* \param[in] subgraph_id: The subgraph to retrieve the map for +* \param[out] subgraph_proc_iid_map: The map parsed from the acdb data files +* \return 0 on Success, non-zero on failure +* +*/ +int32_t DataProcGetSubgraphProcIidMap(uint32_t subgraph_id, AcdbSubgraphPdmMap* subgraph_proc_iid_map); + +/** +* \brief +* Retrieves information about the nodes in the ACDB Heap +* This includes: +* 1. Key Vector +* 2. Map Size +* 3. Key Vector Type (CKV or TKV) +* +* \param[in] rsp: response data containing key vector and map size information for each heap node +* +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcGetHeapInfo(AcdbBufferContext *rsp); + +/** +* \brief +* Retrieves heap data for one node in the heap. Each heap node is associated +* with one key vector +* +* \param[in] key_vector: the key vector to retrieve heap data for +* \param[in] rsp: response containing subgraph calibration data retrieved from the heap +* +* \sa AcdbDeltaSubgraphData +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcGetHeapData(AcdbGraphKeyVector *key_vector, AcdbBufferContext* rsp, uint32_t *blob_offset); + +/** +* \brief +* Writes the map to the heap. The map will be added if it doesnt exist on +* the heap. Otherwise it will be diff/merged with an existing map. +* +* \param[in/out] map: The map to set to the heap +* +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcSetMapToHeap(acdb_delta_data_map_t *map); + +/** +* \brief +* Verifys whether a pid is globaly persistent. +* \param[in] pid: Parameter ID to verify for global persistance +* \return 0 on success, non-zero on failure +*/ +int32_t IsPidGlobalyPersistent(uint32_t pid); + +/** +* \brief +* Verifys whether a pid is persistent. +* \param[in] pid: Parameter ID to verify for global persistance +* \return 0 on success, non-zero on failure +*/ +int32_t IsPidPersistent(uint32_t pid); + +/** +* \brief +* Retrieve tag data from the ACDB heap +* +* \param[in] aaaaaa: +* +* \return 0 on success, non-zero on failure +*/ +//int32_t DataProcGetTagData(AcdbGraphKeyVector *tag_key_vector, uint32_t *blob_offset, AcdbBlob *blob); + +/* \brief +* Retrieves property data from the *.acdb file. The format +* of the property blob is +* +* Property = PropertySize PropertyData[PropertySize] +* +* \param[in/out] prop : the property to retrieve data for from the *.acdb file +* +* \sa AcdbGlobalProperty +* \return status +*/ +int32_t GetAcdbProperty(AcdbProperty *prop); + +/* \brief +* Verifies whether a PID exists in the Offloaded Parameter Data Global +* Property list. The format of the list is: +* +* +* \param[in] paramID : The parameter ID to check +* \param[in] AcdbUintList : A list of offloaded parameters retrieved from +* GetOffloadedParamList +* +* \sa ACDB_GBL_PROPID_OFFLOADED_PARAM_INFO +* \return status +*/ +int32_t IsOffloadedParam(uint32_t param_id, AcdbUintList *offloaded_param_list); + +/* \brief +* Retrieves the Offloaaded parameter list from the Offloaded Parameter +* Data Global Property. The format of the list is: +* +* OffloadedParameterList = numPidEntries PIDEntry+ +* PIDEntry = parameterID +* +* Offloaded parameters are parameters whoes actual data does not +* reside in the ACDB Data files. This data is loaded from a file +* on the target system and stitched into the calibration blob +* +* \param[out] AcdbUintList : A list of offloaded parameters retrieved from +* GetOffloadedParamList +* +* \sa ACDB_GBL_PROPID_OFFLOADED_PARAM_INFO +* \return status +*/ +int32_t GetOffloadedParamList(AcdbUintList *offloaded_param_list); + +/* \brief +* Reads the offloaded param data stored on the file system into the +* calibration buffer. It performs data alignment by adding padding to +* the start of the file data and sets the starting offset of the data. +* +* Parse the offloaded parameter data format.: +* +* [ 4 Bytes | 4 Bytes | 4 Bytes | File Size Bytes ] +* [ Data Alignment | Data Offset | Data Size | Data Blob ] +* +* Offloaded parameters are parameters whoes actual data does not +* reside in the ACDB Data files. This data is loaded from a file +* on the target system and stitched into the calibration blob +* +* \param[in] calData : The ACDB calibration data that contains the file path +* to the parameter data file on the file system +* \param[in/out] paramSize : The size of the offloaded parameter which is +* sizeof(AcdbOffloadedParamHeader) +* + padding + data_size; +* \param[in/out] rsp : The buffer to write to +* \param[in/out] blob_offset : The current point to write to in the buffer +* +* \sa AcdbOffloadedParamHeader +* \sa ACDB_GPROP_OFFLOADED_PARAM_INFO +* \return status +*/ +int32_t GetOffloadedParameterData( + AcdbPayload *caldata, uint32_t *paramSize, + AcdbBlob *rsp, uint32_t *blob_offset); + +/** +* \brief +* Determines the number of partitions to create based on the table +* information provided +* +* Formula for determining partition size: +* +* Stratch Buffer Size - (Stratch Buffer Size % Table Entry Size) +* +* E.x +* buffer_size = 2500 bytes, table_entry_size = 12 bytes +* 2496 = 2500 - (2500 % 12) +* so (2496/12) = 208 table entries can fit into one partition +* +* \depends Elements withing a table entry structure should be uint32_t +* +* \param[in] table_info: Contains information about an ACDB Data file table +* \param[in] scratch_buf_size: size of the buffer that will be used for +* storing partitions +* \param[out] num_partitions: the recommended number of partitions based +* on scratch_buf_size +* \param[in] partition_size: the size of each partition +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t GetPartitionInfo(AcdbTableInfo *table_info, uint32_t scratch_buf_size, + uint32_t* num_partitions, uint32_t *partition_size); + +/** +* \brief +* Partitions an acdb file table and performs a binary search on each part. +* +* Example Setup +* //Setup Table Information +* table_info.table_offset = Starting Offset of the Table; +* table_info.table_size = Table Size; +* table_info.table_entry_size = sizeof(Table Entry); +* +* //Setup Search Information +* search_info.num_search_keys = search_index_count; +* search_info.num_structure_elements = +* (sizeof(Table Entry) / sizeof(uint32_t)); +* search_info.table_entry_struct = Entry to Search For; +* search_info.scratch_space.buf = &glb_buf_1; +* search_info.scratch_space.buf_size = sizeof(glb_buf_1); +* +* status = AcdbPartitionBinarySearch(&table_info, &search_info); +* +* \param[in] table_info: Contains information about an ACDB Data file table +* \param[in/out] part_info: Contains infomation used to +* partitions and search in sractch buffer. The +* part_info.table_entry_struct is updated if data is found +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t AcdbPartitionBinarySearch(AcdbTableInfo *table_info, AcdbPartitionSearchInfo *part_info); + +/** +* \brief +* Performs a binary search on an entire ACDB Table. No scratch buffers +* are used like in AcdbPartitionBinarySearch(..) +* +* Example Setup +* //Setup Table Information +* table_info.table_offset = Starting Offset of the Table; +* table_info.table_size = Table Size; +* table_info.table_entry_size = sizeof(Table Entry); +* +* //Setup Search Information +* search_info.num_search_keys = search_index_count; +* search_info.num_structure_elements = +* (sizeof(Table Entry) / sizeof(uint32_t)); +* search_info.table_entry_struct = Entry to Search For; +* +* status = AcdbTableBinarySearch(&table_info, &search_info); +* +* \param[in] table_info: Contains information about an ACDB Data file table +* \param[in/out] part_info: Contains infomation used to +* partitions and search in sractch buffer. The +* part_info.table_entry_struct is updated if data is found +* +* \return AR_EOK on success, non-zero otherwise +* \sa AcdbPartitionBinarySearch +*/ +int32_t AcdbTableBinarySearch( + AcdbTableInfo *table_info, AcdbTableSearchInfo *part_info); + +/* \brief +* Retrieves the Hardware Accelration info for a Subgraph +* +* \param[in/out] info : The hw accel info for a subgraph. The caller provides +* the Subgraph ID +* +* \sa ACDB_GPROP_HW_ACCEL_SUBGRAPH_INFO +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcGetHwAccelSubgraphInfo(AcdbHwAccelSubgraphInfo* info); + +/* \brief +* Determines if a parameter has hardware acceleration data under a +* module instance in some subgraph +* +* \depends +* DataProcGetHwAccelSubgraphInfo(...) must be called before this API +* to get the list offset +* +* \param[in] module_list_offset : The hw accel +* list offset +* \param[in] module_iid : The module instance ID +* \param[in] param_id : The parameter ID +* +* \sa +* ACDB_GPROP_HW_ACCEL_SUBGRAPH_INFO +* DataProcGetHwAccelSubgraphInfo +* +* \return 0 on success, non-zero on failure +*/ +int32_t DataProcIsHwAccelParam(uint32_t module_list_offset, + uint32_t module_iid, uint32_t param_id); + +/** +* \brief +* Retrieves the virtual machine ID from the database +* +* \param[in/out] vm_id: The returned virtual machine ID +* +* \return 0 on Success, non-zero otherwise +*/ +int32_t DataProcGetVmId(uint32_t* vm_id); + +/** +* \brief +* Checks if the provided ID is in the specified range +* +* \param[in] id: The ID to validate +* \param[in/out] range: The range to use +* +* \return 0 on Success, non-zero otherwise +*/ +bool_t DataProcIsValueInRange(uint32_t id, AcdbRange range); + +/** +* \brief +* Retrieves the range for a component +* +* \param[in] range_property_id: The component to get the range for +* \param[in/out] id_range: The minmax range for the provided component +* +* \return 0 on Success, non-zero otherwise +*/ +int32_t DataProcGetIdRange( + AcdbGlobalProperty range_property_id, AcdbRange* id_range); + +/** +* \brief +* Retrieves an exported/imported shared subgraphs +* from the database +* +* \param[in] subgraph_id: The shared subgraph to search for +* \param[in] im_ex_shared_subgraph_property_id: Either +* 1. ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS or +* 2. ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS +* \param[in/out] guid: The GUID of the provided subgraph +* +* \return 0 on Success, non-zero otherwise +*/ +int32_t DataProcGetSharedSubgraphGuid(uint32_t subgraph_id, + AcdbGlobalProperty im_ex_shared_subgraph_property_id, + uint8_t* guid); + +/** +* \brief +* Retrieves the Exported/Imported Shared Subgraph GUID table +* from the database +* +* \param[in] im_ex_shared_subgraph_property_id: Either +* 1. ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS or +* 2. ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS +* \param[in/out] guid_table: The returned Shared Subgraph GUID table +* +* \return 0 on Success, non-zero otherwise +*/ +int32_t DataProcGetSharedSubgraphGuidTable( + AcdbGlobalProperty im_ex_shared_subgraph_property_id, + AcdbSharedSubgraphGuidTable* guid_table); + +/** +* \brief +* Checks for the existence of a shared subgraph by searching in +* the Shared Subgraph GUID table. +* +* \param[in] subgraph_id: The shared subgraph to search for +* \param[in] guid_table: The Shared Subgraph GUID table to search in +* +* \return TRUE on Success, FALSE otherwise +*/ +bool_t DataProcDoesSharedSubgraphExist(uint32_t subgraph_id, + AcdbSharedSubgraphGuidTable* guid_table); + +/** +* \brief +* Retrieve the mapping between subgraph, processor domain, +* and modules for a given subgraph. +* PDM stands for processor domain module. +* +* \param[in/out] map: Contains the subgraph to search for and the +* data that will be filled by the api +* +* \return 0 on Success, non-zero on failure +*/ +int32_t DataProcGetSubgraphPdmMap(AcdbSubgraphPdmMap* map); + +/** +* \brief +* Search the GKV Key Table for a matching GKV and get back the offset +* to the key value lookup table +* +* \depends The input gkv must be sorted +* +* \param[in] gkv: The GKV to search for +* \param[out] gkv_lut_offset: The offset of the input GKV's value lookup table +* +* \return 0 on success, and non-zero on failure +*/ +int32_t DataProcSearchGkvKeyTable( + AcdbGraphKeyVector* gkv, uint32_t* gkv_lut_offset); + +/** +* \brief +* Search the GKV Lookup Table for a matching value combination and get back +* the offset to the Subgrah List and Subgraph Property Data List +* +* \depends The input gkv must be sorted +* +* \param[in] gkv: The GKV to search for +* \param[in] gkv_lut_offset: The lookup table offset to start at +* \param[out] graph_info: Offset to the subgraph sequence list +* and subgraph property data list +* +* \return 0 on success, and non-zero on failure +*/ +int32_t DataProcSearchGkvLut( + AcdbGraphKeyVector* gkv, + uint32_t gkv_lut_offset, + acdb_graph_info_t *graph_info); + +/** +* \brief +* Search for the first occurance of a tuple using the Module ID as a search key and +* returns the file offset of the first occurrance. +* +* \param[in/out] cal_lut_entry: GSL Calibration Lookuptable entry in the +* format of +* \param[out] cal_lut_entry_offset: The starting offset of one or more +* entries for the MID +* specified in cal_lut_entry.mid +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t DriverDataFindFirstOfModuleID( + acdb_driver_cal_lut_entry_t* cal_lut_entry, + uint32_t* cal_lut_entry_offset); + +#endif //__ACDB_DATA_PROC_H__ diff --git a/acdb/inc/acdb_delta_file_mgr.h b/acdb/inc/acdb_delta_file_mgr.h new file mode 100644 index 0000000..14a4f44 --- /dev/null +++ b/acdb/inc/acdb_delta_file_mgr.h @@ -0,0 +1,71 @@ +#ifndef __ACDB_DELTA_FILE_MGR_H__ +#define __ACDB_DELTA_FILE_MGR_H__ +/** +*============================================================================= +* \file acdb_delta_file_mgr.h +* +* \brief +* This file contains the implementation of the delta acdb file manager +* interfaces. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ +#include "ar_osal_types.h" +#include "acdb_delta_parser.h" +#include "acdb_file_mgr.h" + +/* --------------------------------------------------------------------------- + * Type Declarations + *--------------------------------------------------------------------------- */ + +typedef enum _acdb_delta_data_persist_state { + ACDB_DELTA_DATA_PERSIST_STATE_DISABLED = 0x0, + ACDB_DELTA_DATA_PERSIST_STATE_ENABLED = 0x1 +}AcdbDeltaPersistState; + +enum AcdbDeltaDataCmds { + ACDB_DELTA_DATA_CMD_INIT = 0x0, + ACDB_DELTA_DATA_CMD_ADD_DATABASE, + ACDB_DELTA_DATA_CMD_REMOVE_DATABASE, + ACDB_DELTA_DATA_CMD_ENABLE_PERSISTENCE, + ACDB_DELTA_DATA_CMD_RESET, + ACDB_DELTA_DATA_CMD_GET_FILE_VERSION, + ACDB_DELTA_DATA_CMD_INIT_HEAP, + ACDB_DELTA_DATA_CMD_UPDATE_HEAP, + ACDB_DELTA_DATA_CMD_SAVE, + ACDB_DELTA_DATA_CMD_DELETE_ALL_FILES, + ACDB_DELTA_DATA_CMD_GET_FILE_COUNT, + ACDB_DELTA_DATA_CMD_SWAP_DELTA, + ACDB_DELTA_DATA_CMD_IS_FILE_AT_PATH, +}; + +typedef struct _acdb_delta_data_swap_info_t AcdbDeltaDataSwapInfo; +struct _acdb_delta_data_swap_info_t +{ + /**< The file permissions specifier. See ar_osal_file_io.h */ + uint32_t file_access; + /**< The index of the delta file in the delta file manager file list */ + uint32_t file_index; + /**< The delta path to swap to */ + acdb_path_256_t path_info; +}; + +/* --------------------------------------------------------------------------- +* Class Definitions +*--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- + * Function Declarations and Documentation + *--------------------------------------------------------------------------- */ + +int32_t acdb_delta_data_is_persist_enabled(void); + +int32_t acdb_delta_data_ioctl(uint32_t cmd_id, +void *req, uint32_t req_size, +void *rsp, uint32_t rsp_size); +#endif /* __ACDB_DELTA_FILE_MGR_H__ */ + diff --git a/acdb/inc/acdb_delta_parser.h b/acdb/inc/acdb_delta_parser.h new file mode 100644 index 0000000..c62589a --- /dev/null +++ b/acdb/inc/acdb_delta_parser.h @@ -0,0 +1,98 @@ +#ifndef __ACDB_DELTA_PARSER_H__ +#define __ACDB_DELTA_PARSER_H__ +/** +*============================================================================= +* \file acdb_delta_parser.h +* +* \brief +* The interface of the Acdb Delta Parser/Generator that handles parsing +* and/or generating the ACDB Delta file. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- + * Include Files + *--------------------------------------------------------------------------- */ +#include "ar_osal_types.h" +#include "ar_osal_file_io.h" + +#include "acdb.h" +#include "acdb_utility.h" +/* --------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + *--------------------------------------------------------------------------- */ + +#define ACDB_DELTA_FILE_VERSION_MAJOR 0x00000001 +#define ACDB_DELTA_FILE_VERSION_MINOR 0x00000000 +#define ACDB_DELTA_FILE_REVISION 0x00000000 + +/* --------------------------------------------------------------------------- + * Type Declarations + *--------------------------------------------------------------------------- */ + +typedef struct acdb_delta_file_version_t +{ + uint32_t major; + uint32_t minor; + uint32_t revision; + uint32_t cpl_info; +}acdb_delta_file_version_t; + +//todo: possibly remove or make it external facing +typedef struct _acdb_delta_file_man_file_info_t AcdbDeltaFileManFileInfo; +struct _acdb_delta_file_man_file_info_t { + uint32_t vm_id; + /**< Index of the info structure in the delta file manager file list */ + uint32_t file_index; + /**< Index of the associated acdb file in the acdb file manager file list */ + uint32_t acdb_file_index; + /**< A flag indicating whether the delta file is updated */ + uint32_t is_updated; + /**< A flag that determines the existance of the delta file */ + uint32_t exists; + /**< The size of the delta file */ + uint32_t file_size; + /**< File handle for the delta file */ + ar_fhandle file_handle; + /**< The full delta file path */ + acdb_path_t delta_file_path; + /**< Delta file version and type information */ + acdb_delta_file_version_t file_info; +}; + +typedef struct _acdb_delta_file_header_t AcdbDeltaFileHeader; +#include "acdb_begin_pack.h" +struct _acdb_delta_file_header_t { + uint32_t delta_major; + uint32_t delta_minor; + uint32_t delta_revision; + uint32_t acdb_major; + uint32_t acdb_minor; + uint32_t acdb_revision; + uint32_t acdb_cpl_info; + uint32_t file_data_size; + uint32_t map_count; +} +#include "acdb_end_pack.h" +; + +/* --------------------------------------------------------------------------- + * Function Declarations and Documentation + *--------------------------------------------------------------------------- */ + +int32_t acdb_delta_parser_is_file_valid(ar_fhandle fhandle, uint32_t file_size); + +int32_t acdb_delta_parser_get_file_version(ar_fhandle fhandle, uint32_t file_size, acdb_delta_file_version_t* delta_finfo); + +int32_t acdb_delta_parser_read_map(ar_fhandle fhandle, uint32_t *offset, acdb_delta_data_map_t *map); + +int32_t acdb_delta_parser_write_file_header(ar_fhandle fhandle, acdb_delta_file_version_t* delta_finfo, uint32_t fdata_size, uint32_t map_count); + +int32_t acdb_delta_parser_write_map(ar_fhandle fhandle, acdb_delta_data_map_t *map); + +#endif /* __ACDB_DELTA_PARSER_H__ */ diff --git a/acdb/inc/acdb_file_mgr.h b/acdb/inc/acdb_file_mgr.h new file mode 100644 index 0000000..6afa755 --- /dev/null +++ b/acdb/inc/acdb_file_mgr.h @@ -0,0 +1,213 @@ +#ifndef __ACDB_FILE_MGR_H__ +#define __ACDB_FILE_MGR_H__ +/** +*============================================================================= +* \file acdb_file_mgr.h +* +* \brief +* This file contains the definition of the acdb file manager +* interfaces. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- + * Include Files + *--------------------------------------------------------------------------- */ +#include "acdb.h" +#include "acdb_utility.h" +#include "acdb_context_mgr.h" +#include "acdb_types.h" + +/* --------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + *--------------------------------------------------------------------------- */ + +#define ACDB_MAX_ACDB_FILES 16 +#define INF 4294967295U + +#define PTR_ARG_COUNT(...) \ + ((uint32_t)(sizeof((const void*[]){ __VA_ARGS__ })/sizeof(const void*))) + +//#define ACDB_GET_CHUNK_INFO(...) AcdbGetChunkInfo2(PTR_ARG_COUNT(__VA_ARGS__), __VA_ARGS__) +#define ACDB_GET_CHUNK_INFO(...) \ + acdb_fm_get_db_chunks(PTR_ARG_COUNT(__VA_ARGS__), __VA_ARGS__) + +/* --------------------------------------------------------------------------- + * Type Declarations + *--------------------------------------------------------------------------- */ + + /**path +* Callee must specify info->file_access when info->file_access_io_flag +* is set to ACDB_FUNC_IO_IN +* Callee must set info->file_access_io_flag to ACDB_FUNC_IO_OUT +* to retrieve the file access specifier +* +* +* \param[in] acdb_file_path: The null terminated *.acdb file path string +* \param[in] acdb_file_path_length: The length of the acdb file path +* \param[in] delta_path: The delta path +* \param[out] info: delta file information returned after the function call +* \return 0 on success and non-zero otherwise +*/ +int32_t AcdbInitUtilGetDeltaInfo( + const char_t* acdb_file_path, uint32_t acdb_file_path_length, + acdb_path_t* delta_directory, AcdbInitUtilDeltaInfo *info); + +int32_t AcdbInitUtilGetDeltaInfo2(acdb_path_t* delta_file_path, + acdb_init_util_file_properties_t* info); + +/** +* \brief +* Opens the delta file and retrieves the file handle +* +* \param[in] info: The null terminated *.acdb file path string +* \param[in] acdb_file_path_length: The length of the acdb file path +* \param[in] delta_path: The delta path +* \param[out] delta_fhandle: The delta file handle +* \return 0 on success and non-zero otherwise +* +* \sa +* acdb_init_utility +*/ +int32_t AcdbInitUtilOpenDeltaFile( + AcdbInitUtilDeltaInfo *info, ar_fhandle* delta_fhandle); + +/** +* \brief +* Loads the acdb file from the file handle as a read only buffer +* +* \param[in] fname: The acdb file name +* \param[in] fhandle: The acdb file handle +* \param[out] in_mem_file: The pointer to the read only buffer +* \return AR_EOK on success and an error otherwise +* +* \sa +* acdb_init_utility +*/ +int32_t AcbdInitLoadInMemFile(const char_t* fname, ar_fhandle fhandle, acdb_buffer_t* in_mem_file); + +/** +* \brief +* Unloads an previously loaded acdb file and frees +* any resources used by the readonly buffer +* +* \param[in] in_mem_file: The pointer to the read only buffer +* \return AR_EOK on success and an error otherwise +* +* \sa +* acdb_init_utility +*/ +int32_t AcbdInitUnloadInMemFile(acdb_buffer_t* in_mem_file); +#endif /* __ACDB_INIT_UTILITY_H__ */ diff --git a/acdb/inc/acdb_parser.h b/acdb/inc/acdb_parser.h new file mode 100644 index 0000000..5732b2b --- /dev/null +++ b/acdb/inc/acdb_parser.h @@ -0,0 +1,261 @@ +#ifndef __ACDB_PARSER_H__ +#define __ACDB_PARSER_H__ +/** +*============================================================================= +* \file acdb_parser.h +* +* \brief +* Handle parsing the ACDB Data files. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- +* Include Files +*--------------------------------------------------------------------------- */ +#include "ar_osal_types.h" +#include "ar_osal_file_io.h" +#include "acdb_types.h" + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ + +#define ACDB_PARSE_COMPRESSED 1 +#define ACDB_PARSE_SUCCESS 0 +#define ACDB_PARSE_FAILURE -1 +#define ACDB_PARSE_CHUNK_NOT_FOUND -2 +#define ACDB_PARSE_INVALID_FILE -3 + +/****************************************************************************** +* File Chunks +******************************************************************************/ + +/* +#define ACDB 0x42444341 +#define HEAD 0x44414548 +*/ + +#define ACDB_CHUNKID_HEAD 0x44414548 //HEAD + +//Graph Key Vector +#define ACDB_CHUNKID_GKVKEYTBL 0x54564b47 //GKVT +#define ACDB_CHUNKID_GKVLUTTBL 0x4c564b47 //GKVL +#define ACDB_CHUNKID_GKV_ALIAS 0x534c4147 //GALS + +//Subgraph Connections +#define ACDB_CHUNKID_SGCONNLUT 0x554c4353 //SCLU +#define ACDB_CHUNKID_SGCONNDEF 0x45444353 //SCDE +#define ACDB_CHUNKID_SGCONNDOT 0x4f444353 //SCDO + +//Subgraph Calibration +#define ACDB_CHUNKID_CALSGLUT 0x554c5343 //CSLU +#define ACDB_CHUNKID_CALKEYTBL 0x544b4143 //CAKT +#define ACDB_CHUNKID_CALDATALUT 0x554c4443 //CDLU +#define ACDB_CHUNKID_CALDATADEF 0x45444443 //CDDE +#define ACDB_CHUNKID_CALDATADOT 0x4f444443 //CDD0 +#define ACDB_CHUNKID_CALDATADEF2 0x32444443 //CDD2 + +//PID Persistance +#define ACDB_CHUNKID_PIDPERSIST 0x43545050 //PPTC +#define ACDB_CHUNKID_GLB_PID_PERSIST_MAP 0x4750504d //GPPM (Global PID Persist Map) + +//Datapool +#define ACDB_CHUNKID_DATAPOOL 0x4c4f4f50 //POOL + +//Module Tag Data +#define ACDB_CHUNKID_MODULE_TAGDATA_KEYTABLE 0x544b544d //MTKT +#define ACDB_CHUNKID_MODULE_TAG_KEY_LIST_LUT 0x4c4b544d //MTKL +#define ACDB_CHUNKID_MODULE_TAGDATA_LUT 0x554c544d //MTLU +#define ACDB_CHUNKID_MODULE_TAGDATA_DEF 0x4544544d //MTDE +#define ACDB_CHUNKID_MODULE_TAGDATA_DOT 0x4f44544d //MTDO + +//Tagged Modules +#define ACDB_CHUNKID_TAGGED_MODULE_LUT 0x554c4d54 //TMLU +#define ACDB_CHUNKID_TAGGED_MODULE_DEF 0x45444d54 //TMDE +#define ACDB_CHUNKID_TAGGED_MODULE_MAP 0x204c544d + +//GSL Calibration Data +#define ACDB_CHUNKID_GSL_CAL_LUT 0x554c4347 //GCLU +#define ACDB_CHUNKID_GSL_CALKEY_TBL 0x544b4347 //GCKT +#define ACDB_CHUNKID_GSL_CALDATA_TBL 0x54444347 //GCDT +#define ACDB_CHUNKID_GSL_DEF 0x45444347 //GCDE +#define ACDB_CHUNKID_GSL_DOT 0x4f444347 //GCDO + +//Subgraph Module Map +#define ACDB_CHUNKID_SG_IID_MAP 0x54494753 //SGIT + +//AMDB +#define ACDB_CHUNKID_AMDB_REG_DATA 0x4D444F4D //MODM +#define ACDB_CHUNKID_BOOTUP_LOAD_MODULES 0x50555442 //BTUP + +//VCPM +#define ACDB_CHUNKID_VCPM_CAL_DATA 0x44434356 //VCCD +#define ACDB_CHUNKID_VCPM_MASTER_KEY 0x4b4d4356 //VCMK +#define ACDB_CHUNKID_VCPM_CALKEY_TABLE 0x544b4356 //VCKT +#define ACDB_CHUNKID_VCPM_CALDATA_LUT 0x554c4356 //VCLU +#define ACDB_CHUNKID_VCPM_CALDATA_DEF 0x45444356 //VCDE + +//Hardware Accel Subgraph Info +#define ACDB_CHUNKID_HW_ACCEL_SUBGRAPH_INFO 0x49534148 //HASI + +//Global Properties +#define ACDB_CHUNKID_GLOBAL_PROP 0x4f525047 //GPRO + + +/****************************************************************************** +* Global Properties +******************************************************************************/ + +typedef enum AcdbGlobalProperty +{ + /**< + * This property maintains a list of uint32_t parameters IDs. Offloaded + * parameters are parameters that are stored in a file separate from the + * *.acdb file. The ABNF format of the property is: + * + * Property = EntryCount ParamID+ + * + * DWORDs: EntryCount, ParamID + */ + ACDB_GPROP_OFFLOADED_PARAM_INFO = 0x000133B7, + + /**< Property ID: HWAC (0x43415748) + * This property maintains hardware acceleration info for subgraphs that + * contains hw accel parameter data. The ABNF format of the property is: + * + * Property = NumSubgraphs HwAccelSubgraph+ + * HwAccelSubgraph = SubgraphID ProccesorID HwAccelModuleParamListOffset + * HwAccelModuleParamList = NumModules HwAccelModuleParam+ + * HwAccelModuleParam = ModuleInstanceID ParameterID + * + * DWORDs: NumSubgraphs, SubgraphID, ProccesorID, + * HwAccelModuleParamListOffset, NumModules, + * ModuleInstanceID, ParameterID + */ + ACDB_GPROP_HW_ACCEL_SUBGRAPH_INFO = 0x43415748, + + /**< Property ID: IMSS + * This property contains the subgraph data GUID for imported + * shared subgraphs. + * + * Property = NumSubgraphs SubgraphGuidEntry+ + * SubgraphGuidEntry = SubgraphID Guid + * + * DWORDs: NumSubgraphs, SubgraphID + */ + ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS = 0x53534D49, + + /**< Property ID: EXSS + * This property contains the subgraph data GUID for exported + * shared subgraphs. + * + * Property = NumSubgraphs SubgraphGuidEntry+ + * SubgraphGuidEntry = SubgraphID Guid + * + * DWORDs: NumSubgraphs, SubgraphID + */ + ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS = 0x53535845, + + /**< Property ID: SGIR + * This property contains the subgraph id range [min, max] + * + * Property = SubgraphIdMin SubgraphIdMax + * + * DWORDs: SubgraphIdMin, SubgraphIdMax + */ + ACDB_GPROP_SUBGRAPH_ID_RANGE = 0x52494753, + + /**< Property ID: VMID + * The Virtual Machine ID used by the database. This is + * mainly used by automotive clients. + * + * Property = VMID + * + * DWORDs: VMID + */ + ACDB_GPROP_VIRTUAL_MACHINE_ID = 0X44494D56, +}AcdbGlobalProperty; + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4200) +#endif + +typedef struct acdb_file_version_t +{ + /**< The file major version */ + uint8_t major; + /**< The file minor version */ + uint8_t minor; + /**< The file revision number */ + uint8_t revision; + /**< The cpl version */ + uint8_t cpl_info; +}acdb_file_version_t; + +typedef struct acdb_codec_t +{ + /**< The codec id */ + uint32_t codec_id; + /**< The codec major version */ + uint32_t major; + /**< The codec minor version */ + uint32_t minor; +}acdb_codec_t; + +typedef struct acdb_codec_info_t +{ + /**< The number of codecs */ + uint32_t num_codecs; + /**< List of codecs used in the database */ + acdb_codec_t codecs[0]; +}acdb_codec_info_t; + +typedef struct acdb_oem_info_t +{ + /**< The character length of the description */ + uint32_t legnth; + /**< An OEM description limited to 255 characters */ + char_t description[0]; +}acdb_oem_info_t; + +/**< Version 1 of the ACDB Header Chunk */ +typedef struct acdb_header_v1_t +{ + /**< The version of the header */ + uint32_t header_version; + /**< The version of the file */ + acdb_file_version_t file_version; + /**< Codec ID and Version information used in the file */ + acdb_codec_info_t* codec_info; + /**< A timestamp of when the file was last modified */ + uint32_t date_modified; + /**< OEM specific information */ + acdb_oem_info_t* oem_info; +}acdb_header_v1_t; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +/* --------------------------------------------------------------------------- +* Function Declarations and Documentation +*--------------------------------------------------------------------------- */ + +int32_t acdb_parser_get_chunk( + void* file_buffer, uint32_t buffer_length, + uint32_t chunk_id, uint32_t *chunk_offset, uint32_t *chunk_size); + +int32_t acdb_parser_validate_file(acdb_buffer_t* in_mem_file); + +int32_t acdb_parser_get_acdb_header_v1( + acdb_buffer_t* in_mem_file, acdb_header_v1_t* header); + +#endif /* __ACDB_PARSER_H__ */ diff --git a/acdb/inc/acdb_types.h b/acdb/inc/acdb_types.h new file mode 100644 index 0000000..af58d14 --- /dev/null +++ b/acdb/inc/acdb_types.h @@ -0,0 +1,886 @@ +#ifndef __ACDB_TYPES_H__ +#define __ACDB_TYPES_H__ +/** +*============================================================================= +* \file acdb_types.h +* +* \brief +* Contains type definitions, constatns, and macros used across ACDB SW +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ +#include "ar_osal_types.h" +#include "acdb.h" + +/*----------------------------------------------------------------------------- +* Macros +*----------------------------------------------------------------------------*/ + +/**< Length in bytes of global unique identifiers */ +#define ACDB_GUID_BYTE_LENGTH 16 + +/**< The max character length of a string */ +#define ACDB_MAX_PATH_LENGTH 256 + + /**< The number of elements in Global Buffer 1 */ +#define GLB_BUF_1_LENGTH 2500 + +/**< The number of elements in Global Buffer 2 */ +#define GLB_BUF_2_LENGTH 1000 + +/**< The number of elements in Global Buffer 3 */ +#define GLB_BUF_3_LENGTH 500 + +/**< Max number of keys that can be used. This is capped at half the capacity +of the smallest global buffer length GLB_BUF_3_LENGTH*/ +#define ACDB_MAX_KEY_COUNT (GLB_BUF_3_LENGTH/2) + +/*----------------------------------------------------------------------------- +* Enums Types +*----------------------------------------------------------------------------*/ + +/**< An enumeration for handles that control the where file manager +retrieves data from */ +typedef enum _acdb_handle_override_t { + /**< Context Manager Handle + This is the default handle used by all acdb_ioctl and/or ats commands. */ + ACDB_FM_HANDLE_OVERRIDE_CTX_MANAGER = 0, + /**< File Manager Handle + This handle is used mainly by the file manager during validation for new databases. */ + ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER +} AcdbHandleOverride; + + typedef enum _acdb_op_t { + ACDB_OP_NONE, + ACDB_OP_GET_SIZE, + ACDB_OP_GET_DATA, + ACDB_OP_GET_PARAM_DATA, + ACDB_OP_GET_MODULE_DATA, + ACDB_OP_GET_SUBGRAPH_DATA, +}AcdbOp; + +typedef enum _key_vector_type_t { + TAG_KEY_VECTOR = 0, + CAL_KEY_VECTOR, + GRAPH_KEY_VECTOR, +}KeyVectorType; + + +typedef enum acdb_amdb_reg_dereg_info_type_t +{ + ACDB_AMDB_INFO_REGISTRATION, + ACDB_AMDB_INFO_DEREGISTRATION, +}acdb_amdb_reg_dereg_info_type_t; + +/*----------------------------------------------------------------------------- +* Structure Types +*----------------------------------------------------------------------------*/ + +/**< Holds a pointer to memory of the specified size */ +typedef struct acdb_buffer_t +{ + /**< Size of the buffer */ + uint32_t size; + /**< Pointer to the buffer in memory */ + void *buffer; +}acdb_buffer_t; + +/**< Holds a pointer to a path string */ +typedef struct acdb_path_t +{ + /**< The character length of a path in bytes including the + null terminating character \0 */ + uint32_t path_length; + /**< Pointer to the path string memory */ + char_t *path; +}acdb_path_t; + +/**< Holds 256-byte charater strings */ +typedef struct acdb_path_256_t { + uint32_t path_len; + char_t path[ACDB_MAX_PATH_LENGTH]; +}acdb_path_256_t; + +/**< A linked list node containing a pointer to some +value/structure and the next node */ +typedef struct _linked_list_node_t LinkedListNode; +struct _linked_list_node_t +{ + void* p_struct; + LinkedListNode* p_next; +}; + +typedef struct _linked_list_t LinkedList; +struct _linked_list_t +{ + uint32_t length; + LinkedListNode* p_head; + LinkedListNode* p_tail; +} +; + +typedef struct _acdb_fm_read_seek_req_t acdb_fm_read_req_t; +struct _acdb_fm_read_seek_req_t +{ + /**< Determines which handle to use to retrieve data in the file manager. + By default the context manager handle is used */ + AcdbHandleOverride handle_override; + /**< Pointer to the memory to read data into */ + void* dst_buffer; + /**< The number of bytes to read */ + size_t read_size; + /**< Identifies the property */ + uint32_t offset; +}; + +typedef struct _acdb_fm_mem_ptr_t +{ + /**< Determines which handle to use to retrieve data in the file manager. + By default the context manager handle is used */ + AcdbHandleOverride handle_override; + void *file_ptr; + size_t data_size; + uint32_t offset; +}acdb_fm_file_ptr_req_t; + +typedef struct _chunk_info ChunkInfo; +struct _chunk_info { + /**< Determines which handle to use to retrieve data in the file manager. + By default the context manager handle is used */ + AcdbHandleOverride handle_override; + uint32_t chunk_id; + uint32_t chunk_size; + uint32_t chunk_offset; +}; + +typedef struct _acdb_def_dot_pair_t AcdbDefDotPair; +struct _acdb_def_dot_pair_t { + uint32_t offset_def; + uint32_t offset_dot; +}; + +typedef struct _partition Partition; +struct _partition { + uint32_t size; + uint32_t offset; +}; + +typedef struct _key_table_header_t KeyTableHeader; +struct _key_table_header_t { + uint32_t num_keys; + uint32_t num_entries; +}; + +/**< Holds offsets to the subgraph sequence list properties for the +subgraphs under a graph */ +typedef struct acdb_graph_info_t +{ + /**< Absolute offset to the subgraph list where subgraphs are listed + * in reverse order from sink to source */ + uint32_t sg_list_offset; + /**< Absolute offset to the subgraph property data list + *for all the subgraph in the graph*/ + uint32_t sg_prop_data_offset; +}acdb_graph_info_t; + +typedef struct _sg_list_header_t SgListHeader; +struct _sg_list_header_t { + uint32_t size; + uint32_t num_subgraphs; +}; + +typedef struct _sg_list_obj_header_t SgListObjHeader; +struct _sg_list_obj_header_t { + uint32_t subgraph_id; + uint32_t num_subgraphs; +}; + +/**< Represents and entry in the Module Tag Key Data LUT or Tagged +Module LUT chunks */ +typedef struct _subgraph_tag_key_lut_entry_t SubgraphTagLutEntry; +struct _subgraph_tag_key_lut_entry_t { + /**< Subgraph ID */ + uint32_t sg_id; + /**< Module Tag */ + uint32_t tag_id; + /**< Module Tag Key Data LUT: an offset of the tag key value lut + Tagged Module LUT: an offset to a list of pairs*/ + uint32_t offset; +}; + +/**< Represents and entry in the Module Tag Key List LUT Chunk */ +typedef struct _tag_key_list_entry_t TagKeyListEntry; +struct _tag_key_list_entry_t { + /**< Module Tag */ + uint32_t tag_id; + /**< Offset of the key list in the data pool */ + uint32_t key_list_offset; +}; + +/**< A Tag and Definition Offset pair */ +typedef struct _tag_def_offset_pair AcdbTagDefOffsetPair; +struct _tag_def_offset_pair { + uint32_t tag_id; + uint32_t def_offset; +}; + +typedef struct acdb_driver_cal_lut_entry_t { + uint32_t mid; + uint32_t offset_calkey_table; + uint32_t offset_caldata_table; +}acdb_driver_cal_lut_entry_t; + +typedef struct _gsl_cal_lut_header_t GslCalDataLutHeader; +struct _gsl_cal_lut_header_t +{ + uint32_t num_keys; + uint32_t num_entries; +}; + +typedef struct _calibration_identifier_map_t CalibrationIdMap; +struct _calibration_identifier_map_t +{ + uint32_t cal_id; + uint32_t param_id; + uint32_t cal_data_offset; +}; + +typedef struct _acdb_parameter_tag_data_t AcdbParameterTagData; +struct _acdb_parameter_tag_data_t { + uint32_t subgraph_id; + uint32_t module_iid; + uint32_t parameter_id; + AcdbModuleTag module_tag; +}; + +typedef struct _acdb_parameter_cal_data_t AcdbParameterCalData; +struct _acdb_parameter_cal_data_t { + uint32_t subgraph_id; + uint32_t module_iid; + uint32_t parameter_id; + AcdbGraphKeyVector cal_key_vector; +}; + +typedef struct _acdb_mod_iid_param_id_pair_t AcdbModIIDParamIDPair; +struct _acdb_mod_iid_param_id_pair_t { + uint32_t module_iid; + uint32_t parameter_id; +}; + +typedef struct _acdb_sg_cal_lut_header_t AcdbSgCalLutHeader; +struct _acdb_sg_cal_lut_header_t { + uint32_t subgraph_id; + uint32_t num_ckv_entries; +}; + +typedef struct _acdb_cal_key_tbl_entry AcdbCalKeyTblEntry; +struct _acdb_cal_key_tbl_entry { + uint32_t offset_cal_key_tbl; + uint32_t offset_cal_lut; +}; + +typedef struct _acdb_ckv_lut_entry_offsets_t AcdbCkvLutEntryOffsets; +struct _acdb_ckv_lut_entry_offsets_t { + uint32_t offset_def; + uint32_t offset_dot; + uint32_t offset_dot2; +}; + +/**< The Header format used when retrieving calibration data for the DSP */ +typedef struct _acdb_dsp_module_header_t AcdbDspModuleHeader; +struct _acdb_dsp_module_header_t +{ + /**< Module Instance ID*/ + uint32_t module_iid; + /**< Parameter ID*/ + uint32_t parameter_id; + /**< Size of the parameter*/ + uint32_t param_size; + /**< Error code set by the dsp*/ + uint32_t error_code; +}; + +/**< Same as AcdbDspModuleHeader except that this format does not +contain the error code */ +typedef struct _acdb_module_header_t AcdbModuleHeader; +struct _acdb_module_header_t +{ + /**< Module Instance ID*/ + uint32_t module_iid; + /**< Parameter ID*/ + uint32_t parameter_id; + /**< Size of the parameter*/ + uint32_t param_size; +}; + +/*VCPM Structures Start*/ +typedef struct _acdb_vcpm_subgraph_cal_header_t AcdbVcpmSubgraphCalHeader; +struct _acdb_vcpm_subgraph_cal_header_t +{ + /**< VCPM Module Instance ID*/ + uint32_t module_iid; + /**< VCPM Parameter ID*/ + uint32_t parameter_id; + /**< Number of VCPM Subgraphs*/ + uint32_t num_subgraphs; +}; + +typedef struct _acdb_vcpm_subgraph_cal_table_t AcdbVcpmSubgraphCalTable; +struct _acdb_vcpm_subgraph_cal_table_t +{ + /**< */ + uint32_t subgraph_id; + /**< */ + uint32_t table_size; + /**< */ + uint32_t major; + /**< */ + uint32_t minor; + /**< */ + uint32_t offset_vcpm_master_key_table; + /**< */ + uint32_t num_ckv_data_table; + //List of voice ckv data tables +}; + +typedef struct _acdb_vcpm_ckv_data_table_t AcdbVcpmCkvDataTable; +struct _acdb_vcpm_ckv_data_table_t +{ + /**< Size of the VCPM Calibration Data Table*/ + uint32_t table_size; + /**< Offset of the Voice Calibration Key ID table in the Voice Key Chunk*/ + uint32_t offset_voice_key_table; + /**< Size of the calibration data offset table*/ + uint32_t cal_dot_size; + /**< Number of Calibration data objects*/ + uint32_t num_caldata_obj; + //Cal Dot Table +}; + +typedef struct _acdb_vcpm_caldata_object_t AcdbVcpmCalDataObj; +struct _acdb_vcpm_caldata_object_t +{ + /**< Offset of the Voice CKV LUT in the VCPM CKV LUT Chunk*/ + uint32_t offset_vcpm_ckv_lut; + /**< Offset of the VCPM Cal Definition table in the VCPM Cal Def Chunk*/ + uint32_t offset_cal_def; + /**< The number of parameter calibration payloads in the data pool + This should be the same as the number of pairs in the + Cal Def Table*/ + uint32_t num_data_offsets; + //Cal Dot Tables... +}; + +typedef struct _acdb_vcpm_param_info_t AcdbVcpmParamInfo; +struct _acdb_vcpm_param_info_t +{ + /**< Offset of the parameter in the VCPM data pool*/ + uint32_t offset_vcpm_data_pool; + /**< Flag to check the wheter a parameter is persistent. 0:false, 1:true*/ + uint32_t is_persistent; +}; + + +typedef struct _acdb_mid_pid_pair_t AcdbMiidPidPair; +struct _acdb_mid_pid_pair_t +{ + /**< Module Instance ID*/ + uint32_t module_iid; + /**< Parameter ID*/ + uint32_t parameter_id; +}; + +typedef struct _acdb_vcpm_key_info_t AcdbVcpmKeyInfo; +struct _acdb_vcpm_key_info_t +{ + /**< The Voice Calibration Key ID*/ + uint32_t key_id; + /**< */ + uint32_t is_dynamic; +}; + +typedef struct _acdb_vcpm_chunk_properties_t AcdbVcpmChunkProperties; +struct _acdb_vcpm_chunk_properties_t +{ + /**< The chunks base offset (excluding the chunk size)*/ + uint32_t base_offset; + /**< The current offset */ + uint32_t offset; + /**< The chunk size */ + uint32_t size; +}; + +//typedef struct _acdb_vcpm_kv_info_t AcdbVcpmKvInfo; +//#include "acdb_begin_pack.h" +//struct _acdb_vcpm_kv_info_t +//{ +// /**< Flag for detecting an empty key vector +// 0:Not an empty key vector 1: Is an empty key vector*/ +// uint32_t is_zero_kv; +// /**< Offset of key vector key(s) in VCPM Key ID Chunk */ +// uint32_t offset_cal_key_id; +// /**< Offset of key vector value(s) in VCPM Key LUT Chunk */ +// uint32_t offset_cal_key_lut; +//} +//#include "acdb_end_pack.h" +//; + +typedef struct _acdb_vcpm_offloaded_param_info_t AcdbVcpmOffloadedParamInfo; +struct _acdb_vcpm_offloaded_param_info_t +{ + /**< File offset to the pair in the VCPM Cal DEF Chunk */ + uint32_t file_offset_cal_def; + /**< File offset to the parameters payload in the Global Datapool Chunk */ + uint32_t file_offset_data_pool; + /**< Blob offset of the CalDataObj[n].ParamInfo.offset in the VCPM + Subgraph Info Chunk */ + uint32_t blob_offset_vcpm_param_info; +}; + +typedef struct _acdb_file_to_vcpm_data_pool_offset_info_t AcdbFileToVcpmDataPoolOffsetInfo; +struct _acdb_file_to_vcpm_data_pool_offset_info_t +{ + /**< File offset to the pair in the VCPM Cal DEF Chunk */ + uint32_t file_offset_cal_def; + /**< File offset to the parameters payload in the Global Datapool Chunk */ + uint32_t file_offset_data_pool; + /**< Blob offset to the parameter info in the VCPM Datapool Chunk */ + uint32_t vcpm_offset_data_pool; +}; + +typedef struct _acdb_proc_domain_module_list_t AcdbProcDomainModuleList; +#include "acdb_begin_pack.h" +struct _acdb_proc_domain_module_list_t +{ + /**< The processor domain that the modules in the list run under */ + uint32_t proc_domain_id; + /**< The number of modules in the module list */ + uint32_t module_count; + /**< A list of modules associated with proc_domain_id */ + AcdbModuleInstance module_list[0]; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_subgraph_proc_domain_module_map_t +AcdbSubgraphPdmMap; +#include "acdb_begin_pack.h" +struct _acdb_subgraph_proc_domain_module_map_t +{ + /**< The subgraph associated with the modules */ + uint32_t subgraph_id; + /**< the number of processor domains running in the subgraph */ + uint32_t proc_count; + /**< the size of the proccessor domain module list */ + uint32_t size; + /**< A list that maps modules to a processor domain */ + AcdbProcDomainModuleList* proc_info; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_vcpm_blob_info_t AcdbVcpmBlobInfo; +struct _acdb_vcpm_blob_info_t +{ + /**< Current operation being performed */ + AcdbOp op; + /**< The VCPM Subgraph ID*/ + uint32_t subgraph_id; + /**< The Processor to get calibration for */ + uint32_t proc_id; + /**< A flag used to filter calibration based on processor domain */ + bool_t should_filter_cal_by_proc_domain; + /**< A pointer to a mapping that associates module instances with + the processor domains they run on */ + AcdbSubgraphPdmMap* sg_mod_iid_map; + /**< A flag indicating whether check for hw accel based calibraion */ + bool_t should_check_hw_accel; + /**< An offset to a Subgrahps hardware accel module list */ + uint32_t hw_accel_module_list_offset; + /**< Starting offset of the VCPM Framework Module blob */ + uint32_t offset_vcpm_blob; + /**< The number of offloaded parameters found */ + uint32_t num_offloaded_params; + /**< A pointer to the current offloaded parameter info node */ + LinkedListNode* curr_opi_node; + /**< List of AcdbVcpmOffloadedParamInfo for writting offloaded params + at the end of the vcpm datapool */ + LinkedList offloaded_param_info_list; + /**< List of offloaded parameter IDs*/ + AcdbUintList offloaded_param_list; + /**< 0:Zero CKV has NOT been writen 1: Zero CKV has been writen */ + //AcdbVcpmKvInfo zero_key_vector_info; + /**< A flag indicating whether the module CKV found is the default key + vector(no keys) */ + bool_t is_default_module_ckv; + /**< A flag indicating whether process(true) or skip(false) the + default CKV */ + bool_t ignore_get_default_data; + /**< A flag indicating whether to add (true) iids to the referenced_iid_list + or do nothing (false) */ + bool_t ignore_iid_list_update; + /**< Keeps track of module IIDs that are used in CKVs. This does not include + the default CKV. The list contains AcdbIidRefCount objects */ + AcdbUintList referenced_iid_list; + /**< A list of relative offsets to the ckv data tables with data to write */ + AcdbUintList ckv_data_table_offset_list; + /**< A list of absolute offsets to the found cal key id tables */ + AcdbUintList cal_key_id_table_offset_list; + /**< VCPM Subgraph Info Chunk*/ + AcdbVcpmChunkProperties chunk_subgraph_info; + /**< Master Key Table Chunk that contains the super set of calibration + keys used in the subgraph */ + AcdbVcpmChunkProperties chunk_master_key; + /**< Voice Cal Key Table chunk that contains various key combinations. + The keys are a subset of the keys defined in the Master Key Table */ + AcdbVcpmChunkProperties chunk_cal_key_id; + /**< Voice Cal Key Lookup table that contains the values of the key + combinations in the Voice Cal Key Table chunk */ + AcdbVcpmChunkProperties chunk_cal_key_lut; + /**< Datapool chunk that contains calibration data for modules within + the vcpm subgraph */ + AcdbVcpmChunkProperties chunk_data_pool; +}; + +typedef struct _acdb_vcpm_chunk_info_t AcdbVcpmChunkInfo; +struct _acdb_vcpm_chunk_info_t +{ + ChunkInfo vcpm_sg_cal; + ChunkInfo vcmp_master_key_table; + ChunkInfo vcpm_cal_key_table; + ChunkInfo vcpm_cal_lut; + ChunkInfo vcpm_cal_def; +}; + +/*VCPM Structures End*/ + +typedef struct _acdb_property_entry_t AcdbPropertyEntry; +struct _acdb_property_entry_t +{ + uint32_t property_id; + uint32_t offset_property_data; +}; + +typedef struct _acdb_offloaded_param_header_t AcdbOffloadedParamHeader; +struct _acdb_offloaded_param_header_t +{ + /**< the alignment that determines the amount of padding added before the data */ + uint32_t alignment; + /**< the starting offset of the data */ + uint32_t data_offset; + /**< Size of the data starting at data_offset */ + uint32_t data_size; + /*uint8_t data[0]*/ + /*padding = data_length % 4*/ +}; + +/**< Contains a list of subgraphs and parameter data under the subgraphs. The +parameter data can be calibration or tag data */ +typedef struct _acdb_subgraph_param_data_t AcdbSubgraphParamData; +struct _acdb_subgraph_param_data_t { + /**< The list of subgraphs */ + AcdbUintList subgraph_id_list; + /**< Configures the cal/tag data blob parser to bypass the + error code if its not included with each parameter. For example, + param data set from qact is in the fomrat: + */ + bool_t ignore_error_code; + /**< The size of the subgraph parameter data */ + uint32_t data_size; + /**< Parameter data in the format of: + [1] + ... + [n]*/ + void* data; +}; + +/**< Represents an entry within the subgraph connection lookup table */ +typedef struct _acdb_subgraph_connection_t AcdbSubgraphConnection; +struct _acdb_subgraph_connection_t +{ + /**< The ID of source subgraph */ + uint32_t src_subgraph_id; + /**< The ID of destination subgraph */ + uint32_t dst_subgraph_id; + /**< The offset within the subgraph connection definition table */ + uint32_t def_offset; + /**< The offset within the subgraph connection data offset table */ + uint32_t dot_offset; +}; + +typedef struct _acdb_shared_subgrah_data_guid_entry_t AcdbSharedSubgraphDataGuid; +struct _acdb_shared_subgrah_data_guid_entry_t { + /**< The identifier for the shared subgraph */ + uint32_t subgraph_id; + /**< A globally unique 128-bit integer representing the shared subgraphs data. */ + uint8_t guid[ACDB_GUID_BYTE_LENGTH]; +}; + +typedef struct _acdb_shared_subgraph_guid_table_t AcdbSharedSubgraphGuidTable; +struct _acdb_shared_subgraph_guid_table_t { + uint32_t num_subgraphs; + AcdbSharedSubgraphDataGuid* guid_entries; +}; + +typedef struct _acdb_range_t AcdbRange; +struct _acdb_range_t { + uint32_t min; + uint32_t max; +}; + +typedef struct _acdb_delta_module_cal_data_t AcdbDeltaModuleCalData; +struct _acdb_delta_module_cal_data_t { + uint32_t module_iid; + uint32_t param_id; + uint32_t param_size; + void* param_payload; +}; + +typedef struct _acdb_delta_persistence_payload_t AcdbDeltaPersistanceData; +struct _acdb_delta_persistence_payload_t { + uint32_t data_size; + LinkedList cal_data_list;//List of AcdbDeltaModuleCalData +}; + +typedef struct _acdb_delta_subgraph_data_t AcdbDeltaSubgraphData; +struct _acdb_delta_subgraph_data_t { + uint32_t subgraph_id; + uint32_t subgraph_data_size; + AcdbDeltaPersistanceData non_global_data; + AcdbDeltaPersistanceData global_data; +}; + +/**< Maps a Key Vector to subgraph parameter data instances */ +typedef struct acdb_delta_data_map_t { + /**< Key vector type that describes the data in key_vector_data. + If type=TAG_KEY_VECTOR key_vector_data=AcdbModuleTag. + If type=CAL_KEY_VECTOR key_vector_data=AcdbGraphKeyVector */ + KeyVectorType key_vector_type; + /**< Pointer to AcdbGraphKeyVector Calibration key Vector or AcdbModuleTag*/ + void* key_vector_data; + /**< Size of the Map*/ + uint32_t map_size; + /**< Number of subgraphs in the map*/ + uint32_t num_subgraphs; + /**< List of AcdbDeltaSubgraphData*/ + LinkedList subgraph_data_list; +}acdb_delta_data_map_t; + +typedef struct acdb_amdb_module_reg_info_t +{ + /**< Size of the module registration data */ + uint32_t data_size; + /**< The the processor domain ID*/ + uint16_t interface_type; + uint16_t interface_version; + uint32_t module_type; + uint32_t module_id; + uint16_t file_name_length; + uint16_t tag_length; + uint32_t error_code; + /**< The *.so file name and tag string data */ + //uint8_t data[0]; + +}acdb_amdb_module_reg_info_t; + +typedef struct acdb_amdb_proc_reg_data_t +{ + /**< Size of the processor registration data */ + uint32_t data_size; + /**< The ID of the processor domain that the + AMDB modules will run under */ + uint32_t proc_id; + /**< The number of custom modules under the processor. + See acdb_amdb_module_reg_info_t */ + uint32_t module_count; + /**< The version of the spf acdb_spf_amdb_module_reg_info_t. See + amdb_module_registration_t in amdb_api.h*/ + uint32_t struct_version; + /* All AMDB custom module data for the processor domain */ + acdb_amdb_module_reg_info_t *module_reg_data; +}acdb_amdb_proc_reg_data_t; + +/**< The SPF AMDB module registration v1 structure */ +typedef struct acdb_spf_amdb_module_reg_info_t +{ + uint16_t interface_type; + uint16_t interface_version; + uint32_t module_type; + uint32_t module_id; + uint16_t file_name_length; + uint16_t tag_length; + uint32_t error_code; + /**< The *.so file name and tag string data */ + //uint8_t data[0]; + +}acdb_spf_amdb_module_reg_info_t; + +/* Processor domain based AMDB module registration data. +See AMDB_CMD_REGISTER_MODULES in spf\amdb_api.h */ +typedef struct acdb_spf_amdb_module_reg_t +{ + /**< The ID of the processor domain that the + AMDB modules will run under */ + uint32_t proc_id; + /**< The number of custom modules under the processor. + See acdb_amdb_module_reg_info_t */ + uint32_t num_modules; + /**< The version of the spf acdb_spf_amdb_module_reg_info_t. See + amdb_module_registration_t in amdb_api.h*/ + uint32_t struct_version; + acdb_spf_amdb_module_reg_info_t reg_info[0]; +}acdb_spf_amdb_module_reg_t; + +/* Processor domain based AMDB module de-registration data. +See AMDB_CMD_DEREGISTER_MODULES in spf\amdb_api.h */ +typedef struct acdb_amdb_module_dereg_t +{ + /**< The ID of the processor domain that the + AMDB modules will run under */ + uint32_t proc_id; + /**< Number of modules being de-registered */ + uint32_t num_modules; + /**< List of modules being de-registered */ + uint32_t module_id[0]; +}acdb_amdb_module_dereg_t; + +typedef struct acdb_amdb_bootup_proc_table_entry_t +{ + /**< The ID of the processor domain that the + AMDB modules will run under */ + uint32_t proc_id; + /**< Number of modules bootup modules */ + uint32_t num_modules; + /**< List of bootup module IDs */ + uint32_t module_ids[0]; +}acdb_amdb_bootup_proc_table_entry_t; + +typedef struct acdb_amdb_bootup_module_t +{ + /**< ID of the module being loaded at boot */ + uint32_t module_id; + /**< LSW of the Handle to the bootup module */ + uint32_t handle_lsw; + /**< MSW of the Handle to the bootup module. */ + uint32_t handle_msw; +}acdb_amdb_bootup_module_t; + +/* Processor domain based AMDB module bootup load/unload data. +See AMDB_CMD_LOAD_MODULES in spf\amdb_api.h */ +typedef struct acdb_amdb_proc_bootup_data_t +{ + /**< The ID of the processor domain that the + AMDB modules will run under */ + uint32_t proc_id; + /**< Result of the module loading. For out-of-band payload + this block will be directly updated. */ + uint32_t error_code; + /**< Number of modules bootup modules */ + uint32_t num_modules; + /**< List of module bootup loading/unload info */ + acdb_amdb_bootup_module_t load_unload_info[0]; +}acdb_amdb_proc_bootup_data_t; + +typedef struct _acdb_tag_def_offset_pair_list_t AcdbTagDefOffsetPairList; +struct _acdb_tag_def_offset_pair_list_t +{ + /**< Number of elemts in the list */ + uint32_t count; + /**< Max number of elemts that this list can store */ + uint32_t max_count; + /**< The size of an element. For example is an element where the size is 8 + * bytes */ + uint32_t element_size; + /**< Pointer to AcdbTagDefOffsetPair */ + AcdbTagDefOffsetPair* list; +}; + +typedef struct _acdb_proc_domain_offset_pair_t AcdbProcDomainOffsetPair; +struct _acdb_proc_domain_offset_pair_t +{ + /**< The processor domain id */ + uint32_t proc_domain_id; + /**< An general purpose offset */ + uint32_t offset; +}; + +typedef struct _acdb_generic_list_item_t AcdbGenericListItem; +struct _acdb_generic_list_item_t +{ + /**< The index of an item in an AcdbGenericList instance */ + uint32_t index; + /**< A pointer to the item in AcdbGenericList::list */ + void* item; +}; + +/** +* \brief ACDB_GENERIC_LIST_ADD +* Adds a range of elements to a generic list +* \param [in] list: pointer to a AcdbGenericList type +* \param [in] items: one or more items to add to the list +* \param [in] item_size: the size of one item +* \param [in] count: the number of items to add to the list +*/ +typedef int32_t(*ACDB_GENERIC_LIST_ADD)( + void* list, void* items, uint32_t item_size, uint32_t count); + +/** +* \brief ACDB_GENERIC_LIST_FIND +* Searches for an element in a AcdbGenericList +* each +* \param [in] list: pointer to a AcdbGenericList type +* \param [in] item: the item to search for. The item must be +* 4 bytes or more. If more then its size must be a +* multiple of 4. This is required by the binary search +* used in the find function. For example an item +* can be a structure with two 4 byte fields +* \param [in] item_size: the size of the item +* \param [in] num_search_keys: the number of 4 byte components to use +* for the search +* \param [out] found_item: the item found in the list containing the +* index and a pointer to the item +*/ +typedef int32_t(*ACDB_GENERIC_LIST_FIND)( + void* list, void* item, uint32_t item_size, + uint32_t num_search_keys, AcdbGenericListItem* found_item); + +/** +* \brief ACDB_GENERIC_LIST_FIND +* Searches for an element in a AcdbGenericList +* each +* \param [in] list: pointer to a AcdbGenericList type +* \param [in] key_elem_struct_position: the 4byte key to sort by. Specify the +* position of the key within your structure. E.g +* struct _some_struct{ +* int32_t a; position 0 +* int32_t b; position 1 +* int32_t c; position 2 +* } +*/ +typedef int32_t(*ACDB_GENERIC_LIST_SORT)( + void* list, uint32_t key_elem_struct_position); + +/**< A list with an opaque pointer to store homogeneous elements of a particular size */ +typedef struct _acdb_generic_list_t AcdbGenericList; +struct _acdb_generic_list_t +{ + /**< Number of elemts in the list */ + uint32_t count; + /**< Max number of elemts that this list can store */ + uint32_t max_count; + /**< The size of an element. For example is an element where the size is 8 + * bytes */ + uint32_t element_size; + /**< Pointer to contiguous memory containing items of size element_size */ + void* list; + /**< Pointer to a function that adds a range of elements to the list */ + ACDB_GENERIC_LIST_ADD add_range; + ACDB_GENERIC_LIST_FIND find; + ACDB_GENERIC_LIST_SORT sort; +}; + +#endif /*__ACDB_TYPES_H__*/ diff --git a/acdb/inc/acdb_utility.h b/acdb/inc/acdb_utility.h new file mode 100644 index 0000000..867b293 --- /dev/null +++ b/acdb/inc/acdb_utility.h @@ -0,0 +1,267 @@ +#ifndef __ACDB_UTILITY_H__ +#define __ACDB_UTILITY_H__ +/** +*============================================================================= +* \file acdb_utility.h +* +* \brief +* Provides utility functions to be used accross ACDB SW. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- +* Include Files +*--------------------------------------------------------------------------- */ +#include "acdb.h" +#include "ar_osal_error.h" +#include "ar_osal_types.h" +#include "ar_osal_heap.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_string.h" +#include "acdb_types.h" + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ +#define SEARCH_SUCCESS 0 + +#define SEARCH_ERROR -1 + +#define IsNull(ptr) (ptr == NULL) + +#define ACDB_FIND_STR(string, sub_string) ar_strstr(string, sub_string) + +#define ACDB_MEM_CPY_SAFE(dest, dest_size, src, src_size) ar_mem_cpy((int8_t*) dest, dest_size, (int8_t*)src, src_size) + +#define ACDB_STR_CPY_SAFE(dest, dest_size, src, src_size) ar_strcpy(dest, dest_size, src, src_size) + +#define ACDB_STR_CAT_SAFE(dest, dest_size, src, src_size) ar_strcat(dest, dest_size, src, src_size) + +#define ACDB_ALIGN_8_BYTE(byte_size) AcdbAlign(8, byte_size) + +#define ACDB_PADDING_8_BYTE(byte_size) AcdbPadding(8, byte_size) + +#define ACDB_MALLOC(type, count) (type*)AcdbMalloc(sizeof(type)*count) + +#define ACDB_FREE(data) AcdbFree((void*)data) + +//TODO: Remove this function once its avalible in the OSAL +#ifndef ar_sscanf +#if defined(_WIN64) || defined(_WIN32) +#define ar_sscanf(buf, format, ...) sscanf_s(buf, format, __VA_ARGS__) +#elif defined(__linux__) +#define ar_sscanf(buf, format, ...) sscanf(buf, format, __VA_ARGS__) +#endif +#endif + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ + +typedef enum _acdb_function_io_t { + ACDB_FUNC_IO_UNUSED = 0x0, + ACDB_FUNC_IO_IN, + ACDB_FUNC_IO_OUT, +}AcdbFunctionIO; + +/* --------------------------------------------------------------------------- +* Function Callbacks +*--------------------------------------------------------------------------- */ + +/** +* \brief +* A Callback for freeing objects pointed to by linked list nodes. This +* callback is used in conjunction with AcdbListClear2(...) +* +* \param [in] object: The object to free +*/ +typedef void(*ACDB_LIST_CLEAR_CALLBACK)( + void* object); + +/* --------------------------------------------------------------------------- +* Struct Definitions +*--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- +* Function Declarations and Documentation +*--------------------------------------------------------------------------- */ + +//bool_t IsNullVar(uint32_t count, ...); + +int32_t AcdbARHeapInit(void); + +int32_t AcdbARHeapDeinit(void); + +void* AcdbMalloc(size_t size); + +void AcdbFree(void* data); + +/** +* \brief AcdbDataBinarySearch2 +* Performs a binary search on an array of structures or basic types +* \param [in] p_array: array to be searched +* \param [in] sz_arr: size of p_array +* \param [in] p_cmd: the structure that is used as a search key +* \param [in] n_search_cmd_params: number of structure members to use in the search +* \param [in] n_total_cmd_params: number of search key(s) used in the search +* \param [in] index: index of the located object +*/ +int32_t AcdbDataBinarySearch2(void *p_array, size_t sz_arr, void *p_cmd, + int32_t n_search_cmd_params, int32_t n_total_cmd_params, uint32_t *index); + +/** +* \brief AcdbSort +* Performs insertion sort on an array of basic types +* \param [in/out] p_array: array to be sorted +* \param [in] sz_arr: size of p_array +*/ +void AcdbSort(void* p_array, uint32_t sz_arr); + +/** +* \brief AcdbSort2 +* Performs insertion sort on an array of basic/user defined types +* \param [in] sz_arr: byte size of p_array +* \param [in/out] p_array: array to be sorted +* \param [in] sz_elem: size of an element in the array +* \param [in] key_elem_pos: position of the sorting key within the element (e.g 0, 1, 2, etc...) +* \return 0 on success, non-zero on failure +*/ +int32_t AcdbSort2(size_t sz_arr, void* p_array, size_t sz_elem, uint32_t key_elem_pos); + +/** +* \brief AcdbAlign +* Performs byte alignment +* \param [in] byte_alignment: number of bytes to align by +* \param [in] byte_size: byte size to align +* \return new aligned byte size, but if already aligned returns byte_size +*/ +uint32_t AcdbAlign(uint32_t byte_alignment, uint32_t byte_size); + +/** +* \brief +* Returns padding based on byte alignment and size +* \param [in] byte_alignment: number of bytes to align by +* \param [in] byte_size: byte size to align +* \return non-zero padding if not aligned, otherwise returns 0 +*/ +uint32_t AcdbPadding(uint32_t byte_alignment, uint32_t byte_size); + +/** +* \brief AcdbListCreateNode +* Performs byte alignment +* \param [in/out] p_array: array to be sorted +* \param [in] p_array: size of p_array +* \return NULL on error, LinkedListNode pointer on success +*/ +LinkedListNode *AcdbListCreateNode(void *p_struct); + +/** +* \brief AcdbListAppend +* Add node at the end of the linked list +* \param [in/out] list: linked list to append to +* \param [in] node: linked list node to append +* \return 0 success, non-zero on failure +*/ +int32_t AcdbListAppend(LinkedList *list, LinkedListNode *node); + +/** +* \brief AcdbListClear +* Clear a linked list by freeing each node. *NOTE* This function does not +* free the objects pointed to by each node. +* \param [in/out] list: linked list to free +*/ +void AcdbListClear(LinkedList *list); + +/** +* \brief AcdbListClear2 +* Clear the linked list and use a callback to free the objects +* pointed to by each node. +* *NOTE* This function operates the same as AcdbListClear if +* the free_obj_cb callback is NULL. +* \param [in/out] list: linked list to free +* \param [in] free_obj_cb: a function callback that knows how to +* free the object pointed to by the node +*/ +void AcdbListClear2(LinkedList *list, ACDB_LIST_CLEAR_CALLBACK free_obj_callback); + +/** +* \brief AcdbListFreeAndSetNext +* Deletes a given node and sets the node to its next node +* \param [in/out] node: address of node within a linked list +*/ +void AcdbListFreeAndSetNext(LinkedListNode** node); + +/** +* \brief AcdbListSetNext +* Sets a given node to its next node +* \param [in/out] node: node within a linked list +*/ +//void AcdbListSetNext(LinkedListNode* node); +bool_t AcdbListSetNext(LinkedListNode** node); + +/** +* \brief AcdbListMerge +* Merges two linked list together and sets the merge from list to NULL +* \param[in] merge_to: list to merge to +* \param[in] merge_from: list to merge from +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t AcdbListMerge(LinkedList *merge_to, LinkedList *merge_from); + +/** +* \brief AcdbListMoveToEnd +* Moves a node within a list to the end +* \param[in] list: The linked list to modify +* \param[in] node: The node within list to move to the end +* \param[in] prev_node: The node within list that precedes node +* \return a map pointer on success, Null on failure +*/ +void AcdbListMoveToEnd(LinkedList *list, LinkedListNode** node, LinkedListNode** prev_node); + +/** +* \brief AcdbListRemove +* Detatches a node from the given list. The previous node +* is attached to the node right of the detached node. The caller +* is responsible for freeing the node +* \param [in] list: The linked list containing prev and node +* \param [in] prev: The previous node +* \param [in] node: The node to detach +* \return 0 on success, non-zero on failure +*/ +int32_t AcdbListRemove(LinkedList *list, LinkedListNode *prev, LinkedListNode *node); + +/** +* \brief LogKeyVector +* Prints the keyvector to the console/log +* \param [in] key_vector: pointer to key vector to log +* \param [in] type: The type of key vector(GKV, CKV, TKV) +*/ +void LogKeyVector(const AcdbGraphKeyVector *key_vector, KeyVectorType type); + +/** +* \brief LogKeyIDs +* Prints the key ids to the console/log +* \param [in] keys: list of uint32 key ids +* \param [in] type: The type of key vector(GKV, CKV, TKV) +*/ +void LogKeyIDs(const AcdbUintList *keys, KeyVectorType type); + +uint32_t AcdbCeil(uint32_t x, uint32_t y); + +/** +* \brief AcdbGenericListInit +* Initializes a generic list by setting the element size, max number of elements, list data, and function pointers +* \param [in] list: The list to initialize +* \param [in] element_size: The size of list elements in bytes +* \param [in] max_element_count: The max number of elements the list can store +* \param [in] list_data: A pointer to the memory used for storing data +*/ +int32_t AcdbGenericListInit(AcdbGenericList* list, uint32_t element_size, uint32_t max_element_count, void** list_data); +#endif /* __ACDB_UTILITY_H__ */ diff --git a/acdb/src/acdb.c b/acdb/src/acdb.c new file mode 100644 index 0000000..e5352b2 --- /dev/null +++ b/acdb/src/acdb.c @@ -0,0 +1,1000 @@ +/** +*============================================================================= +* \file acdb.c +* +* \brief +* Contains the implementation of the public interface to the Audio +* Calibration Database (ACDB) module. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ +#include "ar_osal_error.h" +#include "ar_osal_file_io.h" +#include "ar_osal_mutex.h" +#include "acdb.h" +#include "acdb_file_mgr.h" +#include "acdb_delta_file_mgr.h" +#include "acdb_init.h" +#include "acdb_init_utility.h" +#include "acdb_command.h" +#include "acdb_common.h" +#include "acdb_utility.h" +#include "acdb_context_mgr.h" +#include "acdb_heap.h" + +/* --------------------------------------------------------------------------- +* Global Data Definitions +*--------------------------------------------------------------------------- */ + +int32_t acdb_cmd_set_temp_path(AcdbSetTempPathReq *req); + +/* ---------------------------------------------------------------------------- +* Public Function Definitions +*--------------------------------------------------------------------------- */ + +int32_t acdb_init(AcdbDataFiles *acdb_data_files, AcdbFile* delta_file_path) +{ + int32_t status = AR_EOK; + acdb_init_database_paths_t db_paths = { 0 }; + + if (IsNull(acdb_data_files) || acdb_data_files->num_files == 0) + { + ACDB_ERR("Error[%d]: No database files were provided.", AR_EBADPARAM); + return AR_EBADPARAM; + } + + db_paths.num_files = acdb_data_files->num_files; + + for (uint32_t i = 0; i < db_paths.num_files; i++) + { + db_paths.acdb_data_files[i].path_length = + acdb_data_files->acdbFiles[i].fileNameLen; + db_paths.acdb_data_files[i].path = + &acdb_data_files->acdbFiles[i].fileName[0]; + } + + if (!IsNull(delta_file_path)) + { + db_paths.writable_path.path_length = delta_file_path->fileNameLen; + db_paths.writable_path.path = &delta_file_path->fileName[0]; + } + + status = acdb_init_ioctl(ACDB_INIT_CMD_INIT, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to initialize layers.", status); + return status; + } + + status = acdb_init_ioctl(ACDB_INIT_CMD_ADD_DATABASE, + &db_paths, sizeof(acdb_init_database_paths_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to add files to database.", status); + return status; + } + + return status; +} +int32_t acdb_flash_init(uint32_t* acdbdata_base_addr) +{ + *acdbdata_base_addr = 0x0; + int32_t status = AR_EOK; + return status; +} + +int32_t acdb_deinit() +{ + int32_t status = AR_EOK; + + status = acdb_init_ioctl(ACDB_INIT_CMD_RESET, + NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to de-initialized ACDB SW", status); + return status; + } + + return status; +} +int32_t acdb_add_database(AcdbDatabaseFiles *acdb_data_files, + AcdbFile *writable_path, acdb_handle_t *acdb_handle) +{ + int32_t status = AR_EOK; + acdb_init_database_paths_t db_paths = { 0 }; + + if (IsNull(acdb_data_files) || acdb_data_files->num_files == 0) + { + ACDB_ERR("Error[%d]: No database files were provided.", AR_EBADPARAM); + return AR_EBADPARAM; + } + + db_paths.num_files = acdb_data_files->num_files; + + for (uint32_t i = 0; i < db_paths.num_files; i++) + { + db_paths.acdb_data_files[i].path_length = + acdb_data_files->database_files[i].fileNameLen; + db_paths.acdb_data_files[i].path = + &acdb_data_files->database_files[i].fileName[0]; + } + + if (!IsNull(writable_path)) + { + db_paths.writable_path.path_length = writable_path->fileNameLen; + db_paths.writable_path.path = &writable_path->fileName[0]; + } + + status = acdb_init_ioctl(ACDB_INIT_CMD_ADD_DATABASE, + &db_paths, sizeof(acdb_init_database_paths_t), + acdb_handle, sizeof(acdb_handle_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to add files to database.", status); + return status; + } + + return status; +} + +int32_t acdb_remove_database(const acdb_handle_t *acdb_handle) +{ + int32_t status = AR_EOK; + + if (IsNull(acdb_handle)) + { + ACDB_ERR("Error[%d]: The input parameter is null.", AR_EBADPARAM); + return AR_EBADPARAM;; + } + + status = acdb_init_ioctl(ACDB_INIT_CMD_REMOVE_DATABASE, + (acdb_handle_t)acdb_handle, sizeof(acdb_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to add files to database.", status); + return status; + } + + return status; +} + +int32_t acdb_get_handle(AcdbFile *acdb_file, acdb_handle_t *acdb_handle) +{ + int32_t status = AR_EOK; + uint32_t vm_id = 0; + + if (IsNull(acdb_file) || IsNull(acdb_handle)) + { + return AR_EBADPARAM; + } + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_GET_VM_ID_FROM_FILE_NAME, + acdb_file, sizeof(AcdbFile), + &vm_id, sizeof(uint32_t)); + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_GET_ACDB_CLIENT_HANDLE, + &vm_id, sizeof(uint32_t), acdb_handle, sizeof(acdb_handle_t)); + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve the database handle for %s", + status, acdb_file->fileName); + } + + return status; +} + +int32_t acdbCmdIsPersistenceSupported(__UNUSED uint32_t *resp) +{ + __UNREFERENCED_PARAM(resp); + /* This function should not be used. Use the acdb_iotcl with + * the ACDB_CMD_ENABLE_PERSISTENCE command*/ + return AR_ENOTIMPL; +} + +int32_t acdb_ioctl(uint32_t cmd_id, + const void *cmd_struct, + uint32_t cmd_struct_size, + void *rsp_struct, + uint32_t rsp_struct_size) +{ + int32_t status = AR_EOK; + + ACDB_PKT_LOG_DATA("ACDB_IOCTL_CMD_ID", &cmd_id, sizeof(cmd_id)); + + ACDB_MUTEX_LOCK(ACDB_CTX_MAN_CLIENT_CMD_LOCK); + + switch (cmd_id) { + case ACDB_CMD_GET_GRAPH: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbGraphKeyVector) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbGraphKeyVector *req = (AcdbGraphKeyVector *)cmd_struct; + AcdbGetGraphRsp *rsp = (AcdbGetGraphRsp *)rsp_struct; + + if (req->num_keys == 0 || req->num_keys >= ACDB_MAX_KEY_COUNT) + { + status = AR_EBADPARAM; + } + else + status = AcdbCmdGetGraph(req, rsp, rsp_struct_size); + } + break; + case ACDB_CMD_GET_SUBGRAPH_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbSgIdGraphKeyVector) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbSgIdGraphKeyVector *req = (AcdbSgIdGraphKeyVector*)cmd_struct; + AcdbGetSubgraphDataRsp *rsp = (AcdbGetSubgraphDataRsp*)rsp_struct; + if (req->sg_ids == NULL || + req->graph_key_vector.graph_key_vector == NULL || + req->graph_key_vector.num_keys >= ACDB_MAX_KEY_COUNT) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetSubgraphData(req, rsp); + } + } + break; + case ACDB_CMD_GET_SUBGRAPH_CONNECTIONS: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbSubGraphList) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbSubGraphList *req = (AcdbSubGraphList*)cmd_struct; + AcdbBlob *rsp = (AcdbBlob*)rsp_struct; + if ((req->num_subgraphs == 0) || (req->subgraphs == NULL)) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetSubgraphConnections(req, rsp); + } + } + break; + case ACDB_CMD_GET_SUBGRAPH_CALIBRATION_DATA_NONPERSIST: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbSgIdCalKeyVector) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbSgIdCalKeyVector *req = (AcdbSgIdCalKeyVector*)cmd_struct; + AcdbBlob *rsp = (AcdbBlob*)rsp_struct; + if ((req->num_sg_ids == 0) || (req->sg_ids == NULL)) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetSubgraphCalDataNonPersist(req, rsp, rsp_struct_size); + } + } + break; + case ACDB_CMD_GET_SUBGRAPH_CALIBRATION_DATA_PERSIST: + if (IsNull(cmd_struct) || + cmd_struct_size != sizeof(AcdbSgIdCalKeyVector) || + IsNull(rsp_struct) || + rsp_struct_size != sizeof(AcdbSgIdPersistCalData)) + { + status = AR_EBADPARAM; + } + else + { + AcdbSgIdCalKeyVector *req = (AcdbSgIdCalKeyVector*)cmd_struct; + AcdbSgIdPersistCalData *rsp = (AcdbSgIdPersistCalData*)rsp_struct; + if ((req->num_sg_ids == 0) || (req->sg_ids == NULL)) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetSubgraphCalDataPersist(req, rsp); + } + } + break; + case ACDB_CMD_GET_SUBGRAPH_GLB_PSIST_IDENTIFIERS: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbSgIdCalKeyVector) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + //todo: Commenting out to suppress warnings. Uncomment when this api is supported + // AcdbSgIdCalKeyVector *req = (AcdbSgIdCalKeyVector*)cmd_struct; + // AcdbGlbPsistIdentifierList *rsp = (AcdbGlbPsistIdentifierList*)rsp_struct; + // if ((req->num_sg_ids == 0) || (req->sg_ids == NULL)) + // { + // status = AR_EBADPARAM; + // } + // else + // { + // status = AcdbCmdGetSubgraphGlbPersistIds(req, rsp, rsp_struct_size); + // } + + status = AR_ENOTEXIST; + + } + break; + case ACDB_CMD_GET_SUBGRAPH_GLB_PSIST_CALDATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbGlbPersistCalDataCmdType) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + //todo: Commenting out to suppress warnings. Uncomment when this api is supported + // AcdbGlbPersistCalDataCmdType *req = (AcdbGlbPersistCalDataCmdType*)cmd_struct; + // AcdbBlob *rsp = (AcdbBlob*)rsp_struct; + // if (req->cal_Id == 0) + // { + // status = AR_EBADPARAM; + // } + // else + // { + // status = AcdbCmdGetSubgraphGlbPersistCalData(req, rsp, rsp_struct_size); + // } + + status = AR_ENOTEXIST; + + } + break; + case ACDB_CMD_GET_MODULE_TAG_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbSgIdModuleTag) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbSgIdModuleTag *req = (AcdbSgIdModuleTag*)cmd_struct; + AcdbBlob *rsp = (AcdbBlob*)rsp_struct; + status = AcdbCmdGetModuleTagData(req, rsp, rsp_struct_size); + + } + break; + case ACDB_CMD_GET_TAGGED_MODULES: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbGetTaggedModulesReq) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbGetTaggedModulesReq *req = (AcdbGetTaggedModulesReq*)cmd_struct; + AcdbGetTaggedModulesRsp *rsp = (AcdbGetTaggedModulesRsp*)rsp_struct; + status = AcdbCmdGetTaggedModules(req, rsp, rsp_struct_size); + } + break; + case ACDB_CMD_GET_PROC_TAGGED_MODULES: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbGetProcTaggedModulesReq) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbGetProcTaggedModulesReq* req = (AcdbGetProcTaggedModulesReq*)cmd_struct; + AcdbGetProcTaggedModulesRsp* rsp = (AcdbGetProcTaggedModulesRsp*)rsp_struct; + status = AcdbCmdGetProcTaggedModules(req, rsp, rsp_struct_size); + } + break; + case ACDB_CMD_GET_DRIVER_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbDriverData) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbDriverData *req = (AcdbDriverData*)cmd_struct; + AcdbBlob *rsp = (AcdbBlob*)rsp_struct; + + status = AcdbCmdGetDriverData(req, rsp, rsp_struct_size); + } + break; + case ACDB_CMD_SET_CAL_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbSetCalDataReq)) + { + status = AR_EBADPARAM; + } + else + { + AcdbSetCalDataReq *req = (AcdbSetCalDataReq*)cmd_struct; + status = AcdbCmdSetCalData(req); + } + break; + case ACDB_CMD_ENABLE_PERSISTANCE: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(uint8_t)) + { + status = AR_EBADPARAM; + } + else + { + uint8_t *req = (uint8_t*)cmd_struct; + AcdbDeltaPersistState state = *req == 1 ? + ACDB_DELTA_DATA_PERSIST_STATE_ENABLED : + ACDB_DELTA_DATA_PERSIST_STATE_DISABLED; + + status = acdb_delta_data_ioctl( + ACDB_DELTA_DATA_CMD_ENABLE_PERSISTENCE, + &state, sizeof(AcdbDeltaPersistState), NULL, 0); + } + break; + case ACDB_CMD_GET_AMDB_REGISTRATION_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbAmdbProcID) || + IsNull(rsp_struct) || rsp_struct_size != sizeof(AcdbBlob)) + { + status = AR_EBADPARAM; + } + + status = AcdbCmdGetAmdbRegData( + (AcdbAmdbProcID*)cmd_struct, (AcdbBlob*)rsp_struct); + break; + case ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbAmdbProcID) || + IsNull(rsp_struct) || rsp_struct_size != sizeof(AcdbBlob)) + { + status = AR_EBADPARAM; + } + + status = AcdbCmdGetAmdbDeregData( + (AcdbAmdbProcID*)cmd_struct, (AcdbBlob*)rsp_struct); + break; + case ACDB_CMD_GET_SUBGRAPH_PROCIDS: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbCmdGetSubgraphProcIdsReq) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbCmdGetSubgraphProcIdsReq *req = + (AcdbCmdGetSubgraphProcIdsReq*)cmd_struct; + AcdbCmdGetSubgraphProcIdsRsp *rsp = + (AcdbCmdGetSubgraphProcIdsRsp*)rsp_struct; + if (req->num_sg_ids == 0) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetSubgraphProcIds(req, rsp, rsp_struct_size); + } + } + break; + case ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbAmdbProcID) || + IsNull(rsp_struct) || rsp_struct_size != sizeof(AcdbBlob)) + { + status = AR_EBADPARAM; + } + + status = AcdbCmdGetAmdbBootupLoadModules( + (AcdbAmdbProcID*)cmd_struct, (AcdbBlob*)rsp_struct); + + break; + case ACDB_CMD_GET_TAGS_FROM_GKV: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbCmdGetTagsFromGkvReq) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbCmdGetTagsFromGkvReq *req = (AcdbCmdGetTagsFromGkvReq*)cmd_struct; + AcdbCmdGetTagsFromGkvRsp *rsp = (AcdbCmdGetTagsFromGkvRsp*)rsp_struct; + if (req->graph_key_vector->num_keys == 0 || + req->graph_key_vector->num_keys >= ACDB_MAX_KEY_COUNT) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetTagsFromGkv(req, rsp, rsp_struct_size); + } + } + break; + case ACDB_CMD_GET_GRAPH_CAL_KVS: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbGraphKeyVector) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbGraphKeyVector *req = (AcdbGraphKeyVector*)cmd_struct; + AcdbKeyVectorList *rsp = (AcdbKeyVectorList*)rsp_struct; + if (req->num_keys == 0 || req->num_keys >= ACDB_MAX_KEY_COUNT) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetGraphCalKeyVectors( + req, rsp, rsp_struct_size); + } + } + break; + case ACDB_CMD_GET_SUPPORTED_GKVS: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbUintList) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbUintList *req = (AcdbUintList*)cmd_struct; + AcdbKeyVectorList *rsp = (AcdbKeyVectorList*)rsp_struct; + + status = AcdbCmdGetSupportedGraphKeyVectors( + req, rsp, rsp_struct_size); + } + break; + case ACDB_CMD_GET_DRIVER_MODULE_KVS: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(uint32_t) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + uint32_t *req = (uint32_t*)cmd_struct; + AcdbKeyVectorList *rsp = (AcdbKeyVectorList*)rsp_struct; + + status = AcdbCmdGetDriverModuleKeyVectors( + *req, rsp, rsp_struct_size); + } + break; + case ACDB_CMD_GET_GRAPH_TAG_KVS: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbGraphKeyVector) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbGraphKeyVector *req = (AcdbGraphKeyVector*)cmd_struct; + AcdbTagKeyVectorList *rsp = (AcdbTagKeyVectorList*)rsp_struct; + if (req->num_keys == 0 || req->num_keys >= ACDB_MAX_KEY_COUNT) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetGraphTagKeyVectors( + req, rsp, rsp_struct_size); + } + } + break; + case ACDB_CMD_GET_CAL_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbGetCalDataReq) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbGetCalDataReq *req = (AcdbGetCalDataReq*)cmd_struct; + AcdbBlob *rsp = (AcdbBlob*)rsp_struct; + status = AcdbCmdGetCalData(req, rsp); + } + break; + case ACDB_CMD_GET_TAG_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbGetTagDataReq) || + IsNull(rsp_struct) || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbGetTagDataReq *req = (AcdbGetTagDataReq*)cmd_struct; + AcdbBlob *rsp = (AcdbBlob*)rsp_struct; + status = AcdbCmdGetTagData(req, rsp); + } + break; + case ACDB_CMD_SET_TAG_DATA: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbSetTagDataReq)) + { + status = AR_EBADPARAM; + } + else + { + AcdbSetTagDataReq *req = (AcdbSetTagDataReq*)cmd_struct; + status = AcdbCmdSetTagData(req); + } + break; + case ACDB_CMD_SET_TEMP_PATH: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbSetTempPathReq)) + { + status = AR_EBADPARAM; + } + else + { + AcdbSetTempPathReq *req = (AcdbSetTempPathReq*)cmd_struct; + status = acdb_cmd_set_temp_path(req); + } + break; + case ACDB_CMD_GET_HW_ACCEL_SUBGRAPH_INFO: + if (IsNull(cmd_struct) || + cmd_struct_size != sizeof(AcdbHwAccelSubgraphInfoReq) || + IsNull(rsp_struct) || + rsp_struct_size != sizeof(AcdbHwAccelSubgraphInfoRsp)) + { + status = AR_EBADPARAM; + } + else + { + AcdbHwAccelSubgraphInfoReq* req = + (AcdbHwAccelSubgraphInfoReq*)cmd_struct; + AcdbHwAccelSubgraphInfoRsp* rsp = + (AcdbHwAccelSubgraphInfoRsp*)rsp_struct; + status = AcdbCmdGetHwAccelInfo(req, rsp); + } + break; + case ACDB_CMD_GET_PROC_SUBGRAPH_CAL_DATA_PERSIST: + if (IsNull(cmd_struct) || + cmd_struct_size != sizeof(AcdbProcSubgraphPersistCalReq) || + IsNull(rsp_struct) || + rsp_struct_size != sizeof(AcdbSgIdPersistCalData)) + { + status = AR_EBADPARAM; + } + else + { + AcdbProcSubgraphPersistCalReq* req = + (AcdbProcSubgraphPersistCalReq*)cmd_struct; + AcdbSgIdPersistCalData* rsp = + (AcdbSgIdPersistCalData*)rsp_struct; + if (req->num_subgraphs == 0) + { + status = AR_EBADPARAM; + } + else + { + status = AcdbCmdGetProcSubgraphCalDataPersist(req, rsp); + } + } + break; + case ACDB_CMD_GET_AMDB_REGISTRATION_DATA_V2: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbAmdbDbHandle) || + IsNull(rsp_struct) || rsp_struct_size != sizeof(AcdbBlob)) + { + status = AR_EBADPARAM; + } + + status = AcdbCmdGetAmdbRegDataV2( + (AcdbAmdbDbHandle*)cmd_struct, (AcdbBlob*)rsp_struct); + break; + case ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA_V2: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbAmdbDbHandle) || + IsNull(rsp_struct) || rsp_struct_size != sizeof(AcdbBlob)) + { + status = AR_EBADPARAM; + } + + status = AcdbCmdGetAmdbDeregDataV2( + (AcdbAmdbDbHandle*)cmd_struct, (AcdbBlob*)rsp_struct); + break; + case ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES_V2: + if (IsNull(cmd_struct) || cmd_struct_size != sizeof(AcdbAmdbDbHandle) || + IsNull(rsp_struct) || rsp_struct_size != sizeof(AcdbBlob)) + { + status = AR_EBADPARAM; + } + + status = AcdbCmdGetAmdbBootupLoadModulesV2( + (AcdbAmdbDbHandle*)cmd_struct, (AcdbBlob*)rsp_struct); + + break; + case ACDB_CMD_GET_GRAPH_ALIAS: + if (cmd_struct == NULL || cmd_struct_size != sizeof(AcdbGraphKeyVector) || + rsp_struct == NULL || rsp_struct_size == 0) + { + status = AR_EBADPARAM; + } + else + { + AcdbGraphKeyVector* req = (AcdbGraphKeyVector*)cmd_struct; + AcdbString* rsp = (AcdbString*)rsp_struct; + + if (req->num_keys == 0 || req->num_keys >= ACDB_MAX_KEY_COUNT) + { + status = AR_EBADPARAM; + } + else + status = AcdbCmdGetGraphAlias(req, rsp); + } + break; + default: + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Received unsupported command request" + " with Command ID[%08X]", cmd_id); + break; + } + + ACDB_MUTEX_UNLOCK(ACDB_CTX_MAN_CLIENT_CMD_LOCK); + + return status; +} + +/* ---------------------------------------------------------------------------- +* Private Function Definitions +*--------------------------------------------------------------------------- */ + +int32_t acdb_cmd_set_temp_path(AcdbSetTempPathReq *req) +{ + int32_t status = AR_EOK; + bool_t rw_delta_exists = FALSE; + uint32_t findex = 0; + uint32_t host_db_index = 0; + acdb_context_handle_t *ctx_handle = NULL; + AcdbDeltaDataSwapInfo swap_finfo = { 0 }; + /**< read-only directory */ + acdb_file_man_writable_path_info_256_t ro_dir = { 0 }; + acdb_handle_t acdb_handle = NULL; + + if (IsNull(req)) + { + return AR_EBADPARAM; + } + + if (req->path_length == 0) + { + ACDB_ERR("Error[%d]: The directory path length is zero ", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->path_length > ACDB_MAX_PATH_LENGTH) + { + ACDB_ERR("Error[%d]: The directory path length %d " + "is greater than the max path length %d", + AR_EBADPARAM, req->path_length, ACDB_MAX_PATH_LENGTH); + return AR_EBADPARAM; + } + + swap_finfo.file_access = AR_FOPEN_READ_ONLY_WRITE; + swap_finfo.path_info.path_len = req->path_length; + + status = ar_strcpy( + &swap_finfo.path_info.path[0], ACDB_MAX_PATH_LENGTH, + &req->path[0], ACDB_MAX_PATH_LENGTH); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to copy writeable path", status); + return status; + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_GET_CONTEXT_HANDLE_USING_INDEX, + &host_db_index, sizeof(uint32_t), + &ctx_handle, sizeof(acdb_context_handle_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get context handle", status); + return status; + } + + acdb_handle = ACDB_UINT_TO_HANDLE(ctx_handle->vm_id); + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE, + &acdb_handle, sizeof(acdb_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to set context handle", status); + return status; + } + + /* Get read-only path */ + ro_dir.handle = ctx_handle->file_manager_handle; + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_GET_WRITABLE_PATH, + &ro_dir, sizeof(acdb_file_man_writable_path_info_256_t), + NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get readonly path", status); + return status; + } + + /* Set the read/write path which will serve as the new temp directory */ + acdb_file_man_writable_path_info_t a = {0}; + a.handle = ctx_handle->file_manager_handle; + a.writable_path.path_length = swap_finfo.path_info.path_len; + a.writable_path.path = &swap_finfo.path_info.path[0]; + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_SET_WRITABLE_PATH, + &a, sizeof(acdb_file_man_writable_path_info_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set writable path", status); + return status; + } + + findex = host_db_index; + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_IS_FILE_AT_PATH, + &swap_finfo, sizeof(AcdbDeltaDataSwapInfo), + NULL, 0); + if (AR_ENOTEXIST == status) + { + rw_delta_exists = FALSE; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while trying to verify" + " the existance of the following path %s", status, + &swap_finfo.path_info.path[0]); + return status; + } + else + { + rw_delta_exists = TRUE; + } + + if (rw_delta_exists) + { + /* Scenario 2 + * Both the ro and rw files exist. Load the ro delta first followed + * by the rw delta. Do not reload ro_delta since the rw_delta will + * already contain the latest changes. + * This scenario will occur if: + * 1. the device is rebooted and + * 2. the rw delta file still exists on target + * 3. this api is called again + * + * The ro_delta is already loaded during init. Load the rw_delta */ + + swap_finfo.file_access = AR_FOPEN_READ_ONLY_WRITE; + swap_finfo.file_index = findex; + + /* Swap the ro_delta for the rw_delta in the delta file manager */ + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SWAP_DELTA, + &swap_finfo, sizeof(AcdbDeltaDataSwapInfo), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to swap read-only " + "with read/write delta file", status); + return status; + } + + /* load the rw_delta onto the heap */ + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_UPDATE_HEAP, + ctx_handle, sizeof(acdb_context_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to update heap with " + "data from the read/write delta", status); + return status; + } + return status; + } + + /* Scenario 1 + * This scenario occurs when: + * 1. AML is already initialized. + * 2. The ro_delta is already loaded onto the heap and its possible + * that other data has already been set to the heap by QACT or + * a GSL client through the set cal data APIs + * 3. The rw_delta does not exist + * Steps + * 1. Get the temp path that is set during acdb_init. This is the + * ro_delta path that we need to remember + * 2. Update the delta file manager with the rw_delta directory as + * the new delta file path (this will replace the ro_delta file + * info in the delta file manager) + * 3. Save heap to the rw_delta file + * 4. Update the delta file manager with the ro_delta file path to + * load the ro_delta file contents + * 5. Load the ro_delta to the heap + * 6. Again, Update the delta file manager with the rw_delta + * directory as the new delta file path + * 7. Load the rw_delta on top + * + * After all these steps, the location of the ro_delta is forgoten. + */ + swap_finfo.file_access = AR_FOPEN_WRITE_ONLY; + swap_finfo.file_index = findex; + + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SWAP_DELTA, + &swap_finfo, sizeof(AcdbDeltaDataSwapInfo), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to swap read-only " + "with read/write delta file", status); + return status; + } + + /* Save the heap to the rw_delta file */ + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SAVE, + NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to save delta file", status); + } + + /* Update the delta file manager with the ro_delta file + * path to load the ro_delta file contents */ + swap_finfo.file_access = AR_FOPEN_READ_ONLY; + swap_finfo.file_index = findex; + swap_finfo.path_info.path_len = ro_dir.writable_path.path_len; + status = ar_strcpy( + swap_finfo.path_info.path, ACDB_MAX_PATH_LENGTH, + &ro_dir.writable_path.path[0], ACDB_MAX_PATH_LENGTH); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to copy read-only path string", + status); + return status; + } + + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SWAP_DELTA, + &swap_finfo, sizeof(AcdbDeltaDataSwapInfo), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to swap read/write " + "with read-only delta file", status); + return status; + } + + /* Load the ro_delta to the heap */ + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_INIT_HEAP, + ctx_handle, sizeof(acdb_context_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to save delta file", status); + } + + /* Again, Update the delta file manager with the rw_delta + * directory as the new delta file path */ + swap_finfo.file_access = AR_FOPEN_READ_ONLY_WRITE; + swap_finfo.file_index = findex; + swap_finfo.path_info.path_len = req->path_length; + status = ar_strcpy( + &swap_finfo.path_info.path[0], ACDB_MAX_PATH_LENGTH, + &req->path[0], ACDB_MAX_PATH_LENGTH); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to copy read-only path string", + status); + return status; + } + + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SWAP_DELTA, + &swap_finfo, sizeof(AcdbDeltaDataSwapInfo), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to swap read/write " + "with read-only delta file", status); + return status; + } + + /* load the rw_delta on top */ + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_UPDATE_HEAP, + ctx_handle, sizeof(acdb_context_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to update heap with delta data", status); + } + + return status; +} diff --git a/acdb/src/acdb_command.c b/acdb/src/acdb_command.c new file mode 100644 index 0000000..794e439 --- /dev/null +++ b/acdb/src/acdb_command.c @@ -0,0 +1,14053 @@ + +/** +*============================================================================= +* \file acdb_command.c +* +* \brief +* Contains the implementation of the commands exposed by the +* ACDB public interface. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- +* Include Files +*--------------------------------------------------------------------------- */ + +#include "ar_osal_error.h" +#include "ar_osal_file_io.h" +#include "acdb_command.h" +#include "acdb_parser.h" +#include "acdb_file_mgr.h" +#include "acdb_common.h" +#include "acdb_data_proc.h" +#include "acdb_context_mgr.h" + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ +#define ACDB_SOFTWARE_VERSION_MAJOR 0x00000001 +#define ACDB_SOFTWARE_VERSION_MINOR 0x00000030 +#define ACDB_SOFTWARE_VERSION_REVISION 0x00000000 +#define ACDB_SOFTWARE_VERSION_CPLINFO 0x00000000 + +#define INF 4294967295U + +#define ACDB_CLEAR_BUFFER(x) memset(&x, 0, sizeof(x)) + +/* --------------------------------------------------------------------------- +* Global Data Definitions +*--------------------------------------------------------------------------- */ +uint32_t glb_buf_1[GLB_BUF_1_LENGTH]; +uint32_t glb_buf_2[GLB_BUF_2_LENGTH]; +uint32_t glb_buf_3[GLB_BUF_3_LENGTH]; + +/* --------------------------------------------------------------------------- +* Static Variable Definitions +*--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- +* Static Function Declarations and Definitions +*--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ +typedef struct _acdb_audio_cal_context_info_t AcdbAudioCalContextInfo; +#include "acdb_begin_pack.h" +struct _acdb_audio_cal_context_info_t { + AcdbOp op; + AcdbOp data_op; + /**< A flag indicating whether data is being requested for the first + time (only CKV[new] is passed in) */ + bool_t is_first_time; + /**< A flag indicating whether the module CKV found is the default key + vector(no keys) */ + bool_t is_default_module_ckv; + /**< A flag indicating whether process(true) or skip(false) the + default CKV */ + bool_t ignore_get_default_data; + /**< A flag indicating whether check for hw accel based calibraion */ + bool_t should_check_hw_accel; + /**< A flag used to filter calibration based on processor domain */ + bool_t should_filter_cal_by_proc_domain; + /**< Keeps track of module IIDs that are associated with the + default CKV */ + AcdbUintList default_data_iid_list; + /**< The Subgraph to get calibration for */ + uint32_t subgraph_id; + /**< The Processor to get calibration for */ + uint32_t proc_id; + /**< A pointer to a mapping that associates module instances with + the processor domains they run on */ + AcdbSubgraphPdmMap *sg_mod_iid_map; + /**< An offset to a Subgrahps hardware accel module list */ + uint32_t hw_accel_module_list_offset; + /**< The instance of the module that contains tag data */ + uint32_t instance_id; + /**< The parameter(s) to get cal data for */ + AcdbUintListZS *parameter_list; + /**< A pointer to the full CKV[new] */ + AcdbGraphKeyVector *ckv; + /**< A pointer to the Delta CKV containing the difference between + CKV[new] and CKV[old] */ + AcdbGraphKeyVector *delta_ckv; + /**< A pointer to the Module CKV */ + AcdbGraphKeyVector *module_ckv; + /**< The type of parameter to get data for (NONE, SHARED, GLOBAL + SHARED) */ + /**< The parameter type: persistent, non-persistent, globaly persistent */ + AcdbDataPersistanceType param_type; + /**< The DEF, DOT, and DOT2 data offsets */ + AcdbCkvLutEntryOffsets data_offsets; + /**< A list of offloaded parameters from the global offloaded + parameter property */ + AcdbUintList offloaded_parameter_list; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_tag_data_context_info_t AcdbTagDataContextInfo; +#include "acdb_begin_pack.h" +struct _acdb_tag_data_context_info_t { + AcdbOp op; + AcdbOp data_op; + /**< The Subgraph that contains tag data */ + uint32_t subgraph_id; + /**< The instance of the module that contains tag data */ + uint32_t instance_id; + /**< The parameter(s) to get tag data for */ + AcdbUintListZS *parameter_list; + /**< The module tag containing the tag ID and TKV */ + AcdbModuleTag *tag; + /**< The type of parameter to get data for (NONE, SHARED, GLOBAL + SHARED) */ + AcdbDataPersistanceType param_type; + /**< The DEF and DOT offsets */ + AcdbDefDotPair data_offsets; + /**< A list of offloaded parameters from the global offloaded + parameter property */ + AcdbUintList offloaded_parameter_list; +} +#include "acdb_end_pack.h" +; + +typedef struct _acdb_iid_ref_count_t AcdbIidRefCount; +#include "acdb_begin_pack.h" +struct _acdb_iid_ref_count_t +{ + uint32_t module_iid; + uint32_t ref_count; +} +#include "acdb_end_pack.h" +; + +/**< Contains offsets to the key id and value lists that +make up a key vector */ +typedef struct _acdb_key_vector_lut_entry_t AcdbKeyVectorLutEntry; +struct _acdb_key_vector_lut_entry_t +{ + /**< Absolute offset of the key table that includes #keys + and the key id list */ + uint32_t offset_key_tbl; + /**< Absolute offset of the value combination in the LUT */ + uint32_t offset_value_list; +}; + +/**< Maintains offsets for key vectors in the Cal Key ID Table +and Cal Key Value LUT chunks */ +typedef struct _acdb_key_vector_lut_t AcdbKeyVectorLut; +struct _acdb_key_vector_lut_t +{ + /**< The size of the lookup table in bytes*/ + uint32_t size; + /**< Number of entries in the lookup table */ + uint32_t num_entries; + /**< A pointer to the array that stores the lookup table + entries. The format of an entry is: + <#keys, Key ID Table Offset, Value LUT Offset */ + AcdbKeyVectorLutEntry* lookup_table; +}; + +/**< Maintains an unziped key vector; separate key list, separate value list */ +typedef struct _acdb_key_value_list_t AcdbKeyValueList; +struct _acdb_key_value_list_t +{ + /**< Number of keys in the key vector */ + uint32_t num_keys; + /**< list of key ids whose length is num_keys */ + uint32_t *key_list; + /**< list of key value ids whose length is num_keys */ + uint32_t *value_list; +}; + +/* --------------------------------------------------------------------------- +* Function Prototypes +*--------------------------------------------------------------------------- */ + +/** +* \brief +* Search Subgraph Calibration LUT for offsets to the Key ID and Key +* Value tables. Returns a list of CKV entries for a subgraph. +* +* \param[in] req: Request containing the subgraph, module instance, parameter, and CKV +* \param[in] sz_ckv_entry_list: Size of the CKV entry list +* \param[out] ckv_entry_list: CKV Entries found during the search +* \param[out] num_entries: nNumber of CKV Entries found +* \return 0 on success, and non-zero on failure +*/ +int32_t SearchSubgraphCalLut( + uint32_t req_subgraph_id, uint32_t sz_ckv_entry_list, + AcdbCalKeyTblEntry *ckv_entry_list, uint32_t *num_entries); + +/** +* \brief +* Search Subgraph Calibration LUT for offsets to the Key ID and Key +* Value tables. Returns the absolute file offset to the list of CKV entries +* for a subgraph. +* +* \param[in] req: Request containing the subgraph, module instance, parameter, and CKV +* \param[in] sz_ckv_entry_list: Size of the CKV entry list +* \param[out] ckv_entry_list: CKV Entries found during the search +* \param[out] num_entries: nNumber of CKV Entries found +* \return 0 on success, and non-zero on failure +*/ +int32_t SearchSubgraphCalLut2(AcdbSgCalLutHeader *sg_lut_entry_header, + uint32_t *ckv_entry_list_offset); + +void AcdbClearAudioCalContextInfo(AcdbAudioCalContextInfo* info); + +/** +* \brief +* Finds the DEF, DOT, and DOT2 data offsets using the Cal Key Table Entry +* offsets(Key ID Table offset, Value LUT offset) of a subgraph from the +* Subgraph Calibration LUT chunk. +* It also updates the module_ckv in the context info struct which is used +* to locate data on the heap +* +* \param[in] ckv_entry: Contains offsets to the Key ID and Value LUT tables +* \param[in/out] info: Context info containing the module kv to be udpated +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbFindModuleCKV(AcdbCalKeyTblEntry *ckv_entry, + AcdbAudioCalContextInfo *info); + +/** +* \brief +* Uses the DEF, DOT, and DOT2 data offsets in the context info to find +* calibration data for different PID types(non-persist/persist) +* +* \param[in/out] info: Context info containing the module kv +* \param[in/out] blob_offset: current response blob offset +* \param[in/out] rsp: Response blob to write caldata to +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbGetSubgraphCalibration(AcdbAudioCalContextInfo *info, + uint32_t *blob_offset, AcdbBlob *rsp); + +/** +* \brief +* Get the data pool offset of the Tag Key List associated with a Module +* Tag +* +* \param[in] tag_id: The module tag to get the key ID list for +* \param[in/out] dpo: The absolute data pool offset that points to the tag +* key table in the data pool +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t FindTagKeyList(uint32_t tag_id, uint32_t* dpo); + +int32_t AcdbGetUsecaseSubgraphList(AcdbGraphKeyVector* gkv, + AcdbUintList* subgraph_list, AcdbGetGraphRsp* graph); + +/** +* \brief +* Get the vcpm calibration table for the specified subgraph +* +* \param[in] num_subgraphs: +* \param[in] subgraph_id: the subgraph identifier +* \param[in/out] file_offset: the absolute file offset of the subgraphs +* vcpm calibration table +* \param[in/out] subgraph_cal_table: the vcpm calibration table +* for the specified subgraph +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t GetVcpmSubgraphCalTable(uint32_t num_subgraphs, uint32_t subgraph_id, + uint32_t* file_offset, AcdbVcpmSubgraphCalTable* subgraph_cal_table); + +/** +* \brief +* Get offload parameter calibration data from the file +* path specified in the parameter payload +* +* \param[in] op: Specifies the data operation being performed: get size or data +* \param[in] subgraph_id: the subgraph to get data from +* \param[in/out] module_header: The parameter data instance to get data for +* \param[in/out] caldata: The parameter payload containing the offload +* parameter file path +* \param[in/out] rsp: The response buffer to write the data to +* \param[in/out] module_start_blob_offset: The starting offset of the +* parameter data in the response blob (starts are the module +* header which is [iid, pid, size, err, data(...)]) +* \param[in/out] module_start_blob_offset: The ending offset of the +* parameter data in the response blob +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t AcdbGetOffloadedParameterCal( + AcdbOp op, uint32_t subgraph_id, AcdbDspModuleHeader* module_header, + AcdbPayload* caldata, AcdbBlob* rsp, + uint32_t* module_start_blob_offset, uint32_t* module_end_blob_offset); +/* --------------------------------------------------------------------------- +* Function Definitions +*--------------------------------------------------------------------------- */ + +/** +* \brief +* Create partitions for a table and store these partitions in +* partition_buf (use glb_buf2, the smallest global buffer) +* +* Buffers: +* buf - Contains the table that needs to be partitioned +* partition_buf - Holds the partitions in the format: +* [p1.offset, p1.size, ..., pn.offset, pn.size] +* +* Example +* Size Of a Partition = +* Global Buffer Size - (Global Buffer Size % Table Entry Size) +* Ex. +* glb_buf size = 2500Bytes +* Cal LUT Entry size = 12Bytes +* 2500 - (2500 % 12) = +* 2496 (208 = (2496/12) Cal LUT Entries can fit into one partition) +* +* \param[in] table_offset: offset of ACDB table +* \param[in] table_size: size of ACDB table +* \param[in] table_entry_size: size of an entry in the ACDB table +* \param[in] buf_size: size of the buffer that stores each partition +* \param[in/out] partition_buf: buffer that stores partition info +* \param[in/out] num_partitions: number of partitions in partition_buf +* +* \return TRUE (create partitions), FALSE (don't create partitions) +*/ +bool_t create_partitions(uint32_t table_offset, size_t table_size, + size_t table_entry_size, size_t buf_size, uint32_t* partition_buf, + uint32_t* num_partitions) +{ + bool_t should_partition = FALSE; + uint32_t partition_size = 0; + uint32_t parition_offset = 0; + + if (table_size > buf_size) + { + should_partition = TRUE; + //Determine Partition Size + + //Max Readable size + partition_size = (uint32_t)(buf_size - (buf_size % table_entry_size)); + *num_partitions = (uint32_t)AcdbCeil((uint32_t)table_size, partition_size); + parition_offset = 0; + for (uint32_t i = 0; i < (*num_partitions) * 2; i++) + { + if (i % 2 == 0) + { + //Store Size at odd index + partition_buf[i] = partition_size; + } + else + { + //Store Offset at even index + partition_buf[i] = table_offset + parition_offset; + parition_offset += partition_size; + } + } + } + + return should_partition; +} + +/** +* \brief +* Compares key vector values using memcmp +* +* \param[in] key_vector: The key vector used in the comparision +* \param[in/out] cmp_from_kv_values: The key values from key_vector to +* compare with +* \param[in/out] cmp_to_kv_values: The key values to compare against +* \param[in/out] num_keys: number of keys in the key vector +* +* \return AR_EOK on success, non-zero otherwise +*/ +bool_t CompareKeyVectorValues(AcdbGraphKeyVector key_vector, uint32_t* cmp_from_kv_values, + uint32_t *cmp_to_kv_values, uint32_t num_keys) +{ + for (uint32_t i = 0; i < num_keys; i++) + cmp_from_kv_values[i] = key_vector.graph_key_vector[i].value; + + if (0 == ACDB_MEM_CMP(cmp_from_kv_values, cmp_to_kv_values, num_keys * sizeof(uint32_t))) + return TRUE; + + return FALSE; +} + +/** +* \brief +* Compares key vector ids using memcmp. The keys +* must be sorted before passing them to this api +* +* \param[in] key_vector: The key vector used in the comparision +* \param[in/out] cmp_from_kv_ids: The key ids from key_vector to +* compare with +* \param[in/out] cmp_to_kv_ids: The key ids to compare against +* \param[in/out] num_keys: number of keys in the key vector +* +* \return TRUE on success, FALSE otherwise +*/ +bool_t CompareKeyVectorIds(AcdbGraphKeyVector key_vector, uint32_t* cmp_from_kv_ids, + uint32_t *cmp_to_kv_ids, uint32_t num_keys) +{ + for (uint32_t i = 0; i < num_keys; i++) + cmp_from_kv_ids[i] = key_vector.graph_key_vector[i].key; + + if (0 == ACDB_MEM_CMP(cmp_from_kv_ids, cmp_to_kv_ids, num_keys * sizeof(uint32_t))) + return TRUE; + + return FALSE; +} + +/** +* \brief +* Compares key vector ids using a for loop. The keys +* must be sorted before passing them to this api +* +* \param[in] key_vector: The key vector used in the comparision +* \param[in] cmp_with_key_id_list: The key id list to compare with +* +* \return TRUE on success, FALSE otherwise +*/ +bool_t CompareKeyVectorIds2(AcdbGraphKeyVector *key_vector, + const AcdbUintList *cmp_with_key_id_list) +{ + if (IsNull(key_vector) || IsNull(cmp_with_key_id_list)) + return FALSE; + + if (cmp_with_key_id_list->count != key_vector->num_keys) + return FALSE; + + for (uint32_t i = 0; i < cmp_with_key_id_list->count; i++) + { + if (cmp_with_key_id_list->list[i] != key_vector->graph_key_vector[i].key) + return FALSE; + } + + return TRUE; +} + +/** +* \brief CopyFromFileToBuf +* Copies data from the ACDB Data file at a given offset to the provided buffer +* \param[in] file_offset: location in the file to start reading from +* \param[in/out] dst_buf: the buffer to copy data into +* \param[in] sz_dst_buf: size of the destination buffer +* \param[in] sz_block: the block size used to read from the file +* \param[int] calblob: Module calibration blob passed in from the client +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t CopyFromFileToBuf(uint32_t file_offset, void* dst_buf, uint32_t sz_dst_buf, uint32_t sz_block) +{ + if (IsNull(dst_buf) || sz_block == 0 || sz_dst_buf == 0) + return AR_EBADPARAM; + + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t foffset = 0; + //Block Size to use for reading from file + + //Destination size alighned to 'sz_max_buf' bytes + uint32_t sz_dst_aligned = (sz_dst_buf - (sz_dst_buf % sz_block)); + + //Size of the file read initially set to block size + uint32_t read_size = sz_block; + + //The remaining bytes to read from the file into the destination + uint32_t sz_remainder_block = (sz_dst_buf % sz_block); + + //Occurs when the block size is greater than the destination buffer size + if (sz_dst_aligned == 0) + { + read_size = sz_remainder_block; + } + + while (offset < sz_dst_buf) + { + if (offset + sz_remainder_block == sz_dst_buf) + { + read_size = sz_remainder_block; + } + + foffset = file_offset + offset; + status = FileManReadBuffer((uint8_t*)dst_buf + offset, read_size, &foffset); + if (AR_EOK != status) + { + ACDB_ERR("Error[%d]: Failed to read data from file. The read size is %d bytes", read_size); + return status; + } + + if ((offset == sz_dst_aligned && sz_remainder_block != 0)|| + (sz_dst_aligned == 0 && sz_remainder_block != 0)) + { + offset += sz_remainder_block; + //read_size = sz_remainder_block; + } + else + { + offset += sz_block; + } + } + + return status; +} + +/** +* \brief +* Write data to a buffer ensuring not to write past the length of the buffer +* \param[in] dst_blob: the blob to write to +* \param[in] blob_offset: current offset within dst_blob +* \param[in] src_blob: the blob to write from +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbWriteBuffer(AcdbBlob *dst_buf, uint32_t *blob_offset, AcdbBlob *src_buf) +{ + if (*blob_offset + + src_buf->buf_size > dst_buf->buf_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)dst_buf->buf + *blob_offset, + src_buf->buf_size, + src_buf->buf, src_buf->buf_size); + *blob_offset += src_buf->buf_size; + + return AR_EOK; +} + +/** +* \brief +* Search Tag Data Lookup Table for a matching TKV and retrieve the +* def and dot offsets +* +* \param[int] tkv: tag key vector to search for +* \param[in] tag_data_tbl_offset: offset of tag data lut for a pair +* \param[out] offset_pair: Offset of def and dot offsets +* +* \return 0 on success, and non-zero on failure +*/ +int32_t TagDataSearchLut(AcdbGraphKeyVector *tkv, + uint32_t tag_data_tbl_offset, AcdbDefDotPair *offset_pair) +{ + int32_t status = AR_EOK; + uint32_t i = 0; + ChunkInfo ci_tag_data_lut = { 0 }; + KeyTableHeader key_table_header = { 0 }; + size_t sz_tag_key_vector_entry = 0; + uint32_t offset = 0; + bool_t result = FALSE; + + ACDB_CLEAR_BUFFER(glb_buf_1); + ACDB_CLEAR_BUFFER(glb_buf_3); + + ci_tag_data_lut.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_LUT; + status = ACDB_GET_CHUNK_INFO(&ci_tag_data_lut); + if (AR_FAILED(status)) + { + return status; + } + + offset = ci_tag_data_lut.chunk_offset + tag_data_tbl_offset; + status = FileManReadBuffer(&glb_buf_1, 2 * sizeof(uint32_t), &offset); + if (status != 0) + { + ACDB_ERR("Error[%d]: Unable to read TKV length and " + "number of TKV value entries", status); + return status; + } + + key_table_header.num_keys = glb_buf_1[0]; + key_table_header.num_entries = glb_buf_1[1]; + + sz_tag_key_vector_entry = + key_table_header.num_keys * sizeof(uint32_t) + + 2 * sizeof(uint32_t); + //sz_tag_data_lut = num_tag_key_vector_entries * sz_tag_key_vector_entry; + + /* Number of keys for this LUT must match the + * number of keys in the input */ + if (key_table_header.num_keys != tkv->num_keys) + { + ACDB_DBG("Error[%d]: The LUT table key count %d does not " + "match input TKV key count %d", + AR_EFAILED, key_table_header.num_keys, tkv->num_keys); + return AR_EFAILED; + } + + result = FALSE; + for (i = 0; i < key_table_header.num_entries; i++) + { + ACDB_CLEAR_BUFFER(glb_buf_1); + + status = FileManReadBuffer( + &glb_buf_1, sz_tag_key_vector_entry, &offset); + if (status != 0) + { + ACDB_DBG("Error[%d]: Unable to read TKV values entry", AR_EFAILED); + return AR_EFAILED; + } + + if (TRUE == CompareKeyVectorValues( + *tkv, glb_buf_3, glb_buf_1, tkv->num_keys)) + { + offset_pair->offset_def = (glb_buf_1 + key_table_header.num_keys)[0]; + offset_pair->offset_dot = (glb_buf_1 + key_table_header.num_keys)[1]; + result = TRUE; + break; + } + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + ACDB_CLEAR_BUFFER(glb_buf_3); + + if (FALSE == result) + { + ACDB_DBG("Error[%d]: Unable to find matching TKV", AR_ENOTEXIST); + return AR_ENOTEXIST; + } + + return status; +} + +/** +* \brief +* Search Tag Data Key Table for a pair and retrieve the +* offset of the tag data table +* +* \param[int] subgraph_id: Subgraph to search for +* \param[in] tag_id: Module Tag to search for +* \param[out] offset_tag_data_tbl: Offset of the Tag Data Table +* +* \return 0 on success, and non-zero on failure +*/ +int32_t TagDataSearchKeyTable(uint32_t subgraph_id, uint32_t tag_id, uint32_t *offset_tag_data_tbl) +{ + int32_t status = AR_EOK; + int32_t search_index_count = 2; + SubgraphTagLutEntry entry = { subgraph_id, tag_id, 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + ChunkInfo ci_key_table = { 0 }; + + if (IsNull(offset_tag_data_tbl)) + { + ACDB_ERR("Error[%d]: " + "The offset input parameter is null.", AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_key_table.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_KEYTABLE; + status = ACDB_GET_CHUNK_INFO(&ci_key_table); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Unable to retrieve Tag Data Key Table chunk.", status); + return status; + } + + //Setup Table Information (skip table entry count) + table_info.table_offset = ci_key_table.chunk_offset + sizeof(uint32_t); + table_info.table_size = ci_key_table.chunk_size - sizeof(uint32_t); + table_info.table_entry_size = sizeof(SubgraphTagLutEntry); + + //Setup Search Information + search_info.num_search_keys = search_index_count; + search_info.num_structure_elements = + (sizeof(SubgraphTagLutEntry) / sizeof(uint32_t)); + search_info.table_entry_struct = &entry; + + status = AcdbTableBinarySearch(&table_info, &search_info); + + if(AR_SUCCEEDED(status)) + *offset_tag_data_tbl = entry.offset; + + return status; +} + +/** +* \brief +* Retrieve tag data from the file manager or heap for a list of parameters +* +* \param[int] info: context information for tag data +* \param[out] rsp: Response blob containing calibration in the format of +* [, ...] +* +* \return 0 on success, and non-zero on failure +*/ +int32_t TagDataGetParameterData(AcdbTagDataContextInfo *info, uint32_t *blob_offset, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t tmp_blob_offset = 0; + uint32_t data_offset = 0; + uint32_t padded_param_size = 0; + uint32_t param_dot_offset = 0; + uint32_t entry_index = 0; + uint32_t num_id_entries = 0; + bool_t is_offloaded_param = FALSE; + AcdbModIIDParamIDPair iid_pid_pair = { 0 }; + AcdbDspModuleHeader module_header = { 0 }; + ChunkInfo ci_def = { 0 }; + ChunkInfo ci_dot = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbPayload caldata = { 0 }; + AcdbBlob buffer = { 0 }; + AcdbOp op = IsNull(rsp->buf) ? + ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + if (IsNull(info) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: " + "One or more input parameters are null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_def.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_DEF; + ci_dot.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_DOT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + + status = ACDB_GET_CHUNK_INFO( + &ci_def, &ci_dot, &ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Unable to retrieve def, dot, or data pool tables", status); + return status; + } + + offset = ci_def.chunk_offset + info->data_offsets.offset_def; + status = FileManReadBuffer(&num_id_entries, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to read number of tagged entries.", status); + return status; + } + + status = FileManReadBuffer(&glb_buf_3[0], + num_id_entries * sizeof(AcdbModIIDParamIDPair), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read List of .", status); + return status; + } + + iid_pid_pair.module_iid = info->instance_id; + module_header.module_iid = info->instance_id; + + for (uint32_t i = 0; i < info->parameter_list->count; i++) + { + iid_pid_pair.parameter_id = info->parameter_list->list[i]; + module_header.parameter_id = info->parameter_list->list[i]; + + if (SEARCH_ERROR == AcdbDataBinarySearch2((void*)&glb_buf_3, + num_id_entries * sizeof(AcdbModIIDParamIDPair), + &iid_pid_pair, 2, + (int32_t)(sizeof(AcdbModIIDParamIDPair) / sizeof(uint32_t)), + &entry_index)) + { + status = AR_ENOTEXIST; + ACDB_DBG("Error[%d]: Unable to find Parameter(0x%x). Skipping..", + status, module_header.parameter_id); + continue; + } + + status = IsOffloadedParam(module_header.parameter_id, + &info->offloaded_parameter_list); + + is_offloaded_param = AR_SUCCEEDED(status) ? TRUE: FALSE; + + //Get from heap + status = GetSubgraphCalData( + info->param_type, ACDB_DATA_ACDB_CLIENT, + &info->tag->tag_key_vector, info->subgraph_id, + module_header.module_iid, module_header.parameter_id, + is_offloaded_param, blob_offset, rsp); + + if (AR_SUCCEEDED(status)) + { + continue; + } + + //Get from file manager + + offset = ci_dot.chunk_offset + + info->data_offsets.offset_dot; + + /* Calculation for DOT offset of pair + * + * Offset of + Number of + Offset of the desired DOT entry based + * DOT DOT entries on index of in DEF + */ + param_dot_offset = + offset + sizeof(uint32_t) + sizeof(uint32_t) * (uint32_t)( + entry_index + / (sizeof(AcdbModIIDParamIDPair) / sizeof(uint32_t))); + + status = FileManReadBuffer(&data_offset, + sizeof(uint32_t), ¶m_dot_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to read data pool offset from DOT.", status); + return status; + } + + offset = ci_data_pool.chunk_offset + data_offset; + + status = FileManReadBuffer(&module_header.param_size, + sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to read param size from data pool.", status); + return status; + } + + caldata.size = module_header.param_size; + status = FileManGetFilePointer2((void**)&caldata.payload, offset); + + if (is_offloaded_param) + { + status = AcdbGetOffloadedParameterCal( + info->op, info->subgraph_id, &module_header, + &caldata, rsp, blob_offset, &tmp_blob_offset); + if (AR_FAILED(status)) + return status; + + padded_param_size = + ACDB_ALIGN_8_BYTE(module_header.param_size); + } + else + { + padded_param_size = + ACDB_ALIGN_8_BYTE(module_header.param_size); + } + + switch (op) + { + case ACDB_OP_GET_SIZE: + rsp->buf_size += sizeof(AcdbDspModuleHeader) + + padded_param_size; + break; + case ACDB_OP_GET_DATA: + + //Write Module IID, and Parameter ID + buffer.buf = (void*)&module_header; + buffer.buf_size = sizeof(AcdbDspModuleHeader); + status = AcdbWriteBuffer(rsp, blob_offset, &buffer); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to write module header for" + "[0x%x, 0x%x, 0x%x]", + status, info->subgraph_id, module_header.module_iid, + module_header.parameter_id); + return status; + } + + if (is_offloaded_param) + { + *blob_offset = tmp_blob_offset; + continue; + } + + //Write Payload + if (rsp->buf_size < (*blob_offset + module_header.param_size)) + return AR_ENEEDMORE; + + if (module_header.param_size > 0) + { + status = FileManReadBuffer( + (uint8_t*)rsp->buf + *blob_offset, + module_header.param_size, + &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to read param(0x%x) data", + status, module_header.parameter_id); + return status; + } + + *blob_offset += padded_param_size; + } + break; + default: + break; + } + + } + + return status; +} + +/** +* \brief +* Retrieve tag data from the file manager or heap for: +* 1. An entire subgraph OR +* 2. An entire module +* +* \param[int] info: context information for tag data +* \param[int] blob_offset: offset within the rsp blob +* \param[out] rsp: Response blob containing calibration in the format of +* [, ...] +* +* \return 0 on success, and non-zero on failure +*/ +int32_t TagDataGetSubgraphData(AcdbTagDataContextInfo *info, + uint32_t *blob_offset, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + ChunkInfo ci_def = { 0 }; + ChunkInfo ci_dot = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + uint32_t num_id_entries = 0; + uint32_t num_data_offset = 0; + uint32_t num_param_cal_found = 0; + uint32_t cur_def_offset = 0; + uint32_t cur_dot_offset = 0; + uint32_t cur_dpool_offset = 0; + uint32_t data_offset = 0; + uint32_t tmp_blob_offset = 0; + uint32_t padded_param_size = 0; + bool_t is_offloaded_param = FALSE; + AcdbDspModuleHeader module_header = { 0 }; + AcdbPayload caldata = { 0 }; + AcdbBlob buffer = { 0 }; + + ci_def.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_DEF; + ci_dot.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_DOT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_def, &ci_dot, &ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Unable to retrieve def, dot, or data pool tables", status); + return status; + } + + cur_def_offset = ci_def.chunk_offset + info->data_offsets.offset_def; + status = FileManReadBuffer(&num_id_entries, sizeof(uint32_t), &cur_def_offset); + if (status != 0) + { + ACDB_ERR("Error[%d]: Unable to read number of Tag ID entries", AR_EFAILED); + return AR_EFAILED; + } + + //Tag Data DOT Table Chunk + cur_dot_offset = ci_dot.chunk_offset + info->data_offsets.offset_dot; + status = FileManReadBuffer(&num_data_offset, sizeof(uint32_t), &cur_dot_offset); + if (status != 0) + { + ACDB_ERR("Error[%d]: Unable to read number of Tag ID entries", AR_EFAILED); + return AR_EFAILED; + } + + if (num_id_entries != num_data_offset) + { + ACDB_ERR("Error[%d]: Tag def entry count (%d) does not match" + "Tag dot entry count (%d)", + num_id_entries, num_data_offset, AR_EFAILED); + return AR_EFAILED; + } + + for (uint32_t i = 0; i < num_id_entries; i++) + { + status = FileManReadBuffer(&module_header, sizeof(AcdbMiidPidPair), + &cur_def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read entry", status); + return status; + } + + //If Get Module Data is called + if((info->data_op == ACDB_OP_GET_MODULE_DATA) && + (module_header.module_iid != info->instance_id)) + { + cur_dot_offset += sizeof(uint32_t); + continue; + } + + num_param_cal_found++; + + status = IsOffloadedParam(module_header.parameter_id, + &info->offloaded_parameter_list); + + is_offloaded_param = AR_SUCCEEDED(status) ? TRUE : FALSE; + + //Get data from Heap + status = GetSubgraphCalData(info->param_type, ACDB_DATA_ACDB_CLIENT, + &info->tag->tag_key_vector, + info->subgraph_id, module_header.module_iid, + module_header.parameter_id, is_offloaded_param, blob_offset, rsp); + + if (AR_SUCCEEDED(status)) + { + cur_dot_offset += sizeof(uint32_t); + continue; + } + + //Get data from file manager + status = FileManReadBuffer( + &data_offset, sizeof(uint32_t), &cur_dot_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of " + " entries", status); + return status; + } + + cur_dpool_offset = ci_data_pool.chunk_offset + data_offset; + status = FileManReadBuffer(&module_header.param_size, + sizeof(uint32_t), &cur_dpool_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read param size", status); + return status; + } + + caldata.size = module_header.param_size; + status = FileManGetFilePointer2((void**)&caldata.payload, cur_dpool_offset); + + if (is_offloaded_param) + { + status = AcdbGetOffloadedParameterCal( + info->op, info->subgraph_id, &module_header, + &caldata, rsp, blob_offset, &tmp_blob_offset); + if (AR_FAILED(status)) + return status; + + padded_param_size = + ACDB_ALIGN_8_BYTE(module_header.param_size); + } + else + { + padded_param_size = + ACDB_ALIGN_8_BYTE(module_header.param_size); + } + + switch (info->op) + { + case ACDB_OP_GET_SIZE: + rsp->buf_size += + sizeof(AcdbDspModuleHeader) + padded_param_size; + break; + case ACDB_OP_GET_DATA: + //Write Module IID, and Parameter ID + buffer.buf = (void*)&module_header; + buffer.buf_size = sizeof(AcdbDspModuleHeader); + status = AcdbWriteBuffer(rsp, blob_offset, &buffer); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to write module header for" + "", + status, info->subgraph_id, module_header.module_iid, + module_header.parameter_id); + return status; + } + + if (is_offloaded_param) + { + *blob_offset = tmp_blob_offset; + continue; + } + + //Write Payload + if (rsp->buf_size < (*blob_offset + module_header.param_size)) + return AR_ENEEDMORE; + + if (module_header.param_size > 0) + { + buffer.buf = caldata.payload; + buffer.buf_size = caldata.size; + + status = AcdbWriteBuffer(rsp, blob_offset, &buffer); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to write param(0x%x) data", + status, module_header.parameter_id); + return status; + } + } + + *blob_offset += ACDB_PADDING_8_BYTE(caldata.size); + + break; + default: + break; + } + } + + if (num_param_cal_found == 0) return AR_ENOTEXIST; + + return status; +} + +int32_t AcdbCmdGetModuleTagData(AcdbSgIdModuleTag *req, AcdbBlob *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + uint32_t offset_tag_data_tbl = 0; + uint32_t blob_offset = 0; + AcdbTagDataContextInfo info = { 0 }; + AcdbUintList subgraph_list = { 0 }; + + if (rsp_size < sizeof(AcdbBlob)) + { + return AR_EBADPARAM; + } + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: " + "One or more input parameters are null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + subgraph_list.count = req->num_sg_ids; + subgraph_list.list = req->sg_ids; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + if (req->module_tag.tag_key_vector.num_keys == 0) + { + ACDB_ERR("Error[%d]: The TKV cannot be empty. If the intent is to " + "retrieve default data, use the CKV-based 'GET' APIs", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->num_sg_ids == 0 || IsNull(req->sg_ids)) + { + ACDB_ERR("Error[%d]: The subgraph list cannot be empty", AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = AcdbSort2( + req->module_tag.tag_key_vector.num_keys * sizeof(AcdbKeyValuePair), + req->module_tag.tag_key_vector.graph_key_vector, + sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Unable to sort Tag Key Vector", AR_EBADPARAM); + return status; + } + + /* Tag data does not have a param type. Currently tag data is + * stored under non-persistent data in the heap */ + info.param_type = ACDB_DATA_NON_PERSISTENT; + info.op = IsNull(rsp->buf) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + info.data_op = ACDB_OP_GET_SUBGRAPH_DATA; + info.tag = &req->module_tag; + + GetOffloadedParamList(&info.offloaded_parameter_list); + if (info.offloaded_parameter_list.count == 0) + { + ACDB_DBG("Error[%d]: No offloaded parameters found. Skipping..", + status); + } + + for (uint32_t i = 0; i < req->num_sg_ids; i++) + { + info.subgraph_id = req->sg_ids[i]; + + // Search Tag Key Table Chunk + offset_tag_data_tbl = 0; + status = TagDataSearchKeyTable(info.subgraph_id, + info.tag->tag_id, + &offset_tag_data_tbl); + if (AR_FAILED(status)) + { + if (info.op == ACDB_OP_GET_SIZE) + ACDB_DBG("Warning[%d]: No tag data for Tag(0x%x) " + "found under Subgraph(0x%x). Skipping..", + status, info.tag->tag_id, info.subgraph_id); + status = AR_EOK; + continue; + } + + // Search Tag Data LUT + status = TagDataSearchLut(&info.tag->tag_key_vector, + offset_tag_data_tbl, + &info.data_offsets); + if (AR_FAILED(status)) + { + ACDB_DBG("Warning[%d]: No matching TKV " + "found under Subgraph(0x%x) with Tag(0x%x). Skipping..", + status, info.subgraph_id, info.tag->tag_id); + status = AR_EOK; + continue; + } + + //Get Module Tag Data + status = TagDataGetSubgraphData(&info, &blob_offset, rsp); + if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + break; + } + } + + if (AR_FAILED(status) && status != AR_ENOTEXIST) + return status; + + else if (rsp->buf_size <= 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: No tag data found", status); + } + + return status; +} + +int32_t AcdbGetTagDataForSubgraph(AcdbTagDataContextInfo* info, + uint32_t* blob_offset, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t offset_tag_data_tbl = 0; + + if (IsNull(info) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: " + "One or more input parameters are null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + GetOffloadedParamList(&info->offloaded_parameter_list); + if (info->offloaded_parameter_list.count == 0) + { + ACDB_DBG("Error[%d]: No offloaded parameters found. Skipping..", + status); + } + + //Search Tag Key Table Chunk + offset_tag_data_tbl = 0; + status = TagDataSearchKeyTable(info->subgraph_id, + info->tag->tag_id, &offset_tag_data_tbl); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: The [0x0%x, 0x0%x] " + "entry does not exist", status, + info->subgraph_id, info->tag->tag_id); + return status; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while searching " + "the tag key table for entry [0x0%x,0x0%x]", + status, info->subgraph_id, info->tag->tag_id); + return status; + } + + //Search Tag Data LUT + status = TagDataSearchLut(&info->tag->tag_key_vector, + offset_tag_data_tbl, &info->data_offsets); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + return status; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while searching " + "the tag data lut", status); + return status; + } + + if (info->parameter_list->count == 0) + { + //Get Tag data for an entire module + status = TagDataGetSubgraphData(info, blob_offset, rsp); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: No data found for " + "[0x%x, 0x%x, 0x%x]", + status, info->subgraph_id, info->tag->tag_id, info->instance_id); + return status; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while retrieving all tag" + " data for [0x%x, 0x%x, 0x%x]", + status, info->subgraph_id, info->tag->tag_id, info->instance_id); + return status; + } + } + else + { + //Get Tag Data for the specified list of parameters + status = TagDataGetParameterData(info, blob_offset, rsp); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: No data found with the parameter list " + "for [0x%x, 0x%x, 0x%x]", + status, info->subgraph_id, info->tag->tag_id, info->instance_id); + return status; + } + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while retrieving " + "data with parameter list for " + "[0x%x, 0x%x, 0x%x]", + status, info->subgraph_id, info->tag->tag_id, info->instance_id); + return status; + } + } + + return status; +} + +int32_t AcdbCmdGetTagData(AcdbGetTagDataReq* req, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t blob_offset = 0; + AcdbTagDataContextInfo info = { 0 }; + AcdbSubgraph *subgraph = NULL; + AcdbGetGraphRsp graph = { 0 }; + + if (req->graph_key_vector.num_keys == 0) + { + ACDB_ERR("Error[%d]: No data exist for the empty GKV", + AR_ENOTEXIST); + return AR_ENOTEXIST; + } + else + { + ACDB_DBG("Retrieving Tag data for the following graph key vector:"); + LogKeyVector(&req->graph_key_vector, GRAPH_KEY_VECTOR); + } + + if (req->module_tag.tag_key_vector.num_keys == 0) + { + ACDB_ERR("Error[%d]: The TKV cannot be empty", AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = AcdbSort2( + req->module_tag.tag_key_vector.num_keys * sizeof(AcdbKeyValuePair), + req->module_tag.tag_key_vector.graph_key_vector, + sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Unable to sort Tag Key Vector", AR_EBADPARAM); + return status; + } + + /* Tag data does not have a param type. Currently tag data is + * stored under non-persistent data in the heap */ + info.param_type = ACDB_DATA_NON_PERSISTENT; + info.op = IsNull(rsp->buf) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + info.data_op = ACDB_OP_GET_MODULE_DATA; + info.tag = &req->module_tag; + + if (info.op == ACDB_OP_GET_SIZE) + { + ACDB_DBG("Getting data for Tag(0x%x) and TKV:", + info.tag->tag_id); + LogKeyVector(&info.tag->tag_key_vector, TAG_KEY_VECTOR); + } + + status = AcdbGetUsecaseSubgraphList( + &req->graph_key_vector, NULL, &graph); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get usecase subgraphs" + " for the given graph key vector.", + status); + goto end; + } + + AcdbModuleParamList* instance_param_list = NULL; + bool_t found_subgraph = false; + instance_param_list = req->instance_param_list; + for (uint32_t i = 0; i < req->num_module_instance; i++) + { + subgraph = graph.subgraphs; + if (IsNull(subgraph)) + { + ACDB_ERR("Error[%d]: The subgraph list is null", + status); + break; + } + info.instance_id = instance_param_list->instance_id; + info.subgraph_id = subgraph->sg_id; + info.parameter_list = &instance_param_list->parameter_list; + + for (uint32_t j = 0; j < graph.num_subgraphs; j++) + { + info.subgraph_id = subgraph->sg_id; + + if (j != graph.num_subgraphs - 1) + subgraph = (AcdbSubgraph*)((uint8_t*)subgraph + sizeof(AcdbSubgraph) + + subgraph->num_dst_sgids * sizeof(uint32_t)); + + found_subgraph = DoesSubgraphContainModule(info.subgraph_id, + instance_param_list->instance_id, &status); + + if (found_subgraph) + break; + } + + if (i != req->num_module_instance - 1) + instance_param_list = (AcdbModuleParamList*)((uint8_t*)instance_param_list + + sizeof(AcdbModuleParamList) + + instance_param_list->parameter_list.count * sizeof(uint32_t)); + + if (!found_subgraph) + { + ACDB_ERR("Error[%d]: Module instance 0x%x not found in usecase" + , status, info.instance_id); + continue; + } + + status = AcdbGetTagDataForSubgraph(&info, &blob_offset, rsp); + if (AR_SUCCEEDED(status) || status == AR_ENOTEXIST) + { + status = AR_EOK; + continue; + } + else + { + break; + } + } + + if (rsp->buf_size == 0) + status = AR_ENOTEXIST; + +end: + //Clean Up Context Info + info.tag = NULL; + return status; +} + +int32_t AcdbCmdSetTagData(AcdbSetTagDataReq *req) +{ + int32_t status = AR_EOK; + uint32_t subgraph_id = 0; + uint32_t num_subgraphs_found = 0; + uint32_t offset_tag_data_tbl = 0; + uint32_t offset_tag_key_ids = 0; + AcdbUintList tag_key_id_list = { 0 }; + AcdbSubgraphParamData subgraph_param_data = { 0 }; + + if (IsNull(req)) + { + ACDB_ERR("Error[%d]: The input request is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->graph_key_vector.num_keys == 0) + { + ACDB_ERR("Error[%d]: The graph key vector cannot be empty.", + AR_EUNSUPPORTED); + return AR_EUNSUPPORTED; + } + else + { + ACDB_DBG("Setting tag data for the following graph key vector:"); + LogKeyVector(&req->graph_key_vector, GRAPH_KEY_VECTOR); + } + + if (req->module_tag.tag_key_vector.num_keys == 0) + { + ACDB_ERR("Error[%d]: The TKV cannot be empty", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->blob_size == 0 || IsNull(req->blob)) + { + ACDB_ERR("Error[%d]: The input blob is empty. There are not parameters to set", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + /* GLB_BUFFER_3 is used here as the filtered subgraph list. */ + ACDB_CLEAR_BUFFER(glb_buf_3); + subgraph_param_data.subgraph_id_list.count = 0; + subgraph_param_data.subgraph_id_list.list = &glb_buf_3[0]; + subgraph_param_data.data_size = req->blob_size; + subgraph_param_data.data = req->blob; + + status = AcdbGetUsecaseSubgraphList(&req->graph_key_vector, + &subgraph_param_data.subgraph_id_list, NULL); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get usecase subgraph list", status); + return status; + } + + status = AcdbSort2( + req->module_tag.tag_key_vector.num_keys * sizeof(AcdbKeyValuePair), + &req->module_tag.tag_key_vector, + sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort the tag key vector"); + return status; + } + + /* Verify that the input tkv's key ids match the the tag + tkv + defined in the database */ + status = FindTagKeyList(req->module_tag.tag_id, &offset_tag_key_ids); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: The given tag key vectors Key IDs are not associated" + " with Tag 0x0%x. Check the tags definition.", status, + req->module_tag.tag_id, subgraph_id); + return status; + } + else if AR_FAILED(status) + { + return status; + } + + status = FileManReadBuffer(&tag_key_id_list.count, + sizeof(uint32_t), &offset_tag_key_ids); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of keys.", status); + return status; + } + + if (tag_key_id_list.count != 0) + { + status = FileManGetFilePointer2((void**)&tag_key_id_list.list, + offset_tag_key_ids); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read tag Key ID list", status); + return status; + } + } + + if (!CompareKeyVectorIds2(&req->module_tag.tag_key_vector, + &tag_key_id_list)) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: The given tag key vectors Key IDs for " + "Tag 0x0%x do not match the tag defined in the database.", + status, req->module_tag.tag_id, subgraph_id); + return status; + } + + /* Ensure the Tag + Subgraph combination exists in the database + * before commiting data to the heap. */ + for (uint32_t i = 0; i < subgraph_param_data.subgraph_id_list.count; i++) + { + subgraph_id = subgraph_param_data.subgraph_id_list.list[i]; + + status = TagDataSearchKeyTable(subgraph_id, + req->module_tag.tag_id, &offset_tag_data_tbl); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + ACDB_DBG("Error[%d]: Tag 0x0%x not found in any " + "module under Subgraph 0x0%x. Skipping..", status, + req->module_tag.tag_id, subgraph_id); + continue; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while searching " + "the tag key table for entry [0x0%x,0x0%x]", + status, subgraph_id, req->module_tag.tag_id); + goto end; + } + + subgraph_param_data.subgraph_id_list + .list[num_subgraphs_found] = subgraph_id; + num_subgraphs_found++; + } + + subgraph_param_data.subgraph_id_list.count = num_subgraphs_found; + + if (num_subgraphs_found == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Tag 0x0%x not found in any " + "subgraph under the provided usecase", + status, req->module_tag.tag_id); + goto end; + } + + status = DataProcSetTagData(&req->module_tag, &subgraph_param_data); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to set tag data to heap", status); + goto end; + } + + if (acdb_delta_data_is_persist_enabled()) + { + status = acdb_delta_data_ioctl( + ACDB_DELTA_DATA_CMD_SAVE, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to save delta file", status); + } + } + else + { + ACDB_INFO("Error[%d]: Unable to save delta data. " + "Is delta data persistance enabled?", status); + } + +end: + ACDB_CLEAR_BUFFER(glb_buf_3); + + return status; +} + +/** +* \brief +* Retrieve calibration data for a parameter from the data pool +* \param[int] req: Request containing the subgraph, module instance, parameter, and CKV +* \param[in/out] rsp: A data blob containg calibration data +* \param[in] offset_pair: calibration data def and dot offsets +* \return 0 on success, and non-zero on failure +*/ +int32_t CalDataGetParameterData(AcdbAudioCalContextInfo *info, uint32_t *blob_offset, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t tmp_blob_offset = 0; + uint32_t data_offset = 0; + uint32_t padded_param_size = 0; + uint32_t param_dot_offset = 0; + uint32_t entry_index = 0; + uint32_t num_id_entries = 0; + uint32_t num_iid_found = 0; + bool_t is_offloaded_param = FALSE; + AcdbModIIDParamIDPair iid_pid_pair = { 0 }; + AcdbDspModuleHeader module_header = { 0 }; + ChunkInfo ci_def = { 0 }; + ChunkInfo ci_dot = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbPayload caldata = { 0 }; + AcdbBlob buffer = { 0 }; + AcdbIidRefCount *iid_ref = NULL; + AcdbOp op = IsNull(rsp->buf) ? + ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + if (IsNull(info) || IsNull(rsp)) + { + ACDB_ERR("The input request, or response are null"); + return AR_EBADPARAM; + } + + ci_def.chunk_id = ACDB_CHUNKID_CALDATADEF; + ci_dot.chunk_id = ACDB_CHUNKID_CALDATADOT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + + status = ACDB_GET_CHUNK_INFO(&ci_def, &ci_dot, &ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Unable to retrieve def, dot, or data pool tables", status); + return status; + } + + offset = ci_def.chunk_offset + info->data_offsets.offset_def; + + status = FileManReadBuffer(&num_id_entries, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of entries.", status); + return status; + } + + status = FileManReadBuffer( + &glb_buf_3[0], num_id_entries * sizeof(AcdbModIIDParamIDPair), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read List of .", status); + return status; + } + + iid_pid_pair.module_iid = info->instance_id; + module_header.module_iid = info->instance_id; + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + //Ensure global buffer can store the default data IID Reference list + if (GLB_BUF_1_LENGTH < num_id_entries * 2) + { + ACDB_ERR("Error[%d]: Need more memory to store IID reference list", + AR_ENEEDMORE); + return AR_ENEEDMORE; + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + + iid_ref = (AcdbIidRefCount*)glb_buf_1; + } + + for (uint32_t i = 0; i < info->parameter_list->count; i++) + { + iid_pid_pair.parameter_id = info->parameter_list->list[i]; + module_header.parameter_id = info->parameter_list->list[i]; + + if (SEARCH_ERROR == AcdbDataBinarySearch2((void*)&glb_buf_3, + num_id_entries * sizeof(AcdbModIIDParamIDPair), + &iid_pid_pair, 2, + (int32_t)(sizeof(AcdbModIIDParamIDPair) / sizeof(uint32_t)), + &entry_index)) + { + status = AR_ENOTEXIST; + ACDB_DBG("Error[%d]: Unable to find Parameter(0x%x). Skipping..", + status, module_header.parameter_id); + continue; + } + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + //Add IIDs to list and ignore get data + if (iid_ref->module_iid != module_header.module_iid && num_iid_found == 0) + { + iid_ref->module_iid = module_header.module_iid; + iid_ref->ref_count = 1; + num_iid_found++; + } + else if (iid_ref->module_iid != module_header.module_iid) + { + iid_ref++; + iid_ref->module_iid = module_header.module_iid; + iid_ref->ref_count = 1; + num_iid_found++; + } + else + { + /* Increase ref count of the current Obj */ + iid_ref->ref_count++; + } + + continue; + } + else + { + /* For other CKVs, if the module is in the default data list, remove it */ + if (!IsNull(info->default_data_iid_list.list)) + { + iid_ref = (AcdbIidRefCount*) + info->default_data_iid_list.list; + bool_t found_iid = FALSE; + for (uint32_t j = 0; j < info-> + default_data_iid_list.count; j++) + { + if ((module_header.module_iid == iid_ref->module_iid) + && iid_ref->ref_count > 0) + { + iid_ref->ref_count--; + found_iid = TRUE; + break; + } + else if ((module_header.module_iid == iid_ref->module_iid) + && iid_ref->ref_count <= 0) + break; + + iid_ref++; + } + + if (info->is_default_module_ckv && !found_iid) + { + continue; + } + } + } + + status = IsOffloadedParam(module_header.parameter_id, + &info->offloaded_parameter_list); + + is_offloaded_param = AR_SUCCEEDED(status) ? TRUE : FALSE; + + //Get from heap + status = GetSubgraphCalData( + info->param_type, ACDB_DATA_ACDB_CLIENT, + info->module_ckv, info->subgraph_id, module_header.module_iid, + module_header.parameter_id, is_offloaded_param, + blob_offset, rsp); + + if (AR_SUCCEEDED(status)) + { + continue; + } + + //Get from file manager + + offset = ci_dot.chunk_offset + + info->data_offsets.offset_dot; + + /* Calculation for DOT offset of pair + * + * Offset of + Number of + Offset of the desired DOT entry based + * DOT DOT entries on index of in DEF + */ + param_dot_offset = + offset + sizeof(uint32_t) + sizeof(uint32_t) * (uint32_t)( + entry_index + / (sizeof(AcdbModIIDParamIDPair) / sizeof(uint32_t))); + + status = FileManReadBuffer(&data_offset, + sizeof(uint32_t), ¶m_dot_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to read data pool offset from DOT.", status); + return status; + } + + offset = ci_data_pool.chunk_offset + data_offset; + + status = FileManReadBuffer(&module_header.param_size, + sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to read param size from data pool.", status); + return status; + } + + caldata.size = module_header.param_size; + status = FileManGetFilePointer2((void**)&caldata.payload, offset); + + if (is_offloaded_param) + { + status = AcdbGetOffloadedParameterCal( + info->op, info->subgraph_id, &module_header, + &caldata, rsp, blob_offset, &tmp_blob_offset); + if (AR_FAILED(status)) + return status; + + padded_param_size = + ACDB_ALIGN_8_BYTE(module_header.param_size); + } + else + { + padded_param_size = + ACDB_ALIGN_8_BYTE(module_header.param_size); + } + + switch (op) + { + case ACDB_OP_GET_SIZE: + rsp->buf_size += sizeof(AcdbDspModuleHeader) + + padded_param_size; + break; + case ACDB_OP_GET_DATA: + + //Write Module IID, and Parameter ID + buffer.buf = (void*)&module_header; + buffer.buf_size = sizeof(AcdbDspModuleHeader); + status = AcdbWriteBuffer(rsp, blob_offset, &buffer); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to write module header for" + "", + status, info->subgraph_id, module_header.module_iid, + module_header.parameter_id); + return status; + } + + if (is_offloaded_param) + { + *blob_offset = tmp_blob_offset; + continue; + } + + //Write Payload + if (rsp->buf_size < (*blob_offset + module_header.param_size)) + return AR_ENEEDMORE; + + if (module_header.param_size > 0) + { + buffer.buf = caldata.payload; + buffer.buf_size = caldata.size; + + status = AcdbWriteBuffer(rsp, blob_offset, &buffer); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to write param(0x%x) data", + status, module_header.parameter_id); + return status; + } + } + + *blob_offset += ACDB_PADDING_8_BYTE(caldata.size); + + break; + default: + break; + } + + } + + if (info->is_default_module_ckv && !info->ignore_get_default_data) + { + ACDB_FREE(info->default_data_iid_list.list); + info->default_data_iid_list.list = NULL; + } + else if (info->is_default_module_ckv && info->ignore_get_default_data) + { + /* Copy the IID Ref Count list from GLB_BUF_1 since it will be + * cleared outside of this call */ + info->default_data_iid_list.count = num_iid_found; + + //List of AcdbIidRefCount + info->default_data_iid_list.list = (uint32_t*) + ACDB_MALLOC(AcdbIidRefCount, num_iid_found); + + if (IsNull(info->default_data_iid_list.list)) + { + ACDB_ERR("Error[%d]: Unable to allocate memory " + "for instance id reference list", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + ACDB_MEM_CPY_SAFE(info->default_data_iid_list.list, + num_iid_found * sizeof(AcdbIidRefCount), + &glb_buf_1[0], num_iid_found * sizeof(AcdbIidRefCount)); + + iid_ref = NULL; + } + + + return status; +} + +int32_t AcdbGetCalDataForSubgraph(AcdbAudioCalContextInfo* info, + uint32_t* blob_offset, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t ckv_list_offset = 0; + uint32_t default_ckv_entry_offset = 0; + bool_t found_param_data = 0; + AcdbSgCalLutHeader sg_cal_lut_header = { 0 }; + AcdbCalKeyTblEntry ckv_entry = { 0 }; + + if (IsNull(info) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null:" + " req or rsp"); + return AR_EBADPARAM; + } + + sg_cal_lut_header.subgraph_id = info->subgraph_id; + status = SearchSubgraphCalLut2(&sg_cal_lut_header, &ckv_list_offset); + if (AR_FAILED(status)) + { + return status; + } + + if (sg_cal_lut_header.num_ckv_entries == 0) + { + ACDB_ERR("Error[%d]: Subgraph(0x%x) has no CKV entries in" + " the Subgraph Cal LUT. At least one entry should be" + " present.", + AR_ENOTEXIST, info->subgraph_id); + return AR_ENOTEXIST; + } + + info->ignore_get_default_data = + sg_cal_lut_header.num_ckv_entries == 1 ? FALSE : TRUE; + + //The default CKV will be skipped and handeled last + if (sg_cal_lut_header.num_ckv_entries > 1 && info->is_first_time) + sg_cal_lut_header.num_ckv_entries++; + + default_ckv_entry_offset = ckv_list_offset; + + for (uint32_t k = 0; k < sg_cal_lut_header.num_ckv_entries; k++) + { + /* The Default CKV is always the first CKV in the list of CKVs to + * search. It will be skipped and processed last */ + if ((k == sg_cal_lut_header.num_ckv_entries - 1) && + info->ignore_get_default_data == TRUE && info->is_first_time) + { + info->ignore_get_default_data = FALSE; + + status = FileManReadBuffer(&ckv_entry, sizeof(ckv_entry), + &default_ckv_entry_offset); + } + else + { + status = FileManReadBuffer(&ckv_entry, sizeof(ckv_entry), + &ckv_list_offset); + } + + if (AR_FAILED(status)) + { + return status; + } + + status = AcdbFindModuleCKV(&ckv_entry, info); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + continue; + } + else if (AR_FAILED(status)) + { + return status; + } + + if (info->parameter_list->count == 0) + { + //Get data for an entire module + status = AcdbGetSubgraphCalibration(info, blob_offset, rsp); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + continue; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while getting cal " + "data for [0x%x, 0x%x]", + status, info->subgraph_id, info->instance_id); + return status; + } + } + else + { + //Get Data for a list of parameters + status = CalDataGetParameterData(info, blob_offset, rsp); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + continue; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while getting cal " + "data for [0x%x, 0x%x]", + status, info->subgraph_id, info->instance_id); + return status; + } + } + + found_param_data = TRUE; + } + + if (found_param_data) + { + status = AR_EOK; + } + + if (status == AR_ENOTEXIST + && !found_param_data) + { + ACDB_ERR("Error[%d]: No data found for " + "[0x%x, 0x%x].", status, + info->subgraph_id, info->instance_id); + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while getting cal data for " + "[0x%x, 0x%x].", status, + info->subgraph_id, info->instance_id); + } + + return status; +} + +int32_t AcdbFindVoiceCalKeyValues( + AcdbVcpmChunkInfo *ci_vcpm, AcdbUintList *ckv_values, + AcdbVcpmCalDataObj *cal_data_obj, uint32_t *table_offset) +{ + int32_t status = AR_EOK; + uint32_t file_offset = *table_offset; + uint32_t offset = 0; + AcdbUintList values_list = { 0 }; + + if (IsNull(ckv_values) || IsNull(cal_data_obj) + || IsNull(table_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = FileManReadBuffer(cal_data_obj, + sizeof(AcdbVcpmCalDataObj), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Cal " + "Data Object Header.", status); + return status; + } + + offset = ci_vcpm->vcpm_cal_lut.chunk_offset + + cal_data_obj->offset_vcpm_ckv_lut; + status = FileManReadBuffer(&values_list.count, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of voice keys.", status); + return status; + } + + if (values_list.count != ckv_values->count) + { + //Go to Next Cal Data Obj + *table_offset = file_offset + + (cal_data_obj->num_data_offsets * sizeof(uint32_t)); + return AR_ENOTEXIST; + } + + if (values_list.count != 0) + { + offset += sizeof(uint32_t);//num_entries is always 1 + status = FileManGetFilePointer1( + (void*)&values_list.list, values_list.count * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to Voice Key IDs.", status); + return status; + } + + if (0 != ACDB_MEM_CMP(values_list.list, ckv_values->list, + values_list.count * sizeof(uint32_t))) + { + //Go to Next Cal Data Obj + *table_offset = file_offset + + (cal_data_obj->num_data_offsets * sizeof(uint32_t)); + return AR_ENOTEXIST; + } + } + + *table_offset = file_offset; + + return status; +} + +int32_t AcdbFindVoiceModuleCKV( + AcdbAudioCalContextInfo* info, AcdbVcpmChunkInfo* ci_vcpm, + AcdbVcpmCkvDataTable* cal_data_table, uint32_t* cal_data_table_offset, + AcdbVcpmCalDataObj *cal_data_obj, uint32_t* cal_data_obj_offset) +{ + int32_t status = AR_EOK; + uint32_t file_offset = *cal_data_table_offset; + uint32_t offset = 0; + AcdbGraphKeyVector module_ckv = { 0 }; + AcdbUintList ckv_values = { 0 }; + + if (IsNull(info) || IsNull(cal_data_table) || + IsNull(cal_data_table_offset) || IsNull(cal_data_obj_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = FileManReadBuffer(cal_data_table, + sizeof(AcdbVcpmCkvDataTable), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read CKV " + "Data Table Header.", status); + return status; + } + + //Set offset to point to the next ckv data table + *cal_data_table_offset = file_offset + cal_data_table->table_size + - sizeof(AcdbVcpmCkvDataTable) + + sizeof(cal_data_table->table_size); + + //Set offset to first cal data object in the current CKV table + *cal_data_obj_offset = file_offset; + + offset = ci_vcpm->vcpm_cal_key_table.chunk_offset + + cal_data_table->offset_voice_key_table; + status = FileManReadBuffer(&module_ckv.num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of voice keys.", status); + return status; + } + + /* + * GLB_BUF_1: + * 1. Used to store the key ids + * 2. Also stores the CKV LUT used in the partition binary search + * GLB_BUF_3: + * 1. The first portion of the buffer stores the Module CKV + * 2. The other portion stores one CKV LUT entry found + * during the partition binary search + */ + if (module_ckv.num_keys > 0) + { + status = FileManReadBuffer(&glb_buf_1, + module_ckv.num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to Voice Key IDs.", status); + return status; + } + } + + module_ckv.graph_key_vector = + (AcdbKeyValuePair*)&glb_buf_3[0]; + for (uint32_t i = 0; i < module_ckv.num_keys; i++) + { + module_ckv.graph_key_vector[i].key = glb_buf_1[i]; + } + + ckv_values.count = 0; + ckv_values.list = &glb_buf_1[0]; + + /* Check if the Module CKV exist within the usecase + * CKV. Otherwise skip this ckv table */ + uint32_t num_keys_found = 0; + for (uint32_t k = 0; k < module_ckv.num_keys; k++) + { + for (uint32_t l = 0; l < info->ckv->num_keys; l++) + { + if (module_ckv.graph_key_vector[k].key == + info->ckv->graph_key_vector[l].key) + { + ckv_values.list[num_keys_found++] = + info->ckv->graph_key_vector[l].value; + module_ckv.graph_key_vector[k].value = + info->ckv->graph_key_vector[l].value; + break; + } + } + } + + if (info->ckv->num_keys == 0 && module_ckv.num_keys != 0) + return AR_ENOTEXIST; + if ((num_keys_found != module_ckv.num_keys)) + return AR_ENOTEXIST; + + ckv_values.count = num_keys_found; + + //check for cal dot table to see if values exist + for (uint32_t i = 0; i < cal_data_table->num_caldata_obj; i++) + { + status = AcdbFindVoiceCalKeyValues( + ci_vcpm, &ckv_values, cal_data_obj, &file_offset); + + if (AR_FAILED(status) && status != AR_ENOTEXIST) + return status; + else if (AR_SUCCEEDED(status)) break; + } + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to find matching key vector.", status); + return status; + } + + info->module_ckv->num_keys = module_ckv.num_keys; + + if (info->module_ckv->num_keys > 0) + ACDB_MEM_CPY_SAFE(info->module_ckv->graph_key_vector, + module_ckv.num_keys * sizeof(AcdbKeyValuePair), + module_ckv.graph_key_vector, + module_ckv.num_keys * sizeof(AcdbKeyValuePair)); + + + /* Hypervisor + * If we encounter the Default CKV + * Indiciate that the default CKV has been found + * Store the LUT Entry Offsets(DEF DOT, DOT2) separately for the default CKV + * Skip getting data for the default CKV if the next CKV is what we are + * looking for and it contains one of the IIDs that are also associated + * with the default CKV, + */ + + if (module_ckv.num_keys == 0) + { + info->is_default_module_ckv = TRUE; + //info->ignore_get_default_data = TRUE; + + /* Read IIDs into a tracking list. For non-default CKVs, if a module + * is found remove it from the default CKV IID list*/ + } + else + { + info->is_default_module_ckv = FALSE; + info->ignore_get_default_data = TRUE; + } + + return status; +} + +/** +* \brief +* Get calibration for parameters in a voice subgraph. There are +* two modes: +* 1. Get all parameters under info->instance_id (module instance) +* info->parameter_list->count == 0 +* 2. Get specfic parameters under info->instance_id (module instance) +* info->parameter_list->count > 0 +* +* \param[in/out] info: Contains the module instance ID and the parameter list +* which is used for filtering out module instances +* parameters +* \param[in/out] ci_vcpm: The chunk information for voice calibration +* \param[in/out] ci_data_pool: The chunk information for the global datapool +* \param[in/out] cal_data_obj: The header of a cal data object table +* \param[in/out] cal_data_obj_offset: Offset to the voice cal data object +* table in the *.acdb file +* \param[in/out] blob_offset: The current offset in the response blob +* \param[in/out] rsp: The calibration response structure +* +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbGetVoiceParameterCalData( + AcdbAudioCalContextInfo* info, + AcdbVcpmChunkInfo* ci_vcpm, ChunkInfo* ci_data_pool, + AcdbVcpmCalDataObj *cal_data_obj, uint32_t cal_data_obj_offset, + uint32_t *blob_offset, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + uint32_t file_offset = 0; + uint32_t tmp_blob_offset = 0; + uint32_t id_pair_table_size = 0; + uint32_t curr_cal_data_obj_table_offset = 0; + uint32_t curr_cal_def_table_offset = 0; + uint32_t data_pool_offset = 0; + uint32_t data_pool_offset_index = 0; + uint32_t num_params = 0; + bool_t should_get_all_params = FALSE; + bool_t is_offloaded_param = FALSE; + AcdbMiidPidPair id_pair = { 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + AcdbDspModuleHeader module_header = { 0 }; + AcdbPayload caldata = { 0 }; + + /* Binary Search through to find index of . Use the + * index to calculate the Cal Data Object data pool offset to get to the + * data pool offset */ + id_pair_table_size = + cal_data_obj->num_data_offsets * sizeof(AcdbMiidPidPair); + + //Setup Table Information + table_info.table_offset = ci_vcpm->vcpm_cal_def.chunk_offset + + cal_data_obj->offset_cal_def + sizeof(uint32_t);//Skip num id pairs + table_info.table_size = id_pair_table_size; + table_info.table_entry_size = sizeof(AcdbMiidPidPair); + + //Setup Search Information + search_info.num_search_keys = 2;//IID, PID + search_info.num_structure_elements = + (sizeof(AcdbMiidPidPair) / sizeof(uint32_t)); + search_info.table_entry_struct = &id_pair; + + if (info->parameter_list->count == 0) + { + should_get_all_params = TRUE; + num_params = cal_data_obj->num_data_offsets; + curr_cal_def_table_offset = table_info.table_offset; + + //Search for the first occurance of the module instance + search_info.num_search_keys = 1;//IID + id_pair.module_iid = info->instance_id; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_DBG("Unable to find first occurance of Module" + " Instance ID(0x%x) . Skipping..", + id_pair.module_iid, id_pair.parameter_id); + return status; + } + + data_pool_offset_index = search_info.entry_index; + curr_cal_def_table_offset += + data_pool_offset_index * sizeof(AcdbMiidPidPair); + curr_cal_data_obj_table_offset = + cal_data_obj_offset + sizeof(AcdbVcpmCalDataObj) + + data_pool_offset_index * sizeof(uint32_t); + } + else + { + num_params = info->parameter_list->count; + } + + for (uint32_t i = 0; i < num_params; i++) + { + file_offset = cal_data_obj_offset + sizeof(AcdbVcpmCalDataObj); + //id_pair.module_iid = info->instance_id; + //id_pair.parameter_id = info->parameter_list->list[i]; + //module_header.module_iid = id_pair.module_iid; + //module_header.parameter_id = id_pair.parameter_id; + + if (should_get_all_params) + { + //read iid pid from cal def table + status = FileManReadBuffer(&id_pair, sizeof(AcdbMiidPidPair), + &curr_cal_def_table_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read " + "pair in cal def table.", status); + return status; + } + + if (id_pair.module_iid != info->instance_id) + { + //curr_cal_data_obj_table_offset += sizeof(data_pool_offset); + break; + } + } + else + { + id_pair.module_iid = info->instance_id; + id_pair.parameter_id = info->parameter_list->list[i]; + } + + module_header.module_iid = id_pair.module_iid; + module_header.parameter_id = id_pair.parameter_id; + + + /* Get data from heap */ + status = GetSubgraphCalData( + info->param_type, ACDB_DATA_ACDB_CLIENT, + info->module_ckv, info->subgraph_id, module_header.module_iid, + module_header.parameter_id, is_offloaded_param, + blob_offset, rsp); + if (AR_SUCCEEDED(status)) + { + if (should_get_all_params) + curr_cal_data_obj_table_offset += sizeof(data_pool_offset); + continue; + } + + /* Get data from *.acdb file */ + if (should_get_all_params) + { + file_offset = curr_cal_data_obj_table_offset; + curr_cal_data_obj_table_offset += sizeof(data_pool_offset); + } + else + { + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_DBG("Failed to find Module Instance ID(0x%x) " + "Parameter ID(0x%x). Skipping..", + id_pair.module_iid, id_pair.parameter_id); + continue; + } + + data_pool_offset_index = search_info.entry_index; + file_offset += data_pool_offset_index * sizeof(uint32_t); + } + + status = FileManReadBuffer(&data_pool_offset, + sizeof(uint32_t), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read global data pool" + " offset in cal data object table.", status); + return status; + } + + file_offset = ci_data_pool->chunk_offset + data_pool_offset; + status = FileManReadBuffer(&module_header.param_size, + sizeof(uint32_t), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read parameter size.", status); + return status; + } + + caldata.size = module_header.param_size; + status = FileManGetFilePointer2((void**)&caldata.payload, file_offset); + + status = IsOffloadedParam(module_header.parameter_id, + &info->offloaded_parameter_list); + + is_offloaded_param = AR_SUCCEEDED(status) ? TRUE : FALSE; + + if (is_offloaded_param) + { + status = AcdbGetOffloadedParameterCal( + info->op, info->subgraph_id, &module_header, + &caldata, rsp, blob_offset, &tmp_blob_offset); + if (AR_FAILED(status)) + return status; + } + + switch (info->op) + { + case ACDB_OP_GET_SIZE: + rsp->buf_size += sizeof(AcdbDspModuleHeader) + + ACDB_ALIGN_8_BYTE(module_header.param_size); + break; + case ACDB_OP_GET_DATA: + //Write spf module param header + ACDB_MEM_CPY_SAFE( + (uint8_t*)rsp->buf + *blob_offset, sizeof(AcdbDspModuleHeader), + &module_header, sizeof(AcdbDspModuleHeader)); + *blob_offset += sizeof(AcdbDspModuleHeader); + + if (is_offloaded_param) + { + *blob_offset = tmp_blob_offset; + continue; + } + + if (module_header.param_size != 0) + { + status = FileManReadBuffer((uint8_t*)rsp->buf + *blob_offset, + module_header.param_size, &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read parameter payload.", + status); + return status; + } + *blob_offset += ACDB_ALIGN_8_BYTE(module_header.param_size); + } + break; + default: + break; + } + } + + return status; +} + +int32_t AcdbGetVoiceSubgraph( + uint32_t subgraph_id, ChunkInfo *vcpm_sg_cal, + AcdbVcpmSubgraphCalTable *vcpm_sg_cal_table, + uint32_t *vcpm_sg_cal_table_offset) +{ + int32_t status = AR_EOK; + AcdbVcpmSubgraphCalHeader vcpm_cal_header = { 0 }; + + *vcpm_sg_cal_table_offset = vcpm_sg_cal->chunk_offset; + status = FileManReadBuffer(&vcpm_cal_header, + sizeof(AcdbVcpmSubgraphCalHeader), vcpm_sg_cal_table_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read VCPM module header.", status); + return status; + } + + //Search for the matching VCPM Subgraph Cal Data Table + status = GetVcpmSubgraphCalTable(vcpm_cal_header.num_subgraphs, + subgraph_id, vcpm_sg_cal_table_offset, vcpm_sg_cal_table); + if (AR_FAILED(status)) + { + return status; + } + + return status; +} + + +int32_t AcdbGetVoiceCalDataForSubgraph( + AcdbVcpmChunkInfo *ci_vcpm, ChunkInfo *ci_data_pool, + AcdbAudioCalContextInfo *info, + AcdbVcpmSubgraphCalTable *vcpm_sg_cal_table, + uint32_t vcpm_sg_cal_table_offset, + uint32_t* blob_offset, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + AcdbVcpmCkvDataTable cal_data_table = { 0 }; + AcdbVcpmCalDataObj cal_data_obj = { 0 }; + uint32_t file_offset = vcpm_sg_cal_table_offset; + uint32_t cal_data_obj_offset = vcpm_sg_cal_table_offset; + uint32_t current_rsp_size = 0; + uint32_t retrieved_cal_rsp_size = 0; + + current_rsp_size = rsp->buf_size; + //skip default and save for last if no other configuration is found + + //Search for matching key vector then find iid,pid and get voice cal data + for (uint32_t i = 0; i < vcpm_sg_cal_table->num_ckv_data_table; i++) + { + status = AcdbFindVoiceModuleCKV(info, ci_vcpm, + &cal_data_table, &file_offset, + &cal_data_obj, &cal_data_obj_offset); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + continue; + else if(AR_FAILED(status)) + { + return status; + } + + //get calibration for list of parameters + status = AcdbGetVoiceParameterCalData( + info, ci_vcpm, ci_data_pool, + &cal_data_obj, cal_data_obj_offset, + blob_offset, rsp); + + retrieved_cal_rsp_size = rsp->buf_size - current_rsp_size; + + if (AR_ENOTEXIST == status /*&& 0 == retrieved_cal_rsp_size*/) + { + status = AR_EOK; + continue; + } + if (AR_FAILED(status)) + { + return status; + } + } + + return status; +} + +int32_t AcdbCmdGetCalData(AcdbGetCalDataReq* req, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t blob_offset = 0; + uint32_t vcpm_sg_cal_table_offset = 0; + AcdbAudioCalContextInfo info; + AcdbGetGraphRsp graph = { 0 }; + AcdbSubgraph *subgraph = NULL; + ChunkInfo ci_data_pool = { 0 }; + bool_t found_subgraph = false; + bool_t has_voice_data = FALSE; + AcdbVcpmChunkInfo ci_vcpm = { 0 }; + AcdbVcpmSubgraphCalTable vcpm_sg_cal_table = { 0 }; + AcdbModuleParamList* instance_param_list = NULL; + + (void)ar_mem_set(&info, 0, sizeof(AcdbAudioCalContextInfo)); + + if (req->graph_key_vector.num_keys == 0) + { + ACDB_ERR("Error[%d]: No data exist for the empty GKV", + AR_ENOTEXIST); + return AR_ENOTEXIST; + } + else + { + ACDB_DBG("Retrieving calibration data for the following graph key vector:"); + LogKeyVector(&req->graph_key_vector, GRAPH_KEY_VECTOR); + } + + status = AcdbGetUsecaseSubgraphList( + &req->graph_key_vector, NULL, &graph); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get usecase subgraphs" + " for the given graph key vector.", + status); + goto end; + } + + /* CKV Setup + * 1. GLB_BUF_2 stores the module CKV that will be used to locate data in + * the heap(if it exists) + * 2. The Delta CKV and CKV[New] are allocated on the heap by + * AcdbComputeDeltaCKV + * + * tmp - stores the amount of padding after graph_key_vectornum_keys + * tmp2 - stores the position of the KeyValuePair list + * + * The first info.module_ckv->graph_key_vector assignment has the effect + * of storing the address of the pointer in glb_buf_2 after + * graph_key_vector.num_keys + * + * The second info.module_ckv->graph_key_vector assignment has the effect + * of pointer the info.module_ckv->graph_key_vector to the actual list + * of key value pairs + * + * Whats inside global buffer 2 after these operations? + * + * The first 'sizeof(AcdbGraphKeyVector)' bytes is AcdbGraphKeyVector + * followed by 'sizeof(AcdbKeyValuePair) * num_keys' bytes which is + * the KV list + */ + info.module_ckv = (AcdbGraphKeyVector*)&glb_buf_2[0]; + uint32_t tmp = (sizeof(AcdbGraphKeyVector) - sizeof(AcdbKeyValuePair*)) / sizeof(uint32_t); + uint32_t tmp2 = sizeof(AcdbGraphKeyVector) / sizeof(uint32_t); + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp]; + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp2]; + + /* This flag must be set to true since delta CKVs are + * not applicable here */ + info.is_first_time = TRUE; + info.op = IsNull(rsp->buf) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + info.data_op = ACDB_OP_GET_MODULE_DATA; + info.param_type = ACDB_DATA_DONT_CARE; + info.ckv = &req->cal_key_vector; + instance_param_list = req->instance_param_list; + + /* Check if voice data exists */ + ci_vcpm.vcpm_sg_cal.chunk_id = ACDB_CHUNKID_VCPM_CAL_DATA; + ci_vcpm.vcmp_master_key_table.chunk_id = ACDB_CHUNKID_VCPM_MASTER_KEY; + ci_vcpm.vcpm_cal_key_table.chunk_id = ACDB_CHUNKID_VCPM_CALKEY_TABLE; + ci_vcpm.vcpm_cal_lut.chunk_id = ACDB_CHUNKID_VCPM_CALDATA_LUT; + ci_vcpm.vcpm_cal_def.chunk_id = ACDB_CHUNKID_VCPM_CALDATA_DEF; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + + status = ACDB_GET_CHUNK_INFO( + &ci_vcpm.vcpm_sg_cal, &ci_vcpm.vcpm_cal_key_table, + &ci_vcpm.vcpm_cal_lut, &ci_vcpm.vcpm_cal_def, + &ci_data_pool); + if (AR_SUCCEEDED(status)) + { + //voice calibration exists + has_voice_data = TRUE; + } + + GetOffloadedParamList(&info.offloaded_parameter_list); + if (info.offloaded_parameter_list.count == 0) + { + if (info.op == ACDB_OP_GET_SIZE) + ACDB_DBG("Error[%d]: No offloaded parameters found. Skipping..", + status); + } + + for (uint32_t i = 0; i < req->num_module_instance; i++) + { + subgraph = graph.subgraphs; + if (IsNull(subgraph)) + { + ACDB_ERR("Error[%d]: The subgraph list is null", + status); + break; + } + info.instance_id = instance_param_list->instance_id; + info.subgraph_id = subgraph->sg_id; + info.parameter_list = &instance_param_list->parameter_list; + + for (uint32_t j = 0; j < graph.num_subgraphs; j++) + { + info.subgraph_id = subgraph->sg_id; + + if (j != graph.num_subgraphs - 1) + subgraph = (AcdbSubgraph*)((uint8_t*)subgraph + sizeof(AcdbSubgraph) + + subgraph->num_dst_sgids * sizeof(uint32_t)); + + found_subgraph = DoesSubgraphContainModule(info.subgraph_id, + instance_param_list->instance_id, &status); + + if (found_subgraph) + break; + } + + if (i != req->num_module_instance - 1) + instance_param_list = (AcdbModuleParamList*)((uint8_t*)instance_param_list + + sizeof(AcdbModuleParamList) + + instance_param_list->parameter_list.count * sizeof(uint32_t)); + + if (!found_subgraph) + { + ACDB_ERR("Error[%d]: Module instance 0x%x not found in usecase" + , status, + info.instance_id); + continue; + } + + bool_t is_audio_sg = TRUE; + if (has_voice_data) + { + status = AcdbGetVoiceSubgraph( + info.subgraph_id, &ci_vcpm.vcpm_sg_cal, + &vcpm_sg_cal_table, &vcpm_sg_cal_table_offset); + if (AR_SUCCEEDED(status)) + is_audio_sg = FALSE; + } + + if (!is_audio_sg) + { + status = AcdbGetVoiceCalDataForSubgraph( + &ci_vcpm, &ci_data_pool, &info, + &vcpm_sg_cal_table, vcpm_sg_cal_table_offset, + &blob_offset, rsp); + if (status == AR_ENOTEXIST) + { + ACDB_DBG("Error[%d]: Voice subgraph 0x%x does not exist. " + "Skipping..", status); + status = AR_EOK; + } + else if (AR_FAILED(status)) + { + break; + } + continue; + } + + status = AcdbGetCalDataForSubgraph( + &info, &blob_offset, rsp); + switch (status) + { + case AR_EOK: + continue; + case AR_ENOTEXIST: + status = AR_EOK; + if (!has_voice_data) + { + /* This subgraph does not exist if it wasnt found under + * audio and there is no voice calibration data */ + ACDB_DBG("Error[%d]: Subgraph 0x%x does not exist. " + "Skipping..", AR_ENOTEXIST); + continue; + } + break; + default: + //ACDB_ERR("Error[%d]: Unable to get calibration from subgraph"); + break; + } + } + + if (rsp->buf_size == 0) + status = AR_ENOTEXIST; + +end: + //Clean Up Context Info + info.ckv = NULL; + AcdbClearAudioCalContextInfo(&info); + return status; +} + +/** +* \brief +* Search for a pair and return the definition +* table offset in the lut_entry parameter +* +* \param[in/out] ci_lut: chunk information for ACDB_CHUNKID_TAGGED_MODULE_LUT. +* \param[in/out] lut_entry: Contains the . +* The Def Offset will be populated by the search +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t SearchTaggedModuleMapLut(ChunkInfo *ci_lut, SubgraphTagLutEntry *lut_entry) +{ + int32_t status = AR_EOK; + //uint32_t offset = 0; + + //Lookup Table + //Binary Search based on + uint32_t search_index_count = 2; + uint32_t lut_size = 0; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + if (IsNull(ci_lut) || IsNull(lut_entry)) + { + ACDB_ERR("Error[%d]: Invalid input parameter", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + lut_size = ci_lut->chunk_size - sizeof(uint32_t); + + //Setup Table Information + table_info.table_offset = ci_lut->chunk_offset + sizeof(uint32_t); + table_info.table_size = lut_size; + table_info.table_entry_size = sizeof(SubgraphTagLutEntry); + + //Setup Search Information + search_info.num_search_keys = search_index_count; + search_info.num_structure_elements = + (sizeof(SubgraphTagLutEntry) / sizeof(uint32_t)); + search_info.table_entry_struct = lut_entry; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + //ACDB_DBG("Error[%d]: Failed to find Subgraph ID(0x%x) Tag ID(0x%x)", + // status, lut_entry->sg_id, lut_entry->tag_id); + return status; + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + + return status; +} + +/** +* \brief +* Builds the tagged module list response. The size of the list is +* accumulated on the first call. The data is filled once the +* response buffer is allocated. +* +* \param[in/out] ci_def: chunk information for ACDB_CHUNKID_TAGGED_MODULE_DEF. +* \param[in/out] def_offset_list: list of def offsets definition tables that +* contain 's +* \param[in/out] rsp: the response structure to populate +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t BuildTaggedModulePayload(ChunkInfo *ci_def, AcdbUintList *def_offset_list, AcdbGetTaggedModulesRsp *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_modules = 0; + uint32_t total_num_module_inst = 0; + uint32_t sz_module_instances = 0; + uint32_t expected_size = 0; + uint32_t actual_size = 0; + uint32_t mid_list_offset = 0; + AcdbOp op = IsNull(rsp->tagged_mid_list) ? + ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + if (IsNull(ci_def) || IsNull(def_offset_list) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: Invalid input parameter", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + expected_size = rsp->num_tagged_mids * sizeof(AcdbModuleInstance); + rsp->num_tagged_mids = 0; + + for (uint32_t i = 0; i < def_offset_list->count; i++) + { + offset = ci_def->chunk_offset; + offset += def_offset_list->list[i]; + status = FileManReadBuffer(&num_modules, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to read number of module instances " + "from definition table", status); + return status; + } + + if (num_modules == 0) continue; + + if (op == ACDB_OP_GET_SIZE) + { + total_num_module_inst += num_modules; + } + else + { + total_num_module_inst += num_modules; + sz_module_instances = num_modules * sizeof(AcdbModuleInstance); + actual_size += sz_module_instances; + + if (actual_size > expected_size) + { + ACDB_DBG("Error[%d]: Buffer not large enough to store " + "response. Expected Size: %d bytes. Actual Size: %d bytes", + AR_ENEEDMORE, expected_size, actual_size); + return AR_ENEEDMORE; + } + + status = FileManReadBuffer( + (uint8_t*)rsp->tagged_mid_list + mid_list_offset, + sz_module_instances, &offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to read number of module instances" + " from definition table", status); + return status; + } + + mid_list_offset += sz_module_instances; + } + } + + rsp->num_tagged_mids = total_num_module_inst; + + if (rsp->num_tagged_mids == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: No data found", status); + } + + return status; +} + +int32_t AcdbCmdGetTaggedModules(AcdbGetTaggedModulesReq* req, AcdbGetTaggedModulesRsp* rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + ChunkInfo ci_lut = { 0 }; + ChunkInfo ci_def = { 0 }; + SubgraphTagLutEntry lut_entry = { 0 }; + + uint32_t def_offset_list_length = GLB_BUF_2_LENGTH; + AcdbUintList def_offset_list = { 0 }; + AcdbUintList subgraph_list = { 0 }; + + if (req == NULL || rsp_size < sizeof(AcdbGetTaggedModulesRsp)) + { + ACDB_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->num_sg_ids == 0 || IsNull(req->sg_ids)) + { + ACDB_ERR("Error[%d]: The subgraph list cannot be empty", AR_EBADPARAM); + return AR_EBADPARAM; + } + + subgraph_list.count = req->num_sg_ids; + subgraph_list.list = req->sg_ids; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + ci_lut.chunk_id = ACDB_CHUNKID_TAGGED_MODULE_LUT; + ci_def.chunk_id = ACDB_CHUNKID_TAGGED_MODULE_DEF; + status = ACDB_GET_CHUNK_INFO(&ci_lut, &ci_def); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve Tagged Module " + "lookup/definition tables.", status); + return status; + } + + def_offset_list.list = &glb_buf_2[0]; + + lut_entry.tag_id = req->tag_id; + + for (uint32_t i = 0; i < req->num_sg_ids; i++) + { + lut_entry.sg_id = req->sg_ids[i]; + + status = SearchTaggedModuleMapLut(&ci_lut, &lut_entry); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + //ACDB_DBG("Error[%d]: Subgraph(0x%x) does not contain Tag(0x%x). " + // "Skipping..", status, lut_entry.tag_id, lut_entry.sg_id); + continue; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Error occured while looking for " + "Tag(0x%x) under Subgraph(0x%x)", status, + lut_entry.tag_id, lut_entry.sg_id); + return status; + } + + //Add to def offset list + if (def_offset_list.count > def_offset_list_length) + { + /* This will only occur if there are 1000 subgraphs passed in to + * this API that contain the tag that we are looking for. glb_buf_2 + * can store up to 1000 def offsets */ + ACDB_ERR("Error[%d]: Not enough space to store " + "additional def offset", status); + return AR_ENOMEMORY; + } + + def_offset_list.list[def_offset_list.count] = lut_entry.offset; + def_offset_list.count++; + } + + if (def_offset_list.count == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Tag(0x%x) not found in subgraphs provided.", + status, lut_entry.tag_id); + return status; + } + + //Build Instance ID List + status = BuildTaggedModulePayload(&ci_def, &def_offset_list, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to build tagged module list response.", status); + } + + return status; +} + +/** +* \brief +* Builds the tagged module list response. The size of the list is +* accumulated on the first call. The data is filled once the +* response buffer is allocated. +* +* \param[in/out] ci_def: chunk information for ACDB_CHUNKID_TAGGED_MODULE_DEF. +* \param[in/out] def_offset_list: list of def offsets definition tables that +* contain 's +* \param[in/out] rsp: the response structure to populate +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t BuildProcTaggedModulePayload(ChunkInfo* ci_def, AcdbUintList* subgraph_list, AcdbUintList* def_offset_list, AcdbGetProcTaggedModulesRsp* rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_modules = 0; + uint32_t total_num_module_inst = 0; + uint32_t expected_size = 0; + uint32_t actual_size = 0; + uint32_t blob_offset = 0; + /* Stores processor domain id and blob offset pairs.The offset is for + * a AcdbProcTaggedModules entry within the + * AcdbGetProcTaggedModulesRsp::proc_tagged_module_list */ + AcdbGenericList proc_domain_id_list = { 0 }; + AcdbProcDomainOffsetPair proc_domain_offset_pair = { 0 }; + AcdbSubgraphPdmMap sg_iid_map = { 0 }; + AcdbBlob proc_tagged_modules_blob = { 0 }; + AcdbOp op = IsNull(rsp->proc_tagged_module_list) ? + ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + if (IsNull(ci_def) || IsNull(def_offset_list) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: Invalid input parameter", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (op == ACDB_OP_GET_DATA && rsp->list_size == 0) + { + ACDB_DBG("Error[%d]: Unable to fill response since " + "AcdbGetProcTaggedModulesRsp::list_size is zero", + AR_EBADPARAM); + return AR_EFAILED; + } + + /* Use glb_buf_3 to store list of unique processors found while iterating + * through subgraphs and procs. + * GLB_BUFFER_3 can hold up to GLB_BUF_3_LENGTH entries. We will never + * have 500 procs, but we need to add the length check. */ + status = AcdbGenericListInit(&proc_domain_id_list, sizeof(AcdbProcDomainOffsetPair), + GLB_BUF_3_LENGTH * sizeof(uint32_t), (void**)&glb_buf_3); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to initialize list", status); + return status; + } + + proc_tagged_modules_blob.buf = (uint8_t*)rsp->proc_tagged_module_list; + proc_tagged_modules_blob.buf_size = 0; + + expected_size = rsp->list_size; + + for (uint32_t i = 0; i < def_offset_list->count; i++) + { + ar_mem_set((void*)&sg_iid_map, 0, sizeof(AcdbSubgraphPdmMap)); + + status = DataProcGetSubgraphProcIidMap(subgraph_list->list[i], &sg_iid_map); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Failed to get subgraph-to-proccessor domain module map", status); + return status; + } + + offset = ci_def->chunk_offset; + offset += def_offset_list->list[i]; + status = FileManReadBuffer(&num_modules, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to read number of module instances " + "from definition table", status); + return status; + } + + if (num_modules == 0) continue; + + //get tagged module list + AcdbModuleInstance* tagged_modules = NULL; + status = FileManGetFilePointer2((void**)&tagged_modules, offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to read number of module instances " + "from definition table", status); + return status; + } + + for (uint32_t k = 0; k < num_modules; k++) + { + uint32_t proc_domain_id = 0; + status = DataProcGetProcDomainForModule( + &sg_iid_map, + tagged_modules[k].mid_iid, + &proc_domain_id); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get proccessor domain ID for " + "sg: 0x%x iid: 0x%x", + status, sg_iid_map.subgraph_id, tagged_modules[k].mid_iid); + return status; + } + + /* We only need to keep track of the total number of procs during the + * get_size call b/c the rsp should be populated with the total number + * of procs in the get_data call */ + //Add unique proc_domain_id entries to list + bool_t is_new_proc = TRUE; + AcdbGenericListItem found_proc_domain = { 0 }; + proc_domain_offset_pair.proc_domain_id = proc_domain_id; + + status = proc_domain_id_list.find( + &proc_domain_id_list, &proc_domain_offset_pair, + sizeof(proc_domain_offset_pair), 1, &found_proc_domain); + if (AR_SUCCEEDED(status)) + { + is_new_proc = FALSE; + + if (!IsNull(found_proc_domain.item)) + { + proc_domain_offset_pair = *(AcdbProcDomainOffsetPair*)found_proc_domain.item; + } + else + { + ACDB_ERR("Error[%d]: Unable to get proc offset pair from " + "item field after find operation", status); + return AR_EFAILED; + } + } + + if (is_new_proc && proc_domain_id_list.count < proc_domain_id_list.max_count) + { + blob_offset = proc_tagged_modules_blob.buf_size; + proc_domain_offset_pair.offset = blob_offset; + proc_domain_id_list.add_range(&proc_domain_id_list, + &proc_domain_offset_pair, sizeof(AcdbProcDomainOffsetPair), 1); + status = AR_EOK; + + if (proc_domain_id_list.count > 1) + { + proc_domain_id_list.sort(&proc_domain_id_list, 0); + } + } + if (op == ACDB_OP_GET_DATA) + { + /* Implement memory shifting logic. We dont want to create additional memory. + * Add the first processor domain id and the modules associated with it + * If a new processor domain is discovered add it right after the first processor domains info + * If we encounter a module that has the proc domain of the first proc entry make room in the + * memory regoin by shifting the subsequent proc info downward using memmove + */ + AcdbProcTaggedModules* proc_taggged_module = NULL; + + /* Add new proc to the end of the proc list */ + if (is_new_proc) + { + actual_size = proc_tagged_modules_blob.buf_size + + sizeof(AcdbProcTaggedModules) + num_modules * sizeof(AcdbModuleInstance); + + if (actual_size > expected_size) + { + ACDB_DBG("Error[%d]: Buffer not large enough to store " + "response. Expected Size: %d bytes. Actual Size: %d bytes", + AR_ENEEDMORE, expected_size, actual_size); + return AR_ENEEDMORE; + } + + uint32_t module_count = 1; + + ACDB_MEM_CPY_SAFE( + proc_tagged_modules_blob.buf + blob_offset, sizeof(uint32_t), + &proc_domain_id, sizeof(uint32_t)); + blob_offset += sizeof(uint32_t); + ACDB_MEM_CPY_SAFE( + proc_tagged_modules_blob.buf + blob_offset, sizeof(uint32_t), + &module_count, sizeof(uint32_t)); + blob_offset += sizeof(uint32_t); + ACDB_MEM_CPY_SAFE( + proc_tagged_modules_blob.buf + blob_offset, sizeof(AcdbModuleInstance), + &tagged_modules[k], sizeof(AcdbModuleInstance)); + blob_offset += sizeof(AcdbModuleInstance); + + proc_tagged_modules_blob.buf_size += sizeof(AcdbProcTaggedModules) + + module_count * sizeof(AcdbModuleInstance); + continue; + } + + /* Add new module entry to an existing procs module + * list and shift the memory of subsequent procs */ + proc_taggged_module = (AcdbProcTaggedModules*)( + (uint8_t*)rsp->proc_tagged_module_list + proc_domain_offset_pair.offset); + + if (proc_taggged_module != NULL) + { + //Proc already exists, but we are adding a new module entry + uint32_t blob_module_entry_offset = proc_domain_offset_pair.offset + + sizeof(AcdbProcTaggedModules) + + proc_taggged_module->num_tagged_mids * sizeof(AcdbModuleInstance); + proc_taggged_module->num_tagged_mids++; + + size_t size_of_data_to_move = (size_t)proc_tagged_modules_blob.buf_size + - (size_t)blob_module_entry_offset; + + actual_size = proc_tagged_modules_blob.buf_size + sizeof(AcdbModuleInstance); + if (actual_size > expected_size) + { + ACDB_DBG("Error[%d]: Buffer not large enough to store " + "response. Expected Size: %d bytes. Actual Size: %d bytes", + AR_ENEEDMORE, expected_size, actual_size); + return AR_ENEEDMORE; + } + + if (0 != size_of_data_to_move) + { + ar_mem_move( + (uint8_t*)proc_tagged_modules_blob.buf + + blob_module_entry_offset + sizeof(AcdbModuleInstance), size_of_data_to_move, + (uint8_t*)proc_tagged_modules_blob.buf + + blob_module_entry_offset, size_of_data_to_move); + } + + ACDB_MEM_CPY_SAFE( + proc_tagged_modules_blob.buf + blob_module_entry_offset, sizeof(AcdbModuleInstance), + &tagged_modules[k], sizeof(AcdbModuleInstance)); + proc_tagged_modules_blob.buf_size += sizeof(AcdbModuleInstance); + + /* We need to update the offsets of our proc domain entries after shifting data */ + for (uint32_t j = 0; j < proc_domain_id_list.count; j++) + { + AcdbProcDomainOffsetPair* p = (AcdbProcDomainOffsetPair*)proc_domain_id_list.list + j; + if (p->proc_domain_id == proc_domain_offset_pair.proc_domain_id) + continue; + + if (p->offset > proc_domain_offset_pair.offset) + { + p->offset += sizeof(AcdbModuleInstance); + } + } + } + } + } + + if (op == ACDB_OP_GET_SIZE) + { + total_num_module_inst += num_modules; + } + } + + if (op == ACDB_OP_GET_SIZE) + { + rsp->num_procs = proc_domain_id_list.count; + rsp->list_size = rsp->num_procs * sizeof(AcdbProcTaggedModules) + + total_num_module_inst * sizeof(AcdbModuleInstance); + } + + if (rsp->num_procs == 0 || rsp->list_size == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: No tagged modules found", status); + } + + return status; +} + +int32_t AcdbCmdGetProcTaggedModules(AcdbGetProcTaggedModulesReq* req, AcdbGetProcTaggedModulesRsp* rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + ChunkInfo ci_lut = { 0 }; + ChunkInfo ci_def = { 0 }; + SubgraphTagLutEntry lut_entry = { 0 }; + uint32_t sg_def_offset_list_length = GLB_BUF_2_LENGTH/2; + AcdbUintList def_offset_list = { 0 }; + AcdbUintList subgraph_list = { 0 }; + + if (req == NULL || rsp_size < sizeof(AcdbGetProcTaggedModulesRsp)) + { + ACDB_ERR("Error[%d]: Invalid input parameter(s)", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->num_sg_ids == 0 || IsNull(req->sg_ids)) + { + ACDB_ERR("Error[%d]: The subgraph list cannot be empty", AR_EBADPARAM); + return AR_EBADPARAM; + } + + /* Use subgraph list here for setting the database context */ + subgraph_list.count = req->num_sg_ids; + subgraph_list.list = req->sg_ids; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + ci_lut.chunk_id = ACDB_CHUNKID_TAGGED_MODULE_LUT; + ci_def.chunk_id = ACDB_CHUNKID_TAGGED_MODULE_DEF; + status = ACDB_GET_CHUNK_INFO(&ci_lut, &ci_def); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve Tagged Module " + "lookup/definition tables.", status); + return status; + } + + /* Repurpose the subgraph list here for storing subgraphs containing the + * tag we are searching for. def_offset_list and subgraph_list have + * matching indexes. For example: + * + * subgraph_list.list[i] is associated with def_offset_list.list[i] + */ + def_offset_list.list = &glb_buf_2[0]; + subgraph_list.list = &glb_buf_2[sg_def_offset_list_length - 1]; + subgraph_list.count = 0; + + lut_entry.tag_id = req->tag_id; + + for (uint32_t i = 0; i < req->num_sg_ids; i++) + { + lut_entry.sg_id = req->sg_ids[i]; + + status = SearchTaggedModuleMapLut(&ci_lut, &lut_entry); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + //ACDB_DBG("Error[%d]: Subgraph(0x%x) does not contain Tag(0x%x). " + // "Skipping..", status, lut_entry.tag_id, lut_entry.sg_id); + continue; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Error occured while looking for " + "Tag(0x%x) under Subgraph(0x%x)", status, + lut_entry.tag_id, lut_entry.sg_id); + return status; + } + + //Add to def offset list + if (def_offset_list.count > sg_def_offset_list_length || + subgraph_list.count > sg_def_offset_list_length) + { + /* This will only occur if there are 500 subgraphs passed in to + * this API that contain the tag that we are looking for. glb_buf_2 + * can store up to 1000 entries: 500 sg ids, 500 def offsets */ + ACDB_ERR("Error[%d]: Not enough space to store " + "additional def offset", status); + return AR_ENOMEMORY; + } + + def_offset_list.list[def_offset_list.count] = lut_entry.offset; + subgraph_list.list[subgraph_list.count] = lut_entry.sg_id; + def_offset_list.count++; + subgraph_list.count++; + } + + if (def_offset_list.count == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Tag(0x%x) not found in subgraphs provided.", + status, lut_entry.tag_id); + return status; + } + + //Build Instance ID List + status = BuildProcTaggedModulePayload(&ci_def, &subgraph_list, &def_offset_list, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to build tagged module list response.", status); + } + + return status; +} + +/** +* \brief +* Search for a +* tuple using the Module ID and Key Table Offset as search keys +* +* \param[in/out] cal_lut_entry: GSL Calibration Lookuptable entry in the +* format of +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t DriverDataSearchForModuleID(acdb_driver_cal_lut_entry_t *cal_lut_entry) +{ + int32_t status = AR_EOK; + //uint32_t offset = 0; + ChunkInfo gsl_cal_lut = { 0 }; + + //Lookup Table + //Binary Search based on MID and Key Table Offset + uint32_t search_index_count = 2; + uint32_t sz_gsl_cal_lut = 0; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + gsl_cal_lut.chunk_id = ACDB_CHUNKID_GSL_CAL_LUT; + status = ACDB_GET_CHUNK_INFO(&gsl_cal_lut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get GSL Calibration Data Chunk", status); + return status; + } + + sz_gsl_cal_lut = gsl_cal_lut.chunk_size - sizeof(uint32_t); + + //Setup Table Information + table_info.table_offset = gsl_cal_lut.chunk_offset + sizeof(uint32_t); + table_info.table_size = sz_gsl_cal_lut; + table_info.table_entry_size = sizeof(acdb_driver_cal_lut_entry_t); + + //Setup Search Information + search_info.num_search_keys = search_index_count; + search_info.num_structure_elements = + (sizeof(acdb_driver_cal_lut_entry_t) / sizeof(uint32_t)); + search_info.table_entry_struct = cal_lut_entry; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Failed to find Module ID(0x%x)", cal_lut_entry->mid); + return status; + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + + return status; +} + +int32_t DriverDataSearchForKeys( + AcdbDriverData *req, uint32_t *offset_calkey_table) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_keys = 0; + ChunkInfo gsl_cal_key_tbl = { 0 }; + + gsl_cal_key_tbl.chunk_id = ACDB_CHUNKID_GSL_CALKEY_TBL; + status = ACDB_GET_CHUNK_INFO(&gsl_cal_key_tbl); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get GSL Key Table Chunk", status); + return status; + } + + offset = gsl_cal_key_tbl.chunk_offset; + + do + { + *offset_calkey_table = offset; + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of keys", status); + return status; + } + + if (num_keys != req->key_vector.num_keys) + { + offset += num_keys * sizeof(uint32_t); + continue; + } + + if (num_keys > 0) + { + status = FileManReadBuffer( + &glb_buf_1, num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key vector", status); + return status; + } + + if (TRUE == CompareKeyVectorIds( + req->key_vector, glb_buf_3, glb_buf_1, num_keys)) + { + *offset_calkey_table -= gsl_cal_key_tbl.chunk_offset; + return status; + } + } + else + { + *offset_calkey_table -= gsl_cal_key_tbl.chunk_offset; + return status; + } + + } while (offset < + gsl_cal_key_tbl.chunk_offset + gsl_cal_key_tbl.chunk_size); + + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Unable to find matching key vector. " + "One or more key IDs do not exist.", status); + + ACDB_CLEAR_BUFFER(glb_buf_1); + ACDB_CLEAR_BUFFER(glb_buf_3); + + return status; +} + +int32_t DriverDataSearchCalDataLUT(AcdbDriverData *req, AcdbBlob* rsp, + uint32_t offset_caldata_table, AcdbDefDotPair *offset_pair) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_struct_elements = 0; + uint32_t entry_size = 0; + uint32_t table_size = 0; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + KeyTableHeader caldata_lut_header = { 0 }; + ChunkInfo gsl_cal_data_tbl = { 0 }; + + if (IsNull(req) || IsNull(rsp) || IsNull(offset_pair)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + gsl_cal_data_tbl.chunk_id = ACDB_CHUNKID_GSL_CALDATA_TBL; + status = ACDB_GET_CHUNK_INFO(&gsl_cal_data_tbl); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get GSL " + "Calibration Data Chunk", status); + return status; + } + + offset = gsl_cal_data_tbl.chunk_offset + offset_caldata_table; + status = FileManReadBuffer( + &caldata_lut_header, sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to seek/read GSL " + "Calibration Data LUT header", status); + return status; + } + + //Plus 2 for def and dot offsets + num_struct_elements = caldata_lut_header.num_keys + 2; + entry_size = sizeof(uint32_t) * num_struct_elements; + table_size = caldata_lut_header.num_entries * entry_size; + + //glb_buf_3 stores key vector values to search for + for (uint32_t i = 0; i < req->key_vector.num_keys; i++) + { + glb_buf_3[i] = req->key_vector.graph_key_vector[i].value; + } + + //Setup Table Information + table_info.table_offset = offset; + table_info.table_size = table_size; + table_info.table_entry_size = entry_size; + + //Setup Search Information + search_info.num_search_keys = caldata_lut_header.num_keys; + search_info.num_structure_elements = num_struct_elements; + search_info.table_entry_struct = &glb_buf_3; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to find matching key vector. " + "One or more key values do not match", status); + return status; + } + + ACDB_MEM_CPY_SAFE(offset_pair, sizeof(AcdbDefDotPair), + &glb_buf_3[0] + (caldata_lut_header.num_keys) * sizeof(uint32_t), + sizeof(AcdbDefDotPair)); + + ACDB_CLEAR_BUFFER(glb_buf_1); + ACDB_CLEAR_BUFFER(glb_buf_3); + return status; +} + +int32_t DriverDataGetCalibration(AcdbDriverData *req, AcdbBlob* rsp, AcdbDefDotPair *offset_pair) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_pids = 0; + uint32_t num_caldata_offsets = 0; + uint32_t param_size = 0; + uint32_t *pid_list = NULL; + uint32_t *caldata_offset_list = NULL; + uint32_t param_offset = 0; + uint32_t pid = 0; + ChunkInfo ci_def = { 0 }; + ChunkInfo ci_dot = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + + if (IsNull(req) || IsNull(rsp) || IsNull(offset_pair)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_def.chunk_id = ACDB_CHUNKID_GSL_DEF; + ci_dot.chunk_id = ACDB_CHUNKID_GSL_DOT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_def, &ci_dot, &ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get chunk info for either " + "DEF, DOT, or Data Pool", status); + return status; + } + + //Def + offset = ci_def.chunk_offset + offset_pair->offset_def; + status = FileManReadBuffer(&num_pids, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of Parameter IDs", status); + return status; + } + + status = FileManReadBuffer(&glb_buf_2, sizeof(uint32_t)* num_pids, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Parameter List", status); + return status; + } + + //Dot + offset = ci_dot.chunk_offset + offset_pair->offset_dot; + status = FileManReadBuffer(&num_caldata_offsets, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of parameter calibration offset", status); + return status; + } + + status = FileManReadBuffer(&glb_buf_3, sizeof(uint32_t)* num_caldata_offsets, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read parameter calibration offset list", status); + return status; + } + + if (num_pids != num_caldata_offsets) + { + ACDB_ERR("Number of parameter IDs in DEF to not match number off offsets in DOT"); + return AR_EFAILED; + } + + //glb_buf_2 stores pid list + //glb_buf_3 stores dot data pool offsets + pid_list = &glb_buf_2[0]; + caldata_offset_list = &glb_buf_3[0]; + + if (rsp->buf != NULL) + { + if (rsp->buf_size >= sizeof(uint32_t)) + { + ACDB_MEM_CPY_SAFE(rsp->buf, sizeof(uint32_t), &req->module_id, sizeof(uint32_t)); + } + else + { + return AR_ENEEDMORE; + } + param_offset += sizeof(uint32_t); + } + else + { + rsp->buf_size += sizeof(req->module_id); + } + + for (uint32_t i = 0; i < num_pids; i++) + { + pid = pid_list[i]; + offset = ci_data_pool.chunk_offset + caldata_offset_list[i]; + + status = FileManReadBuffer(¶m_size, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read parameter size", status); + return status; + } + + if (rsp->buf != NULL) + { + if (rsp->buf_size >= (param_offset + (2 * sizeof(uint32_t)))) + { + ACDB_MEM_CPY_SAFE(rsp->buf + param_offset, sizeof(uint32_t), + &pid, sizeof(uint32_t)); + param_offset += sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE(rsp->buf + param_offset, sizeof(uint32_t), + ¶m_size, sizeof(uint32_t)); + param_offset += sizeof(uint32_t); + } + else + { + return AR_ENEEDMORE; + } + + if (param_size != 0) + { + if ((rsp->buf_size - param_offset) >= param_size) + { + status = FileManReadBuffer( + (uint8_t*)rsp->buf + param_offset, + param_size, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read " + "parameter payload", status); + return status; + } + } + else + { + return AR_ENEEDMORE; + } + + param_offset += param_size; + } + } + else + { + // + rsp->buf_size += 2 * sizeof(uint32_t) + param_size; + } + } + + pid_list = NULL; + caldata_offset_list = NULL; + ACDB_CLEAR_BUFFER(glb_buf_1); + ACDB_CLEAR_BUFFER(glb_buf_2); + ACDB_CLEAR_BUFFER(glb_buf_3); + + return status; +} + +int32_t AcdbCmdGetDriverData(AcdbDriverData *req, AcdbBlob* rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + uint32_t cal_lut_entry_offset = 0; + acdb_driver_cal_lut_entry_t cal_lut_entry = { 0 }; + AcdbDefDotPair offset_pair = { 0 }; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input " + "parameters are null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (rsp_size < sizeof(AcdbBlob)) + { + ACDB_ERR("Error[%d]: The response structure size is smaller" + "than the size of AcdbBlob ", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->key_vector.num_keys > 0) + { + status = AcdbSort2( + req->key_vector.num_keys * sizeof(AcdbKeyValuePair), + req->key_vector.graph_key_vector, + sizeof(AcdbKeyValuePair), 0); + + if (AR_FAILED(status)) + { + return status; + } + } + + /* The modules in the ACDB_CHUNKID_GSL_CAL_LUT can be associated with + * more than one key vector. So performing a binary search on just the + * module ID will not necessarily yield the correct result. In the + * example below item 1 and 2 are possible candidates. + * + * Ex + * + * List of GSL LUT Entries: + * [0x801 KT1 LUT1 | 0x801 KT2 LUT2 | 0x802 KT3 LUT4 | ...] + * [ 0x801 x x ] <== search key, x = dont care + * To alleviate this we calculate the Key Table offset and use it in + * the binary search so that the search key is unique. + */ + cal_lut_entry.mid = req->module_id; + cal_lut_entry.offset_caldata_table = 0; + cal_lut_entry.offset_calkey_table = 0; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_DRIVER_MODULE, + &cal_lut_entry, sizeof(cal_lut_entry), + &cal_lut_entry_offset, sizeof(uint32_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set database context " + "using driver module(0x%x)", status, req->module_id); + return status; + } + + /* A module will only have one entry in the Key Table and Lookup + * Table if the key count is 0 + */ + //if (req->key_vector.num_keys > 0) + //{ + status = DriverDataSearchForKeys(req, + &cal_lut_entry.offset_calkey_table); + if (AR_FAILED(status)) return status; + //} + + status = DriverDataSearchForModuleID(&cal_lut_entry); + if (AR_FAILED(status)) return status; + + status = DriverDataSearchCalDataLUT(req, rsp, + cal_lut_entry.offset_caldata_table, &offset_pair); + if (AR_FAILED(status)) return status; + + + status = DriverDataGetCalibration(req, rsp, &offset_pair); + if (AR_FAILED(status)) return status; + + return status; +} + +int32_t BuildGetGraphResponse(AcdbGetGraphRsp *rsp, uint32_t sg_list_offset) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t expected_size = rsp->size; + ChunkInfo ci_data_pool = { 0 }; + SgListHeader sg_list_header = { 0 }; + + if (IsNull(rsp)) + { + ACDB_ERR("Error[%d]: The rsp input parameter is null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve Data Pool chunk info.", + status); + return status; + } + + offset = ci_data_pool.chunk_offset + sg_list_offset; + status = FileManReadBuffer(&sg_list_header, sizeof(SgListHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read the subgraph list header", status); + return status; + } + + rsp->num_subgraphs = sg_list_header.num_subgraphs; + rsp->size = sg_list_header.size - sizeof(sg_list_header.num_subgraphs); + + if (IsNull(rsp->subgraphs)) + { + return AR_EOK; + } + + if (expected_size >= rsp->size) + { + status = FileManReadBuffer(rsp->subgraphs, rsp->size, &offset); + } + else + { + return AR_ENEEDMORE; + } + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read the subgraph list", status); + return status; + } + + return status; +} + +/** +* \brief +* Retrieves the subgraphs list either as: +* 1. a unique set of subgraph ids (subgraph_list) or +* 2. the graph topology with source and destination subgraphs specified (graph) +* +* \depends The input gkv must be sorted +* +* \param[in] sg_list_offset: The relative offset of the subgraph list in the datapool +* \param[in/out] subgraph_list: A unique list of subgraph IDs where the list +* buffer is provided by the caller. +* *NOTE*: This can be NULL to ignore filling the parameter. +* \param[in/out] graph: The graph topology describing the relationship between +* subgraphs. The AcdbGetGraphRsp.subgraphs is returned by +* this function. It points to a location in the acdb file +* memory. This should not be modified subgraph list should +* not be modified. +* *NOTE*: This can be NULL to ignore filling the parameter. +* +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbGetSubgraphList(uint32_t sg_list_offset, + AcdbUintList *subgraph_list, AcdbGetGraphRsp *graph) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t subgraph_list_size = 0; + uint32_t subgraph_offset = 0; + ChunkInfo ci_data_pool = { 0 }; + SgListHeader sg_list_header = { 0 }; + AcdbSubgraph *subgraphs = NULL; + + + if (IsNull(subgraph_list) && IsNull(graph)) + { + ACDB_ERR("Error[%d]: One of the subgraph list parameters needs to be provided.", + status); + return AR_EBADPARAM; + } + + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve Data Pool chunk info.", + status); + return status; + } + + offset = ci_data_pool.chunk_offset + sg_list_offset; + status = FileManReadBuffer(&sg_list_header, sizeof(SgListHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read the subgraph list header", status); + return status; + } + + subgraph_list_size = sg_list_header.size - sizeof(sg_list_header.num_subgraphs); + status = FileManGetFilePointer2((void **)&subgraphs, offset); + + + if (!IsNull(subgraph_list)) + { + subgraph_list->count = sg_list_header.num_subgraphs; + + if (!IsNull(subgraph_list->list)) + { + for (uint32_t i = 0; i < sg_list_header.num_subgraphs; i++) + { + AcdbSubgraph* subgraph = (AcdbSubgraph*) + ((uint8_t*)subgraphs + subgraph_offset); + subgraph_list->list[i] = subgraph->sg_id; + subgraph_offset += sizeof(AcdbSubgraph) + + subgraph->num_dst_sgids * sizeof(uint32_t); + } + } + else + { + ACDB_ERR("Error[%d]: The subgraph list cannot be null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + } + + if (!IsNull(graph)) + { + graph->num_subgraphs = sg_list_header.num_subgraphs; + graph->size = subgraph_list_size; + graph->subgraphs = subgraphs; + } + + subgraphs = NULL; + return status; +} + +int32_t AcdbGetUsecaseSubgraphList(AcdbGraphKeyVector* gkv, + AcdbUintList* subgraph_list, AcdbGetGraphRsp* graph) +{ + int32_t status = AR_EOK; + AcdbGraphKeyVector graph_kv = { 0 }; + acdb_graph_info_t graph_info = { 0 }; + + if (IsNull(gkv)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null:" + " GKV or Response", status); + return AR_EBADPARAM; + } + + if (gkv->num_keys == 0) + { + ACDB_DBG("Error[%d]: Detected empty usecase. " + "No data will be returned. Skipping..", AR_EOK); + return AR_EOK; + } + + //GLB BUF 1 is used for the GKV search + //GLB BUF 2 is used for storing the found GKV entry + //GLB BUF 3 is used to store the sorted GKV + + graph_kv.num_keys = gkv->num_keys; + graph_kv.graph_key_vector = (AcdbKeyValuePair*)&glb_buf_3[0]; + ACDB_MEM_CPY_SAFE(&glb_buf_3[0], gkv->num_keys * sizeof(AcdbKeyValuePair), + gkv->graph_key_vector, gkv->num_keys * sizeof(AcdbKeyValuePair)); + + //Sort Key Vector by Key IDs(position 0 of AcdbKeyValuePair) + status = AcdbSort2(gkv->num_keys * sizeof(AcdbKeyValuePair), + graph_kv.graph_key_vector, sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort graph key vector.", status); + return status; + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_GKV, + &graph_kv, sizeof(AcdbGraphKeyVector), + &graph_info, sizeof(acdb_graph_info_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to find the graph key vector", status); + return status; + } + + status = AcdbGetSubgraphList(graph_info.sg_list_offset, subgraph_list, graph); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get subgraph list", status); + } + + return status; +} + +int32_t AcdbCmdGetGraph(AcdbGraphKeyVector *gkv, AcdbGetGraphRsp *rsp, + uint32_t rsp_struct_size) +{ + int32_t status = AR_EOK; + AcdbGraphKeyVector graph_kv = { 0 }; + acdb_graph_info_t graph_info = { 0 }; + + if (IsNull(gkv) || IsNull(rsp) || IsNull(gkv->graph_key_vector)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null:" + " GKV or Response", status); + return AR_EBADPARAM; + } + + if (rsp_struct_size < sizeof(AcdbGetGraphRsp)) + { + ACDB_ERR("Error[%d]: The size of the response structure is less " + "than %d bytes", status, sizeof(AcdbGetGraphRsp)); + return AR_EBADPARAM; + } + + if (IsNull(rsp->subgraphs)) + { + //Log GKV when this API is called for the first time + ACDB_DBG("Retrieving subgraph list for the following graph key vector:"); + LogKeyVector(gkv, GRAPH_KEY_VECTOR); + } + + if (gkv->num_keys == 0) + { + ACDB_DBG("Error[%d]: Detected empty usecase. " + "No data will be returned. Skipping..", AR_EOK); + return AR_EOK; + } + //GLB BUF 1 is used for the GKV search + //GLB BUF 2 is used for storing the found GKV entry + //GLB BUF 3 is used to store the sorted GKV + + graph_kv.num_keys = gkv->num_keys; + graph_kv.graph_key_vector = (AcdbKeyValuePair*)&glb_buf_3[0]; + ACDB_MEM_CPY_SAFE(&glb_buf_3[0], gkv->num_keys * sizeof(AcdbKeyValuePair), + gkv->graph_key_vector, gkv->num_keys * sizeof(AcdbKeyValuePair)); + + //Sort Key Vector by Key IDs(position 0 of AcdbKeyValuePair) + status = AcdbSort2(gkv->num_keys * sizeof(AcdbKeyValuePair), + graph_kv.graph_key_vector, sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort graph key vector.", status); + return status; + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_GKV, + &graph_kv, sizeof(AcdbGraphKeyVector), + &graph_info, sizeof(acdb_graph_info_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to find the graph key vector", status); + return status; + } + + status = BuildGetGraphResponse(rsp, graph_info.sg_list_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to build response", status); + } + + return status; +} + +int32_t AcdbCmdGetGraphAlias(AcdbGraphKeyVector* gkv, AcdbString* rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_key_tables = 0; + uint32_t key_table_size = 0; + uint32_t key_table_entry_size = 0; + uint32_t gkv_alias_data_offset = 0; + uint32_t expected_size = 0; + uint32_t string_length = 0; + bool_t found = FALSE; + ChunkInfo ci_gkv_alias_table = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + KeyTableHeader key_table_header = { 0 }; + AcdbOp op = ACDB_OP_NONE; + AcdbGraphKeyVector graph_kv = { 0 }; + acdb_graph_info_t graph_info = { 0 }; + + if (IsNull(gkv) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null:" + " GKV or Response", status); + return AR_EBADPARAM; + } + + if (gkv->num_keys == 0) + { + ACDB_DBG("Error[%d]: Detected empty graph key vector. " + "No data will be returned. Skipping..", AR_EOK); + return AR_EOK; + } + + if (IsNull(rsp->string)) + op = ACDB_OP_GET_SIZE; + else + { + expected_size = rsp->length; + op = ACDB_OP_GET_DATA; + } + + if (gkv->num_keys > ACDB_MAX_KEY_COUNT - 1) + return AR_ENOMEMORY; + + //GLB BUF 3 is used to store the sorted GKV and the found GKV entry + graph_kv.num_keys = gkv->num_keys; + graph_kv.graph_key_vector = (AcdbKeyValuePair*)&glb_buf_3[0]; + ACDB_MEM_CPY_SAFE(&glb_buf_3[0], gkv->num_keys * sizeof(AcdbKeyValuePair), + gkv->graph_key_vector, gkv->num_keys * sizeof(AcdbKeyValuePair)); + + //Sort Key Vector by Key IDs (position 0 of AcdbKeyValuePair) + status = AcdbSort2(gkv->num_keys * sizeof(AcdbKeyValuePair), + graph_kv.graph_key_vector, sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort graph key vector.", status); + return status; + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_GKV, + &graph_kv, sizeof(AcdbGraphKeyVector), + &graph_info, sizeof(acdb_graph_info_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to find the graph key vector", status); + return status; + } + + ci_gkv_alias_table.chunk_id = ACDB_CHUNKID_GKV_ALIAS; + status = ACDB_GET_CHUNK_INFO(&ci_gkv_alias_table); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Graph Alias chunk data does not exist. Is it enabled?.", + status); + return status; + } + + offset = ci_gkv_alias_table.chunk_offset; + status = FileManReadBuffer(&num_key_tables, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of GKV Key ID tables.", + status); + return status; + } + + for (uint32_t i = 0; i < num_key_tables; i++) + { + status = FileManReadBuffer(&key_table_header, + sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key table header.", + status); + return status; + } + + key_table_entry_size = key_table_header.num_keys + * sizeof(AcdbKeyValuePair) + + sizeof(uint32_t); + key_table_size = key_table_header.num_entries + * key_table_entry_size; + + if (key_table_header.num_keys != graph_kv.num_keys) + { + offset += key_table_size; + continue; + } + + found = TRUE; + break; + } + + if (!found) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Graph alias not found for" + " given graph key vector.", status); + return status; + } + + //Setup Table Information + table_info.table_offset = offset; + table_info.table_size = key_table_size; + table_info.table_entry_size = key_table_entry_size; + + //Setup Search Information + search_info.num_search_keys = key_table_header.num_keys * 2; + search_info.num_structure_elements = + key_table_header.num_keys * 2 + 1;//key_ids + gkv alias Offset + search_info.table_entry_struct = &glb_buf_3; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to find graph key vector. " + "No matching key value pairs were found", status); + return status; + } + + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get datapool chunk.", + status); + return status; + } + + gkv_alias_data_offset = glb_buf_3[graph_kv.num_keys * 2]; + offset = ci_data_pool.chunk_offset + gkv_alias_data_offset; + + status = FileManReadBuffer(&string_length, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read graph alias string length.", + status); + return status; + } + + rsp->length = string_length; + + if (0 == string_length) + { + ACDB_ERR("Error[%d]: The graph alias is empty for the provided " + "graph key vector. Check if an alias has been assigned.", + AR_ENOTEXIST); + return status; + } + + if (op == ACDB_OP_GET_DATA) + { + if (expected_size < string_length) + return AR_ENOMEMORY; + + offset += sizeof(uint32_t); + status = FileManReadBuffer(rsp->string, string_length, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read usecase alias string.", + status); + return status; + } + } + + return status; +} + +int32_t BuildSpfPropertyBlob(uint32_t prop_index, size_t spf_blob_offset, + uint32_t *prop_data_offset, + AcdbGetSubgraphDataRsp *pOutput) +{ + /* + Order of Spf Property Data Blob: + ------------------------------------ + Property Index | Spf Property + ------------------------------------ + 0 | Subgraph Config + + 1 | Container Config + + 2 | Module List + + 3 | Module Properties + + 4 | Module Connections + + 5 | Data Links + */ + + int32_t status = AR_EOK; + uint32_t errcode = 0; + + /* Subgraph Spf Property Data Header: + * (does not include error code)*/ + uint32_t sz_sg_spf_prop_header = 3 * sizeof(uint32_t); + uint32_t sz_spf_param = 0; + uint32_t sz_padded_spf_param = 0; + uint32_t padding = 0; + uint32_t idx = 0;//GLB BUF index + + if (pOutput->spf_blob.buf != NULL) + { + //Copy Header + if (pOutput->spf_blob.buf_size < (spf_blob_offset + *prop_data_offset + + (prop_index * sizeof(errcode)) + sz_sg_spf_prop_header)) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(pOutput->spf_blob.buf + spf_blob_offset + *prop_data_offset + + (prop_index * sizeof(errcode)), sz_sg_spf_prop_header, + &glb_buf_1 + *prop_data_offset, sz_sg_spf_prop_header); + + *prop_data_offset += sz_sg_spf_prop_header - sizeof(sz_spf_param); + + //Copy Payload Size + idx = (*prop_data_offset) / sizeof(uint32_t); + sz_spf_param = glb_buf_1[idx]; + + *prop_data_offset += sizeof(sz_spf_param); + + //Add paddig if necessary before sending the response back + if ((sz_spf_param % 8) != 0) + { + sz_padded_spf_param = sz_spf_param + (8 - ((sz_spf_param % 8))); + + padding = (8 - ((sz_spf_param % 8))); + } + else + { + sz_padded_spf_param = sz_spf_param; + } + + //Insert Error Code + if (pOutput->spf_blob.buf_size < (spf_blob_offset + *prop_data_offset + + (prop_index * sizeof(errcode)) + sizeof(errcode))) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(pOutput->spf_blob.buf + spf_blob_offset + *prop_data_offset + + (prop_index * sizeof(errcode)), sizeof(errcode), + &errcode, sizeof(errcode)); + + spf_blob_offset += sizeof(errcode); + + //Copy Payload + idx = (*prop_data_offset) / sizeof(uint32_t); + if (pOutput->spf_blob.buf_size < (spf_blob_offset + *prop_data_offset + + (prop_index * sizeof(errcode)) + sz_spf_param)) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(pOutput->spf_blob.buf + spf_blob_offset + *prop_data_offset + + (prop_index * sizeof(errcode)), sz_spf_param, + &glb_buf_1[idx], sz_spf_param); + + *prop_data_offset += sz_spf_param; + + //Add Padding + if ((sz_spf_param % 8) != 0) + { + memset((uint8_t*)pOutput->spf_blob.buf + spf_blob_offset + *prop_data_offset + (prop_index * sizeof(errcode)), 0, padding); + *prop_data_offset += padding; + } + + } + else + { + //Add + *prop_data_offset += sz_sg_spf_prop_header - sizeof(uint32_t); + + //Copy Payload Size + idx = (*prop_data_offset) / sizeof(uint32_t); + sz_spf_param = glb_buf_1[idx]; + + //Add paddig if necessary before sending the response back + if ((sz_spf_param % 8) != 0) + { + sz_padded_spf_param = sz_spf_param + (8 - ((sz_spf_param % 8))); + + //*padded_bytes += (8 - ((sz_spf_param % 8))); + } + else + { + sz_padded_spf_param = sz_spf_param; + } + + //Add Param Size + *prop_data_offset += sizeof(sz_padded_spf_param); + + *prop_data_offset += sz_padded_spf_param; + } + + return status; +} + +int32_t BuildDriverPropertyBlob(uint32_t sz_driver_prop_data, uint32_t *driver_data_buf, AcdbGetSubgraphDataRsp *pOutput, uint32_t *rsp_offset) +{ + if (IsNull(driver_data_buf) || IsNull(rsp_offset)) + { + return AR_EBADPARAM; + } + + int32_t status = AR_EOK; + uint32_t sg_driver_prop_offset = 0; + + //Subgraph Driver Property Data Header: + size_t sz_sg_driver_prop_header = 2 * sizeof(uint32_t); + + // + size_t sz_prop_header = 2 * sizeof(uint32_t); + + uint32_t sg_id = driver_data_buf[0]; + uint32_t num_sg_prop = driver_data_buf[1]; + uint32_t sz_prop = 0; + uint32_t sz_all_prop_payload = 0; + uint32_t tmp_sz_sg_driver_prop_data = 0; + uint32_t index = 0; + + if (pOutput->driver_prop.sub_graph_prop_data != NULL) + { + //SG ID + if (pOutput->driver_prop.size < (*rsp_offset + sizeof(uint32_t))) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(pOutput->driver_prop.sub_graph_prop_data + + *rsp_offset, sizeof(uint32_t), + &sg_id, sizeof(uint32_t)); + + sg_driver_prop_offset += sizeof(sg_id); + *rsp_offset += sizeof(sg_id); + + //Number of SG Properties + if (pOutput->driver_prop.size < (*rsp_offset + sizeof(uint32_t))) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(pOutput->driver_prop.sub_graph_prop_data + + *rsp_offset, sizeof(uint32_t), + &num_sg_prop, sizeof(uint32_t)); + + sg_driver_prop_offset += sizeof(num_sg_prop); + *rsp_offset += sizeof(num_sg_prop); + + for (uint32_t i = 0; i < num_sg_prop; i++) + { + //SG Property ID + index = (uint32_t)(sg_driver_prop_offset / sizeof(uint32_t)); + if (pOutput->driver_prop.size < (*rsp_offset + sizeof(uint32_t))) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(pOutput->driver_prop.sub_graph_prop_data + + *rsp_offset, sizeof(uint32_t), + &driver_data_buf[index], sizeof(uint32_t)); + + sg_driver_prop_offset += sizeof(uint32_t); + *rsp_offset += sizeof(uint32_t); + + //Property Size + index = (uint32_t)(sg_driver_prop_offset / sizeof(uint32_t)); + if (pOutput->driver_prop.size < (*rsp_offset + sizeof(uint32_t))) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(pOutput->driver_prop.sub_graph_prop_data + + *rsp_offset, sizeof(uint32_t), + &driver_data_buf[index], sizeof(uint32_t)); + + index = (uint32_t)(sg_driver_prop_offset / sizeof(uint32_t)); + sz_prop = driver_data_buf[index]; + sz_all_prop_payload += sz_prop; + + sg_driver_prop_offset += sizeof(uint32_t); + *rsp_offset += sizeof(uint32_t); + + //Property Paylaod + index = (uint32_t)(sg_driver_prop_offset / sizeof(uint32_t)); + if (pOutput->driver_prop.size < (*rsp_offset + sz_prop)) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(pOutput->driver_prop.sub_graph_prop_data + + *rsp_offset, sz_prop, + &driver_data_buf[index], sz_prop); + + sg_driver_prop_offset += sz_prop; + *rsp_offset += sz_prop; + } + } + else + { + sg_driver_prop_offset += (uint32_t)(sz_sg_driver_prop_header); + *rsp_offset += (uint32_t)(sz_sg_driver_prop_header); + + for (uint32_t i = 0; i < num_sg_prop; i++) + { + //SG Property ID + sg_driver_prop_offset += sizeof(uint32_t); + *rsp_offset += sizeof(uint32_t); + + //Property Size + index = (uint32_t)(sg_driver_prop_offset / sizeof(uint32_t)); + sz_prop = driver_data_buf[index]; + + sg_driver_prop_offset += sizeof(uint32_t); + *rsp_offset += sizeof(uint32_t); + + //Skip the actual payload + sg_driver_prop_offset += sz_prop; + *rsp_offset += sz_prop; + + //Property Paylaod + sz_all_prop_payload += sz_prop; + } + } + + //Accumulate size of subgraph property data + tmp_sz_sg_driver_prop_data = + (uint32_t)sz_sg_driver_prop_header + num_sg_prop *((uint32_t)sz_prop_header) + +sz_all_prop_payload; + + if (sz_driver_prop_data != tmp_sz_sg_driver_prop_data) + { + status = AR_EFAILED; + ACDB_ERR_MSG_1("Driver property data size does not match accumulated data size", status); + } + + return status; +} + +int32_t BuildSubgraphDataRsp(AcdbSgIdGraphKeyVector *pInput, uint32_t sg_data_offset, AcdbGetSubgraphDataRsp *pOutput) +{ + int32_t status = AR_EOK; + uint32_t i = 0; + uint32_t offset = 0; + + //Data offset for spf portion of the output Blob + uint32_t spf_blob_offset = 0; + uint32_t driver_prop_data_offset = 0; + ChunkInfo ci_data_pool = { 0 }; + //Subgraph Property Data Header: + size_t sz_sg_prop_data_header = 2 * sizeof(uint32_t); + + //Subgraph Property Data Header: + size_t sz_sg_obj_header = 2 * sizeof(uint32_t); + + //Accumulated sum of driver property data size for all subgraphs + size_t sz_all_driver_prop_data = 0; + + //Size of driver property data for a subgraphs + size_t sz_sg_driver_prop_data = 0; + + //Size of spf property data for a subgraph + size_t sz_sg_spf_prop_data = 0; + + //Size of the Spf Data portion of the output blob + size_t sz_spf_blob = 0; + bool_t found = FALSE; + + ACDB_CLEAR_BUFFER(glb_buf_1); + ACDB_CLEAR_BUFFER(glb_buf_3); + + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get data pool chunk", status); + + return status; + } + + //status = AcdbGetChunkInfo(ACDB_CHUNKID_DATAPOOL, &chkBuf, &chkLen); + + //if (AR_EOK != status) return status; + + //Sort Subgraph IDs + //for (i = 0; i < pInput->num_sgid; i++) + //{ + // glb_buf_3[i] = pInput->sg_ids[i]; + //} + + //AcdbSort(glb_buf_3, pInput->num_sgid); + + for (i = 0; i < pInput->num_sgid; i++) + { + found = FALSE; + offset = ci_data_pool.chunk_offset + sg_data_offset + (uint32_t)sz_sg_prop_data_header; + do + { + status = FileManReadBuffer(&glb_buf_1, sz_sg_obj_header, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read subgraph ID from subgraph property data", status); + + return status; + } + + if (0 == ACDB_MEM_CMP(&glb_buf_1[0], &pInput->sg_ids[i], sizeof(uint32_t))) + { + found = TRUE; + break; + } + else + { + offset += glb_buf_1[1]; //+ (uint32_t)sz_sg_prop_data_header - sz_sg_obj_header; + } + + } while (offset < ci_data_pool.chunk_offset + ci_data_pool.chunk_size && !found); + + if (!found) + { + ACDB_ERR("Error[%d]: subgraph 0x%x does not exist", AR_EFAILED, pInput->sg_ids[i]); + + return AR_EFAILED; + } + else + { + //copy driver prop and spf prop data + //offset += (uint32_t)sz_sg_obj_header; + + ACDB_CLEAR_BUFFER(glb_buf_1); + + status = FileManReadBuffer(&sz_sg_driver_prop_data, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read subgraph driver property size", status); + + return status; + } + + sz_all_driver_prop_data += sz_sg_driver_prop_data; + + status = FileManReadBuffer(&glb_buf_1, sz_sg_driver_prop_data, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read subgraph driver properties", status); + + return status; + } + + //Build Driver Property Data Blob + status = BuildDriverPropertyBlob((uint32_t)sz_sg_driver_prop_data, &glb_buf_1[0], pOutput, &driver_prop_data_offset); + if (AR_EOK != status) + { + ACDB_ERR("Error[%d]: Unable to parse driver property data", status); + return status; + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + + status = FileManReadBuffer(&sz_sg_spf_prop_data, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read subgraph SPF property size", status); + + return status; + } + + status = FileManReadBuffer(&glb_buf_1, sz_sg_spf_prop_data, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read subgraph SPF properties", status); + + return status; + } + + uint32_t prop_data_offset = 0; + + int property_index = 0; + while (prop_data_offset < sz_sg_spf_prop_data) + { + status = BuildSpfPropertyBlob(property_index, spf_blob_offset, &prop_data_offset, pOutput); + + if (AR_EOK != status) + { + ACDB_ERR("Error[%d]: Unable to build spf blob. Encountered error while " + "getting property at index %d", status, property_index); + + return status; + } + + property_index++; + } + + //Add sizeof(error code) for each spf property + sz_spf_blob += (sz_sg_spf_prop_data + (property_index * sizeof(uint32_t))); + + spf_blob_offset = (uint32_t)sz_spf_blob; + } + } + + pOutput->driver_prop.num_sgid = pInput->num_sgid; + + pOutput->driver_prop.size = (uint32_t)sz_all_driver_prop_data; + + pOutput->spf_blob.buf_size = (uint32_t)sz_spf_blob; + + return status; +} + +int32_t AcdbCmdGetSubgraphData(AcdbSgIdGraphKeyVector *req, AcdbGetSubgraphDataRsp *rsp) +{ + int32_t status = AR_EOK; + AcdbGraphKeyVector graph_kv = { 0 }; + acdb_graph_info_t graph_info = { 0 }; + + graph_kv.num_keys = req->graph_key_vector.num_keys; + graph_kv.graph_key_vector = (AcdbKeyValuePair*)&glb_buf_3[0]; + ACDB_MEM_CPY_SAFE(&glb_buf_3[0], + graph_kv.num_keys * sizeof(AcdbKeyValuePair), + req->graph_key_vector.graph_key_vector, + graph_kv.num_keys * sizeof(AcdbKeyValuePair)); + + //Sort Key Vector by Key IDs(position 0 of AcdbKeyValuePair) + status = AcdbSort2(graph_kv.num_keys * sizeof(AcdbKeyValuePair), + graph_kv.graph_key_vector, sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort graph key vector.", status); + return status; + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_GKV, + &graph_kv, sizeof(AcdbGraphKeyVector), + &graph_info, sizeof(acdb_graph_info_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to find the graph key vector", status); + return status; + } + + status = BuildSubgraphDataRsp(req, graph_info.sg_prop_data_offset, rsp); + + if (AR_EOK != status) return status; + + return status; +} + +/** +* \brief +* Searches the Subgraph Connection LUT for matching subgraph +* connection and retreives the offsets. +* +* \param[in/out] connection: A subgraph connection to get the def +* and dot offsets for +* \param[in] table_info: information about the Subgraph Connection LUT +* +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbSearchSubgraphConnectionLut(AcdbSubgraphConnection *connection, + AcdbTableInfo *table_info) +{ + int32_t status = AR_EOK; + AcdbTableSearchInfo search_info = { 0 }; + + if (IsNull(connection) || IsNull(table_info)) + { + return AR_EBADPARAM; + } + + //format : + //LUT = SourceSubgraphId, DestinationSubgraphId, DefOffset, DotOffset + + //Setup Table Information + //table_info.table_offset = offset; + //table_info.table_size = key_table_size; + //table_info.table_entry_size = key_table_entry_size; + + //Setup Search Information + search_info.num_search_keys = 2;//Source and Destination Subgraph IDs + search_info.num_structure_elements = + sizeof(AcdbSubgraphConnection) / sizeof(uint32_t); + search_info.table_entry_struct = connection; + + status = AcdbTableBinarySearch(table_info, &search_info); + + return status; +} + +int32_t AcdbGetSubgraphConnectionData(AcdbSubgraphConnection *connection, + ChunkInfo *def, ChunkInfo *dot, ChunkInfo *data_pool, + uint32_t *blob_offset, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + uint32_t num_def_entries = 0; + uint32_t num_dot_entries = 0; + uint32_t def_offset = 0; + uint32_t dot_offset = 0; + uint32_t data_pool_offset = 0; + uint32_t param_size = 0; + uint32_t padding = 0; + AcdbOp op = ACDB_OP_NONE; + AcdbDspModuleHeader apm_conn_param = { 0 }; + + op = IsNull(rsp->buf) ? + ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + def_offset = def->chunk_offset + connection->def_offset; + dot_offset = dot->chunk_offset + connection->dot_offset; + + status = FileManReadBuffer(&num_def_entries, sizeof(uint32_t), &def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read def entry count", status); + return status; + } + + status = FileManReadBuffer(&num_dot_entries, sizeof(uint32_t), &dot_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read dot entry count", status); + return status; + } + + //Num Entries in Def and Num Entries in Dot should be equal + if (num_def_entries != num_dot_entries) + { + ACDB_ERR("Error[%d]: Number of entries between Def and " + "Dot tables do not match.", AR_EFAILED); + return AR_EFAILED; + } + + for (uint32_t k = 0; k < num_def_entries; k++) + { + status = FileManReadBuffer(&apm_conn_param, + sizeof(AcdbMiidPidPair), &def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read APM " + "module instance and parameter IDs", status); + return status; + } + + status = FileManReadBuffer(&data_pool_offset, + sizeof(uint32_t), &dot_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read datapool offset", status); + return status; + } + + uint32_t dpo = data_pool->chunk_offset + data_pool_offset; + status = FileManReadBuffer(¶m_size, + sizeof(uint32_t), &dpo); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read parameter size for " + "APM parameter[0x%x]", status, apm_conn_param.parameter_id); + return status; + } + + padding = ACDB_PADDING_8_BYTE(param_size); + apm_conn_param.param_size = param_size; + + if (op == ACDB_OP_GET_SIZE) + { + rsp->buf_size += sizeof(apm_conn_param) + + apm_conn_param.param_size + padding; + } + else if (op == ACDB_OP_GET_DATA) + { + if (rsp->buf_size < *blob_offset + sizeof(AcdbDspModuleHeader) + + apm_conn_param.param_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(rsp->buf + *blob_offset, sizeof(apm_conn_param), + &apm_conn_param, sizeof(apm_conn_param)); + *blob_offset += sizeof(apm_conn_param); + + status = FileManReadBuffer((uint8_t*)rsp->buf + *blob_offset, + param_size, &dpo); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read size of APM" + " connection parameter[0x%x]", status, apm_conn_param.parameter_id); + return status; + } + + *blob_offset += param_size; + + //Add Padding + if (padding) + { + ar_mem_set((void*)((uint8_t*)rsp->buf + *blob_offset), + 0, padding); + *blob_offset += padding; + } + } + } + + return status; +} + +int32_t AcdbCmdGetSubgraphConnections(AcdbSubGraphList* req, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t blob_offset = 0; + //uint32_t expected_size = 0; + ChunkInfo ci_lut = { 0 }; + ChunkInfo ci_def = { 0 }; + ChunkInfo ci_dot = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbUintList subgraph_list = {0}; + AcdbSubgraph *subgraph = NULL; + AcdbSubgraphConnection subgraph_connection = { 0 }; + AcdbTableInfo lut_info = { 0 }; + + //set file index based on subgraph list + for (uint32_t i = 0; i < req->num_subgraphs; i++) + { + subgraph = (AcdbSubgraph*)((uint8_t*)req->subgraphs + offset); + glb_buf_3[i] = subgraph->sg_id; + + offset += sizeof(AcdbSubgraph) + + subgraph->num_dst_sgids * sizeof(uint32_t); + } + + subgraph_list.count = req->num_subgraphs; + subgraph_list.list = &glb_buf_3[0]; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + ACDB_CLEAR_BUFFER(glb_buf_3); + + ci_lut.chunk_id = ACDB_CHUNKID_SGCONNLUT; + ci_def.chunk_id = ACDB_CHUNKID_SGCONNDEF; + ci_dot.chunk_id = ACDB_CHUNKID_SGCONNDOT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_lut, &ci_def, &ci_dot, &ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read one or more chunks", status); + return status; + } + + lut_info.table_size = ci_lut.chunk_size - sizeof(uint32_t); + lut_info.table_offset = ci_lut.chunk_offset + sizeof(uint32_t); + lut_info.table_entry_size = sizeof(AcdbSubgraphConnection); + offset = 0; + + for (uint32_t i = 0; i < req->num_subgraphs; i++) + { + subgraph = (AcdbSubgraph*)((uint8_t*)req->subgraphs + offset); + offset += sizeof(AcdbSubgraph) + + subgraph->num_dst_sgids * sizeof(uint32_t); + + for (uint32_t j = 0; j < subgraph->num_dst_sgids; j++) + { + subgraph_connection.src_subgraph_id = subgraph->sg_id; + subgraph_connection.dst_subgraph_id = subgraph->dst_sg_ids[j]; + + status = AcdbSearchSubgraphConnectionLut( + &subgraph_connection, &lut_info); + if (AR_FAILED(status)) + { + //connection not found + return status; + } + + status = AcdbGetSubgraphConnectionData(&subgraph_connection, + &ci_def, &ci_dot, &ci_data_pool, &blob_offset, rsp); + if (AR_FAILED(status)) + { + //connection data not found + return status; + } + } + } + + subgraph = NULL; + + if (rsp->buf_size == 0) + return AR_ENOTEXIST; + + return status; +} + +int32_t AcdbGetOffloadedParameterCal( + AcdbOp op, uint32_t subgraph_id, AcdbDspModuleHeader *module_header, + AcdbPayload *caldata, AcdbBlob* rsp, + uint32_t *module_start_blob_offset, uint32_t *module_end_blob_offset) +{ + int32_t status = AR_EOK; + uint32_t tmp_blob_offset = 0; + + if (op == ACDB_OP_GET_SIZE) + tmp_blob_offset = rsp->buf_size; + else + { + tmp_blob_offset = *module_start_blob_offset; + //*module_start_blob_offset = *module_end_blob_offset; + //*module_start_blob_offset = *module_end_blob_offset; + } + + tmp_blob_offset += sizeof(AcdbDspModuleHeader); + + status = GetOffloadedParameterData( + caldata, &module_header->param_size, rsp, &tmp_blob_offset); + if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + return status; + } + else if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + if (op == ACDB_OP_GET_SIZE) + ACDB_ERR("Error[%d]: No file path provided for offloaded " + "parameter [sg: 0x%x, inst.: 0x%x, param: 0x%x]", status, + subgraph_id, module_header->module_iid, + module_header->parameter_id); + status = AR_EOK; + } + + if (op == ACDB_OP_GET_DATA) + *module_end_blob_offset = tmp_blob_offset; + //padded_param_size = + // ACDB_ALIGN_8_BYTE(module_header.param_size); + + return status; +} + +int32_t AcdbGetSubgraphCalibration(AcdbAudioCalContextInfo *info, + uint32_t *blob_offset, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + uint32_t cur_def_offset = 0; + uint32_t cur_dot_offset = 0; + uint32_t cur_dpool_offset = 0; + uint32_t data_offset = 0; + uint32_t padded_param_size = 0; + uint32_t num_param_cal_found = 0; + uint32_t num_iid_found = 0; + uint32_t tmp_blob_offset = 0; + bool_t is_offloaded_param = FALSE; + ChunkInfo ci_cal_def = { 0 }; + ChunkInfo ci_cal_dot = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + uint32_t num_id_entries = 0; + AcdbDspModuleHeader module_header = { 0 }; + AcdbIidRefCount *iid_ref = NULL; + AcdbBlob src = { 0 }; + AcdbPayload caldata = { 0 }; + AcdbHwAccelMemType mem_type = ACDB_HW_ACCEL_MEM_TYPE(info->proc_id); + + ci_cal_def.chunk_id = ACDB_CHUNKID_CALDATADEF; + ci_cal_dot.chunk_id = ACDB_CHUNKID_CALDATADOT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_cal_def, + &ci_cal_dot, &ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get Subgraph Calibration " + "DEF, DOT, or Datapool chunk information", status); + return status; + } + + // Skip number of DOT offsets since number of IID Pairs is the same thing + cur_dot_offset = ci_cal_dot.chunk_offset + info->data_offsets.offset_dot + + sizeof(uint32_t); + cur_def_offset = ci_cal_def.chunk_offset + info->data_offsets.offset_def; + status = FileManReadBuffer(&num_id_entries, sizeof(uint32_t), &cur_def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of " + " entries", status); + return status; + } + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + //Ensure global buffer can store the default data IID Reference list + if (GLB_BUF_1_LENGTH < num_id_entries * 2) + { + ACDB_ERR("Error[%d]: Need more memory to store IID reference list", + AR_ENEEDMORE); + return AR_ENEEDMORE; + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + + iid_ref = (AcdbIidRefCount*)glb_buf_1; + } + + for (uint32_t i = 0; i < num_id_entries; i++) + { + status = FileManReadBuffer(&module_header, sizeof(AcdbMiidPidPair), + &cur_def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read entry", status); + return status; + } + + //If Get Module Data is called + if ((info->data_op == ACDB_OP_GET_MODULE_DATA) && + (module_header.module_iid != info->instance_id)) + { + cur_dot_offset += sizeof(uint32_t); + continue; + } + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + //Add IIDs to list and ignore get data + if (iid_ref->module_iid != module_header.module_iid && num_iid_found == 0) + { + iid_ref->module_iid = module_header.module_iid; + iid_ref->ref_count = 1; + num_iid_found++; + //iid_ref++; + } + else if (iid_ref->module_iid != module_header.module_iid) + { + iid_ref++; + iid_ref->module_iid = module_header.module_iid; + iid_ref->ref_count = 1; + num_iid_found++; + } + else + { + /* Increase ref count of the current Obj */ + iid_ref->ref_count++; + } + + continue; + } + else + { + /* For other CKVs, if the module is in the default data list, remove it */ + if (!IsNull(info->default_data_iid_list.list)) + { + iid_ref = (AcdbIidRefCount*) + info->default_data_iid_list.list; + bool_t found_iid = FALSE; + for (uint32_t j = 0; j < info-> + default_data_iid_list.count; j++) + { + if ((module_header.module_iid == iid_ref->module_iid) + && iid_ref->ref_count > 0) + { + iid_ref->ref_count--; + found_iid = TRUE; + break; + } + else if ((module_header.module_iid == iid_ref->module_iid) + && iid_ref->ref_count <= 0) + break; + + iid_ref++; + } + + if (info->is_default_module_ckv && !found_iid) + { + cur_dot_offset += sizeof(uint32_t); + continue; + } + } + } + + //todo: Swap to this impementation when Global Persist is supported + //status = DataProcGetPersistenceType( + // module_header.parameter_id, ¶m_type); + //if (AR_FAILED(status)) + //{ + // ACDB_ERR("Error[%d]: Failed to get parameter persist type " + // "for Parameter(0x%x)", status, module_header.parameter_id); + // return status; + //} + + //if (info->param_type != param_type) + //{ + // cur_dot_offset += sizeof(uint32_t); + // continue; + //} + + switch (info->param_type) + { + case ACDB_DATA_NON_PERSISTENT: + if (AR_SUCCEEDED(IsPidPersistent(module_header.parameter_id))) + { + //cur_def_offset += sizeof(AcdbMiidPidPair); + cur_dot_offset += sizeof(uint32_t); + continue; + } + break; + case ACDB_DATA_PERSISTENT: + if (AR_FAILED(IsPidPersistent(module_header.parameter_id))) + { + //cur_def_offset += sizeof(AcdbMiidPidPair); + cur_dot_offset += sizeof(uint32_t); + continue; + } + break; + //case ACDB_DATA_GLOBALY_PERSISTENT: + // break; + case ACDB_DATA_DONT_CARE: + default: + break; + } + + if (info->param_type == ACDB_DATA_PERSISTENT && info->should_filter_cal_by_proc_domain) + { + //check for proc id + + uint32_t proc_domain_id = 0; + status = DataProcGetProcDomainForModule( + info->sg_mod_iid_map, + module_header.module_iid, + &proc_domain_id); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get proccessor domain ID for " + "sg: 0x%x iid: 0x%x", + status, info->subgraph_id, module_header.module_iid); + return status; + } + + if (proc_domain_id != ACDB_HW_ACCEL_PROC_ID(info->proc_id)) + { + //go to next parameter + cur_dot_offset += sizeof(uint32_t); + continue; + } + } + + if (info->should_check_hw_accel) + { + status = DataProcIsHwAccelParam(info->hw_accel_module_list_offset, + module_header.module_iid, module_header.parameter_id); + + switch (mem_type) + { + case ACDB_HW_ACCEL_MEM_DEFAULT: + if (AR_SUCCEEDED(status)) + { + cur_dot_offset += sizeof(uint32_t); + continue; + } + break; + case ACDB_HW_ACCEL_MEM_CMA: + if (AR_FAILED(status)) + { + cur_dot_offset += sizeof(uint32_t); + continue; + } + break; + case ACDB_HW_ACCEL_MEM_BOTH: + status = AR_EBADPARAM; + ACDB_ERR("Error[%d]: The HW Accel Memory Type is set to BOTH. " + "It needs to be either DEFAULT or CMA", status); + goto end; + } + } + + num_param_cal_found++; + + status = IsOffloadedParam(module_header.parameter_id, + &info->offloaded_parameter_list); + is_offloaded_param = AR_SUCCEEDED(status) ? TRUE : FALSE; + + //Get data from Heap + status = GetSubgraphCalData(info->param_type, ACDB_DATA_ACDB_CLIENT, + info->module_ckv, info->subgraph_id, module_header.module_iid, + module_header.parameter_id, is_offloaded_param, blob_offset, rsp); + + if (AR_SUCCEEDED(status)) + { + //cur_def_offset += sizeof(AcdbMiidPidPair); + cur_dot_offset += sizeof(uint32_t); + continue; + } + + //Get data from file + status = FileManReadBuffer( + &data_offset, sizeof(uint32_t), &cur_dot_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of " + " entries", status); + return status; + } + + cur_dpool_offset = ci_data_pool.chunk_offset + data_offset; + status = FileManReadBuffer( + &module_header.param_size, sizeof(uint32_t), &cur_dpool_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read param size", status); + return status; + } + + src.buf_size = sizeof(module_header); + src.buf = (void*)&module_header; + tmp_blob_offset = 0; + caldata.size = module_header.param_size; + status = FileManGetFilePointer2((void**)&caldata.payload, cur_dpool_offset); + + if (is_offloaded_param) + { + status = AcdbGetOffloadedParameterCal( + info->op, info->subgraph_id, &module_header, + &caldata, rsp, blob_offset, &tmp_blob_offset); + if (AR_FAILED(status)) + return status; + + padded_param_size = + ACDB_ALIGN_8_BYTE(module_header.param_size); + } + else + { + padded_param_size = + ACDB_ALIGN_8_BYTE(module_header.param_size); + } + + + switch (info->op) + { + case ACDB_OP_GET_SIZE: + rsp->buf_size += sizeof(AcdbDspModuleHeader) + + padded_param_size; + break; + case ACDB_OP_GET_DATA: + status = AcdbWriteBuffer(rsp, blob_offset, &src); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Need more memory to write module header", + status); + return status; + } + + if (is_offloaded_param) + { + *blob_offset = tmp_blob_offset; + continue; + } + + if (rsp->buf_size < (*blob_offset + padded_param_size)) + { + ACDB_ERR("Error[%d]: Need more memory to write param data", + status); + return AR_ENEEDMORE; + } + + if (module_header.param_size > 0) + { + src.buf = caldata.payload; + src.buf_size = caldata.size; + + status = AcdbWriteBuffer(rsp, blob_offset, &src); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to write param data", + status); + return status; + } + } + + *blob_offset += ACDB_PADDING_8_BYTE(caldata.size); + break; + default: + break; + } + } +end: + if (info->is_default_module_ckv && !info->ignore_get_default_data) + { + ACDB_FREE(info->default_data_iid_list.list); + info->default_data_iid_list.list = NULL; + } + else if (info->is_default_module_ckv && info->ignore_get_default_data) + { + /* Copy the IID Ref Count list from GLB_BUF_1 since it will be + * cleared outside of this call */ + info->default_data_iid_list.count = num_iid_found; + + //List of AcdbIidRefCount + info->default_data_iid_list.list = (uint32_t*) + ACDB_MALLOC(AcdbIidRefCount, num_iid_found); + + if (IsNull(info->default_data_iid_list.list)) + { + ACDB_ERR("Error[%d]: Unable to allocate memory " + "for instance id reference list", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + ACDB_MEM_CPY_SAFE(info->default_data_iid_list.list, + num_iid_found * sizeof(AcdbIidRefCount), + &glb_buf_1[0], num_iid_found * sizeof(AcdbIidRefCount)); + + iid_ref = NULL; + } + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + return AR_EOK; + } + else if (num_param_cal_found == 0) return AR_ENOTEXIST; + + return status; +} + +int32_t AcdbFindModuleCKV(AcdbCalKeyTblEntry *ckv_entry, + AcdbAudioCalContextInfo *info) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_keys_found = 0; + uint32_t key_table_size = 0; + uint32_t key_table_entry_size = 0; + ChunkInfo ci_sg_key_tbl = { 0 }; + ChunkInfo ci_cal_lut = { 0 }; + AcdbGraphKeyVector module_ckv = { 0 }; + KeyTableHeader key_table_header = { 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + if (IsNull(ckv_entry) || IsNull(info)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (IsNull(info->module_ckv)) + { + ACDB_ERR("Error[%d]: The module CKV in the context" + " info struct is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_sg_key_tbl.chunk_id = ACDB_CHUNKID_CALKEYTBL; + ci_cal_lut.chunk_id = ACDB_CHUNKID_CALDATALUT; + status = ACDB_GET_CHUNK_INFO(&ci_sg_key_tbl, &ci_cal_lut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get Subgraph CKV Tables " + "(Key ID and Value Lookup)chunk information", status); + return status; + } + + /* + * GLB_BUF_1: + * 1. Used to store the key ids + * 2. Also stores the CKV LUT used in the partition binary search + * GLB_BUF_3: + * 1. The first portion of the buffer stores the Module CKV + * 2. The other portion stores one CKV LUT entry found + * the partition binary search during + */ + offset = ci_sg_key_tbl.chunk_offset + ckv_entry->offset_cal_key_tbl; + status = FileManReadBuffer(&module_ckv.num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of CKV keys", status); + return status; + } + + if (module_ckv.num_keys > 0) + { + status = FileManReadBuffer(&glb_buf_1, + module_ckv.num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key id list", status); + } + } + + uint32_t ckv_lut_entry_index = module_ckv.num_keys * 2; + + module_ckv.graph_key_vector = + (AcdbKeyValuePair*)&glb_buf_3[0]; + for (uint32_t i = 0; i < module_ckv.num_keys; i++) + { + module_ckv.graph_key_vector[i].key = glb_buf_1[i]; + } + + /* Check if the Module CKV exist within the new CKV. If it doesn't + * skip this module CKV */ + num_keys_found = 0; + for (uint32_t k = 0; k < module_ckv.num_keys; k++) + { + for (uint32_t l = 0; l < info->ckv->num_keys; l++) + { + if (module_ckv.graph_key_vector[k].key == + info->ckv->graph_key_vector[l].key) + { + glb_buf_3[ckv_lut_entry_index + num_keys_found] = + info->ckv->graph_key_vector[l].value; + module_ckv.graph_key_vector[k].value = + info->ckv->graph_key_vector[l].value; + num_keys_found += 1; + break; + } + } + } + + if (info->ckv->num_keys == 0 && module_ckv.num_keys != 0 && + info->is_first_time) + return AR_ENOTEXIST; + if (module_ckv.num_keys == 0 && !info->is_first_time) + return AR_ENOTEXIST; + if ((num_keys_found != module_ckv.num_keys) && !info->is_first_time) + return AR_ENOTEXIST; + if (!info->is_first_time) + { + bool_t deltaKey = FALSE;//Is delta key vector found + + /* We are checking for all the key combinations. Compare the KeyVector + * KeyIDs in the CalKeyTable to the DeltaKV KeyIDs + * Case 1: + * If all the keys are missing, go to the next CKV KeyID table offset + * Case 2: + * If its a partial match, break and get the module data + */ + for (uint32_t k = 0; k < module_ckv.num_keys; k++) + { + for (uint32_t l = 0; l < info->delta_ckv->num_keys; l++) + { + if (module_ckv.graph_key_vector[k].key == + info->delta_ckv->graph_key_vector[l].key) + { + deltaKey = TRUE; + break; + } + } + + if (deltaKey) + break; + } + + if (!deltaKey) + return AR_ENOTEXIST; + //continue;//return AR_ENOTEXIST as there is no difference + } + + //Search LUT for Value Entry + offset = ci_cal_lut.chunk_offset + ckv_entry->offset_cal_lut; + status = FileManReadBuffer(&key_table_header, sizeof(KeyTableHeader), + &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read value lookup table header", + status); + } + + if (0 == key_table_header.num_entries) + { + /* The lookup table should not be empty. If this is true, + * then there is an issue with the ACDB file. */ + + if (0 == module_ckv.num_keys) + { + ACDB_ERR("Error[%d]: Subgraph (0x%x) | There is a module in this" + " subgraph with missing default calibration data. Check the" + " subgraph.", + AR_EFAILED, info->subgraph_id); + } + else + { + ACDB_ERR("Error[%d]: Subgraph (0x%x) | There is a module in this" + " subgraph with missing calibration data for the module ckv" + " below: ", + AR_EFAILED, info->subgraph_id); + + LogKeyVector(&module_ckv, CAL_KEY_VECTOR); + } + + return AR_EFAILED; + } + + key_table_entry_size = (module_ckv.num_keys * sizeof(uint32_t)) + + sizeof(AcdbCkvLutEntryOffsets); + key_table_size = key_table_header.num_entries * key_table_entry_size; + + //Setup Table Information + table_info.table_offset = offset; + table_info.table_size = key_table_size; + table_info.table_entry_size = key_table_entry_size; + + //Setup Search Information + search_info.num_search_keys = key_table_header.num_keys; + search_info.num_structure_elements = + key_table_header.num_keys + 3;//Values + DEF + DOT + DOT2 + search_info.table_entry_struct = &glb_buf_3[ckv_lut_entry_index]; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + //ACDB_ERR("Error[%d]: Unable to find cal key vector. " + // "No matching values were found", status); + + //if (info->op == ACDB_OP_GET_SIZE) + // LogKeyVector(&module_ckv, CAL_KEY_VECTOR); + + return status; + } + + ACDB_MEM_CPY_SAFE(&info->data_offsets, sizeof(AcdbCkvLutEntryOffsets), + &glb_buf_3[ckv_lut_entry_index + module_ckv.num_keys], + sizeof(AcdbCkvLutEntryOffsets)); + + info->module_ckv->num_keys = module_ckv.num_keys; + + if(info->module_ckv->num_keys > 0) + ACDB_MEM_CPY_SAFE(info->module_ckv->graph_key_vector, + module_ckv.num_keys * sizeof(AcdbKeyValuePair), + module_ckv.graph_key_vector, + module_ckv.num_keys * sizeof(AcdbKeyValuePair)); + + + /* Hypervisor + * If we encounter the Default CKV + * Indiciate that the default CKV has been found + * Store the LUT Entry Offsets(DEF DOT, DOT2) separately for the default CKV + * Skip getting data for the default CKV if the next CKV is what we are + * looking for and it contains one of the IIDs that are also associated + * with the default CKV, + */ + + if (module_ckv.num_keys == 0) + { + info->is_default_module_ckv = TRUE; + //info->ignore_get_default_data = TRUE; + + //Read IIDs into a tracking list. For non-default CKVs, if a module is found remove it from the default CKV IID list + } + else + { + info->is_default_module_ckv = FALSE; + info->ignore_get_default_data = TRUE; + } + + return status; +} + +/** +* \brief +* Calculates the Delta Key Vector which is the difference between the +* old and new key vector and also updates the is_first_time flag in the +* context info struct +* +* \depends +* The Delta CKV and CKV[New] in the context info struct must be freed +* when no longer in use +* +* \param[in] ckv_new: The current calibration key vector +* \param[in] ckv_prior: The previous calibration key vector +* \param[out] context_info: Context info containing the Delta CKV and CKV[New] +* to be updated +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbComputeDeltaCKV( + AcdbGraphKeyVector* ckv_new, AcdbGraphKeyVector* ckv_prior, + AcdbAudioCalContextInfo *context_info) +{ + int32_t status = AR_EOK; + bool_t first_time = FALSE; + uint32_t kv_size = 0; + AcdbGraphKeyVector *cmdKV = NULL; + AcdbGraphKeyVector *deltaKV = NULL; + + if (IsNull(ckv_new) || IsNull(ckv_prior) || IsNull(context_info)) + { + ACDB_ERR("Error[%d]: One or more input parameter(s) is null.", + AR_EBADPARAM); + + return AR_EBADPARAM; + } + + cmdKV = ACDB_MALLOC(AcdbGraphKeyVector, 1); + if (IsNull(cmdKV)) + { + ACDB_ERR("Error[%d]: Insufficient memory for allocating ckv", + AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + (void)ar_mem_set(cmdKV, 0, sizeof(AcdbGraphKeyVector)); + + if (ckv_prior->num_keys == 0) + { + first_time = TRUE; + cmdKV->num_keys = ckv_new->num_keys; + + if(cmdKV->num_keys > 0) + cmdKV->graph_key_vector = + ACDB_MALLOC(AcdbKeyValuePair, cmdKV->num_keys); + + if (IsNull(cmdKV->graph_key_vector) && cmdKV->num_keys > 0) + { + status = AR_ENOMEMORY; + ACDB_ERR("Error[%d]: Insufficient memory for allocating ckv", + status); + goto end; + } + + kv_size = cmdKV->num_keys * sizeof(AcdbKeyValuePair); + (void)ar_mem_set(cmdKV->graph_key_vector, 0, kv_size); + ACDB_MEM_CPY_SAFE(cmdKV->graph_key_vector, kv_size, + ckv_new->graph_key_vector, kv_size); + } + else + { + status = AcdbSort2( + ckv_prior->num_keys * sizeof(AcdbKeyValuePair), + ckv_prior->graph_key_vector, + sizeof(AcdbKeyValuePair), 0); + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort the old CKV"); + goto end; + } + + status = AcdbSort2( + ckv_new->num_keys * sizeof(AcdbKeyValuePair), + ckv_new->graph_key_vector, + sizeof(AcdbKeyValuePair), 0); + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort the new CKV"); + goto end; + } + + //compute delta KV (from prior and new) and number of keys + if (ckv_prior->num_keys != ckv_new->num_keys) + { + ACDB_ERR("CKV[old] num of keys = %d do not match " + "CKV[new] num of keys = %d", + ckv_prior->num_keys, + ckv_new->num_keys); + status = AR_EFAILED; + goto end; + } + + cmdKV->num_keys = ckv_new->num_keys; + + if (cmdKV->num_keys > 0) + cmdKV->graph_key_vector = + ACDB_MALLOC(AcdbKeyValuePair, cmdKV->num_keys); + + if (IsNull(cmdKV->graph_key_vector) && cmdKV->num_keys > 0) + { + ACDB_ERR("Error[%d]: Insufficient memory for allocating ckv", + AR_ENOMEMORY); + status = AR_ENOMEMORY; + goto end; + } + + kv_size = cmdKV->num_keys * sizeof(AcdbKeyValuePair); + (void)ar_mem_set(cmdKV->graph_key_vector, 0, kv_size); + + for (uint32_t i = 0; i < cmdKV->num_keys; i++) + { + ACDB_MEM_CPY_SAFE(cmdKV->graph_key_vector, kv_size, + ckv_new->graph_key_vector, kv_size); + } + + uint32_t key_count = 0; + for (uint32_t i = 0; i < ckv_prior->num_keys; i++) + { + if (ckv_prior->graph_key_vector[i].key != + ckv_new->graph_key_vector[i].key) + { + status = AR_ENOTEXIST; + break; + } + if (ckv_prior->graph_key_vector[i].value != + ckv_new->graph_key_vector[i].value) + key_count++; + } + + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("CKV[new] and CKV[old] have ""different sets of " + "keys", status); + goto end; + } + + if (key_count == 0) + { + ACDB_ERR("Error[%d]: No calibration data can be found. There is no" + " difference between CKV[new] and CKV[old].", AR_ENOTEXIST); + + status = AR_ENOTEXIST; + goto end; + } + + deltaKV = ACDB_MALLOC(AcdbGraphKeyVector, 1); + if (deltaKV == NULL) + { + ACDB_ERR("Error[%d]: Insufficient memory for allocating delta ckv", + AR_ENOMEMORY); + status = AR_ENOMEMORY; + goto end; + } + (void)ar_mem_set(deltaKV, 0, sizeof(AcdbGraphKeyVector)); + + deltaKV->num_keys = key_count; + deltaKV->graph_key_vector = ACDB_MALLOC(AcdbKeyValuePair, key_count); + if (IsNull(deltaKV->graph_key_vector)) + { + ACDB_ERR("Error[%d]: Insufficient memory to allocate delta ckv key" + " value pair list", AR_ENOMEMORY); + status = AR_ENOMEMORY; + goto end; + } + + (void)ar_mem_set(deltaKV->graph_key_vector, 0, + key_count * sizeof(AcdbKeyValuePair)); + + key_count = 0; + for (uint32_t i = 0; i < ckv_prior->num_keys; i++) + { + if (ckv_prior->graph_key_vector[i].value != + ckv_new->graph_key_vector[i].value) + { + deltaKV->graph_key_vector[key_count].key = + ckv_new->graph_key_vector[i].key; + deltaKV->graph_key_vector[key_count].value = + ckv_new->graph_key_vector[i].value; + key_count++; + } + } + } + +end: + if (AR_FAILED(status)) + { + if (!IsNull(cmdKV)) + { + ACDB_FREE(cmdKV->graph_key_vector); + ACDB_FREE(cmdKV); + } + + if (!IsNull(deltaKV)) + { + ACDB_FREE(deltaKV->graph_key_vector); + ACDB_FREE(deltaKV); + } + + return status; + } + + context_info->ckv = cmdKV; + context_info->delta_ckv = deltaKV; + context_info->is_first_time = first_time; + + return status; +} + +/** +* \brief +* Frees memory allocated to the CKV and Delta CKV +* +* \param[in/out] info: Context info containing the Delta CKV and CKV[New] +* \return none +*/ +void AcdbClearAudioCalContextInfo(AcdbAudioCalContextInfo* info) +{ + if (IsNull(info)) + { + ACDB_ERR("Error[%d]: Input parameter is null", + AR_EBADPARAM); + return; + } + + if (!IsNull(info->ckv)) + { + if (!IsNull(info->ckv->graph_key_vector)) + ACDB_FREE(info->ckv->graph_key_vector); + ACDB_FREE(info->ckv); + } + + if (!IsNull(info->delta_ckv)) + { + if (!IsNull(info->delta_ckv->graph_key_vector)) + ACDB_FREE(info->delta_ckv->graph_key_vector); + ACDB_FREE(info->delta_ckv); + } + + info->module_ckv = NULL; + info->delta_ckv = NULL; + info->ckv = NULL; + + return; +} + +int32_t AcdbCmdGetSubgraphCalDataNonPersist(AcdbSgIdCalKeyVector *req, + AcdbBlob *rsp, uint32_t rsp_struct_size) +{ + int32_t status = AR_EOK; + bool_t found_sg = FALSE; + bool_t has_cal_data = FALSE; + uint32_t offset = 0; + uint32_t prev_sg_cal_lut_offset = 0; + uint32_t prev_subgraph_id = 0; + uint32_t sg_cal_lut_offset = 0; + uint32_t default_ckv_entry_offset = 0; + uint32_t blob_offset = 0; + uint32_t num_subgraph = 0; + uint32_t num_subgraph_found = 0; + ChunkInfo ci_sg_cal_lut = { 0 }; + AcdbSgCalLutHeader sg_cal_lut_header = { 0 }; + AcdbCalKeyTblEntry ckv_entry = { 0 }; + AcdbAudioCalContextInfo info; + AcdbUintList subgraph_list = { 0 }; + + (void)ar_mem_set(&info, 0, sizeof(AcdbAudioCalContextInfo)); + + if (rsp_struct_size < sizeof(AcdbBlob)) + { + ACDB_ERR("Error[%d]: The response structure size is less than %d", + AR_EBADPARAM, sizeof(AcdbBlob)); + return AR_EBADPARAM; + } + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null"); + return AR_EBADPARAM; + } + + subgraph_list.count = req->num_sg_ids; + subgraph_list.list = req->sg_ids; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + ci_sg_cal_lut.chunk_id = ACDB_CHUNKID_CALSGLUT; + status = ACDB_GET_CHUNK_INFO(&ci_sg_cal_lut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get Subgraph Calibration LUT " + "chunk information", status); + return status; + } + + info.param_type = ACDB_DATA_NON_PERSISTENT; + if (rsp->buf_size > 0 && !IsNull(rsp->buf)) + { + info.op = ACDB_OP_GET_DATA; + memset(rsp->buf, 0, rsp->buf_size); + } + else + info.op = ACDB_OP_GET_SIZE; + + if (info.op == ACDB_OP_GET_SIZE) + { + //Log CKV when this API is called for the first time + ACDB_DBG("Retrieving non-persistent calibration for " + "the following cal key vector:"); + ACDB_DBG("CKV[new]:"); + LogKeyVector(&req->cal_key_vector_new, CAL_KEY_VECTOR); + ACDB_DBG("CKV[old]:"); + LogKeyVector(&req->cal_key_vector_prior, CAL_KEY_VECTOR); + } + + /* CKV Setup + * 1. GLB_BUF_2 stores the module CKV that will be used to locate data in + * the heap(if it exists) + * 2. The Delta CKV and CKV[New] are allocated on the heap by + * AcdbComputeDeltaCKV + * + * tmp - stores the amount of padding after graph_key_vectornum_keys + * tmp2 - stores the position of the KeyValuePair list + * + * The first info.module_ckv->graph_key_vector assignment has the effect + * of storing the address of the pointer in glb_buf_2 after + * graph_key_vector.num_keys + * + * The second info.module_ckv->graph_key_vector assignment has the effect + * of pointer the info.module_ckv->graph_key_vector to the actual list + * of key value pairs + * + * Whats inside global buffer 2 after these operations? + * + * The first 'sizeof(AcdbGraphKeyVector)' bytes is AcdbGraphKeyVector + * followed by 'sizeof(AcdbKeyValuePair) * num_keys' bytes which is + * the KV list + */ + info.module_ckv = (AcdbGraphKeyVector*)&glb_buf_2[0]; + uint32_t tmp = (sizeof(AcdbGraphKeyVector) - sizeof(AcdbKeyValuePair *)) / sizeof(uint32_t); + uint32_t tmp2 = sizeof(AcdbGraphKeyVector) / sizeof(uint32_t); + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp]; + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp2]; + + status = AcdbComputeDeltaCKV( + &req->cal_key_vector_new, &req->cal_key_vector_prior, &info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get the delta CKV", status); + AcdbClearAudioCalContextInfo(&info); + return status; + } + + offset = ci_sg_cal_lut.chunk_offset; + status = FileManReadBuffer(&num_subgraph, + sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of Subgraphs", + status); + AcdbClearAudioCalContextInfo(&info); + return status; + } + + /* Sort the subgraph list so that the linear search for subgraph + * takes less time. The Subgraph CAL LUT sorts the subgraphs. By + * sorting the input subgraph list we can locate the subgraphs + * in the chunk sequentially. Therefore there is no need to reset + * the table offset */ + status = AcdbSort2(req->num_sg_ids * sizeof(uint32_t), + req->sg_ids, sizeof(uint32_t), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort subgraph list", + status); + AcdbClearAudioCalContextInfo(&info); + return status; + } + + GetOffloadedParamList(&info.offloaded_parameter_list); + if (info.offloaded_parameter_list.count == 0) + { + ACDB_DBG("Error[%d]: No offloaded parameters found. Skipping..", + status); + } + + prev_sg_cal_lut_offset = offset; + for (uint32_t i = 0; i < req->num_sg_ids; i++) + { + found_sg = FALSE; + has_cal_data = FALSE; + /*offset = tmp_offset;*/ + + while(offset < ci_sg_cal_lut.chunk_offset + ci_sg_cal_lut.chunk_size) + { + status = FileManReadBuffer(&sg_cal_lut_header, + sizeof(AcdbSgCalLutHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to read Subgraph " + "Cal LUT header", status); + } + + if (req->sg_ids[i] == sg_cal_lut_header.subgraph_id) + { + found_sg = TRUE; + prev_sg_cal_lut_offset = offset - sizeof(AcdbSgCalLutHeader); + prev_subgraph_id = sg_cal_lut_header.subgraph_id; + break; + } + else if ( + (req->sg_ids[i] < sg_cal_lut_header.subgraph_id) || + (req->sg_ids[i] > prev_subgraph_id && + req->sg_ids[i] < sg_cal_lut_header.subgraph_id)) + { + /* The input subgraph is a voice subgraph or it + * does not exist */ + offset = prev_sg_cal_lut_offset; + break; + } + else + { + //Go to next Subgraph entry + offset += (sg_cal_lut_header.num_ckv_entries + * sizeof(AcdbCalKeyTblEntry)); + } + } + + if (!found_sg) + { + if(info.op == ACDB_OP_GET_SIZE) + ACDB_DBG("Error[%d]: Subgraph(%x) is not an audio subgraph." + " Skipping..", + AR_ENOTEXIST, req->sg_ids[i]); + continue; + } + + if (sg_cal_lut_header.num_ckv_entries == 0) + { + ACDB_DBG("Error[%d]: Subgraph(%x) contains zero CKV entries in" + " the Subgraph Cal LUT. At least one entry should be" + " present. Skipping..", + AR_ENOTEXIST, req->sg_ids[i]); + continue; + } + + info.ignore_get_default_data = + sg_cal_lut_header.num_ckv_entries == 1 ? FALSE : TRUE; + + //The default CKV will be skipped and handeled last + if (sg_cal_lut_header.num_ckv_entries > 1 && info.is_first_time) + sg_cal_lut_header.num_ckv_entries++; + + for (uint32_t k = 0; k < sg_cal_lut_header.num_ckv_entries; k++) + { + /* The Default CKV is always the first CKV in the list of CKVs to + * search. It will be skipped and processed last */ + if ((k == sg_cal_lut_header.num_ckv_entries - 1) && + info.ignore_get_default_data == TRUE && info.is_first_time) + { + sg_cal_lut_offset = default_ckv_entry_offset; + info.ignore_get_default_data = FALSE; + + status = FileManReadBuffer(&ckv_entry, sizeof(ckv_entry), + &sg_cal_lut_offset); + } + else + { + status = FileManReadBuffer(&ckv_entry, sizeof(ckv_entry), + &offset); + sg_cal_lut_offset = offset; + } + + if (AR_FAILED(status)) + { + AcdbClearAudioCalContextInfo(&info); + return status; + } + + info.subgraph_id = sg_cal_lut_header.subgraph_id; + + status = AcdbFindModuleCKV(&ckv_entry, &info); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + continue; + } + else if(AR_FAILED(status)) + { + AcdbClearAudioCalContextInfo(&info); + return status; + } + + if (info.is_default_module_ckv) + { + default_ckv_entry_offset = + sg_cal_lut_offset - sizeof(ckv_entry); + } + + //Get Calibration + status = AcdbGetSubgraphCalibration(&info, &blob_offset, rsp); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + //No calibration found for subgraph with module ckv_entry + //has_cal_data = FALSE; + continue; + } + else if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: An error occured while getting " + "calibration data for Subgraph(%x)", status, + sg_cal_lut_header.subgraph_id); + AcdbClearAudioCalContextInfo(&info); + return status; + } + + if (info.is_default_module_ckv && info.ignore_get_default_data) + { + continue; + } + + has_cal_data = TRUE; + } + + if (AR_FAILED(status) && !has_cal_data) + { + ACDB_DBG("Warning[%d]: Unable to retrieve calibration data for " + "Subgraph(%x). Skipping..", status, + sg_cal_lut_header.subgraph_id); + status = AR_EOK; + } + else + { + status = AR_EOK; + num_subgraph_found++; + } + } + + if (num_subgraph_found == 0) + { + status = AR_ENOTEXIST; + ACDB_DBG("Error[%d]: No calibration found", status); + } + + //Clean Up Context Info + AcdbClearAudioCalContextInfo(&info); + + return status; +} + +int32_t GetVcpmSubgraphCalTable(uint32_t num_subgraphs, uint32_t subgraph_id, + uint32_t *file_offset, AcdbVcpmSubgraphCalTable *subgraph_cal_table) +{ + int32_t status = AR_EOK; + bool_t found = FALSE; + uint32_t offset = *file_offset; + + if (IsNull(subgraph_cal_table) || IsNull(file_offset)) + { + return AR_EBADPARAM; + } + + for (uint32_t i = 0; i < num_subgraphs; i++) + { + status = FileManReadBuffer(subgraph_cal_table, sizeof(AcdbVcpmSubgraphCalTable), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Module Header.", status); + return status; + } + + if (subgraph_id == subgraph_cal_table->subgraph_id) + { + *file_offset = offset; + found = TRUE; + return AR_EOK; + } + + /* Minus sizeof since + this was read as part of FileManReadBuffer for subgraph_cal_table */ + offset += subgraph_cal_table->table_size - (4 * sizeof(uint32_t)); + } + + status = !found ? AR_ENOTEXIST : status; + + return status; +} + +int32_t GetVcpmMasterKeyTable(AcdbVcpmBlobInfo *vcpm_info, + uint32_t file_offset, AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t master_key_table_file_offset = 0; + uint32_t cal_key_id_table_file_offset = 0; + uint32_t num_keys = 0; + uint32_t num_keys_found = 0; + uint32_t sz_key_table = 0; + ChunkInfo ci_vcpm_master_key = { 0 }; + AcdbVcpmKeyInfo *master_key_list = NULL; + AcdbUintList cal_key_id_list = { 0 }; + uint32_t found_key_index = 0; + AcdbBlob key_bit_check_list = { 0 }; + + ci_vcpm_master_key.chunk_id = ACDB_CHUNKID_VCPM_MASTER_KEY; + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_master_key); + if (AR_FAILED(status)) return status; + + master_key_table_file_offset = ci_vcpm_master_key.chunk_offset + file_offset; + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &master_key_table_file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number " + "of vcpm master keys.", status); + return status; + } + + //determine what keys will actually be in the master key table + status = FileManGetFilePointer2( + (void**)&master_key_list, master_key_table_file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get " + "pointer to vcpm master keys.", status); + return status; + } + + if (vcpm_info->op == ACDB_OP_GET_DATA && num_keys > 0) + { + key_bit_check_list.buf_size = + ACDB_ALIGN_8_BYTE(num_keys); + key_bit_check_list.buf = + ACDB_MALLOC(uint8_t, key_bit_check_list.buf_size); + if (IsNull(key_bit_check_list.buf)) + return AR_ENOMEMORY; + + status = ar_mem_set( + key_bit_check_list.buf, 0, key_bit_check_list.buf_size); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Failed to memset key check list.", status); + goto end; + } + } + + /* determine master key table based on found cal key id tables */ + for (uint32_t i = 0; i < num_keys; i++) + { + for (uint32_t j = 0; j < vcpm_info-> + cal_key_id_table_offset_list.count; j++) + { + cal_key_id_table_file_offset = + vcpm_info->cal_key_id_table_offset_list.list[j]; + + status = FileManReadBuffer( + &cal_key_id_list.count, sizeof(uint32_t), + &cal_key_id_table_file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read num cal key ids.", status); + goto end; + } + + status = FileManGetFilePointer2( + (void**)&cal_key_id_list.list, cal_key_id_table_file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read cal key table.", status); + goto end; + } + + if (0 == AcdbDataBinarySearch2( + cal_key_id_list.list, cal_key_id_list.count * sizeof(uint32_t), + &master_key_list[i].key_id, 1, 1, &found_key_index)) + { + if (vcpm_info->op == ACDB_OP_GET_DATA) + ((uint8_t*)key_bit_check_list.buf)[i] = 1; + num_keys_found++; + break; + } + } + } + + sz_key_table = num_keys_found * sizeof(AcdbVcpmKeyInfo); + + switch (vcpm_info->op) + { + case ACDB_OP_GET_SIZE: + vcpm_info->chunk_master_key.size += sizeof(uint32_t); + + if (sz_key_table > 0) + { + vcpm_info->chunk_master_key.size += sz_key_table; + } + + break; + case ACDB_OP_GET_DATA: + + if (IsNull(rsp->buf)) + { + status = AR_EFAILED; + goto end; + } + + //Write Num Keys + if(vcpm_info->chunk_master_key.offset + + sizeof(uint32_t) > tot_cal_size) + { + status = AR_ENEEDMORE; + goto end; + } + + ACDB_MEM_CPY_SAFE( + (uint8_t*)rsp->buf + vcpm_info->chunk_master_key.offset, + sizeof(uint32_t), &num_keys_found, sizeof(uint32_t)); + vcpm_info->chunk_master_key.offset += sizeof(uint32_t); + + if (sz_key_table == 0) + goto end; + + //Write Chunk data + if (vcpm_info->chunk_master_key.offset + + sz_key_table > tot_cal_size) + { + status = AR_ENEEDMORE; + goto end; + } + + if (num_keys == num_keys_found) + { + //just write the entire table + status = FileManReadBuffer( + (uint8_t*)rsp->buf + vcpm_info->chunk_master_key.offset, + sz_key_table, &master_key_table_file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read " + "number of vcpm master keys.", status); + goto end; + } + } + else + { + //only write the key for the ckv data tables that were found + uint32_t key_offset = 0; + for (uint32_t i = 0; i < num_keys; i++) + { + if (((uint8_t*)key_bit_check_list.buf)[i] == 0) + continue; + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + + vcpm_info->chunk_master_key.offset + key_offset, + sizeof(AcdbVcpmKeyInfo), + &master_key_list[i], sizeof(AcdbVcpmKeyInfo)); + key_offset += sizeof(AcdbVcpmKeyInfo); + } + } + + vcpm_info->chunk_master_key.offset += sz_key_table; + + break; + default: + break; + } + +end: + if (vcpm_info->op == ACDB_OP_GET_DATA) + ACDB_FREE(key_bit_check_list.buf); + + return status; +} + +int32_t IsDefaultVcpmCalibrationKeyIDTable(AcdbVcpmBlobInfo *vcpm_info, + uint32_t table_offset) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_keys = 0; + ChunkInfo ci_vcpm_cal_key = { 0 }; + + ci_vcpm_cal_key.chunk_id = ACDB_CHUNKID_VCPM_CALKEY_TABLE; + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_cal_key); + if (AR_FAILED(status)) + { + ACDB_ERR("Failed to get VCPM Cal Key Table Chunk"); + return status; + } + + offset = ci_vcpm_cal_key.chunk_offset + table_offset; + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of voice calibration keys.", status); + return status; + } + + vcpm_info->is_default_module_ckv = num_keys == 0 ? TRUE : FALSE; + + if (vcpm_info->is_default_module_ckv && + vcpm_info->ignore_get_default_data) + return AR_EOK; + + return status; +} + + +int32_t GetVcpmCalibrationKeyIDTable(AcdbVcpmBlobInfo *vcpm_info, + uint32_t table_offset, AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_keys = 0; + uint32_t sz_key_table = 0; + ChunkInfo ci_vcpm_cal_key = { 0 }; + + ci_vcpm_cal_key.chunk_id = ACDB_CHUNKID_VCPM_CALKEY_TABLE; + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_cal_key); + if (AR_FAILED(status)) + { + ACDB_ERR("Failed to get VCPM Cal Key Table Chunk"); + return status; + } + + offset = ci_vcpm_cal_key.chunk_offset + table_offset; + + if (vcpm_info->op == ACDB_OP_GET_SIZE && + vcpm_info->cal_key_id_table_offset_list.count + + 1 < GLB_BUF_3_LENGTH / 2) + { + vcpm_info->cal_key_id_table_offset_list + .list[vcpm_info->cal_key_id_table_offset_list.count] = offset; + vcpm_info->cal_key_id_table_offset_list.count++; + } + else if (vcpm_info->cal_key_id_table_offset_list.count + + 1 > GLB_BUF_3_LENGTH / 2) + { + ACDB_ERR("Error[%d]: No space to store key id table offsets.", + AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of" + " voice calibration keys.", status); + return status; + } + + sz_key_table = num_keys * sizeof(uint32_t); + + switch (vcpm_info->op) + { + case ACDB_OP_GET_SIZE: + + vcpm_info->chunk_cal_key_id.size += sizeof(uint32_t); + + if (sz_key_table > 0) + { + vcpm_info->chunk_cal_key_id.size += sz_key_table; + } + break; + case ACDB_OP_GET_DATA: + + if (IsNull(rsp->buf)) return AR_EFAILED; + + /* If the Master Key table doesnt have any keys, then it is evident + * that the voice key table is empty. It is a valid scenario if + * num_keys is zero. + */ + + //Write Cal Key Table to Voc Cal Key Chunk + //Write Num Keys + + if ((vcpm_info->chunk_cal_key_id.offset + sizeof(num_keys)) + > tot_cal_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + vcpm_info->chunk_cal_key_id.offset, + sizeof(num_keys), &num_keys, sizeof(num_keys)); + vcpm_info->chunk_cal_key_id.offset += sizeof(num_keys); + + if (sz_key_table > 0) + { + //Write Key IDs + if ((vcpm_info->chunk_cal_key_id.offset + sz_key_table) + > tot_cal_size) + { + return AR_ENEEDMORE; + } + + status = FileManReadBuffer( + (uint8_t*)rsp->buf + vcpm_info->chunk_cal_key_id.offset, + sz_key_table, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read voice calibration keys.", + status); + return status; + } + vcpm_info->chunk_cal_key_id.offset += sz_key_table; + } + break; + default: + break; + } + + return status; +} + +int32_t GetVcpmCalibrationKeyValueTable(AcdbVcpmBlobInfo *vcpm_info, uint32_t table_offset, + AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_keys = 0; + uint32_t sz_key_table = 0; + ChunkInfo ci_vcpm_cal_lut = { 0 }; + + ci_vcpm_cal_lut.chunk_id = ACDB_CHUNKID_VCPM_CALDATA_LUT; + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_cal_lut); + if (AR_FAILED(status)) return status; + + offset = ci_vcpm_cal_lut.chunk_offset + table_offset; + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of voice calibration key values.", status); + return status; + } + + sz_key_table = num_keys * sizeof(uint32_t); + + switch (vcpm_info->op) + { + case ACDB_OP_GET_SIZE: + + vcpm_info->chunk_cal_key_lut.size += sizeof(uint32_t); + + if (sz_key_table > 0) + { + vcpm_info->chunk_cal_key_lut.size += sz_key_table; + } + break; + case ACDB_OP_GET_DATA: + + if (IsNull(rsp->buf)) return AR_EFAILED; + + //Write Num Keys + if ((vcpm_info->chunk_cal_key_lut.offset + sizeof(num_keys)) + > tot_cal_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + vcpm_info->chunk_cal_key_lut.offset, + sizeof(num_keys), &num_keys, sizeof(num_keys)); + vcpm_info->chunk_cal_key_lut.offset += sizeof(num_keys); + + if (sz_key_table > 0) + { + //Write Key Values + offset += sizeof(uint32_t);//num entries is always 1 + if ((vcpm_info->chunk_cal_key_lut.offset + sz_key_table) + > tot_cal_size) + { + return AR_ENEEDMORE; + } + + status = FileManReadBuffer((uint8_t*)rsp->buf + + vcpm_info->chunk_cal_key_lut.offset, sz_key_table, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read voice calibration key values.", status); + return status; + } + vcpm_info->chunk_cal_key_lut.offset += sz_key_table; + } + break; + default: + break; + } + + return status; +} + +int32_t GetVcpmModuleParamPair( + AcdbVcpmBlobInfo *vcpm_info, AcdbMiidPidPair *id_pair, + bool_t *is_offloaded_param, bool_t *should_skip_param, + AcdbVcpmParamInfo *param_info, + uint32_t table_offset, AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + ChunkInfo ci_vcpm_cal_def = { 0 }; + AcdbHwAccelMemType mem_type = ACDB_HW_ACCEL_MEM_TYPE(vcpm_info->proc_id); + AcdbIidRefCount *iid_ref = NULL; + uint32_t proc_domain_id = 0; + + if (IsNull(vcpm_info) || IsNull(id_pair) || + IsNull(param_info) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameter(s) is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_vcpm_cal_def.chunk_id = ACDB_CHUNKID_VCPM_CALDATA_DEF; + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_cal_def); + if (AR_FAILED(status)) return status; + + //Skip num_mid_pid_pairs + offset = ci_vcpm_cal_def.chunk_offset + table_offset + sizeof(uint32_t); + + status = FileManReadBuffer(id_pair, sizeof(AcdbMiidPidPair), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read .", status); + return status; + } + + if (vcpm_info->should_filter_cal_by_proc_domain) + { + status = DataProcGetProcDomainForModule( + vcpm_info->sg_mod_iid_map, + id_pair->module_iid, + &proc_domain_id); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get proccessor domain ID for " + "sg: 0x%x iid: 0x%x", + status, vcpm_info->subgraph_id, id_pair->module_iid); + //return status; + } + + if ((proc_domain_id != ACDB_HW_ACCEL_PROC_ID(vcpm_info->proc_id)) && AR_SUCCEEDED(status)) + { + //go to next parameter + *should_skip_param = TRUE; + return AR_EOK; + } + } + + if (vcpm_info->should_check_hw_accel) + { + status = DataProcIsHwAccelParam(vcpm_info->hw_accel_module_list_offset, + id_pair->module_iid, id_pair->parameter_id); + + *should_skip_param = TRUE; + + switch (mem_type) + { + case ACDB_HW_ACCEL_MEM_DEFAULT: + if (AR_SUCCEEDED(status)) return AR_EOK; + break; + case ACDB_HW_ACCEL_MEM_CMA: + if (AR_FAILED(status)) return AR_EOK; + break; + case ACDB_HW_ACCEL_MEM_BOTH: + /*This should not occur, but is here to resolve a + compiler warning. Not possible since GSL should only + pass in DEFAULT or CMA. Return success to skip param*/ + return AR_EOK; + } + + *should_skip_param = FALSE; + status = AR_EOK; + } + + + iid_ref = (AcdbIidRefCount*)vcpm_info->referenced_iid_list.list; + + if (!vcpm_info->is_default_module_ckv && + !vcpm_info->ignore_iid_list_update) + { + if ((iid_ref)->module_iid != id_pair->module_iid && + vcpm_info->referenced_iid_list.count > 0) + iid_ref += vcpm_info->referenced_iid_list.count - 1; + + //Add IIDs to list and ignore get data + if ((iid_ref)->module_iid != id_pair->module_iid && + vcpm_info->referenced_iid_list.count == 0) + { + (iid_ref)->module_iid = id_pair->module_iid; + (iid_ref)->ref_count = 1; + vcpm_info->referenced_iid_list.count++; + } + else if ((iid_ref)->module_iid != id_pair->module_iid) + { + iid_ref++; + iid_ref->module_iid = id_pair->module_iid; + iid_ref->ref_count = 1; + vcpm_info->referenced_iid_list.count++; + } + else + { + /* Increase ref count of the current Obj */ + (iid_ref)->ref_count++; + } + } + else if (vcpm_info->is_default_module_ckv) + { + /* For default CKVs, if the module is in the default data list, remove it */ + if (!IsNull(vcpm_info->referenced_iid_list.list)) + { + bool_t found_iid = FALSE; + for (uint32_t j = 0; j < vcpm_info-> + referenced_iid_list.count; j++) + { + if ((id_pair->module_iid == iid_ref->module_iid) + && iid_ref->ref_count > 0) + { + iid_ref->ref_count--; + found_iid = TRUE; + break; + } + else if ((id_pair->module_iid == iid_ref->module_iid) + && iid_ref->ref_count <= 0) + { + found_iid = TRUE; + *should_skip_param = TRUE; + return AR_EOK; + } + + iid_ref++; + } + + if (found_iid) + { + *should_skip_param = TRUE; + return AR_EOK; + } + + *should_skip_param = FALSE; + } + } + + if (!IsNull(is_offloaded_param)) + { + /* Defer handling offloaded params until later as long as + * is_offloaded_param is not NULL */ + *is_offloaded_param = (AR_EOK == IsOffloadedParam( + id_pair->parameter_id, &vcpm_info->offloaded_param_list)) + ? TRUE : FALSE; + + if(*is_offloaded_param) + return status; + } + + param_info->is_persistent = + AR_SUCCEEDED( + IsPidPersistent(id_pair->parameter_id) + ) ? 0x1 : 0x0; + + switch (vcpm_info->op) + { + case ACDB_OP_GET_SIZE: + vcpm_info->chunk_data_pool.size += sizeof(AcdbMiidPidPair); + break; + case ACDB_OP_GET_DATA: + if (IsNull(rsp->buf)) return AR_EFAILED; + + if((vcpm_info->chunk_data_pool.offset + sizeof(AcdbMiidPidPair)) + > tot_cal_size) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + vcpm_info->chunk_data_pool.offset, + sizeof(AcdbMiidPidPair), id_pair, sizeof(AcdbMiidPidPair)); + + param_info->offset_vcpm_data_pool = + vcpm_info->chunk_data_pool.offset - + vcpm_info->chunk_data_pool.base_offset; + vcpm_info->chunk_data_pool.offset += sizeof(AcdbMiidPidPair); + break; + default: + break; + } + return status; +} + +int32_t GetVcpmParamPayload( + AcdbVcpmBlobInfo *vcpm_info, AcdbMiidPidPair *id_pair, + AcdbVcpmParamInfo *param_info, bool_t is_offloaded_param, + uint32_t table_offset, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t data_pool_blob_offset = 0; + uint32_t param_size = 0; + uint32_t padded_param_size = 0; + uint32_t padding = 0; + uint32_t error_code = 0; + uint32_t offloaded_param_size_offset = 0; + AcdbBlob blob = { 0 }; + AcdbPayload caldata = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbGraphKeyVector kv = { 0 }; + AcdbDataPersistanceType persist_type = ACDB_DATA_UNKNOWN; + + if (IsNull(vcpm_info) || IsNull(id_pair) || + IsNull(param_info) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameter(s) is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + persist_type = (AcdbDataPersistanceType)param_info->is_persistent; + + if (is_offloaded_param) + { + if (vcpm_info->op == ACDB_OP_GET_SIZE) + offloaded_param_size_offset = + vcpm_info->chunk_data_pool.base_offset + + vcpm_info->chunk_data_pool.size; + else if (vcpm_info->op == ACDB_OP_GET_DATA) + offloaded_param_size_offset = + vcpm_info->chunk_data_pool.offset; + + data_pool_blob_offset = offloaded_param_size_offset; + blob.buf_size = offloaded_param_size_offset; + } + else + { + if (vcpm_info->op == ACDB_OP_GET_SIZE) + data_pool_blob_offset = + vcpm_info->chunk_data_pool.base_offset + + vcpm_info->chunk_data_pool.size; + else if (vcpm_info->op == ACDB_OP_GET_DATA) + data_pool_blob_offset = + vcpm_info->chunk_data_pool.offset; + + //Get data from heap + blob.buf_size = rsp->buf_size; + } + + if(vcpm_info->op == ACDB_OP_GET_SIZE) + blob.buf = NULL; + else if (vcpm_info->op == ACDB_OP_GET_DATA) + blob.buf = rsp->buf; + + acdb_heap_request_t heap_req = { 0 }; + heap_req.persist_type = persist_type; + heap_req.client = ACDB_DATA_ACDB_CLIENT; + heap_req.key_vector = &kv; + heap_req.subgraph_id = vcpm_info->subgraph_id; + heap_req.module_iid = id_pair->module_iid; + heap_req.param_id = id_pair->parameter_id; + heap_req.is_offloaded_param = is_offloaded_param; + heap_req.should_write_iid_pid = FALSE; + heap_req.blob = &blob; + heap_req.blob_offset = data_pool_blob_offset; + + status = DataProcGetHeapSubgraphCalData(&heap_req); + + data_pool_blob_offset = heap_req.blob_offset; + //status = GetSubgraphCalData( + // persist_type, ACDB_DATA_ACDB_CLIENT, + // &kv, vcpm_info->subgraph_id, id_pair->module_iid, + // id_pair->parameter_id, is_offloaded_param, + // &data_pool_blob_offset, &blob); + + if (AR_SUCCEEDED(status)) + { + if (is_offloaded_param) + { + data_pool_blob_offset -= offloaded_param_size_offset; + blob.buf_size -= offloaded_param_size_offset; + } + else + data_pool_blob_offset -= vcpm_info->chunk_data_pool.offset; + + switch (vcpm_info->op) + { + case ACDB_OP_GET_SIZE: + vcpm_info->chunk_data_pool.size += + blob.buf_size; + break; + case ACDB_OP_GET_DATA: + if (IsNull(rsp->buf)) return AR_EFAILED; + vcpm_info->chunk_data_pool.offset += data_pool_blob_offset; + break; + + default: + break; + } + + return status; + } + + status = AR_EOK; + + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool); + if (AR_FAILED(status)) return status; + + offset = ci_data_pool.chunk_offset + table_offset; + status = FileManReadBuffer(¶m_size, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read parameter size.", status); + return status; + } + + + if (is_offloaded_param) + { + uint32_t tmp_dpo = 0; + + if (vcpm_info->op == ACDB_OP_GET_SIZE) + offloaded_param_size_offset = + vcpm_info->chunk_data_pool.base_offset + + vcpm_info->chunk_data_pool.size; + else if (vcpm_info->op == ACDB_OP_GET_DATA) + offloaded_param_size_offset = + vcpm_info->chunk_data_pool.offset; + + //Make room to write param size and error code later + tmp_dpo = offloaded_param_size_offset + 2 * sizeof(uint32_t); + + caldata.size = param_size; + status = FileManGetFilePointer2((void**)&caldata.payload, offset); + + status = GetOffloadedParameterData( + &caldata, ¶m_size, rsp, &tmp_dpo); + if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + return status; + } + else if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + if (vcpm_info->op == ACDB_OP_GET_SIZE) + ACDB_ERR("Error[%d]: No file path provided for offloaded " + "parameter. " + "[0x%x, 0x%x, 0x%x]", status, + vcpm_info->subgraph_id, id_pair->module_iid, + id_pair->parameter_id); + status = AR_EOK; + } + + if (vcpm_info->op == ACDB_OP_GET_DATA) + { + vcpm_info->chunk_data_pool.offset = tmp_dpo; + } + + padded_param_size = + ACDB_ALIGN_8_BYTE(param_size); + } + else + { + padding = ACDB_PADDING_8_BYTE(param_size); + padded_param_size = ACDB_ALIGN_8_BYTE(param_size); + } + + status = AR_EOK; + + switch (vcpm_info->op) + { + case ACDB_OP_GET_SIZE: + //Write size, errorcode, payload + vcpm_info->chunk_data_pool.size += + 2 * sizeof(uint32_t) + padded_param_size; + break; + case ACDB_OP_GET_DATA: + if (IsNull(rsp->buf)) return AR_EFAILED; + + if (is_offloaded_param) + { + ACDB_MEM_CPY_SAFE(rsp->buf + offloaded_param_size_offset, + sizeof(uint32_t), ¶m_size, sizeof(uint32_t)); + offloaded_param_size_offset += sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE(rsp->buf + offloaded_param_size_offset, + sizeof(uint32_t), &error_code, sizeof(uint32_t)); + + return status; + } + + //Param Size + ACDB_MEM_CPY_SAFE(rsp->buf + vcpm_info->chunk_data_pool.offset, + sizeof(uint32_t), ¶m_size, sizeof(uint32_t)); + vcpm_info->chunk_data_pool.offset += sizeof(uint32_t); + + //Error Code + ACDB_MEM_CPY_SAFE(rsp->buf + vcpm_info->chunk_data_pool.offset, + sizeof(uint32_t), &error_code, sizeof(uint32_t)); + vcpm_info->chunk_data_pool.offset += sizeof(uint32_t); + + if (param_size == 0) return status; + + //Payload + status = FileManReadBuffer( + (uint8_t*)rsp->buf + vcpm_info->chunk_data_pool.offset, + (size_t)param_size, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read parameter payload.", status); + return status; + } + vcpm_info->chunk_data_pool.offset += param_size; + + //Padding + ar_mem_set((uint8_t*)rsp->buf + vcpm_info->chunk_data_pool.offset, + 0, padding); + + vcpm_info->chunk_data_pool.offset += padding; + break; + + default: + break; + } + + return status; +} + +int32_t GetVcpmOffloadedData( + AcdbVcpmBlobInfo *vcpm_info, AcdbBlob *rsp, + uint32_t total_cal_size) +{ + int32_t status = AR_EOK; + uint32_t offset_data_pool = 0; + bool_t should_skip_param = FALSE; + AcdbMiidPidPair id_pair = { 0 }; + AcdbVcpmParamInfo param_info = { 0 }; + AcdbUintList datapool_offset_list = { 0 }; + AcdbVcpmOffloadedParamInfo *offloaded_param_info = NULL; + if (IsNull(vcpm_info) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One ore more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + LinkedListNode *opi_node = vcpm_info->offloaded_param_info_list.p_head; + if (vcpm_info->offloaded_param_info_list.length == 0) + return status; + if (IsNull(opi_node) && vcpm_info->offloaded_param_info_list.length > 0) + { + ACDB_ERR("Error[%d]: The offloaded param list is empty although " + "there are %d params in the list", + AR_EBADPARAM, vcpm_info->offloaded_param_info_list.length); + return AR_EBADPARAM; + } + + //keep track of data offsets + uint32_t offset_list_index = 0; + datapool_offset_list.count = vcpm_info->offloaded_param_info_list.length; + datapool_offset_list.list = (uint32_t*)ACDB_MALLOC(AcdbFileToVcpmDataPoolOffsetInfo, datapool_offset_list.count); + + if (datapool_offset_list.list == NULL) + { + ACDB_ERR("Error[%d]: Failed allocate memory", AR_EFAILED); + goto end; + } + + ar_mem_set(datapool_offset_list.list, 0, sizeof(AcdbFileToVcpmDataPoolOffsetInfo) * datapool_offset_list.count); + + vcpm_info->ignore_iid_list_update = TRUE; + + do + { + offloaded_param_info = + (AcdbVcpmOffloadedParamInfo*)opi_node->p_struct; + + bool_t found_existing_offset = FALSE; + AcdbFileToVcpmDataPoolOffsetInfo* offset_pair = NULL; + + /* prevent writing the same payload multiple times in the data pool */ + for (uint32_t i = 0; i < datapool_offset_list.count; i++) + { + offset_pair = (AcdbFileToVcpmDataPoolOffsetInfo*)datapool_offset_list.list + i; + if (offloaded_param_info->file_offset_data_pool == offset_pair->file_offset_data_pool) + { + found_existing_offset = TRUE; + break; + } + } + + if (!found_existing_offset) + { + //Add new entry + offset_pair = (AcdbFileToVcpmDataPoolOffsetInfo*)datapool_offset_list.list + offset_list_index; + offset_pair->file_offset_cal_def = offloaded_param_info->file_offset_cal_def; + offset_pair->file_offset_data_pool = offloaded_param_info->file_offset_data_pool; + offset_list_index++; + } + + if (found_existing_offset) + { + param_info.offset_vcpm_data_pool = offset_pair->vcpm_offset_data_pool; + } + else + { + status = GetVcpmModuleParamPair( + vcpm_info, &id_pair, NULL, &should_skip_param, ¶m_info, + offloaded_param_info->file_offset_cal_def, rsp, total_cal_size); + if (AR_FAILED(status)) + { + goto end; + } + + offset_pair->vcpm_offset_data_pool = param_info.offset_vcpm_data_pool; + + if (should_skip_param) + { + ACDB_ERR("skipped iid: %x pid:%x", id_pair.module_iid, id_pair.parameter_id) + continue; + } + + offset_data_pool = offloaded_param_info->file_offset_data_pool; + status = GetVcpmParamPayload(vcpm_info, &id_pair, ¶m_info, TRUE, + offset_data_pool, rsp); + if (AR_FAILED(status)) + { + goto end; + } + } + + /* Update Param Info for offloaded param in the VCPM Subgraph + * info Chunk */ + if (!IsNull(rsp->buf) && vcpm_info->op == ACDB_OP_GET_DATA) + { + if((offloaded_param_info->blob_offset_vcpm_param_info + + sizeof(AcdbVcpmParamInfo)) > total_cal_size) + return AR_ENEEDMORE; + ACDB_MEM_CPY_SAFE(rsp->buf + offloaded_param_info-> + blob_offset_vcpm_param_info, sizeof(AcdbVcpmParamInfo), + ¶m_info, sizeof(AcdbVcpmParamInfo)); + } + + } while (TRUE != AcdbListSetNext(&opi_node)); + +end: + ACDB_FREE(datapool_offset_list.list); + return status; +} + +int32_t GetVcpmCalDataObject(AcdbVcpmBlobInfo *vcpm_info, uint32_t *cal_obj_size, + uint32_t *table_offset, AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t file_offset = *table_offset; + uint32_t offset_data_pool = 0; + uint32_t offset_vcpm_ckv_lut = 0; + uint32_t total_data_offset_found = 0; + uint32_t tmp_offset = 0; + bool_t is_offloaded_param = FALSE; + bool_t should_skip_param = FALSE; + AcdbVcpmCalDataObj data_obj = { 0 }; + AcdbVcpmParamInfo param_info = { 0 }; + AcdbMiidPidPair id_pair = { 0 }; + LinkedListNode *opi_node = NULL; + AcdbVcpmOffloadedParamInfo *opi = NULL; + + if (IsNull(vcpm_info) || IsNull(cal_obj_size) || IsNull(table_offset) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: Input parameter(s) is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + file_offset = *table_offset; + status = FileManReadBuffer(&data_obj, sizeof(AcdbVcpmCalDataObj), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read cal data object.", status); + return status; + } + + offset_vcpm_ckv_lut = data_obj.offset_vcpm_ckv_lut; + data_obj.offset_vcpm_ckv_lut = vcpm_info->chunk_cal_key_lut.offset; + + /* Write CKV LUT offset and num param payload offsets to + * VCPM Subgraph Info Chunk. + */ + *cal_obj_size += 2 * sizeof(uint32_t);// + if (!IsNull(rsp->buf) && vcpm_info->op == ACDB_OP_GET_DATA) + { + opi_node = vcpm_info->curr_opi_node; + + data_obj.offset_vcpm_ckv_lut -= + vcpm_info->chunk_cal_key_lut.base_offset; + + if (tot_cal_size < (vcpm_info->chunk_subgraph_info.offset + + (2 * sizeof(uint32_t)))) + return AR_ENEEDMORE; + + tmp_offset = vcpm_info->chunk_subgraph_info.offset; + vcpm_info->chunk_subgraph_info.offset += 2 * sizeof(uint32_t); + + //ACDB_MEM_CPY_SAFE(rsp->buf + vcpm_info->chunk_subgraph_info.offset, + // sizeof(uint32_t), &data_obj.offset_vcpm_ckv_lut, sizeof(uint32_t)); + //vcpm_info->chunk_subgraph_info.offset += sizeof(uint32_t); + + //tmp_offset = vcpm_info->chunk_subgraph_info.offset; + + //ACDB_MEM_CPY_SAFE(rsp->buf + vcpm_info->chunk_subgraph_info.offset, + // sizeof(uint32_t), &data_obj.num_data_offsets, sizeof(uint32_t)); + //vcpm_info->chunk_subgraph_info.offset += sizeof(uint32_t); + } + + for (uint32_t i = 0; i < data_obj.num_data_offsets; i++) + { + should_skip_param = FALSE; + + status = GetVcpmModuleParamPair(vcpm_info, &id_pair, + &is_offloaded_param, &should_skip_param , + ¶m_info, data_obj.offset_cal_def, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get %d/%d", + status, i, data_obj.num_data_offsets); + return status; + } + + if (!vcpm_info->ignore_get_default_data && should_skip_param) + { + data_obj.offset_cal_def += sizeof(AcdbMiidPidPair); + file_offset += sizeof(uint32_t); + continue; + } + + if (vcpm_info->should_check_hw_accel && should_skip_param) + { + data_obj.offset_cal_def += sizeof(AcdbMiidPidPair); + file_offset += sizeof(uint32_t); + continue; + } + + *cal_obj_size += sizeof(AcdbVcpmParamInfo); + + status = FileManReadBuffer( + &offset_data_pool, sizeof(uint32_t), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read CalDataObj's data" + " pool offset. Offset %d of %d", + status, i, data_obj.num_data_offsets); + return status; + } + + /* Offloaded parameters are defered till later: when the size of the + * VCPM blob is calculated. These params are added at the end of the + * VCPM datapool. + */ + if (!is_offloaded_param) + { + status = GetVcpmParamPayload( + vcpm_info, &id_pair, ¶m_info, FALSE, offset_data_pool, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get payload for" + " %d/%d", + status, i, data_obj.num_data_offsets); + return status; + } + } + else + { + /* If the param is an offloaded param add its data to the end of the datapool + * Save the offset_data_pool, data_obj.offset_cal_def, and blob offset of the + * CaldataObj.ParamInfo.offset + */ + + if (vcpm_info->op == ACDB_OP_GET_SIZE) + { + opi = ACDB_MALLOC(AcdbVcpmOffloadedParamInfo, 1); + + if (IsNull(opi)) + { + return AR_ENOMEMORY; + } + + opi->file_offset_cal_def = data_obj.offset_cal_def; + opi->file_offset_data_pool = offset_data_pool; + opi->blob_offset_vcpm_param_info = + vcpm_info->chunk_subgraph_info.offset; + + opi_node = AcdbListCreateNode(opi); + if (!IsNull(opi_node)) + { + status = AcdbListAppend( + &vcpm_info->offloaded_param_info_list, + opi_node); + } + + if(IsNull(opi_node)) + return AR_ENOMEMORY; + } + else if (vcpm_info->op == ACDB_OP_GET_DATA) + { + if(IsNull(opi_node)) + return AR_ENOMEMORY; + + opi = (AcdbVcpmOffloadedParamInfo*)opi_node->p_struct; + + if (IsNull(opi)) + { + return AR_EBADPARAM; + } + + opi->file_offset_cal_def = data_obj.offset_cal_def; + opi->file_offset_data_pool = offset_data_pool; + opi->blob_offset_vcpm_param_info = + vcpm_info->chunk_subgraph_info.offset; + + AcdbListSetNext(&opi_node); + vcpm_info->curr_opi_node = opi_node; + } + } + + /* Go to next Global Data Pool Offset within the CalDataObj + * Go to next pair within the Cal Def Table */ + data_obj.offset_cal_def += sizeof(AcdbMiidPidPair); + total_data_offset_found++; + + //Write Param Info to VCPM Subgraph info Chunk + if (!IsNull(rsp->buf) && vcpm_info->op == ACDB_OP_GET_DATA) + { + if (tot_cal_size < (vcpm_info->chunk_subgraph_info.offset + + sizeof(AcdbVcpmParamInfo))) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE(rsp->buf + vcpm_info->chunk_subgraph_info.offset, + sizeof(AcdbVcpmParamInfo), ¶m_info, sizeof(AcdbVcpmParamInfo)); + + vcpm_info->chunk_subgraph_info.offset += sizeof(AcdbVcpmParamInfo); + } + } + + *table_offset = file_offset; + + if (total_data_offset_found == 0) + { + *cal_obj_size = 0; + if(vcpm_info->chunk_subgraph_info.offset > 0 && vcpm_info->op == ACDB_OP_GET_DATA) + vcpm_info->chunk_subgraph_info.offset -= 2 * sizeof(uint32_t); + return status; + } + + //write total number of data offsets found at offset + if (!IsNull(rsp->buf) && vcpm_info->op == ACDB_OP_GET_DATA) + { + data_obj.num_data_offsets = total_data_offset_found; + + //tmp_offset = vcpm_info->chunk_subgraph_info.offset; + + ACDB_MEM_CPY_SAFE(rsp->buf + tmp_offset, + sizeof(uint32_t), &data_obj.offset_vcpm_ckv_lut, sizeof(uint32_t)); + tmp_offset += sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE(rsp->buf + tmp_offset, + sizeof(uint32_t), &data_obj.num_data_offsets, sizeof(uint32_t)); + + //ACDB_MEM_CPY_SAFE(rsp->buf + tmp_offset, + // sizeof(uint32_t), &data_obj.num_data_offsets, sizeof(uint32_t)); + } + + status = GetVcpmCalibrationKeyValueTable(vcpm_info, + offset_vcpm_ckv_lut, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get CKV LUT", status); + return status; + } + + + return status; +} + +int32_t GetVcpmCalibrationDataTable(AcdbVcpmBlobInfo *vcpm_info, + uint32_t *data_table_size, uint32_t *table_offset, bool_t *has_data, + AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t offset_voice_key_table = 0; //file offset + uint32_t table_blob_offset = 0; + uint32_t cal_dot_size = 0; + uint32_t tmp_cal_dot_size = 0; + AcdbVcpmCkvDataTable caldata_table = { 0 }; + + if (IsNull(vcpm_info) || IsNull(data_table_size) || + IsNull(rsp) || IsNull(table_offset)) + { + ACDB_ERR("Error[%d]: Input paramert(s) is null"); + return AR_EBADPARAM; + } + + offset = *table_offset; + status = FileManReadBuffer(&caldata_table, + sizeof(AcdbVcpmCkvDataTable), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Module Header.", status); + return status; + } + + offset_voice_key_table = caldata_table.offset_voice_key_table; + caldata_table.offset_voice_key_table = vcpm_info->chunk_cal_key_id.offset; + + //Write Voc Cal Key Table to Voc Cal Key Chunk + status = IsDefaultVcpmCalibrationKeyIDTable(vcpm_info, + offset_voice_key_table); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read get calibration key id table.", status); + return status; + } + + if (vcpm_info->ignore_get_default_data && vcpm_info->is_default_module_ckv) + { + //skip default ckv table + offset += caldata_table.table_size + + sizeof(uint32_t) - sizeof(AcdbVcpmCkvDataTable); + *table_offset = offset; + return AR_EOK; + } + + //Make room to write header and remember table offset + if (vcpm_info->op == ACDB_OP_GET_DATA) + { + table_blob_offset = vcpm_info->chunk_subgraph_info.offset; + vcpm_info->chunk_subgraph_info.offset += sizeof(caldata_table); + } + + //Clear cal data table size read from acdb and recaculate for VCPM blob + caldata_table.table_size = 0; + uint32_t num_caldata_obj_found = 0; + for (uint32_t i = 0; i < caldata_table.num_caldata_obj; i++) + { + tmp_cal_dot_size = 0; + status = GetVcpmCalDataObject(vcpm_info, &tmp_cal_dot_size, + &offset, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get VCPM Cal" + " Data Object. Skipping..", status); + continue; + } + + if (tmp_cal_dot_size > 0) + { + num_caldata_obj_found++; + cal_dot_size += tmp_cal_dot_size; + } + + /* Ignore adding mmodules to the default iid list since + they only need to be added once */ + if(!vcpm_info->ignore_iid_list_update) + vcpm_info->ignore_iid_list_update = TRUE; + } + + vcpm_info->ignore_iid_list_update = FALSE; + *table_offset = offset; + + //Only write ckv data table if it has data + if (cal_dot_size == 0) + { + if (vcpm_info->is_default_module_ckv) + { + vcpm_info->ignore_get_default_data = TRUE; + } + + if (!IsNull(has_data)) + *has_data = FALSE; + + return AR_EOK; + } + + status = GetVcpmCalibrationKeyIDTable(vcpm_info, + offset_voice_key_table, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read get calibration key id table.", status); + return status; + } + + /* Size of the CKV Data Table is the size of the header: + * + * + Cal Dot Size */ + caldata_table.table_size = 3 * sizeof(uint32_t) + + cal_dot_size; + caldata_table.cal_dot_size = cal_dot_size; + caldata_table.num_caldata_obj = num_caldata_obj_found; + *data_table_size += sizeof(uint32_t) + caldata_table.table_size; + + //Write CKV Data Table Header info to VCPM Subgraph Info Chunk + if (!IsNull(rsp->buf) && vcpm_info->op == ACDB_OP_GET_DATA) + { + caldata_table.offset_voice_key_table -= + vcpm_info->chunk_cal_key_id.base_offset; + + if ((table_blob_offset + sizeof(caldata_table)) > tot_cal_size) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE(rsp->buf + table_blob_offset, + sizeof(caldata_table), &caldata_table, sizeof(caldata_table)); + } + + if(!IsNull(has_data)) + *has_data = TRUE; + + return status; +} + +int32_t GetVcpmSubgraphChunkData(AcdbVcpmBlobInfo *vcpm_info, + uint32_t table_offset, AcdbVcpmSubgraphCalTable *subgraph_cal_table, + AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t chunk_size = 0; + //Number of Subgraphs is always 1 for each VCPM Subgraph Blob + uint32_t num_subgraphs = 1; + uint32_t offset_vcpm_master_key_table = 0; + uint32_t cal_data_table_size = 0; + uint32_t chunk_offset_master_key = + vcpm_info->chunk_master_key.base_offset; + uint32_t chunk_offset_voice_cal_key = + vcpm_info->chunk_cal_key_id.base_offset; + uint32_t chunk_offset_voice_cal_lut = + vcpm_info->chunk_cal_key_lut.base_offset; + uint32_t chunk_offset_data_pool = + vcpm_info->chunk_data_pool.base_offset; + + if (IsNull(vcpm_info) || IsNull(subgraph_cal_table) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + vcpm_info->op = ACDB_OP_GET_DATA; + + //Save the base offset of each chunk so that chunk size can be written + chunk_offset_master_key -= sizeof(chunk_size); + chunk_offset_voice_cal_key -= sizeof(chunk_size); + chunk_offset_voice_cal_lut -= sizeof(chunk_size); + chunk_offset_data_pool -= sizeof(chunk_size); + + /* Write Subgraph Cal Data Table Header to VCPM Subgraph Info + and move blob offset */ + offset_vcpm_master_key_table = + subgraph_cal_table->offset_vcpm_master_key_table; + + if (vcpm_info->ignore_get_default_data && + subgraph_cal_table->num_ckv_data_table > 0) + { + subgraph_cal_table->num_ckv_data_table -= 1; + } + + subgraph_cal_table->offset_vcpm_master_key_table = 0; + subgraph_cal_table->num_ckv_data_table = + vcpm_info->ckv_data_table_offset_list.count; + + if (!IsNull(rsp->buf)) + { + if ((vcpm_info->chunk_subgraph_info.offset + sizeof(uint32_t)) + > tot_cal_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + + vcpm_info->chunk_subgraph_info.offset, + sizeof(uint32_t), &num_subgraphs, sizeof(uint32_t)); + vcpm_info->chunk_subgraph_info.offset += sizeof(uint32_t); + + if ((vcpm_info->chunk_subgraph_info.offset + + sizeof(AcdbVcpmSubgraphCalTable)) + > tot_cal_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + + vcpm_info->chunk_subgraph_info.offset, + sizeof(AcdbVcpmSubgraphCalTable), + subgraph_cal_table, sizeof(AcdbVcpmSubgraphCalTable)); + vcpm_info->chunk_subgraph_info.offset += + sizeof(AcdbVcpmSubgraphCalTable); + } + + status = GetVcpmMasterKeyTable(vcpm_info, + offset_vcpm_master_key_table, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + return status; + } + + vcpm_info->curr_opi_node = vcpm_info->offloaded_param_info_list.p_head; + + for (uint32_t i = 0; i < vcpm_info->ckv_data_table_offset_list.count; i++) + { + table_offset = vcpm_info->ckv_data_table_offset_list.list[i]; + + status = GetVcpmCalibrationDataTable(vcpm_info, &cal_data_table_size, + &table_offset, NULL, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Subgraph(0x%x) - " + "Failed to get Calibration Data Table %d/%d", + vcpm_info->subgraph_id, i, + subgraph_cal_table->num_ckv_data_table); + return status; + } + } + + vcpm_info->is_default_module_ckv = FALSE; + + /*Write Chunk Sizes for mkt, vckt, vclut, and vcpmdp*/ + if (rsp->buf != NULL) + { + if ((chunk_offset_master_key + sizeof(chunk_size)) > tot_cal_size) + return AR_ENEEDMORE; + + chunk_size = vcpm_info->chunk_master_key.size; + ACDB_MEM_CPY_SAFE(rsp->buf + chunk_offset_master_key, + sizeof(chunk_size), &chunk_size, sizeof(chunk_size)); + + if((chunk_offset_voice_cal_key + sizeof(chunk_size)) > tot_cal_size) + return AR_ENEEDMORE; + + chunk_size = vcpm_info->chunk_cal_key_id.size; + ACDB_MEM_CPY_SAFE(rsp->buf + chunk_offset_voice_cal_key, + sizeof(chunk_size), &chunk_size, sizeof(chunk_size)); + + if((chunk_offset_voice_cal_lut + sizeof(chunk_size)) > tot_cal_size) + return AR_ENEEDMORE; + + chunk_size = vcpm_info->chunk_cal_key_lut.size; + ACDB_MEM_CPY_SAFE(rsp->buf + chunk_offset_voice_cal_lut, + sizeof(chunk_size), &chunk_size, sizeof(chunk_size)); + + if((chunk_offset_data_pool + sizeof(chunk_size)) > tot_cal_size) + return AR_ENEEDMORE; + + chunk_size = vcpm_info->chunk_data_pool.size; + ACDB_MEM_CPY_SAFE(rsp->buf + chunk_offset_data_pool, + sizeof(chunk_size), &chunk_size, sizeof(chunk_size)); + } + + return status; +} + +int32_t GetVcpmSubgraphChunkInfo(AcdbVcpmBlobInfo *vcpm_info, + uint32_t table_offset, AcdbVcpmSubgraphCalTable *subgraph_cal_table, + AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t blob_offset = 0; + uint32_t cal_data_table_offset = 0; + bool_t has_data = FALSE; + + vcpm_info->op = ACDB_OP_GET_SIZE; + + //Clear table size read from file and recalculate it based on blob + subgraph_cal_table->table_size = 0; + + /* The default ckv is always the first ckv data table */ + uint32_t default_ckv_table_offset = table_offset; + vcpm_info->ignore_get_default_data = TRUE; + + for (uint32_t i = 0; i < subgraph_cal_table->num_ckv_data_table + 1; i++) + { + if (i == subgraph_cal_table->num_ckv_data_table) + { + vcpm_info->ignore_get_default_data = FALSE; + table_offset = default_ckv_table_offset; + } + else if (i > 0) + { + vcpm_info->ignore_get_default_data = FALSE; + } + + cal_data_table_offset = table_offset; + + status = GetVcpmCalibrationDataTable( + vcpm_info, &subgraph_cal_table->table_size, + &table_offset, &has_data, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + return status; + } + + if (has_data && vcpm_info->ckv_data_table_offset_list.count + + 1 < GLB_BUF_3_LENGTH/2) + { + vcpm_info->ckv_data_table_offset_list + .list[vcpm_info->ckv_data_table_offset_list.count] = + cal_data_table_offset; + vcpm_info->ckv_data_table_offset_list.count++; + } + } + + vcpm_info->is_default_module_ckv = FALSE; + + status = GetVcpmMasterKeyTable(vcpm_info, + subgraph_cal_table->offset_vcpm_master_key_table, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + return status; + } + + //Size of + subgraph_cal_table->table_size += 4 * sizeof(uint32_t); + + vcpm_info->chunk_subgraph_info.size = + sizeof(uint32_t) + //num_subgraphs + sizeof(subgraph_cal_table->subgraph_id) + + sizeof(subgraph_cal_table->table_size) + + subgraph_cal_table->table_size; + + //Calculate Chunk Offsets to use when building the response + blob_offset = vcpm_info->offset_vcpm_blob; + blob_offset += sizeof(AcdbDspModuleHeader);//VCPM Blob Header + + vcpm_info->chunk_subgraph_info.base_offset = blob_offset; + vcpm_info->chunk_subgraph_info.offset = blob_offset; + blob_offset += vcpm_info->chunk_subgraph_info.size; + + vcpm_info->chunk_master_key.base_offset = blob_offset; + vcpm_info->chunk_master_key.offset = blob_offset; + blob_offset += sizeof(uint32_t) + vcpm_info->chunk_master_key.size; + + vcpm_info->chunk_cal_key_id.base_offset = blob_offset; + vcpm_info->chunk_cal_key_id.offset = blob_offset; + blob_offset += sizeof(uint32_t) + vcpm_info->chunk_cal_key_id.size; + + vcpm_info->chunk_cal_key_lut.base_offset = blob_offset; + vcpm_info->chunk_cal_key_lut.offset = blob_offset; + blob_offset += sizeof(uint32_t) + vcpm_info->chunk_cal_key_lut.size; + + vcpm_info->chunk_data_pool.base_offset = blob_offset; + vcpm_info->chunk_data_pool.offset = blob_offset; + + /* Make room to write chunk size */ + vcpm_info->chunk_master_key.base_offset += sizeof(uint32_t); + vcpm_info->chunk_master_key.offset += sizeof(uint32_t); + vcpm_info->chunk_cal_key_id.base_offset += sizeof(uint32_t); + vcpm_info->chunk_cal_key_id.offset += sizeof(uint32_t); + vcpm_info->chunk_cal_key_lut.base_offset += sizeof(uint32_t); + vcpm_info->chunk_cal_key_lut.offset += sizeof(uint32_t); + vcpm_info->chunk_data_pool.base_offset += sizeof(uint32_t); + vcpm_info->chunk_data_pool.offset += sizeof(uint32_t); + + return status; +} + +int32_t BuildVcpmBlob(AcdbVcpmBlobInfo *vcpm_info, + AcdbBlob *rsp, uint32_t tot_cal_size) +{ + int32_t status = AR_EOK; + uint32_t file_offset = 0; + uint32_t vcpm_blob_offset = 0; + uint32_t padding = 0; + uint32_t padded_param_size = 0; + uint32_t prev_data_pool_size = 0; + ChunkInfo ci_vcpm_cal = { 0 }; + AcdbVcpmSubgraphCalHeader subgraph_cal_header = { 0 }; + AcdbDspModuleHeader fwk_module_header = { 0 }; + AcdbVcpmSubgraphCalTable subgraph_cal_table_header = { 0 }; + + if (IsNull(vcpm_info) || IsNull(rsp)) + { + ACDB_DBG("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_vcpm_cal.chunk_id = ACDB_CHUNKID_VCPM_CAL_DATA; + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_cal); + if (AR_FAILED(status)) return status; + + file_offset = ci_vcpm_cal.chunk_offset; + status = FileManReadBuffer(&subgraph_cal_header, + sizeof(AcdbVcpmSubgraphCalHeader), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Module Header.", status); + return status; + } + + //Search for the matching VCPM Subgraph Cal Data Table + status = GetVcpmSubgraphCalTable(subgraph_cal_header.num_subgraphs, + vcpm_info->subgraph_id, &file_offset, &subgraph_cal_table_header); + if (AR_FAILED(status)) + { + return status; + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + vcpm_info->referenced_iid_list.count = 0; + vcpm_info->referenced_iid_list.list = &glb_buf_1[0]; + + /* This lists are small so glb_buff 3 split in half should be good enough */ + ACDB_CLEAR_BUFFER(glb_buf_3); + vcpm_info->cal_key_id_table_offset_list.count = 0; + vcpm_info->cal_key_id_table_offset_list.list = &glb_buf_3[0]; + + vcpm_info->ckv_data_table_offset_list.count = 0; + vcpm_info->ckv_data_table_offset_list.list = &glb_buf_3[GLB_BUF_3_LENGTH/2]; + + status = GetVcpmSubgraphChunkInfo( + vcpm_info, file_offset, &subgraph_cal_table_header, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to calculate vcpm " + "subgraph cal data size", status); + goto end; + } + + prev_data_pool_size = vcpm_info->chunk_data_pool.size; + //Calculate Size of vcpm blob: sizeof(chunk.size) + chunk.size + fwk_module_header.param_size = + vcpm_info->chunk_subgraph_info.size + + sizeof(uint32_t) + vcpm_info->chunk_master_key.size + + sizeof(uint32_t) + vcpm_info->chunk_cal_key_id.size + + sizeof(uint32_t) + vcpm_info->chunk_cal_key_lut.size + + sizeof(uint32_t) + vcpm_info->chunk_data_pool.size; + + /* Get offloaded data size: Add any offloaded parameters at the end + * of the vcpm data pool */ + status = GetVcpmOffloadedData(vcpm_info, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + goto end; + } + + //Recalculate vcpm blob size since the offloaded param size has been added + fwk_module_header.param_size -= prev_data_pool_size; + fwk_module_header.param_size += vcpm_info->chunk_data_pool.size; + + padded_param_size = ACDB_ALIGN_8_BYTE(fwk_module_header.param_size); + padding = padded_param_size - fwk_module_header.param_size; + + rsp->buf_size += padded_param_size; + rsp->buf_size += sizeof(AcdbDspModuleHeader); + + if (IsNull(rsp->buf)) + { + goto end; + } + + status = GetVcpmSubgraphChunkData(vcpm_info, file_offset, + &subgraph_cal_table_header, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + goto end; + } + + /* Get offloaded data: Add any offloaded parameters at the end + * of the vcpm data pool */ + status = GetVcpmOffloadedData(vcpm_info, rsp, tot_cal_size); + if (AR_FAILED(status)) + { + goto end; + } + + //Write VCPM Framework Module Header + fwk_module_header.module_iid = subgraph_cal_header.module_iid; + fwk_module_header.parameter_id = subgraph_cal_header.parameter_id; + if (!IsNull(rsp->buf)) + { + if ((vcpm_info->offset_vcpm_blob + sizeof(AcdbDspModuleHeader)) + > tot_cal_size) + { + status = AR_ENEEDMORE; + goto end; + } + + ACDB_MEM_CPY_SAFE(rsp->buf + vcpm_info->offset_vcpm_blob, + sizeof(AcdbDspModuleHeader), + &fwk_module_header, sizeof(AcdbDspModuleHeader)); + + vcpm_blob_offset += vcpm_info->offset_vcpm_blob + + sizeof(AcdbDspModuleHeader) + fwk_module_header.param_size; + + //Padding + memset((uint8_t*)rsp->buf + vcpm_blob_offset, + 0, padding); + } + +end: + ACDB_CLEAR_BUFFER(glb_buf_1); + AcdbListClear2(&vcpm_info->offloaded_param_info_list, AcdbFree); + + return status; +} + +int32_t AcdbGetSupbgraphCalPersist( + AcdbAudioCalContextInfo *info, uint32_t *blob_offset, + AcdbSgIdPersistCalData* rsp) +{ + int32_t status = AR_EOK; + bool_t found_sg = FALSE; + bool_t has_persist_cal = FALSE; + uint32_t offset = 0; + uint32_t sg_cal_lut_offset = 0; + uint32_t default_ckv_entry_offset = 0; + uint32_t sg_persist_header_offset = 0; + uint32_t sg_persist_cal_offset = 0; + uint32_t num_subgraph = 0; + ChunkInfo ci_sg_cal_lut = { 0 }; + AcdbSgCalLutHeader sg_cal_lut_header = { 0 }; + AcdbCalKeyTblEntry ckv_entry = { 0 }; + AcdbBlob vcpm_blob = { 0 }; + AcdbBlob audio_blob = { 0 }; + AcdbSgIdPersistData sg_persist_data = { 0 }; + + if (IsNull(info) || IsNull(rsp)) + { + ACDB_DBG("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_sg_cal_lut.chunk_id = ACDB_CHUNKID_CALSGLUT; + status = ACDB_GET_CHUNK_INFO(&ci_sg_cal_lut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get Subgraph Calibration LUT " + "chunk information", status); + return status; + } + + offset = ci_sg_cal_lut.chunk_offset; + status = FileManReadBuffer(&num_subgraph, + sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of Subgraphs", + status); + AcdbClearAudioCalContextInfo(info); + return status; + } + + found_sg = FALSE; + audio_blob.buf_size = rsp->cal_data_size; + audio_blob.buf = (void*)rsp->cal_data; + has_persist_cal = FALSE; + + //Get VCPM Subgraph Data + if (info->is_first_time) + { + AcdbVcpmBlobInfo vcpm_info; + int32_t vcpm_status = AR_EOK; + uint32_t vcpm_blob_offset = 0; + + (void)ar_mem_set(&vcpm_info, 0, sizeof(AcdbVcpmBlobInfo)); + + vcpm_blob.buf_size = 0; + vcpm_blob.buf = (void*)rsp->cal_data; + + if (info->op == ACDB_OP_GET_SIZE) + { + rsp->cal_data_size += sizeof(AcdbSgIdPersistData); + sg_persist_cal_offset = rsp->cal_data_size; + } + else if (info->op == ACDB_OP_GET_DATA) + { + vcpm_blob_offset = *blob_offset; + *blob_offset += sizeof(AcdbSgIdPersistData); + sg_persist_cal_offset = *blob_offset; + } + + vcpm_info.offset_vcpm_blob = sg_persist_cal_offset; + vcpm_info.subgraph_id = info->subgraph_id; + vcpm_info.proc_id = info->proc_id; + vcpm_info.should_filter_cal_by_proc_domain = info->should_filter_cal_by_proc_domain; + vcpm_info.sg_mod_iid_map = info->sg_mod_iid_map; + vcpm_info.offloaded_param_list = info->offloaded_parameter_list; + vcpm_info.should_check_hw_accel = info->should_check_hw_accel; + vcpm_info.hw_accel_module_list_offset = + info->hw_accel_module_list_offset; + + vcpm_status = BuildVcpmBlob( + &vcpm_info, &vcpm_blob, rsp->cal_data_size); + if (AR_SUCCEEDED(vcpm_status)) + { + if (info->op == ACDB_OP_GET_SIZE) + { + rsp->cal_data_size += vcpm_blob.buf_size; + sg_persist_cal_offset = 0; + } + else if (info->op == ACDB_OP_GET_DATA) + { + if (rsp->cal_data_size < (vcpm_blob_offset + + sizeof(uint32_t))) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(rsp->cal_data + vcpm_blob_offset, + sizeof(uint32_t), &info->subgraph_id, sizeof(uint32_t)); + vcpm_blob_offset += sizeof(uint32_t); + + if (rsp->cal_data_size < (vcpm_blob_offset + + sizeof(vcpm_blob.buf_size))) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(rsp->cal_data + vcpm_blob_offset, + sizeof(vcpm_blob.buf_size), + &vcpm_blob.buf_size, sizeof(vcpm_blob.buf_size)); + vcpm_blob_offset += sizeof(vcpm_blob.buf_size); + + *blob_offset += vcpm_blob.buf_size; + } + + return vcpm_status; + } + + if (AR_FAILED(vcpm_status) && vcpm_status != AR_ENOTEXIST) + { + return vcpm_status; + } + else + { + if (info->op == ACDB_OP_GET_SIZE) + rsp->cal_data_size -= sizeof(AcdbSgIdPersistData); + else if (info->op == ACDB_OP_GET_DATA) + *blob_offset -= sizeof(AcdbSgIdPersistData); + } + } + + for (uint32_t j = 0; j < num_subgraph; j++) + { + status = FileManReadBuffer(&sg_cal_lut_header, + sizeof(AcdbSgCalLutHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read Subgraph " + "Cal LUT header", status); + } + + if (info->subgraph_id == sg_cal_lut_header.subgraph_id) + { + found_sg = TRUE; + break; + } + else + { + //Go to next Subgraph entry + offset += (sg_cal_lut_header.num_ckv_entries + * sizeof(AcdbCalKeyTblEntry)); + } + } + + if (!found_sg) + { + ACDB_DBG("Error[%d]: Subgraph(%x) does not exist. Skipping..", + AR_ENOTEXIST, info->subgraph_id); + return AR_ENOTEXIST; + } + + if (sg_cal_lut_header.num_ckv_entries == 0) + { + ACDB_DBG("Error[%d]: Subgraph(%x) contains zero CKV entries in" + " the Subgraph Cal LUT. At least one entry should be" + " present. Skipping..", + AR_ENOTEXIST, info->subgraph_id); + return AR_ENOTEXIST; + } + + /* Save starting offset of a subgraphs persist cal. Move the blob + * offset to start at the calibration. If there is no calibration + * move the offset back by subtracting the size of the header and + * skip the subgraph. + */ + if (info->op == ACDB_OP_GET_SIZE) + { + //rsp->cal_data_size += sizeof(AcdbSgIdPersistData); + audio_blob.buf_size += sizeof(AcdbSgIdPersistData); + } + else if (info->op == ACDB_OP_GET_DATA) + { + sg_persist_header_offset = *blob_offset; + *blob_offset += sizeof(AcdbSgIdPersistData); + sg_persist_cal_offset = *blob_offset; + } + + info->ignore_get_default_data = + sg_cal_lut_header.num_ckv_entries == 1 ? FALSE : TRUE; + + //The default CKV will be skipped and handeled last + if (sg_cal_lut_header.num_ckv_entries > 1 && info->is_first_time) + sg_cal_lut_header.num_ckv_entries++; + + for (uint32_t k = 0; k < sg_cal_lut_header.num_ckv_entries; k++) + { + /* The Default CKV is always the first CKV in the list of CKVs to + * search. It will be skipped and processed last */ + if ((k == sg_cal_lut_header.num_ckv_entries - 1) && + info->ignore_get_default_data == TRUE && info->is_first_time) + { + sg_cal_lut_offset = default_ckv_entry_offset; + info->ignore_get_default_data = FALSE; + + status = FileManReadBuffer(&ckv_entry, sizeof(ckv_entry), + &sg_cal_lut_offset); + } + else + { + status = FileManReadBuffer(&ckv_entry, sizeof(ckv_entry), + &offset); + sg_cal_lut_offset = offset; + } + + if (AR_FAILED(status)) + { + AcdbClearAudioCalContextInfo(info); + return status; + } + + info->subgraph_id = sg_cal_lut_header.subgraph_id; + + status = AcdbFindModuleCKV(&ckv_entry, info); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + continue; + } + else if (AR_FAILED(status)) + { + AcdbClearAudioCalContextInfo(info); + return status; + } + + if (info->is_default_module_ckv) + { + default_ckv_entry_offset = + sg_cal_lut_offset - sizeof(ckv_entry); + } + + //Get Calibration + status = AcdbGetSubgraphCalibration( + info, blob_offset, &audio_blob); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + //No calibration found for subgraph with module ckv_entry + //has_persist_cal = FALSE; + continue; + } + else if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: An error occured while getting " + "calibration data for Subgraph(%x)", status, + info->subgraph_id); + AcdbClearAudioCalContextInfo(info); + return status; + } + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + continue; + } + + has_persist_cal = TRUE; + } + + if (AR_FAILED(status) && !has_persist_cal) + { + //if (info->op == ACDB_OP_GET_SIZE) + // rsp->cal_data_size -= sizeof(AcdbSgIdPersistData); + if (info->op == ACDB_OP_GET_DATA) + *blob_offset -= sizeof(AcdbSgIdPersistData); + + if (info->op == ACDB_OP_GET_SIZE) + ACDB_DBG("Warning[%d]: Unable to retrieve calibration data for " + "Subgraph(%x). Skipping..", status, + info->subgraph_id); + } + else + { + status = AR_EOK; + + if (info->op == ACDB_OP_GET_SIZE) + rsp->cal_data_size = audio_blob.buf_size; + else if (info->op == ACDB_OP_GET_DATA) + { + //Write subgraph persist data header + sg_persist_data.sg_id = info->subgraph_id; + //sg_persist_data.persist_data_size = audio_blob.buf_size; + sg_persist_data.persist_data_size = + *blob_offset - sg_persist_cal_offset; + + if (rsp->cal_data_size < (sg_persist_header_offset + + sizeof(AcdbSgIdPersistData))) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(rsp->cal_data + sg_persist_header_offset, + sizeof(AcdbSgIdPersistData), + &sg_persist_data, sizeof(AcdbSgIdPersistData)); + } + } + + return status; +} + +int32_t AcdbCmdGetSubgraphCalDataPersist( + AcdbSgIdCalKeyVector* req, AcdbSgIdPersistCalData* rsp) +{ + int32_t status = AR_EOK; + uint32_t blob_offset = 0; + AcdbAudioCalContextInfo info; + AcdbUintList subgraph_list = { 0 }; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + subgraph_list.count = req->num_sg_ids; + subgraph_list.list = req->sg_ids; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + (void)ar_mem_set(&info, 0, sizeof(AcdbAudioCalContextInfo)); + + rsp->num_sg_ids = 0; + + if (rsp->cal_data_size > 0 && !IsNull(rsp->cal_data)) + { + info.op = ACDB_OP_GET_DATA; + memset(rsp->cal_data, 0, rsp->cal_data_size); + } + else + info.op = ACDB_OP_GET_SIZE; + + if (info.op == ACDB_OP_GET_SIZE) + { + //Log CKV when this API is called for the first time + ACDB_DBG("Retrieving persistent calibration for " + "the following cal key vector:"); + ACDB_DBG("CKV[new]:"); + LogKeyVector(&req->cal_key_vector_new, CAL_KEY_VECTOR); + ACDB_DBG("CKV[old]:"); + LogKeyVector(&req->cal_key_vector_prior, CAL_KEY_VECTOR); + } + + /* CKV Setup + * 1. GLB_BUF_2 stores the module CKV that will be used to locate data in + * the heap(if it exists) + * 2. The Delta CKV and CKV[New] are allocated on the heap by + * AcdbComputeDeltaCKV + * + * tmp - stores the amount of padding after graph_key_vectornum_keys + * tmp2 - stores the position of the KeyValuePair list + * + * The first info->module_ckv->graph_key_vector assignment has the effect + * of storing the address of the pointer in glb_buf_2 after + * graph_key_vector.num_keys + * + * The second info->module_ckv->graph_key_vector assignment has the effect + * of pointer the info->module_ckv->graph_key_vector to the actual list + * of key value pairs + * + * Whats inside global buffer 2 after these operations? + * + * The first 'sizeof(AcdbGraphKeyVector)' bytes is AcdbGraphKeyVector + * followed by 'sizeof(AcdbKeyValuePair) * num_keys' bytes which is + * the KV list + */ + info.module_ckv = (AcdbGraphKeyVector*)&glb_buf_2[0]; + uint32_t tmp = (sizeof(AcdbGraphKeyVector) + - sizeof(AcdbKeyValuePair*)) / sizeof(uint32_t); + uint32_t tmp2 = sizeof(AcdbGraphKeyVector) / sizeof(uint32_t); + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp]; + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp2]; + info.should_check_hw_accel = FALSE; + info.param_type = ACDB_DATA_PERSISTENT; + + status = AcdbComputeDeltaCKV( + &req->cal_key_vector_new, + &req->cal_key_vector_prior, &info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get the delta CKV", status); + AcdbClearAudioCalContextInfo(&info); + return status; + } + + (void)GetOffloadedParamList(&info.offloaded_parameter_list); + if (info.offloaded_parameter_list.count == 0) + { + ACDB_DBG("Error[%d]: No offloaded parameters found. Skipping..", + status); + } + + for (uint32_t i = 0; i < req->num_sg_ids; i++) + { + status = AR_EOK; + info.subgraph_id = req->sg_ids[i]; + + status = AcdbGetSupbgraphCalPersist( + &info, &blob_offset, rsp); + if (status == AR_ENOTEXIST) + { + ACDB_DBG("Error[%d]: No calibration found for Subraph(0x%x)", + status, info.subgraph_id); + status = AR_EOK; + continue; + } + else if (AR_FAILED(status)) + break; + + rsp->num_sg_ids++; + } + + if (rsp->num_sg_ids == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: No calibration found", status); + } + + AcdbClearAudioCalContextInfo(&info); + + return status; +} + +int32_t AcdbCmdGetHwAccelInfo( + AcdbHwAccelSubgraphInfoReq* req, AcdbHwAccelSubgraphInfoRsp* rsp) +{ + int32_t status = AR_EOK; + uint32_t current_size = 0; + uint32_t expected_size = 0; + uint32_t num_subgraphs_found = 0; + AcdbHwAccelSubgraphInfo hw_accel_sg_info = { 0 }; + AcdbOp op = IsNull(rsp->subgraph_list) ? + ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->subgraph_list.count == 0) + { + ACDB_ERR("Error[%d]: The subgraph list is empty", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &req->subgraph_list, sizeof(AcdbUintList), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + expected_size = rsp->list_size; + + for (uint32_t i = 0; i < req->subgraph_list.count; i++) + { + hw_accel_sg_info.subgraph_id = req->subgraph_list.list[i]; + + status = DataProcGetHwAccelSubgraphInfo(&hw_accel_sg_info); + if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + break; + } + + if (op == ACDB_OP_GET_SIZE) + { + rsp->list_size += sizeof(AcdbHwAccelSubgraph); + rsp->num_subgraphs = ++num_subgraphs_found; + + if (AR_ENOTEXIST == status) + { + status = AR_EOK; + } + } + else if (op == ACDB_OP_GET_DATA && !IsNull(rsp->subgraph_list)) + { + if (current_size > expected_size) + { + return AR_ENEEDMORE; + } + + rsp->subgraph_list[i].subgraph_id = hw_accel_sg_info.subgraph_id; + rsp->subgraph_list[i].mem_type = hw_accel_sg_info.mem_type; + + if (AR_ENOTEXIST == status) + { + rsp->subgraph_list[i].mem_type = ACDB_HW_ACCEL_MEM_DEFAULT; + status = AR_EOK; + } + + current_size += sizeof(AcdbHwAccelSubgraph); + } + } + + return status; +} + +int32_t AcdbCmdGetProcSubgraphCalDataPersist( + AcdbProcSubgraphPersistCalReq *req, AcdbSgIdPersistCalData *rsp) +{ + int32_t status = AR_EOK; + uint32_t blob_offset = 0; + AcdbHwAccelSubgraphInfo hw_accel_sg_info = { 0 }; + AcdbAudioCalContextInfo info; + AcdbHwAccelMemType mem_type = ACDB_HW_ACCEL_MEM_DEFAULT; + AcdbUintList subgraph_list = { 0 }; + AcdbSubgraphPdmMap sg_mod_iid_map = { 0 }; + + //mask out mem type + //uint32_t proc_id_mask = 0x3FFFFFFF; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + for (uint32_t i = 0; i < req->num_subgraphs; i++) + { + glb_buf_3[i] = req->subgraph_list->subgraph_id; + } + + subgraph_list.count = req->num_subgraphs; + subgraph_list.list = &glb_buf_3[0]; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + ACDB_CLEAR_BUFFER(glb_buf_3); + + (void)ar_mem_set(&info, 0, sizeof(AcdbAudioCalContextInfo)); + + //we should filter calibration based on proc in this api + info.should_filter_cal_by_proc_domain = TRUE; + rsp->num_sg_ids = 0; + + if (rsp->cal_data_size > 0 && !IsNull(rsp->cal_data)) + { + info.op = ACDB_OP_GET_DATA; + memset(rsp->cal_data, 0, rsp->cal_data_size); + } + else + info.op = ACDB_OP_GET_SIZE; + + if (info.op == ACDB_OP_GET_SIZE) + { + //Log CKV when this API is called for the first time + ACDB_DBG("Retrieving processor-based persistent calibration for " + "the following cal key vector:"); + ACDB_DBG("CKV[new]:"); + LogKeyVector(&req->cal_key_vector_new, CAL_KEY_VECTOR); + ACDB_DBG("CKV[old]:"); + LogKeyVector(&req->cal_key_vector_prior, CAL_KEY_VECTOR); + } + + /* CKV Setup + * 1. GLB_BUF_2 stores the module CKV that will be used to locate data in + * the heap(if it exists) + * 2. The Delta CKV and CKV[New] are allocated on the heap by + * AcdbComputeDeltaCKV + * + * tmp - stores the amount of padding after graph_key_vectornum_keys + * tmp2 - stores the position of the KeyValuePair list + * + * The first info->module_ckv->graph_key_vector assignment has the effect + * of storing the address of the pointer in glb_buf_2 after + * graph_key_vector.num_keys + * + * The second info->module_ckv->graph_key_vector assignment has the effect + * of pointer the info->module_ckv->graph_key_vector to the actual list + * of key value pairs + * + * Whats inside global buffer 2 after these operations? + * + * The first 'sizeof(AcdbGraphKeyVector)' bytes is AcdbGraphKeyVector + * followed by 'sizeof(AcdbKeyValuePair) * num_keys' bytes which is + * the KV list + */ + info.module_ckv = (AcdbGraphKeyVector*)&glb_buf_2[0]; + uint32_t tmp = (sizeof(AcdbGraphKeyVector) + - sizeof(AcdbKeyValuePair*)) / sizeof(uint32_t); + uint32_t tmp2 = sizeof(AcdbGraphKeyVector) / sizeof(uint32_t); + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp]; + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp2]; + info.should_check_hw_accel = TRUE; + info.param_type = ACDB_DATA_PERSISTENT; + + status = AcdbComputeDeltaCKV( + &req->cal_key_vector_new, + &req->cal_key_vector_prior, &info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get the delta CKV", status); + AcdbClearAudioCalContextInfo(&info); + return status; + } + + (void)GetOffloadedParamList(&info.offloaded_parameter_list); + if (info.offloaded_parameter_list.count == 0) + { + ACDB_DBG("Warning[%d]: No offloaded parameters found. Skipping..", + status); + } + + for (uint32_t i = 0; i < req->num_subgraphs; i++) + { + status = AR_EOK; + info.subgraph_id = req->subgraph_list[i].subgraph_id; + info.proc_id = req->subgraph_list[i].proc_id; + + hw_accel_sg_info.subgraph_id = info.subgraph_id; + mem_type = ACDB_HW_ACCEL_MEM_TYPE(info.proc_id); + + status = DataProcGetHwAccelSubgraphInfo(&hw_accel_sg_info); + if (AR_FAILED(status) && mem_type == ACDB_HW_ACCEL_MEM_CMA) + { + status = AR_EOK; + continue; + } + + info.hw_accel_module_list_offset = + hw_accel_sg_info.module_list_offset; + + status = DataProcGetSubgraphProcIidMap(info.subgraph_id, &sg_mod_iid_map); + if (AR_EOK != status) + { + //Return even if it can't find data for one of the given subgraphs + goto end; + } + + info.sg_mod_iid_map = &sg_mod_iid_map; + + status = AcdbGetSupbgraphCalPersist( + &info, &blob_offset, rsp); + if (status == AR_ENOTEXIST) + { + ACDB_DBG("Warning[%d]: No calibration found for Subraph(0x%x)", + status, info.subgraph_id); + status = AR_EOK; + continue; + } + else if (AR_FAILED(status)) + break; + + rsp->num_sg_ids++; + } + +end: + + if (rsp->num_sg_ids == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: No calibration found", status); + } + + AcdbClearAudioCalContextInfo(&info); + + return status; +} + +/* TODO: This api needs to be supported when the ACDB file supports global +* persistent data. This API also needs to be refactored and follow the +* approach used in AcdbCmdGetSubgraphCalNonPersist +*/ +// int32_t AcdbCmdGetSubgraphGlbPersistIds(AcdbSgIdCalKeyVector *pInput, AcdbGlbPsistIdentifierList *pOutput, uint32_t rsp_struct_size) +// { +// __UNREFERENCED_PARAM(pInput); +// __UNREFERENCED_PARAM(pOutput); +// __UNREFERENCED_PARAM(rsp_struct_size); +// return AR_ENOTEXIST; +// } + +/* TODO: This api needs to be supported when the ACDB file supports global + * persistent data. This API also needs to be refactored and follow the + * approach used in AcdbCmdGetSubgraphCalNonPersist + */ +//int32_t AcdbCmdGetSubgraphGlbPersistIds(AcdbSgIdCalKeyVector *pInput, AcdbGlbPsistIdentifierList *pOutput, uint32_t rsp_struct_size) +//{ +// int32_t result = AR_EOK; +// uint32_t entryCnt = 0; +// uint32_t chkBuf = 0; +// uint32_t chkLen = 0; +// uint32_t sgLutChkBuf = 0; +// uint32_t sgLutChkLen = 0; +// uint32_t calKeyChkBuf = 0; +// uint32_t calKeyChkLen = 0; +// uint32_t calLutChkBuf = 0; +// uint32_t calLutChkLen = 0; +// uint32_t calDef2ChkBuf = 0; +// uint32_t calDef2ChkLen = 0; +// uint32_t pidMapChkBuf = 0; +// uint32_t pidMapChkLen = 0; +// uint32_t offset = 0; +// uint32_t data_offset = 0; +// size_t totalsize = 0; +// uint32_t calKeyTblOffset = 0; +// uint32_t calDataTblOffset = 0; +// uint32_t calDataDefOffset = 0; +// bool_t found = FALSE; +// bool_t key_found = FALSE; +// bool_t first_time = FALSE; +// uint32_t* iid_list = NULL; +// +// ACDB_PKT_LOG_DATA("NumSGIDs", &pInput->num_sg_ids, sizeof(pInput->num_sg_ids)); +// ACDB_PKT_LOG_DATA("SGIDs", pInput->sg_ids, sizeof(pInput->sg_ids) * pInput->num_sg_ids); +// ACDB_PKT_LOG_DATA("CKVPrior_NumKeys", &pInput->cal_key_vector_prior.num_keys, sizeof(pInput->cal_key_vector_prior.num_keys)); +// if (pInput->cal_key_vector_prior.num_keys != 0) +// ACDB_PKT_LOG_DATA("CKVPrior_KV", pInput->cal_key_vector_prior.graph_key_vector, sizeof(pInput->cal_key_vector_prior.graph_key_vector) * pInput->cal_key_vector_prior.num_keys); +// ACDB_PKT_LOG_DATA("CKVNew_NumKeys", &pInput->cal_key_vector_new.num_keys, sizeof(pInput->cal_key_vector_new.num_keys)); +// if (pInput->cal_key_vector_new.num_keys != 0) +// ACDB_PKT_LOG_DATA("CKVNew_KV", pInput->cal_key_vector_new.graph_key_vector, sizeof(pInput->cal_key_vector_new.graph_key_vector) * pInput->cal_key_vector_new.num_keys); +// +// if (rsp_struct_size < 12) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, rsp_struct_size is invalid"); +// return AR_EBADPARAM; +// } +// +// if (pInput->cal_key_vector_prior.num_keys == 0) +// first_time = TRUE; +// +// AcdbGraphKeyVector* deltaKV = (AcdbGraphKeyVector*)malloc(sizeof(AcdbGraphKeyVector)); +// if (deltaKV == NULL) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, Insufficient memory to allocate deltaKV"); +// return AR_ENOMEMORY; +// } +// +// if (pInput->cal_key_vector_prior.num_keys == 0) +// { +// first_time = TRUE; +// deltaKV->num_keys = pInput->cal_key_vector_new.num_keys; +// deltaKV->graph_key_vector = (AcdbKeyValuePair*)malloc(2 * sizeof(uint32_t) * deltaKV->num_keys); +// if (IsNull(deltaKV->graph_key_vector)) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, Insufficient memory to allocate deltaKV->graph_key_vector"); +// return AR_ENOMEMORY; +// } +// +// for (uint32_t i = 0; i < deltaKV->num_keys; i++) +// { +// deltaKV->graph_key_vector[i].key = pInput->cal_key_vector_new.graph_key_vector[i].key; +// deltaKV->graph_key_vector[i].value = pInput->cal_key_vector_new.graph_key_vector[i].value; +// } +// } +// else +// { +// //compute delta KV (from prior and new) and number of keys +// if (pInput->cal_key_vector_prior.num_keys != pInput->cal_key_vector_new.num_keys) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, calkeyvectorprior - num of keys do not match calkeyvectornew - num of keys"); +// return AR_EFAILED; +// } +// uint32_t cnt = 0; +// for (uint32_t i = 0; i < pInput->cal_key_vector_prior.num_keys; i++) +// { +// if (pInput->cal_key_vector_prior.graph_key_vector[i].value != pInput->cal_key_vector_new.graph_key_vector[i].value) +// cnt++; +// } +// deltaKV->num_keys = cnt; +// deltaKV->graph_key_vector = (AcdbKeyValuePair*)malloc(2 * sizeof(uint32_t) * cnt); +// if (IsNull(deltaKV->graph_key_vector)) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, Insufficient memory to allocate deltaKV->graph_key_vector"); +// return AR_ENOMEMORY; +// } +// +// cnt = 0; +// for (uint32_t i = 0; i < pInput->cal_key_vector_prior.num_keys; i++) +// { +// if (pInput->cal_key_vector_prior.graph_key_vector[i].value != pInput->cal_key_vector_new.graph_key_vector[i].value) +// { +// deltaKV->graph_key_vector[cnt].key = pInput->cal_key_vector_new.graph_key_vector[i].key; +// deltaKV->graph_key_vector[cnt].value = pInput->cal_key_vector_new.graph_key_vector[i].value; +// cnt++; +// } +// } +// } +// +// ACDB_PKT_LOG_DATA("deltaNumKeys", &deltaKV->num_keys, sizeof(deltaKV->num_keys)); +// ACDB_PKT_LOG_DATA("deltaKV", &deltaKV->graph_key_vector, sizeof(deltaKV->graph_key_vector) * deltaKV->num_keys); +// +// result = AcdbGetChunkInfo(ACDB_CHUNKID_CALSGLUT, &sgLutChkBuf, &sgLutChkLen); +// if (result != AR_EOK) +// return result; +// +// result = AcdbGetChunkInfo(ACDB_CHUNKID_CALKEYTBL, &calKeyChkBuf, &calKeyChkLen); +// if (result != AR_EOK) +// return result; +// +// result = AcdbGetChunkInfo(ACDB_CHUNKID_CALDATALUT, &calLutChkBuf, &calLutChkLen); +// if (result != AR_EOK) +// return result; +// +// result = AcdbGetChunkInfo(ACDB_CHUNKID_CALDATADEF, &calDef2ChkBuf, &calDef2ChkLen); +// if (result != AR_EOK) +// return result; +// +// result = AcdbGetChunkInfo(ACDB_CHUNKID_PIDPERSIST, &pidMapChkBuf, &pidMapChkLen); +// if (result != AR_EOK) +// return result; +// +// result = AcdbGetChunkInfo(ACDB_CHUNKID_DATAPOOL, &chkBuf, &chkLen); +// if (result != AR_EOK) +// return result; +// +// for (uint32_t i = 0;i < pInput->num_sg_ids;i++) +// { +// uint32_t sgID = pInput->sg_ids[i]; +// offset = sizeof(uint32_t); //ignore num of SGID's in ACDB_CHUNKID_CALSGLUT chunk +// found = FALSE; +// do +// { +// memset(&glb_buf_1, 0, sizeof(glb_buf_1)); +// int ret = file_seek(sgLutChkBuf + offset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", sgLutChkBuf + offset); +// return AR_EFAILED; +// } +// ret = file_read(&glb_buf_1, 2 * sizeof(uint32_t)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, sgID read was unsuccessful"); +// return AR_EFAILED; +// } +// +// if (memcmp(&sgID, &glb_buf_1[0], sizeof(sgID)) == 0) +// { +// found = TRUE; +// uint32_t num_cktbl_entries = glb_buf_1[1]; +// offset = offset + (2 * sizeof(uint32_t)); +// for (uint32_t j = 0; j < num_cktbl_entries;j++) +// { +// memset(&glb_buf_1, 0, sizeof(glb_buf_1)); +// ret = file_seek(sgLutChkBuf + offset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", sgLutChkBuf + offset); +// return AR_EFAILED; +// } +// ret = file_read(&glb_buf_1, 2 * sizeof(uint32_t)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, calKeyTblOffset read was unsuccessful"); +// return AR_EFAILED; +// } +// +// offset = offset + (2 * sizeof(uint32_t)); +// calKeyTblOffset = glb_buf_1[0]; +// calDataTblOffset = glb_buf_1[1]; +// +// ACDB_PKT_LOG_DATA("calKeyTblOffset", &calKeyTblOffset, sizeof(calKeyTblOffset)); +// ACDB_PKT_LOG_DATA("calDataTblOffset", &calDataTblOffset, sizeof(calDataTblOffset)); +// +// if (calKeyTblOffset == 0xffffffff && !first_time) +// continue; +// else +// { +// if (calKeyTblOffset != 0xffffffff) +// { +// uint32_t num_keys = 0; +// memset(&glb_buf_1, 0, sizeof(glb_buf_1)); +// ret = file_seek(calKeyChkBuf + calKeyTblOffset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calKeyChkBuf + calKeyTblOffset); +// return AR_EFAILED; +// } +// ret = file_read(&num_keys, sizeof(uint32_t)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, num of keys read was unsuccessful"); +// return AR_EFAILED; +// } +// +// ret = file_seek(calKeyChkBuf + calKeyTblOffset + sizeof(num_keys), AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calKeyChkBuf + calKeyTblOffset + sizeof(num_keys)); +// return AR_EFAILED; +// } +// +// if (num_keys > 0) +// { +// ret = file_read(&glb_buf_1, num_keys * sizeof(num_keys)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, keys read was unsuccessful"); +// return AR_EFAILED; +// } +// } +// +// //perform SG key validation with CKV->keys provided, if SG key doesn't exist in CKV, flag an error, since the input is invalid +// for (uint32_t k = 0; k < num_keys; k++) +// { +// key_found = FALSE; +// for (uint32_t l = 0; l < deltaKV->num_keys; l++) +// { +// if (glb_buf_1[k] == deltaKV->graph_key_vector[l].key) +// { +// key_found = TRUE; +// break; +// } +// } +// if (!key_found) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, key doesn't exist %d", glb_buf_1[i]); +// return AR_EFAILED; +// } +// +// } +// } +// +// uint32_t num_entries = 0; +// uint32_t num_values = 0; +// memset(&glb_buf_2, 0, sizeof(glb_buf_2)); +// ret = file_seek(calLutChkBuf + calDataTblOffset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calLutChkBuf + calDataTblOffset); +// return AR_EFAILED; +// } +// ret = file_read(&num_entries, sizeof(uint32_t)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, num of entries read was unsuccessful"); +// return AR_EFAILED; +// } +// +// ret = file_seek(calLutChkBuf + calDataTblOffset + sizeof(num_entries), AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calLutChkBuf + calDataTblOffset + sizeof(num_entries)); +// return AR_EFAILED; +// } +// ret = file_read(&num_values, sizeof(uint32_t)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, num of values read was unsuccessful"); +// return AR_EFAILED; +// } +// +// ret = file_seek(calLutChkBuf + calDataTblOffset + sizeof(num_entries) + sizeof(num_values), AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calLutChkBuf + calDataTblOffset + sizeof(num_entries) + sizeof(num_values)); +// return AR_EFAILED; +// } +// ret = file_read(&glb_buf_2, num_entries * ((num_values * sizeof(uint32_t)) + (3 * sizeof(uint32_t)))); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, values read was unsuccessful"); +// return AR_EFAILED; +// } +// +// ACDB_PKT_LOG_DATA("NumEntries", &num_entries, sizeof(num_entries)); +// ACDB_PKT_LOG_DATA("NumValues", &num_values, sizeof(num_values)); +// ACDB_PKT_LOG_DATA("Values", &glb_buf_2, num_entries * ((num_values * sizeof(uint32_t)) + (3 * sizeof(uint32_t)))); +// +// uint32_t temp_offset = 0; +// uint32_t marked_offset = 0; +// +// for (uint32_t k = 0; k < num_entries; k++, temp_offset += 4) +// { +// for (uint32_t m = 0;m < num_values; m++, temp_offset++) +// { +// key_found = FALSE; +// for (uint32_t n = 0;n < deltaKV->num_keys;n++) +// { +// if (glb_buf_1[m] == deltaKV->graph_key_vector[n].key && glb_buf_2[temp_offset] == deltaKV->graph_key_vector[n].value) +// { +// marked_offset = temp_offset; +// key_found = TRUE; +// } +// } +// } +// } +// if (!key_found && !first_time) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, value doesn't exist"); +// return AR_EFAILED; //return error is there is one mis-match +// } +// +// calDataDefOffset = glb_buf_2[marked_offset + 3]; //DEF2 offset +// +// ACDB_PKT_LOG_DATA("calDataDefOffset", &calDataDefOffset, sizeof(calDataDefOffset)); +// +// ret = file_seek(calDef2ChkBuf + calDataDefOffset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calDef2ChkBuf + calDataDefOffset); +// return AR_EFAILED; +// } +// ret = file_read(&num_entries, sizeof(uint32_t)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, DEF2 offset read was unsuccessful"); +// return AR_EFAILED; +// } +// +// calDataDefOffset += sizeof(uint32_t); //num of entries +// ret = file_seek(calDef2ChkBuf + calDataDefOffset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calDef2ChkBuf + calDataDefOffset); +// return AR_EFAILED; +// } +// +// do +// { +// +// uint32_t pid = 0; +// uint32_t num_of_iids = 0; +// uint32_t cal_ID = 0; +// ret = file_read(&cal_ID, sizeof(uint32_t)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, calId read was unsuccessful"); +// return AR_EFAILED; +// } +// +// calDataDefOffset += sizeof(uint32_t); //calID value; +// +// ret = file_seek(calDef2ChkBuf + calDataDefOffset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calDef2ChkBuf + calDataDefOffset); +// return AR_EFAILED; +// } +// ret = file_read(&pid, sizeof(pid)); // pid +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, pid read was unsuccessful"); +// return AR_EFAILED; +// } +// +// calDataDefOffset += sizeof(pid); //pid value; +// +// ret = file_seek(calDef2ChkBuf + calDataDefOffset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calDef2ChkBuf + calDataDefOffset); +// return AR_EFAILED; +// } +// ret = file_read(&num_of_iids, sizeof(num_of_iids)); // num of iid's +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, num of iid's read was unsuccessful"); +// return AR_EFAILED; +// } +// +// iid_list = (uint32_t*)malloc(sizeof(uint32_t) * num_of_iids); +// if (iid_list == NULL) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, cannot allocate memory for iid_list"); +// return AR_ENOMEMORY; +// } +// +// calDataDefOffset += sizeof(uint32_t); // num of iid's +// uint32_t iid_offset = 0; +// for (uint32_t r = 0; r < num_of_iids; r++) +// { +// memset(&glb_buf_3, 0, sizeof(glb_buf_3)); +// ret = file_seek(calDef2ChkBuf + calDataDefOffset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, file seek to %d was unsuccessful", calDef2ChkBuf + calDataDefOffset); +// return AR_EFAILED; +// } +// ret = file_read(&glb_buf_3, sizeof(uint32_t)); // iid value; +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistIds() failed, iid value read was unsuccessful"); +// return AR_EFAILED; +// } +// +// ACDB_MEM_CPY(&iid_list + iid_offset, &glb_buf_3, sizeof(uint32_t)); +// iid_offset += sizeof(uint32_t); +// calDataDefOffset += sizeof(uint32_t); +// } +// +// totalsize += sizeof(cal_ID) + sizeof(num_of_iids); +// totalsize += sizeof(iid_list); +// +// if (pOutput->global_persistent_cal_info != NULL) +// { +// if (pOutput->size >= (data_offset + (2 * sizeof(uint32_t)))) +// { +// ACDB_MEM_CPY(pOutput->global_persistent_cal_info + data_offset, &cal_ID, sizeof(cal_ID)); +// data_offset += sizeof(cal_ID); +// ACDB_MEM_CPY(pOutput->global_persistent_cal_info + data_offset, &num_of_iids, sizeof(num_of_iids)); +// data_offset += sizeof(num_of_iids); +// } +// else +// { +// return AR_ENEEDMORE; +// } +// for (uint32_t r = 0; r < num_of_iids; r++) +// { +// if (pOutput->size >= (data_offset + sizeof(uint32_t))) +// { +// ACDB_MEM_CPY(pOutput->global_persistent_cal_info + data_offset, &iid_list[r], sizeof(uint32_t)); +// } +// else +// { +// return AR_ENEEDMORE; +// } +// data_offset += sizeof(uint32_t); +// } +// } +// +// entryCnt++; +// } while (entryCnt < num_entries); +// +// } +// +// } +// } +// else +// { +// offset = offset + (2 * sizeof(uint32_t) + (2 * sizeof(uint32_t) * glb_buf_1[1])); +// } +// } while (offset < sgLutChkLen && !found); +// } +// if (iid_list != NULL) +// free(iid_list); +// +// pOutput->num_glb_persist_identifiers = entryCnt; +// pOutput->size = (uint32_t)totalsize; +// +// ACDB_PKT_LOG_DATA("RspBufSize", &pOutput->size, sizeof(pOutput->size)); +// ACDB_PKT_LOG_DATA("RspBufNumGlbIds", &pOutput->num_glb_persist_identifiers, sizeof(pOutput->num_glb_persist_identifiers)); +// if (pOutput->global_persistent_cal_info != NULL) +// { +// ACDB_PKT_LOG_DATA("RspBuf", pOutput->global_persistent_cal_info, totalsize); +// } +// +// return result; +//} + +/* TODO: This api needs to be supported when the ACDB file supports global +* persistent data. This API also needs to be refactored and follow the +* approach used in AcdbCmdGetSubgraphCalNonPersist +*/ +// int32_t AcdbCmdGetSubgraphGlbPersistCalData(AcdbGlbPersistCalDataCmdType *pInput, AcdbBlob *pOutput, uint32_t rsp_struct_size) +// { +// __UNREFERENCED_PARAM(pInput); +// __UNREFERENCED_PARAM(pOutput); +// __UNREFERENCED_PARAM(rsp_struct_size); +// return AR_ENOTEXIST; +// } + +/*TODO: This api needs to be supported when the ACDB file supports global persistent data. This API also needs to be refactored */ +//int32_t AcdbCmdGetSubgraphGlbPersistCalData(AcdbGlbPersistCalDataCmdType *pInput, AcdbBlob *pOutput, uint32_t rsp_struct_size) +//{ +// int32_t result = AR_EOK; +// uint32_t chkBuf = 0; +// uint32_t chkLen = 0; +// uint32_t pidMapChkBuf = 0; +// uint32_t pidMapChkLen = 0; +// uint32_t pid_offset = 0; +// uint32_t calBlobSize = 0; +// size_t totalsize = 0; +// uint32_t data_offset = 0; +// bool_t cal_id_found = FALSE; +// uint32_t pid = 0; +// +// ACDB_PKT_LOG_DATA("CalID", &pInput->cal_Id, sizeof(pInput->cal_Id)); +// +// if (rsp_struct_size < 8) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistCalData() failed, rsp_struct_size is invalid"); +// return AR_EFAILED; +// } +// +// result = AcdbGetChunkInfo(ACDB_CHUNKID_PIDPERSIST, &pidMapChkBuf, &pidMapChkLen); +// if (result != AR_EOK) +// return result; +// +// result = AcdbGetChunkInfo(ACDB_CHUNKID_DATAPOOL, &chkBuf, &chkLen); +// if (result != AR_EOK) +// return result; +// +// uint32_t calID = pInput->cal_Id; +// pid_offset += (2 * sizeof(uint32_t));//size and num of calId's +// do +// { +// memset(&glb_buf_1, 0, sizeof(glb_buf_1)); +// int ret = file_seek(pidMapChkBuf + pid_offset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistCalData() failed, file seek to %d was unsuccessful", pidMapChkBuf + pid_offset); +// return AR_EFAILED; +// } +// ret = file_read(&glb_buf_1, 3 * sizeof(uint32_t)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistCalData() failed, calID read was unsuccessful"); +// return AR_EFAILED; +// } +// +// if (calID == glb_buf_1[0]) +// { +// pid = glb_buf_1[1]; +// data_offset = glb_buf_1[2]; +// cal_id_found = TRUE; +// break; +// } +// else +// { +// pid_offset += ((4 * sizeof(uint32_t)) + (glb_buf_1[3] * sizeof(uint32_t))); +// } +// +// } while (pid_offset < pidMapChkLen && !cal_id_found); +// if (!cal_id_found) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistCalData() failed, cal_ID %d is not found", calID); +// return AR_EFAILED; +// } +// +// ACDB_PKT_LOG_DATA("DataOffset", &data_offset, sizeof(data_offset)); +// +// //read the payload for each cal_identifier +// uint32_t param_size = 0, new_param_size = 0, errcode = 0, iid_val = 0; +// uint64_t zero_val_payload = 0; +// int ret = file_seek(chkBuf + data_offset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistCalData() failed, file seek to %d was unsuccessful", chkBuf + data_offset); +// return AR_EFAILED; +// } +// ret = file_read(¶m_size, sizeof(param_size)); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistCalData() failed, param_size read was unsuccessful"); +// return AR_EFAILED; +// } +// ACDB_PKT_LOG_DATA("ParamSize", ¶m_size, sizeof(param_size)); +// data_offset += sizeof(param_size); +// +// memset(&glb_buf_1, 0, sizeof(glb_buf_1)); +// ret = file_seek(chkBuf + data_offset, AR_FSEEK_BEGIN); +// if (ret != 0) +// { +// ACDB_ERR("AcdbCmdGetSubgraphGlbPersistCalData() failed, file seek to %d was unsuccessful", chkBuf + data_offset); +// return AR_EFAILED; +// } +// +// //Add paddig if necessary before sending the response back +// if ((param_size % 8) != 0) +// { +// new_param_size = param_size + (8 - ((param_size % 8))); +// } +// else +// { +// new_param_size = param_size; +// } +// +// totalsize += sizeof(iid_val) + sizeof(pid) + sizeof(errcode) + sizeof(new_param_size); +// totalsize += new_param_size; +// +// if (pOutput->buf != NULL) +// { +// if (pOutput->buf_size >= (calBlobSize + (4 * sizeof(uint32_t)))) +// { +// ACDB_MEM_CPY(pOutput->buf + calBlobSize, &iid_val, sizeof(iid_val)); +// calBlobSize += sizeof(iid_val); +// ACDB_MEM_CPY(pOutput->buf + calBlobSize, &pid, sizeof(pid)); +// calBlobSize += sizeof(pid); +// ACDB_MEM_CPY(pOutput->buf + calBlobSize, ¶m_size, sizeof(param_size)); +// calBlobSize += sizeof(param_size); +// ACDB_MEM_CPY(pOutput->buf + calBlobSize, &errcode, sizeof(errcode)); +// calBlobSize += sizeof(errcode); +// } +// else +// { +// return AR_ENEEDMORE; +// } +// +// if (param_size != 0) +// { +// if (param_size < sizeof(glb_buf_1)) +// { +// ret = file_read(&glb_buf_1, param_size); +// if (ret != 0) +// { +// ACDB_ERR_MSG_1("Failed to read parameter payload from database.", ret); +// ACDB_ERR("IID: %x PID: %x Size: %d", iid_val, pid, param_size); +// return ret; +// } +// if (pOutput->buf_size >= (calBlobSize + param_size)) +// { +// ACDB_MEM_CPY(pOutput->buf + calBlobSize, &glb_buf_1, param_size); +// } +// else +// { +// return AR_ENEEDMORE; +// } +// } +// else +// { +// //ret = CopyFromFileToBuf(chkBuf + data_offset, (uint8_t*)(pOutput->buf) + calBlobSize, param_size, sizeof(glb_buf_1)); +// if (pOutput->buf_size >= (calBlobSize + param_size)) +// { +// ret = CopyFromFileToBuf(chkBuf + data_offset, (uint8_t*)(pOutput->buf) + calBlobSize, param_size, param_size); +// if (AR_EOK != ret) +// { +// ACDB_ERR_MSG_1("Failed to read parameter payload from database.", ret); +// ACDB_ERR("IID: %x PID: %x Size: %d", iid_val, pid, param_size); +// return ret; +// } +// } +// else +// { +// return AR_ENEEDMORE; +// } +// } +// } +// calBlobSize += param_size; +// +// if (pOutput->buf_size >= (calBlobSize + new_param_size - param_size)) +// { +// ACDB_MEM_CPY(pOutput->buf + calBlobSize, &zero_val_payload, new_param_size - param_size); +// } +// else +// { +// return AR_ENEEDMORE; +// } +// calBlobSize += (new_param_size - param_size); +// +// ACDB_PKT_LOG_DATA("RspBuf", pOutput->buf, totalsize); +// } +// pOutput->buf_size = (uint32_t)totalsize; +// ACDB_PKT_LOG_DATA("RspBufSize", &pOutput->buf_size, sizeof(pOutput->buf_size)); +// return result; +//} + +/** +* \brief +* Sets parameter calibration to the heap and saves to the delta file if +* delta support is enabled. +* +* \param[in/out] info: Context info containing the module kv +* \param[in/out] req: Contains calibration to be set +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbSetSubgraphCalibration(AcdbAudioCalContextInfo *info, + AcdbSetCalDataReq *req) +{ + int32_t status = AR_EOK; + uint32_t cur_def_offset = 0; + uint32_t blob_offset = 0; + uint32_t num_param_cal_found = 0; + uint32_t num_iid_found = 0; + ChunkInfo ci_cal_def = { 0 }; + uint32_t num_id_entries = 0; + AcdbModuleHeader blob_module_header = { 0 }; + AcdbModuleHeader file_module_header = { 0 }; + AcdbSubgraphParamData subgraph_param_data = { 0 }; + AcdbIidRefCount* iid_ref = NULL; + + ci_cal_def.chunk_id = ACDB_CHUNKID_CALDATADEF; + status = ACDB_GET_CHUNK_INFO(&ci_cal_def); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get Subgraph Calibration " + "DEF chunk information", status); + return status; + } + + cur_def_offset = ci_cal_def.chunk_offset + info->data_offsets.offset_def; + status = FileManReadBuffer(&num_id_entries, sizeof(uint32_t), &cur_def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of " + " entries", status); + return status; + } + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + //Ensure global buffer can store the default data IID Reference list + if (GLB_BUF_1_LENGTH < num_id_entries * 2) + { + ACDB_ERR("Error[%d]: Need more memory to store IID reference list", + AR_ENEEDMORE); + return AR_ENEEDMORE; + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + + iid_ref = (AcdbIidRefCount*)glb_buf_1; + } + + /* Parse the input cal blob, find the matching pair and set + * the calibration to the heap */ + for (uint32_t i = 0; i < num_id_entries; i++) + { + status = FileManReadBuffer(&file_module_header, sizeof(AcdbMiidPidPair), + &cur_def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of " + " entries", status); + goto end; + } + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + //Add IIDs to list and ignore set data + if (iid_ref->module_iid != file_module_header.module_iid && num_iid_found == 0) + { + iid_ref->module_iid = file_module_header.module_iid; + iid_ref->ref_count = 1; + num_iid_found++; + //iid_ref++; + } + else if (iid_ref->module_iid != file_module_header.module_iid) + { + iid_ref++; + iid_ref->module_iid = file_module_header.module_iid; + iid_ref->ref_count = 1; + num_iid_found++; + } + else + { + /* Increase ref count of the current Obj */ + iid_ref->ref_count++; + } + + continue; + } + else + { + /* For other CKVs, if the module is in the default data list, remove it */ + if (!IsNull(info->default_data_iid_list.list)) + { + iid_ref = (AcdbIidRefCount*) + info->default_data_iid_list.list; + bool_t found_iid = FALSE; + for (uint32_t j = 0; j < info-> + default_data_iid_list.count; j++) + { + if ((file_module_header.module_iid == iid_ref->module_iid) + && iid_ref->ref_count > 0) + { + iid_ref->ref_count--; + found_iid = TRUE; + break; + } + else if ((file_module_header.module_iid == iid_ref->module_iid) + && iid_ref->ref_count <= 0) + break; + + iid_ref++; + } + + if (info->is_default_module_ckv && !found_iid) + { + //cur_dot_offset += sizeof(uint32_t); + continue; + } + } + } + + blob_offset = 0; + do + { + ACDB_MEM_CPY_SAFE(&blob_module_header, sizeof(AcdbModuleHeader), + (uint8_t*)req->cal_blob + blob_offset, + sizeof(AcdbModuleHeader)); + + if (0 == memcmp(&file_module_header, &blob_module_header, + sizeof(AcdbMiidPidPair))) + { + //set calibration to heap + subgraph_param_data.data_size = sizeof(AcdbDspModuleHeader) + + ACDB_ALIGN_8_BYTE(blob_module_header.param_size); + subgraph_param_data.data = + (uint8_t*)req->cal_blob + blob_offset; + subgraph_param_data.subgraph_id_list.count = 1; + subgraph_param_data.subgraph_id_list.list = glb_buf_3; + /* Use glb_buf_3 to resolve Warning C4366 caused by: + * (uint32_t*)&info->subgraph_id */ + glb_buf_3[0] = info->subgraph_id; + + status = DataProcSetCalData( + info->module_ckv, &subgraph_param_data); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Failed to set calibration for " + "Subgraph(0x%x) Module(0x%x) Parameter(0x%x)"); + } + + num_param_cal_found++; + break; + } + + blob_offset += sizeof(AcdbDspModuleHeader) + + + ACDB_ALIGN_8_BYTE(blob_module_header.param_size); + } while (blob_offset < req->cal_blob_size); + } + +end: + if (info->is_default_module_ckv && !info->ignore_get_default_data) + { + ACDB_FREE(info->default_data_iid_list.list); + info->default_data_iid_list.list = NULL; + } + else if (info->is_default_module_ckv && info->ignore_get_default_data) + { + /* Copy the IID Ref Count list from GLB_BUF_1 since it will be + * cleared outside of this call */ + info->default_data_iid_list.count = num_iid_found; + + //List of AcdbIidRefCount + info->default_data_iid_list.list = (uint32_t*) + ACDB_MALLOC(AcdbIidRefCount, num_iid_found); + + if (IsNull(info->default_data_iid_list.list)) + { + ACDB_ERR("Error[%d]: Unable to allocate memory " + "for instance id reference list", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + ACDB_MEM_CPY_SAFE(info->default_data_iid_list.list, + num_iid_found * sizeof(AcdbIidRefCount), + &glb_buf_1[0], num_iid_found * sizeof(AcdbIidRefCount)); + + iid_ref = NULL; + } + + if (info->is_default_module_ckv && info->ignore_get_default_data) + { + return AR_EOK; + } + else if (num_param_cal_found == 0) return AR_ENOTEXIST; + + return status; +} + +int32_t AcdbCmdSetCalData(AcdbSetCalDataReq *req) +{ + int32_t status = AR_EOK; + bool_t is_data_set = FALSE; + uint32_t offset = 0; + uint32_t num_subgraph = 0; + uint32_t subgraph_id = 0; + //Number of subgraphs that data was found for + uint32_t num_subgraph_found = 0; + uint32_t ckv_list_offset = 0; + uint32_t default_ckv_entry_offset = 0; + AcdbSubgraph* subgraph = NULL; + ChunkInfo ci_sg_cal_lut = { 0 }; + AcdbSgCalLutHeader sg_cal_lut_header = { 0 }; + AcdbCalKeyTblEntry ckv_entry = { 0 }; + AcdbAudioCalContextInfo info; + AcdbGetGraphRsp graph = {0}; + + (void)ar_mem_set(&info, 0, sizeof(AcdbAudioCalContextInfo)); + + if (IsNull(req)) + { + ACDB_ERR("Error[%d]: The input parameter is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->cal_blob_size == 0 || IsNull(req->cal_blob)) + { + ACDB_ERR("Error[%d]: The input blob is empty. " + "There are no parameters to set.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (req->graph_key_vector.num_keys == 0) + { + ACDB_ERR("Error[%d]: The graph key vector can not be empty.", + AR_EUNSUPPORTED); + return AR_EUNSUPPORTED; + } + else + { + ACDB_DBG("Setting cal data for the following graph key vector:"); + LogKeyVector(&req->graph_key_vector, GRAPH_KEY_VECTOR); + } + + status = AcdbGetUsecaseSubgraphList( + &req->graph_key_vector, NULL, &graph); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get usecase subgraphs.", + status); + goto end; + } + + ci_sg_cal_lut.chunk_id = ACDB_CHUNKID_CALSGLUT; + status = ACDB_GET_CHUNK_INFO(&ci_sg_cal_lut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get Subgraph Calibration LUT " + "chunk information", status); + return status; + } + + /* CKV Setup + * 1. GLB_BUF_2 stores the module CKV that will be used to locate data in + * the heap(if it exists) + * 2. The Delta CKV and CKV[New] are allocated on the heap by + * AcdbComputeDeltaCKV + * + * tmp - stores the amount of padding after graph_key_vectornum_keys + * tmp2 - stores the position of the KeyValuePair list + * + * The first info.module_ckv->graph_key_vector assignment has the effect + * of storing the address of the pointer in glb_buf_2 after + * graph_key_vector.num_keys + * + * The second info.module_ckv->graph_key_vector assignment has the effect + * of pointer the info.module_ckv->graph_key_vector to the actual list + * of key value pairs + * + * Whats inside global buffer 2 after these operations? + * + * The first 'sizeof(AcdbGraphKeyVector)' bytes is AcdbGraphKeyVector + * followed by 'sizeof(AcdbKeyValuePair) * num_keys' bytes which is + * the KV list + */ + info.module_ckv = (AcdbGraphKeyVector*)&glb_buf_2[0]; + uint32_t tmp = (sizeof(AcdbGraphKeyVector) - sizeof(AcdbKeyValuePair *)) / sizeof(uint32_t); + uint32_t tmp2 = sizeof(AcdbGraphKeyVector) / sizeof(uint32_t); + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp]; + info.module_ckv->graph_key_vector = (AcdbKeyValuePair*)&glb_buf_2[tmp2]; + + info.ckv = &req->cal_key_vector; + + /* For Set Data this flag must be set to true since delta CKVs are + * not applicable */ + info.is_first_time = TRUE; + + offset = ci_sg_cal_lut.chunk_offset; + status = FileManReadBuffer(&num_subgraph, + sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of Subgraphs", + status); + goto end; + } + + subgraph = graph.subgraphs; + if (IsNull(subgraph)) + { + ACDB_ERR("Error[%d]: The subgraph list is null", + status); + goto end; + } + + subgraph_id = 0; + for (uint32_t i = 0; i < graph.num_subgraphs; i++) + { + subgraph_id = subgraph->sg_id; + offset = ci_sg_cal_lut.chunk_offset + sizeof(uint32_t); + + //Go to the next subgraph as long as we are not on the last subgraph + if(i != graph.num_subgraphs - 1) + subgraph = (AcdbSubgraph*)((uint8_t*)subgraph + + sizeof(AcdbSubgraph) + + subgraph->num_dst_sgids * sizeof(uint32_t)); + + sg_cal_lut_header.subgraph_id = subgraph_id; + status = SearchSubgraphCalLut2(&sg_cal_lut_header, &ckv_list_offset); + if (AR_ENOTEXIST == status) + { + ACDB_ERR("Error[%d] Subgraph(%x) does not exist. Skipping..", + AR_ENOTEXIST, subgraph_id); + continue; + } + + if (sg_cal_lut_header.num_ckv_entries == 0) + { + ACDB_ERR("Error[%d]: Subgraph(%x) contains zero CKV entries in" + " the Subgraph Cal LUT. At least one entry should be" + " present. Skipping..", + AR_ENOTEXIST, subgraph_id); + continue; + } + + info.ignore_get_default_data = + sg_cal_lut_header.num_ckv_entries == 1 ? FALSE : TRUE; + + //The default CKV will be skipped and handeled last + if (sg_cal_lut_header.num_ckv_entries > 1) + sg_cal_lut_header.num_ckv_entries++; + + default_ckv_entry_offset = ckv_list_offset; + + for (uint32_t k = 0; k < sg_cal_lut_header.num_ckv_entries; k++) + { + /* The Default CKV is always the first CKV in the list of CKVs to + * search. It will be skipped and processed last */ + if ((k == sg_cal_lut_header.num_ckv_entries - 1) && + info.ignore_get_default_data == TRUE) + { + info.ignore_get_default_data = FALSE; + + status = FileManReadBuffer(&ckv_entry, sizeof(ckv_entry), + &default_ckv_entry_offset); + } + else + { + status = FileManReadBuffer(&ckv_entry, sizeof(ckv_entry), + &ckv_list_offset); + } + + if (AR_FAILED(status)) + { + goto end; + } + + info.subgraph_id = sg_cal_lut_header.subgraph_id; + + status = AcdbFindModuleCKV(&ckv_entry, &info); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + continue; + } + else if (AR_FAILED(status)) + { + goto end; + } + + //Set Calibration to heap and save to delta file + status = AcdbSetSubgraphCalibration(&info, req); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + continue; + } + + is_data_set = TRUE; + } + + if (AR_FAILED(status) && !is_data_set) + { + ACDB_DBG("Error[%d]: Unable to set calibration data for " + "Subgraph(%x). Skipping..", status, + sg_cal_lut_header.subgraph_id); + status = AR_EOK; + } + else + { + status = AR_EOK; + is_data_set = FALSE; + num_subgraph_found++; + } + } + + if (num_subgraph_found == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Unable to set calibration for the " + "provided usecase graph key vector", status); + goto end; + } + + //Save Heap data to Delta File if there is data to save + if (acdb_delta_data_is_persist_enabled()) + { + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_SAVE, + NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to save delta file.", status); + } + } + else + { + ACDB_ERR("Error[%d]: Unable to save delta data. Is delta data" + " persistance enabled?", status); + } + +end: + + //Clean Up Context Info + info.ckv = NULL; + AcdbClearAudioCalContextInfo(&info); + + return status; +} + +int32_t AcdbGetAmdbProcDeregData( + acdb_amdb_proc_reg_data_t* proc_reg_data, uint32_t expected_size, + uint32_t *blob_offset, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t data_size = 0; + acdb_amdb_module_reg_info_t* module_reg_data = NULL; + AcdbOp op = ACDB_OP_NONE; + + if (IsNull(rsp)) + return AR_EBADPARAM; + + op = IsNull(rsp->buf) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + if (ACDB_OP_GET_SIZE == op) + { + return status; + } + + module_reg_data = proc_reg_data->module_reg_data; + data_size = *(uint32_t*)module_reg_data; + + for (uint32_t j = 0; j < proc_reg_data->module_count; j++) + { + uint32_t module_id = *((uint32_t*)module_reg_data + 3); + if (*blob_offset > expected_size) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE(rsp->buf + *blob_offset, sizeof(uint32_t), + &module_id, sizeof(uint32_t)); + *blob_offset += sizeof(module_id); + + //Go to next module + module_reg_data = (acdb_amdb_module_reg_info_t*) + ((uint8_t*)module_reg_data + data_size + + sizeof(uint32_t)); + data_size = *(uint32_t*)module_reg_data; + } + + return status; +} + +int32_t AcdbGetAmdbProcRegData( + acdb_amdb_proc_reg_data_t* proc_reg_data, uint32_t expected_size, + uint32_t *blob_offset, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t data_size = 0; + acdb_amdb_module_reg_info_t* module_reg_data = NULL; + AcdbOp op = ACDB_OP_NONE; + void* moudule_reg_data_start = NULL; + + if (IsNull(rsp)) + return AR_EBADPARAM; + + op = IsNull(rsp->buf) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + if (ACDB_OP_GET_SIZE == op) + { + return status; + } + + module_reg_data = proc_reg_data->module_reg_data; + data_size = *(uint32_t*)module_reg_data; + + for (uint32_t j = 0; j < proc_reg_data->module_count; j++) + { + if (*blob_offset > expected_size) + return AR_ENEEDMORE; + + moudule_reg_data_start = (uint8_t*)module_reg_data + + sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE( + rsp->buf + *blob_offset, data_size, + moudule_reg_data_start, data_size); + *blob_offset += data_size; + + //Go to next module + module_reg_data = (acdb_amdb_module_reg_info_t*) + ((uint8_t*)module_reg_data + data_size + + sizeof(uint32_t)); + data_size = *(uint32_t*)module_reg_data; + } + + return status; +} + +int32_t AcdbGetAmdbProcRegDeregData( + acdb_amdb_reg_dereg_info_type_t info_type, + bool_t use_active_context, + uint32_t proc_id, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t blob_offset = 0; + uint32_t expected_size = 0; + uint32_t processor_count = 0; + uint32_t total_num_modules = 0; + uint32_t total_proc_data_size = 0; + uint32_t curr_struct_version = 0; + uint32_t db_index = 0; + uint32_t amdb_proc_reg_data_header_size = 0; + bool_t found = FALSE; + uint32_t db_count = 0; + ChunkInfo ci_amdb_reg = { 0 }; + acdb_amdb_module_reg_info_t module_reg_info = { 0 }; + acdb_amdb_proc_reg_data_t proc_reg_data = { 0 }; + acdb_spf_amdb_module_reg_t spf_amdb_reg = { 0 }; + acdb_amdb_module_dereg_t spf_amdb_dereg = { 0 }; + AcdbOp op = ACDB_OP_NONE; + + if (IsNull(rsp)) + return AR_EBADPARAM; + + op = IsNull(rsp->buf) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + expected_size = rsp->buf_size; + ci_amdb_reg.chunk_id = ACDB_CHUNKID_AMDB_REG_DATA; + proc_reg_data.module_reg_data = &module_reg_info; + + if (ACDB_OP_GET_DATA == op) + { + /* Make space to write the header, collect the total + * number of modules */ + switch (info_type) + { + case ACDB_AMDB_INFO_REGISTRATION: + if (sizeof(acdb_spf_amdb_module_reg_t) > expected_size) + return AR_ENEEDMORE; + blob_offset += sizeof(acdb_spf_amdb_module_reg_t); + break; + case ACDB_AMDB_INFO_DEREGISTRATION: + if (sizeof(acdb_amdb_module_dereg_t) > expected_size) + return AR_ENEEDMORE; + blob_offset += sizeof(acdb_amdb_module_dereg_t); + break; + default: + status = AR_EUNSUPPORTED; + ACDB_ERR("Error[%d]: Unknown AMDB info type", status); + return status; + } + } + + db_count = use_active_context ? 1 : ACDB_CTX_MAN_DATABASE_COUNT; + for (db_index = 0; db_index < db_count; db_index++) + { + if (!use_active_context) + { + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_INDEX, + &db_index, sizeof(uint32_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set database context", + status); + return status; + } + } + + status = ACDB_GET_CHUNK_INFO(&ci_amdb_reg); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get AMDB " + "registration data chunk.", status); + return status; + } + + offset = ci_amdb_reg.chunk_offset; + status = FileManReadBuffer(&processor_count, + sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read processor count.", status); + return status; + } + + amdb_proc_reg_data_header_size = + sizeof(acdb_amdb_proc_reg_data_t) + - sizeof(acdb_amdb_module_reg_info_t*); + for (uint32_t i = 0; i < processor_count; i++) + { + status = FileManReadBuffer(&proc_reg_data, + amdb_proc_reg_data_header_size, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get processor reg " + "from database.", status); + return status; + } + + if (proc_id == proc_reg_data.proc_id) + { + status = FileManGetFilePointer2((void **)&proc_reg_data.module_reg_data, offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get module reg " + "info for Proccessor %d from database.", + status, proc_reg_data.proc_id); + return status; + } + + found = TRUE; + break; + } + + // Go to next processor reg data + offset += proc_reg_data.data_size + - amdb_proc_reg_data_header_size + + sizeof(proc_reg_data.data_size); + } + + if (!found) + { + status = AR_ENOTEXIST; + ACDB_ERR("Warning[%d]: Processor ID(%d) does not exist in " + "database for VM-%d. Skipping..", AR_ENOTEXIST, proc_id, 0); + continue; + } + + status = AR_EOK; + total_num_modules += proc_reg_data.module_count; + /* Remove acdb_amdb_module_reg_info_t::data_size in all modules + * from the total proc reg data output size */ + total_proc_data_size += proc_reg_data.data_size + - sizeof(uint32_t) * proc_reg_data.module_count; + + if (!curr_struct_version) + curr_struct_version = proc_reg_data.struct_version; + else if (curr_struct_version != proc_reg_data.struct_version) + { + /* User needs to correct their files b/c we can only send + * 1 structure version in the response for + * ACDB_AMDB_INFO_REGISTRATION */ + ACDB_ERR("Error[%d]: The AMDB structure version is different " + "between database at index %d with v%d and %d with v%d. " + "Only one struct version is allowed in registration data " + "response", AR_EFAILED, db_index - 1, curr_struct_version, + db_index, proc_reg_data.struct_version); + return AR_EFAILED; + } + + switch (info_type) + { + case ACDB_AMDB_INFO_REGISTRATION: + status = AcdbGetAmdbProcRegData( + &proc_reg_data, expected_size, &blob_offset, rsp); + break; + case ACDB_AMDB_INFO_DEREGISTRATION: + status = AcdbGetAmdbProcDeregData( + &proc_reg_data, expected_size, &blob_offset, rsp); + break; + default: + status = AR_EUNSUPPORTED; + ACDB_ERR("Error[%d]: Unknown AMDB info type", + AR_EUNSUPPORTED); + break; + } + } + + if (AR_FAILED(status)) + { + return status; + } + + /* Write AMDB reg/dereg response header */ + switch (info_type) + { + case ACDB_AMDB_INFO_REGISTRATION: + + rsp->buf_size = sizeof(acdb_spf_amdb_module_reg_t) + + total_proc_data_size - (sizeof(acdb_spf_amdb_module_reg_t) + * db_count); + if (ACDB_OP_GET_SIZE == op) return status; + + //get data + spf_amdb_reg.proc_id = proc_id; + spf_amdb_reg.num_modules = total_num_modules; + spf_amdb_reg.struct_version = curr_struct_version; + + ACDB_MEM_CPY_SAFE( + (uint8_t*)rsp->buf, sizeof(acdb_spf_amdb_module_reg_t), + &spf_amdb_reg, sizeof(acdb_spf_amdb_module_reg_t)); + break; + case ACDB_AMDB_INFO_DEREGISTRATION: + rsp->buf_size = sizeof(acdb_amdb_module_dereg_t) + + sizeof(uint32_t) * total_num_modules; + + if (ACDB_OP_GET_SIZE == op) return status; + + //get data + spf_amdb_dereg.proc_id = proc_id; + spf_amdb_dereg.num_modules = total_num_modules; + + ACDB_MEM_CPY_SAFE( + (uint8_t*)rsp->buf, sizeof(acdb_amdb_module_dereg_t), + &spf_amdb_dereg, sizeof(acdb_amdb_module_dereg_t)); + break; + default: + status = AR_EUNSUPPORTED; + ACDB_ERR("Error[%d]: Unknown AMDB info type", AR_EUNSUPPORTED); + break; + } + + return status; +} + +int32_t AcdbGetAmdbBootLoadModuleData( + bool_t use_active_context, uint32_t proc_id, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t blob_offset = 0; + uint32_t processor_count = 0; + uint32_t expected_size = 0; + uint32_t db_count = 0; + uint32_t total_num_modules = 0; + bool_t found = FALSE; + ChunkInfo ci_boot_load = { 0 }; + acdb_amdb_bootup_proc_table_entry_t* proc_entry = NULL; + uint32_t *bootup_modules = NULL; + acdb_amdb_bootup_module_t bootup_module = { 0 }; + acdb_amdb_proc_bootup_data_t bootup_proc_data = { 0 }; + AcdbOp op = ACDB_OP_NONE; + + ci_boot_load.chunk_id = ACDB_CHUNKID_BOOTUP_LOAD_MODULES; + + + op = IsNull(rsp->buf) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + expected_size = rsp->buf_size; + + if (ACDB_OP_GET_DATA == op) + { + /* Make room to write acdb_amdb_proc_bootup_data_t header */ + blob_offset = sizeof(bootup_proc_data); + } + + db_count = use_active_context ? 1 : ACDB_CTX_MAN_DATABASE_COUNT; + for (uint32_t db_index = 0; db_index < db_count; db_index++) + { + if (!use_active_context) + { + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_INDEX, + &db_index, sizeof(uint32_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set database context", + status); + return status; + } + } + + status = ACDB_GET_CHUNK_INFO(&ci_boot_load); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get AMDB registration data chunk.", + status); + return status; + } + + offset = ci_boot_load.chunk_offset; + + status = FileManReadBuffer(&processor_count, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read processor count.", status); + return status; + } + + status = FileManGetFilePointer2((void **)&proc_entry, offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read processor count.", status); + return status; + } + + for (uint32_t i = 0; i < processor_count; i++) + { + if (proc_id == proc_entry->proc_id) + { + found = TRUE; + break; + } + + // Go to next processor bootup entry + proc_entry = (acdb_amdb_bootup_proc_table_entry_t*) + ((uint8_t*)proc_entry + proc_entry->num_modules + * sizeof(uint32_t) + sizeof(acdb_amdb_bootup_proc_table_entry_t)); + } + + if (!found) + { + ACDB_ERR("Error[%d]: Processor ID(%d) does not exist", + AR_ENOTEXIST, proc_id); + return AR_ENOTEXIST; + } + + total_num_modules += proc_entry->num_modules; + + if (ACDB_OP_GET_SIZE == op) continue; + + bootup_modules = &proc_entry->module_ids[0]; + for (uint32_t j = 0; j < proc_entry->num_modules; j++) + { + if (blob_offset > expected_size) + return AR_ENEEDMORE; + + bootup_module.module_id = bootup_modules[j]; + + ACDB_MEM_CPY_SAFE( + (uint8_t*)rsp->buf + blob_offset, sizeof(bootup_module), + &bootup_module, sizeof(bootup_module)); + blob_offset += sizeof(bootup_module); + } + } + + switch (op) + { + case ACDB_OP_GET_SIZE: + rsp->buf_size = sizeof(acdb_amdb_proc_bootup_data_t) + + sizeof(acdb_amdb_bootup_module_t) * total_num_modules; + break; + case ACDB_OP_GET_DATA: + bootup_proc_data.proc_id = proc_id; + bootup_proc_data.num_modules = total_num_modules; + + ACDB_MEM_CPY_SAFE( + (uint8_t*)rsp->buf, sizeof(bootup_proc_data), + &bootup_proc_data, sizeof(bootup_proc_data)); + break; + default: + break; + } + + return status; +} + +int32_t AcdbCmdGetAmdbRegData(AcdbAmdbProcID *req, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = AcdbGetAmdbProcRegDeregData(ACDB_AMDB_INFO_REGISTRATION, + FALSE, req->proc_id, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get AMDB module registration info.", + status); + return status; + } + + return status; +} + +int32_t AcdbCmdGetAmdbDeregData(AcdbAmdbProcID* req, + AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = AcdbGetAmdbProcRegDeregData(ACDB_AMDB_INFO_DEREGISTRATION, + FALSE, req->proc_id, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get AMDB module de-registration info.", + status); + return status; + } + + return status; +} + +int32_t AcdbCmdGetSubgraphProcIds(AcdbCmdGetSubgraphProcIdsReq *req, + AcdbCmdGetSubgraphProcIdsRsp *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + uint32_t num_sgIds = 0; + uint32_t total_sz = 0; + uint32_t data_offset = 0; + uint32_t proc_offset = 0; + uint32_t num_modules_proc = 0; + AcdbSubgraphPdmMap sg_mod_iid_map = { 0 }; + AcdbUintList subgraph_list = { 0 }; + + if (rsp_size < sizeof(AcdbCmdGetSubgraphProcIdsRsp)) + { + ACDB_ERR("Error[%d]: The response structure size is less than %d", + AR_EBADPARAM, sizeof(AcdbCmdGetSubgraphProcIdsRsp)); + return AR_EBADPARAM; + } + + subgraph_list.count = req->num_sg_ids; + subgraph_list.list = req->sg_ids; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS, + &subgraph_list, sizeof(subgraph_list), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set file index", + status); + return status; + } + + for (uint32_t i = 0; i < req->num_sg_ids; i++) + { + ar_mem_set((void*)&sg_mod_iid_map, 0, sizeof(AcdbSubgraphPdmMap)); + proc_offset = 0; + status = DataProcGetSubgraphProcIidMap(req->sg_ids[i], &sg_mod_iid_map); + if (AR_EOK != status) + { + //Return even if it can't find data for one of the given subgraphs + goto end; + } + + num_sgIds++; + total_sz += sizeof(AcdbSgProcIdsMap) + + sg_mod_iid_map.proc_count * sizeof(uint32_t); //sg_mod_iid_map->size; + if (rsp->sg_proc_ids != NULL) + { + if (rsp->size < (data_offset + (2 * sizeof(uint32_t)))) + { + status = AR_ENEEDMORE; + goto end; + } + + ACDB_MEM_CPY_SAFE( + rsp->sg_proc_ids + data_offset, + sizeof(sg_mod_iid_map.subgraph_id), + &sg_mod_iid_map.subgraph_id, + sizeof(sg_mod_iid_map.subgraph_id)); + data_offset += sizeof(sg_mod_iid_map.subgraph_id); + + ACDB_MEM_CPY_SAFE(rsp->sg_proc_ids + data_offset, + sizeof(sg_mod_iid_map.proc_count), + &sg_mod_iid_map.proc_count, + sizeof(sg_mod_iid_map.proc_count)); + data_offset += sizeof(sg_mod_iid_map.proc_count); + + for (uint32_t j = 0; j < sg_mod_iid_map.proc_count; j++) + { + if (rsp->size < (data_offset + sizeof(uint32_t))) + { + status = AR_ENEEDMORE; + goto end; + } + + ACDB_MEM_CPY_SAFE(rsp->sg_proc_ids + data_offset, + sizeof(uint32_t), + sg_mod_iid_map.proc_info + proc_offset, + sizeof(uint32_t)); + data_offset += sizeof(uint32_t); //size of each procID + + proc_offset += sizeof(uint32_t); + ACDB_MEM_CPY_SAFE(&num_modules_proc, + sizeof(uint32_t), + sg_mod_iid_map.proc_info + proc_offset, + sizeof(uint32_t)); + proc_offset += (sizeof(num_modules_proc) + + (num_modules_proc * sizeof(AcdbModuleInstance))); + } + } + } + +end: + if (AR_FAILED(status)) + { + return status; + } + + rsp->num_sg_ids = num_sgIds; + rsp->size = total_sz; + return status; +} + +int32_t AcdbCmdGetAmdbBootupLoadModules(AcdbAmdbProcID *req, + AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = AcdbGetAmdbBootLoadModuleData(FALSE, req->proc_id, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get AMDB bootup load/unload info.", + status); + return status; + } + + return status; +} + +int32_t AcdbCmdGetAmdbRegDataV2(AcdbAmdbDbHandle *req, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + bool_t should_use_handle = TRUE; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (IsNull(req->acdb_handle)) + { + should_use_handle = FALSE; + } + + if (should_use_handle) + { + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE, + &req->acdb_handle, sizeof(acdb_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set databae context", + status); + return status; + } + } + + status = AcdbGetAmdbProcRegDeregData(ACDB_AMDB_INFO_REGISTRATION, + should_use_handle, req->proc_id, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get AMDB module registration info.", + status); + return status; + } + + return status; +} + +int32_t AcdbCmdGetAmdbDeregDataV2(AcdbAmdbDbHandle *req, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + bool_t should_use_handle = TRUE; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (IsNull(req->acdb_handle)) + { + should_use_handle = FALSE; + } + + if (should_use_handle) + { + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE, + &req->acdb_handle, sizeof(acdb_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set databae context", + status); + return status; + } + } + + status = AcdbGetAmdbProcRegDeregData(ACDB_AMDB_INFO_DEREGISTRATION, + should_use_handle, req->proc_id, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get AMDB module de-registration info.", + status); + return status; + } + + return status; +} + +int32_t AcdbCmdGetAmdbBootupLoadModulesV2(AcdbAmdbDbHandle *req, AcdbBlob *rsp) +{ + int32_t status = AR_EOK; + bool_t should_use_handle = TRUE; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (IsNull(req->acdb_handle)) + { + should_use_handle = FALSE; + } + + if (should_use_handle) + { + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE, + &req->acdb_handle, sizeof(acdb_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set databae context", + status); + return status; + } + } + + status = AcdbGetAmdbBootLoadModuleData( + should_use_handle, req->proc_id, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get AMDB bootup load/unload info.", + status); + return status; + } + + return status; +} + +/** +* \brief SearchTaggedModuleMapLutForAnyTag +* Search the Tagged Module Map LUT for SubgraphTagEntries that match the input subgraph with any tag. +* \param[int] sg_id: Subgraph ID to search for +* \param[int] sg_lut_buf: List of Tagged Module Map entries +* \param[int] buf_size: size of Tagged Module Map buffer +* \param[out] tag_id: The Tag ID associated with the Subgraph +* \param[out] def_offset: Offset of the Module(s) associated with the tag +* \param[out] entry_offset: Offset of the SubgraphTagLutEntry in the sg_lut_buf +* \return AR_EOK on success, and AR_ENOTEXIST otherwise as well as tag id and def offset +*/ +int32_t SearchTaggedModuleMapLutForAnyTag(uint32_t sg_id, uint32_t* sg_lut_buf, uint32_t buf_size, uint32_t *tag_id, uint32_t* def_offset, uint32_t *entry_offset) +{ + uint32_t entry_offset_tmp = 0; + uint32_t search_index_count = 1; + //Search for any tag + SubgraphTagLutEntry sgTagEntry; + + sgTagEntry.sg_id = sg_id; + sgTagEntry.tag_id = 0; + sgTagEntry.offset = 0; + + if (SEARCH_ERROR == AcdbDataBinarySearch2((void*)sg_lut_buf, buf_size, + &sgTagEntry, search_index_count, + (int32_t)(sizeof(SubgraphTagLutEntry) / sizeof(uint32_t)), + &entry_offset_tmp)) + { + return AR_ENOTEXIST; + } + + ACDB_MEM_CPY_SAFE(&sgTagEntry, sizeof(SubgraphTagLutEntry), + sg_lut_buf + entry_offset_tmp * sizeof(uint32_t), + sizeof(SubgraphTagLutEntry)); + + if (sg_id == sgTagEntry.sg_id) + { + *tag_id = sgTagEntry.tag_id; + *def_offset = sgTagEntry.offset; + *entry_offset = entry_offset_tmp; + } + + return AR_EOK; +} + +/** +* \brief +* Search for the first occurance of a +* tuple using the Subgraph ID as a search key and returns the file +* offset of the first occurrance. +* +* \param[in/out] sg_tag_entry: Tag Key Data Table entry in the +* format of +* \param[in/out] file_offset: The absolute offset of the +* entry +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t TaggedModuleMapLutFindFirstOfSubgraphID( + ChunkInfo *ci_tagged_module_map_lut, SubgraphTagLutEntry *sg_tag_entry, + uint32_t *file_offset) +{ + int32_t status = AR_EOK; + uint32_t search_index_count = 1;//Binary Search based on Subgraph id + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + if (IsNull(sg_tag_entry) || IsNull(file_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameters is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + //Setup Table Information + table_info.table_offset = ci_tagged_module_map_lut->chunk_offset + + sizeof(uint32_t); + table_info.table_size = ci_tagged_module_map_lut->chunk_size + - sizeof(uint32_t); + table_info.table_entry_size = sizeof(SubgraphTagLutEntry); + + //Setup Search Information + search_info.num_search_keys = search_index_count; + search_info.num_structure_elements = + (sizeof(SubgraphTagLutEntry) / sizeof(uint32_t)); + search_info.table_entry_struct = sg_tag_entry; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: No tags found under Subgraph(0x%x).", + status, sg_tag_entry->sg_id); + return status; + } + + *file_offset = ci_tagged_module_map_lut->chunk_offset + + sizeof(uint32_t) //Number of entries + + search_info.entry_offset; + + return status; +} + +int32_t GetTagsFromGkvGetSize( + ChunkInfo *lut_chunk, ChunkInfo *def_chunk, + AcdbUintList* subgraph_list, + AcdbTagDefOffsetPairList *tag_defofst_list, + AcdbCmdGetTagsFromGkvRsp* rsp) +{ + int32_t status = AR_EOK; + uint32_t cur_sg_id = 0; + uint32_t offset = 0; + uint32_t def_offset = 0; + uint32_t num_modules = 0; + uint32_t sz_tag_module_obj = 0; + uint32_t sz_module_list = 0; + bool_t new_tag_found = TRUE; + SubgraphTagLutEntry* tagged_module_lut = NULL; + AcdbUintList found_tags = { 0 }; + SubgraphTagLutEntry sg_tag_entry = { 0 }; + uint32_t sg_tag_entry_offset = 0; + uint32_t lut_end_offset = 0; + AcdbTagDefOffsetPair tag_def_pair = { 0 }; + + /* GLB BUF 1 stores entries + * GLB BUF 2 stores the tags already found + * GLB BUF 3 stores the subgraph list */ + if (IsNull(subgraph_list) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameter(s) are null", status); + return AR_EBADPARAM; + } + + offset = lut_chunk->chunk_offset + sizeof(uint32_t);//skip num entries + status = FileManGetFilePointer2((void**)&tagged_module_lut, offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get file pointer to" + " tagged module lookup table", status); + return status; + } + + rsp->num_tags = 0; + rsp->list_size = 0; + found_tags.list = &glb_buf_2[0]; + lut_end_offset = + lut_chunk->chunk_offset + lut_chunk->chunk_size; + + for (uint32_t i = 0; i < subgraph_list->count; i++) + { + cur_sg_id = subgraph_list->list[i]; + sg_tag_entry.sg_id = cur_sg_id; + sg_tag_entry.tag_id = 0; + + status = TaggedModuleMapLutFindFirstOfSubgraphID( + lut_chunk, &sg_tag_entry, &sg_tag_entry_offset); + if (AR_ENOTEXIST == status) + { + status = AR_EOK; + continue; + } + else if (AR_FAILED(status)) + { + return status; + } + + //Set offset to next entry + sg_tag_entry_offset += sizeof(sg_tag_entry); + + do + { + if (cur_sg_id != sg_tag_entry.sg_id) + break; + + //Get list from Def offset + def_offset = def_chunk->chunk_offset + sg_tag_entry.offset; + tag_def_pair.tag_id = sg_tag_entry.tag_id; + tag_def_pair.def_offset = def_offset; + new_tag_found = TRUE; + offset = 0; + + status = FileManReadBuffer( + &num_modules, sizeof(uint32_t), &def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number " + "of modules", status); + return status; + } + + offset += sizeof(num_modules); + sz_module_list = num_modules * sizeof(AcdbModule); + + if (sz_module_list == 0) + { + ACDB_DBG("Ignoring unused tag Tag(0x%x). It is " + "not associated with any module.", tag_def_pair.tag_id); + continue; + } + + for (uint32_t j = 0; j < found_tags.count; j++) + { + if (tag_def_pair.tag_id == found_tags.list[j]) + { + new_tag_found = FALSE; + break; + } + } + + if (!new_tag_found) + { + //found tag id in found_tags_list + sz_tag_module_obj = sz_module_list; + } + else + { + //A new tag is being added + + found_tags.list[found_tags.count++] = tag_def_pair.tag_id; + sz_tag_module_obj = sizeof(tag_def_pair.tag_id) + + sizeof(num_modules) + sz_module_list; + rsp->num_tags += 1; + } + + if (tag_defofst_list->count + 1 > tag_defofst_list->max_count) + { + ACDB_ERR_MSG_1("Tag definition offset list is full", status); + status = AR_EFAILED; + break; + } + else + { + tag_defofst_list->list[tag_defofst_list->count++] = tag_def_pair; + } + + rsp->list_size += sz_tag_module_obj; + + if (sg_tag_entry_offset == lut_end_offset) + break; + + //go to next entry + status = FileManReadBuffer(&sg_tag_entry, + sizeof(sg_tag_entry), &sg_tag_entry_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read " + "subgraph & tag lut entry", status); + return status; + } + } while (sg_tag_entry_offset <= lut_end_offset); + } + + return status; +} + +int32_t GetTagsFromGkvGetData( + AcdbTagDefOffsetPairList *tag_defofst_list, + AcdbCmdGetTagsFromGkvRsp* rsp) +{ + int32_t status = AR_EOK; + uint32_t rsp_offset = 0; + uint32_t tag_id = 0; + uint32_t def_offset = 0; + uint32_t num_modules = 0; + uint32_t sz_module_list = 0; + uint32_t expected_size = 0; + uint32_t prev_tag_id = 0; + uint32_t total_num_modules = 0; + uint32_t rsp_offset_num_modules = 0; + uint32_t sz_tag_defofst_list = 0; + uint8_t* mid_iid_list = NULL; + AcdbTagDefOffsetPair *tag_def_pair = NULL; + + if (IsNull(tag_defofst_list) || IsNull(rsp) + || IsNull(rsp->tag_module_list)) + { + ACDB_ERR("Error[%d]: One or more input parameters " + "are null", AR_EBADPARAM) + return AR_EBADPARAM; + } + + expected_size = rsp->list_size; + sz_tag_defofst_list = + tag_defofst_list->count * tag_defofst_list->element_size; + + //Sort tag def list based on tag ID + status = AcdbSort2( + sz_tag_defofst_list, + (uint32_t*)tag_defofst_list->list, + 2 * sizeof(uint32_t), 0); + + if (AR_FAILED(status)) + { + ACDB_ERR_MSG_1("Failed to sort Tag ID & def offset list", status); + return status; + } + + for (uint32_t i = 0; i < tag_defofst_list->count; i++) + { + tag_def_pair = &tag_defofst_list->list[i]; + tag_id = tag_def_pair->tag_id; + num_modules = 0; + sz_module_list = 0; + + def_offset = tag_def_pair->def_offset; + status = FileManReadBuffer( + &num_modules, sizeof(uint32_t), &def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of modules", status); + return status; + } + + sz_module_list = num_modules * sizeof(AcdbModule); + + if (sz_module_list == 0) + continue; + + if (prev_tag_id != tag_id || i == 0) + { + if (expected_size < (rsp_offset + sizeof(tag_id))) + return AR_ENEEDMORE; + + //Write Tag ID + ACDB_MEM_CPY_SAFE(rsp->tag_module_list + rsp_offset, + sizeof(tag_id), &tag_id, sizeof(tag_id)); + rsp_offset += sizeof(tag_id); + + if (expected_size < (rsp_offset + sizeof(num_modules))) + return AR_ENEEDMORE; + + //Write num modules + ACDB_MEM_CPY_SAFE(rsp->tag_module_list + rsp_offset, + sizeof(num_modules), &num_modules, sizeof(num_modules)); + rsp_offset_num_modules = rsp_offset; + rsp_offset += sizeof(num_modules); + total_num_modules = num_modules; + + /* Write module id list: + * [...] */ + if (num_modules != 0) + { + if (expected_size < (rsp_offset + sz_module_list)) + return AR_ENEEDMORE; + + status = FileManGetFilePointer2((void**)&mid_iid_list, def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR_MSG_1("Failed to read Tag module list", status); + return status; + } + + ACDB_MEM_CPY_SAFE(rsp->tag_module_list + rsp_offset, + sz_module_list, mid_iid_list, sz_module_list); + + rsp_offset += sz_module_list; + def_offset += sz_module_list; + } + } + else + { + //update num_modules and write new ... + total_num_modules += num_modules; + if (expected_size < (rsp_offset_num_modules + sizeof(total_num_modules))) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE(rsp->tag_module_list + rsp_offset_num_modules, + sizeof(total_num_modules), &total_num_modules, sizeof(total_num_modules)); + + if (num_modules != 0) + { + if (expected_size < (rsp_offset + sz_module_list)) + return AR_ENEEDMORE; + + status = FileManGetFilePointer2((void**)&mid_iid_list, def_offset); + if (AR_FAILED(status)) + { + ACDB_ERR_MSG_1("Failed to read Tag module list", status); + return status; + } + + ACDB_MEM_CPY_SAFE(rsp->tag_module_list + rsp_offset, + sz_module_list, mid_iid_list, sz_module_list); + + rsp_offset += sz_module_list; + def_offset += sz_module_list; + } + } + + if (AR_FAILED(status)) + { + ACDB_ERR_MSG_1("Failed to read Tag module list from file", status); + return status; + } + + prev_tag_id = tag_id; + } + + return status; +} + +int32_t BuildGetTagsFromGkvRsp(AcdbUintList* subgraph_list, + AcdbCmdGetTagsFromGkvRsp* rsp) +{ + int32_t status = AR_EOK; + ChunkInfo ci_lut = { 0 }; + ChunkInfo ci_def = { 0 }; + + AcdbTagDefOffsetPairList tag_defofst_list = { 0 }; + AcdbOp op = ACDB_OP_NONE; + + ci_lut.chunk_id = ACDB_CHUNKID_TAGGED_MODULE_LUT; + ci_def.chunk_id = ACDB_CHUNKID_TAGGED_MODULE_DEF; + status = ACDB_GET_CHUNK_INFO(&ci_lut, &ci_def); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get one or more chunks", status); + return status; + } + + op = IsNull(rsp->tag_module_list) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + tag_defofst_list.max_count = (uint32_t)(sizeof(glb_buf_1) / sizeof(uint32_t)); + tag_defofst_list.element_size = sizeof(AcdbTagDefOffsetPair); + tag_defofst_list.list = (AcdbTagDefOffsetPair*)&glb_buf_1[0]; + + status = GetTagsFromGkvGetSize(&ci_lut, &ci_def, + subgraph_list, (void*)&tag_defofst_list, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get size of " + "tagged module list", status); + return status; + } + + if (op == ACDB_OP_GET_DATA) + { + status = GetTagsFromGkvGetData((void*)&tag_defofst_list, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get " + "tagged module list", status); + } + } + + ACDB_CLEAR_BUFFER(glb_buf_1); + ACDB_CLEAR_BUFFER(glb_buf_2); + ACDB_CLEAR_BUFFER(glb_buf_3); + + if (rsp->num_tags == 0) + { + status = AR_ENOTEXIST; + ACDB_ERR_MSG_1("No tags were found", status); + } + + return status; +} + +int32_t AcdbCmdGetTagsFromGkv(AcdbCmdGetTagsFromGkvReq *req, AcdbCmdGetTagsFromGkvRsp *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + AcdbGraphKeyVector graph_kv = { 0 }; + AcdbUintList subgraph_list = { 0 }; + + if (req->graph_key_vector->num_keys == 0) + { + ACDB_ERR("Error[%d]: No data exist for the empty GKV", + AR_ENOTEXIST); + return AR_ENOTEXIST; + } + else + { + ACDB_DBG("Retrieving Tag list for the following graph key vector:"); + LogKeyVector(req->graph_key_vector, GRAPH_KEY_VECTOR); + } + + if (rsp_size < sizeof(AcdbCmdGetTagsFromGkvRsp)) + { + ACDB_ERR("Error[%d]: The response structure size is less than %d", + AR_EBADPARAM, sizeof(AcdbCmdGetTagsFromGkvRsp)); + return AR_EBADPARAM; + } + + //GLB BUF 3 is used to store the sorted GKV + graph_kv.num_keys = req->graph_key_vector->num_keys; + graph_kv.graph_key_vector = (AcdbKeyValuePair*)&glb_buf_3[0]; + ACDB_MEM_CPY_SAFE(&glb_buf_3[0], + graph_kv.num_keys * sizeof(AcdbKeyValuePair), + req->graph_key_vector->graph_key_vector, + graph_kv.num_keys * sizeof(AcdbKeyValuePair)); + + //Sort Key Vector by Key IDs(position 0 of AcdbKeyValuePair) + status = AcdbSort2(graph_kv.num_keys * sizeof(AcdbKeyValuePair), + graph_kv.graph_key_vector, sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort the graph key vector.", status); + return status; + } + + subgraph_list.list = &glb_buf_3[0]; + + status = AcdbGetUsecaseSubgraphList(req->graph_key_vector, + &subgraph_list, NULL); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get subgraphs " + "from graph key vector", status); + return status; + } + + status = BuildGetTagsFromGkvRsp(&subgraph_list, rsp); + + if (AR_FAILED(status)) return status; + + return status; +} + +/** +* \brief +* Interleaves two lists. If List 1 is [1 2 3 4] and List 2 is [5 6 7 8] +* The resulting list is List[1 5 2 6 3 7 4 8] +* +* Note: An inplace shuffle can be used zip within the same array +* +* \param[in] num_elem_1: Number of elements in list 1 +* \param[in] list_1: List to be interleaved with list 2 +* \param[in] num_elem_2: Number of elements in list 2 +* \param[in] list_2: List to be interleaved with list 1 +* \param[in] num_elem_3: Number of elements in list 3 +* \param[in/out] list_3: The interleaved list +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbZip1(uint32_t num_elem_1, uint32_t *list_1, + uint32_t num_elem_2, uint32_t *list_2, + uint32_t num_elem_3, uint32_t *list_3) +{ + if (num_elem_1 != num_elem_2) + return AR_EBADPARAM; + + if(IsNull(list_1) || IsNull(list_2)) + return AR_EBADPARAM; + + if(num_elem_3 != num_elem_1 + num_elem_2) + return AR_EBADPARAM; + + uint32_t index_1 = 0, index_2 = 0; + for (uint32_t i = 0; i < num_elem_3 ; i++) + { + if (i % 2 == 0) + { + list_3[i] = list_1[index_1]; + index_1++; + } + else + { + list_3[i] = list_2[index_2]; + index_2++; + } + } + + return AR_EOK; +} + +/** +* \brief +* Checks for the existance of a CKV within the lookup table +* +* \param[in] kv_list: contains the key id and value lists that are +* used to compare against an entry in the lookup table +* \param[in] lookup: a look up table that contains +* pairs +* \param[in/out] status: AR status +* +* \return FALSE(0) or TRUE(1) +*/ +bool_t LookupContainsCKV(AcdbKeyValueList *kv_list, + AcdbKeyVectorLut* lookup, int32_t *status) +{ + uint32_t offset = 0; + uint32_t num_keys = 0; + uint32_t *key_list = NULL; + uint32_t *value_list = NULL; + uint32_t *tmp_buf = NULL; + bool_t contains_ckv = FALSE; + if (IsNull(kv_list) || IsNull(lookup) || IsNull(status)) + return AR_EBADPARAM; + + *status = AR_EOK; + AcdbKeyVectorLutEntry entry = { 0 }; + for (uint32_t i = 0; i < lookup->num_entries; i++) + { + entry = lookup->lookup_table[i]; + offset = entry.offset_key_tbl; + + *status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(*status)) + { + ACDB_ERR("Error[%d]: Failed to read number of keys.", *status); + return contains_ckv; + } + + if (num_keys != kv_list->num_keys) + continue; + + if (num_keys == 0) + return TRUE; + + if (IsNull(tmp_buf)) + { + tmp_buf = ACDB_MALLOC(uint32_t, 2 * num_keys); + if (IsNull(tmp_buf)) + { + *status = AR_ENOMEMORY; + return contains_ckv; + } + key_list = &tmp_buf[0]; + value_list = &tmp_buf[num_keys]; + } + + *status = FileManReadBuffer(key_list, + num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(*status)) + { + ACDB_ERR("Error[%d]: Failed to read Key ID List", *status); + goto end; + } + + if (0 != ACDB_MEM_CMP(kv_list->key_list, key_list, + num_keys * sizeof(uint32_t))) + { + continue; + } + + offset = entry.offset_value_list; + *status = FileManReadBuffer(value_list, + num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(*status)) + { + ACDB_ERR("Error[%d]: Failed to read Value List", *status); + goto end; + } + + if (0 == ACDB_MEM_CMP(kv_list->value_list, value_list, + num_keys * sizeof(uint32_t))) + { + contains_ckv = TRUE; + break; + } + } + +end: + + if (!IsNull(tmp_buf)) + { + ACDB_FREE(tmp_buf); + tmp_buf = NULL; + key_list = NULL; + value_list = NULL; + } + + return contains_ckv; +} + +/** +* \brief +* Adds a pair to the lookup table. The +* value tbl off. points to an entry with in the Value LUT, i.e the +* actual list of values. +* Ex. value tbl off -> [v1, v2, v3, def, dot] (one entry in the +* Value LUT) +* +* \param[in] entry: a pair +* used to compare against an entry in the lookup table +* \param[in] lookup: a look up table that contains +* pairs +* +* \return 0 on success, and non-zero on failure +*/ +int32_t AddCkvEntryToLookup(AcdbKeyVectorLutEntry *entry, + AcdbKeyVectorLut* lookup) +{ + int32_t status = AR_EOK; + ChunkInfo ci_calkeytbl = { 0 }; + ChunkInfo ci_callut = { 0 }; + + ci_calkeytbl.chunk_id = ACDB_CHUNKID_CALKEYTBL; + ci_callut.chunk_id = ACDB_CHUNKID_CALDATALUT; + + status = ACDB_GET_CHUNK_INFO(&ci_calkeytbl, &ci_callut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get chunk info for either " + "Cal Key or Cal Lookup table.", AR_EBADPARAM); + return status; + } + + if (IsNull(entry) || IsNull(lookup)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null:" + " key vector entry or lookup.", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (lookup->size == 0) + { + ACDB_ERR("Error[%d]: The lookup table size is zero", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (lookup->num_entries * sizeof(entry) >= lookup->size) + { + ACDB_ERR("Error[%d]: The lookup table is full", AR_EBADPARAM); + return AR_EBADPARAM; + } + + ACDB_MEM_CPY_SAFE(&lookup->lookup_table[lookup->num_entries], + sizeof(*entry), entry, sizeof(*entry)); + lookup->num_entries++; + + return AR_EOK; +} + +/** +* \brief +* Retrieves all the audio cal key vector combinations for a set of keys given +* the offset of the Key ID and Key Value tables +* +* \depends +* Makes use of GLB_BUF_3 to store key vector data +* +* \param[in/out] lookup: Keeps track of key vectors already found +* Key ID and Key Value tables +* \param[in] cal_key_table_entry: An entry that holds the offsets to the +* Key ID and Key Value tables +* \param[in/out] blob_offset: current offset in the rsp +* \param[in] expected_size: the expected size of the rsp.list_size +* \param[out] rsp: The Key Vector List to be populated +* +* \return 0 on success, and non-zero on failure +*/ +int32_t GetAllAudioCKVVariations(AcdbKeyVectorLut *lookup, + AcdbCalKeyTblEntry *cal_key_table_entry, + uint32_t *blob_offset, uint32_t expected_size, AcdbKeyVectorList *rsp) +{ + int32_t status = AR_EOK; + //bool_t found = FALSE; + uint32_t offset = 0; + uint32_t num_keys = 0; + //uint32_t num_lut_entries = 0; + ChunkInfo ci_calkeytbl = { 0 }; + ChunkInfo ci_callut = { 0 }; + AcdbOp op = ACDB_OP_NONE; + KeyTableHeader key_value_table_header = { 0 }; + uint32_t *key_id_list = NULL; + uint32_t *key_value_list = NULL; + uint32_t *ckv = NULL; + /* Contains offsets to key table and offset of a particualr value list + * in the value lut. The offsets include the respective chunk offset */ + AcdbKeyVectorLutEntry ckv_entry = { 0 }; + AcdbKeyValueList kv_list = { 0 }; + + if (IsNull(lookup) || IsNull(cal_key_table_entry) + || IsNull(blob_offset) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + op = IsNull(rsp->key_vector_list) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + ci_calkeytbl.chunk_id = ACDB_CHUNKID_CALKEYTBL; + ci_callut.chunk_id = ACDB_CHUNKID_CALDATALUT; + + status = ACDB_GET_CHUNK_INFO(&ci_calkeytbl, &ci_callut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get chunk info for either " + "Cal Key or Cal Lookup table.", AR_EBADPARAM); + return status; + } + + offset = ci_calkeytbl.chunk_offset + + cal_key_table_entry->offset_cal_key_tbl; + ckv_entry.offset_key_tbl = offset; + + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of keys.", status); + return status; + } + + if (num_keys != 0) + { + status = FileManReadBuffer(&glb_buf_3[0], + num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key ID List", status); + return status; + } + } + + offset = ci_callut.chunk_offset + + cal_key_table_entry->offset_cal_lut; + status = FileManReadBuffer(&key_value_table_header, + sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of values " + "and lut entries.", status); + return status; + } + + if (num_keys != key_value_table_header.num_keys) + { + ACDB_ERR("Error[%d]: Number of keys and values are" + " different!", AR_EFAILED); + return AR_EFAILED; + } + //GLB_BUF_3 stores the key vector IDs followed by the Values + //Ex. [K1 K2 K2 V1 V2 V3] + key_id_list = &glb_buf_3[0]; + key_value_list = &glb_buf_3[num_keys]; + ckv = &glb_buf_3[num_keys * 2]; + + kv_list.num_keys = num_keys; + kv_list.key_list = key_id_list; + kv_list.value_list = key_value_list; + + for (uint32_t i = 0; i < key_value_table_header.num_entries; i++) + { + ckv_entry.offset_value_list = offset; + + if (num_keys != 0) + { + status = FileManReadBuffer(key_value_list, + num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key Value List.", status); + return status; + } + } + + offset += sizeof(AcdbCkvLutEntryOffsets); + + /* Check to see if we already accounted for the CKV. If so, skip + * the CKV. Otherwise add the CKV to the lookup */ + if (LookupContainsCKV(&kv_list, lookup, &status) + && AR_SUCCEEDED(status)) + { + continue; + } + + status = AddCkvEntryToLookup(&ckv_entry, lookup); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to add ckv entry to lookup.", status); + } + + rsp->num_key_vectors ++; + rsp->list_size += (sizeof(num_keys) + + num_keys * sizeof(AcdbKeyValuePair)); + + if (op == ACDB_OP_GET_SIZE) continue; + + //Write Key Vector + status = AcdbZip1(num_keys, key_id_list, + num_keys, key_value_list, + num_keys * 2, ckv); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to zip key id and" + " key value list.", status); + return status; + } + + //Write num keys + if (*blob_offset + + sizeof(uint32_t) > expected_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->key_vector_list + *blob_offset, + sizeof(uint32_t), + &num_keys, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + if (num_keys == 0) continue; + + //Write Key Vector + if (*blob_offset + + num_keys * sizeof(AcdbKeyValuePair) > expected_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->key_vector_list + *blob_offset, + num_keys * sizeof(AcdbKeyValuePair), + ckv, num_keys * sizeof(AcdbKeyValuePair)); + *blob_offset += num_keys * sizeof(AcdbKeyValuePair); + + // + //offset += sizeof(AcdbCkvLutEntryOffsets); + } + + ACDB_CLEAR_BUFFER(glb_buf_3); + return status; +} + +/** +* \brief +* Retrieves all the voice cal key vector combinations +* for one voice subgraph +* +* \depends +* Makes use of GLB_BUF_3 to store key vector data +* +* \param[in/out] lookup: Keeps track of key vectors already found +* Key ID and Key Value tables +* \param[in] file_offset: absolute file offset of a +* subgraphs vcpm cal data +* \param[in/out] blob_offset: current offset in the rsp +* \param[in] expected_size: the expected size of the rsp.list_size +* \param[out] rsp: The Key Vector List to be populated +* +* \return 0 on success, and non-zero on failure +*/ +int32_t GetAllVoiceCKVVariations(AcdbKeyVectorLut *lookup, + uint32_t *file_offset, AcdbVcpmSubgraphCalTable *sg_cal_data_tbl_header, + uint32_t *blob_offset, uint32_t expected_size, AcdbKeyVectorList *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t kv_tbl_offset = 0; + uint32_t num_keys = 0; + uint32_t *ckv = NULL; + uint32_t *key_id_list = NULL; + uint32_t *key_value_list = NULL; + AcdbKeyVectorLutEntry ckv_entry = { 0 }; + AcdbKeyValueList kv_list = { 0 }; + ChunkInfo ci_vcpm_key_tbl = { 0 }; + ChunkInfo ci_vcpm_value_tbl = { 0 }; + AcdbVcpmCkvDataTable ckv_data_tbl_header = { 0 }; + AcdbVcpmCalDataObj cal_data_obj = { 0 }; + AcdbOp op = ACDB_OP_NONE; + + if (IsNull(lookup) || IsNull(file_offset) + || IsNull(sg_cal_data_tbl_header) + || IsNull(blob_offset) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + op = IsNull(rsp->key_vector_list) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + ci_vcpm_key_tbl.chunk_id = ACDB_CHUNKID_VCPM_CALKEY_TABLE; + ci_vcpm_value_tbl.chunk_id = ACDB_CHUNKID_VCPM_CALDATA_LUT; + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_key_tbl, &ci_vcpm_value_tbl); + if (AR_FAILED(status)) + { + if (ci_vcpm_key_tbl.chunk_size == 0) + ACDB_ERR("Error[%d]: Failed to get chunk info for the" + " VCPM Calibration Key Table", status); + if (ci_vcpm_value_tbl.chunk_size == 0) + ACDB_ERR("Error[%d]: Failed to get chunk info for the" + " VCPM Calibration Data Table", status); + } + + offset = *file_offset; + + for (uint32_t i = 0; i < sg_cal_data_tbl_header->num_ckv_data_table; i++) + { + //Get Voice Key Table offset and combine key id list with value list + status = FileManReadBuffer(&ckv_data_tbl_header, + sizeof(AcdbVcpmCkvDataTable), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read VCPM CKV Data Table header.", + status); + return status; + } + + for (uint32_t j = 0; j < ckv_data_tbl_header.num_caldata_obj; j++) + { + status = FileManReadBuffer(&cal_data_obj, + sizeof(AcdbVcpmCalDataObj), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read VCPM Cal Data Obj" , + status); + return status; + } + + offset += cal_data_obj.num_data_offsets * sizeof(uint32_t); + + ckv_entry.offset_key_tbl = ci_vcpm_key_tbl.chunk_offset + + ckv_data_tbl_header.offset_voice_key_table; + ckv_entry.offset_value_list = ci_vcpm_value_tbl.chunk_offset + + cal_data_obj.offset_vcpm_ckv_lut + + 2 * sizeof(uint32_t); + + kv_tbl_offset = ckv_entry.offset_key_tbl; + + //read number of keys from key table + status = FileManReadBuffer(&num_keys, + sizeof(uint32_t), &kv_tbl_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read VCPM Cal Data Obj" + , status); + return status; + } + + //GLB_BUF_3 stores the key vector IDs followed by the Values + //Ex. [K1 K2 K2 V1 V2 V3] + key_id_list = &glb_buf_3[0]; + key_value_list = &glb_buf_3[num_keys]; + ckv = &glb_buf_3[num_keys * 2]; + + kv_list.num_keys = num_keys; + kv_list.key_list = key_id_list; + kv_list.value_list = key_value_list; + + if (num_keys != 0) + { + status = FileManReadBuffer(&glb_buf_3[0], + num_keys * sizeof(uint32_t), &kv_tbl_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key ID List", status); + return status; + } + + /* Skip #keys and #entries(#entries is always 1 for + * each voice value table */ + kv_tbl_offset = ckv_entry.offset_value_list; + status = FileManReadBuffer(key_value_list, + num_keys * sizeof(uint32_t), &kv_tbl_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key Value List.", status); + return status; + } + } + + /* Check to see if we already accounted for the CKV. If so, skip + * the CKV. Otherwise add the CKV to the lookup */ + if (LookupContainsCKV(&kv_list, lookup, &status) + && AR_SUCCEEDED(status)) + { + continue; + } + + status = AddCkvEntryToLookup(&ckv_entry, lookup); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to add ckv entry to lookup.", status); + } + + rsp->num_key_vectors++; + rsp->list_size += (sizeof(num_keys) + + num_keys * sizeof(AcdbKeyValuePair)); + + if (op == ACDB_OP_GET_SIZE) continue; + + //Write Key Vector + status = AcdbZip1(num_keys, key_id_list, + num_keys, key_value_list, + num_keys * 2, ckv); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to zip key id and" + " key value list.", status); + return status; + } + + //Write num keys + if (*blob_offset + + sizeof(uint32_t) > expected_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->key_vector_list + *blob_offset, + sizeof(uint32_t), &num_keys, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + if (num_keys == 0) continue; + + //Write Key Vector + if (*blob_offset + + num_keys * sizeof(AcdbKeyValuePair) > expected_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->key_vector_list + *blob_offset, + num_keys * sizeof(AcdbKeyValuePair), + ckv, num_keys * sizeof(AcdbKeyValuePair)); + *blob_offset += num_keys * sizeof(AcdbKeyValuePair); + + } + } + + return status; +} + +/** +* \brief +* Builds a list of cal key vectors using the subgraphs defined in a graph +* +* \param[in] sg_list_offset: Offset of the subgraph list +* \param[out] rsp: The Key Vector List to be populated +* +* \return 0 on success, and non-zero on failure +*/ +int32_t BuildCalKeyVectorList( + AcdbKeyVectorList *rsp, uint32_t sg_list_offset) +{ + int32_t status = AR_EOK; + bool_t ignore_voice_ckv = FALSE; + uint32_t offset = 0; + uint32_t sg_vcpm_data_offset = 0; + uint32_t data_pool_offset = 0; + uint32_t ckv_list_offset = 0; + uint32_t blob_offset = 0; + //The expected size of rps.key_vector_list set by client + uint32_t expected_size = 0; + ChunkInfo ci_data_pool = { 0 }; + ChunkInfo ci_vcpm_cal = { 0 }; + SgListHeader sg_list_header = { 0 }; + SgListObjHeader sg_obj = { 0 }; + AcdbSgCalLutHeader sg_entry_header = { 0 }; + AcdbCalKeyTblEntry e = { 0 }; + /* Keeps track of key vectors that have already been found */ + AcdbKeyVectorLut lookup = { 0 }; + AcdbVcpmSubgraphCalHeader sg_vcpm_caldata_header = { 0 }; + AcdbVcpmSubgraphCalTable sg_cal_tbl_header = { 0 }; + if (IsNull(rsp)) + { + ACDB_ERR("Error[%d]: The input parameter rsp is null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (!IsNull(rsp->key_vector_list)) + { + expected_size = rsp->list_size; + rsp->list_size = 0; + rsp->num_key_vectors = 0; + } + + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + ci_vcpm_cal.chunk_id = ACDB_CHUNKID_VCPM_CAL_DATA; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool, &ci_vcpm_cal); + if (AR_FAILED(status)) + { + if (0 == ci_vcpm_cal.chunk_size) + { + ignore_voice_ckv = TRUE; + ACDB_DBG("Warning[%d]: No voice cal data found in file. " + "Ignoring voice ckvs..", status); + status = AR_EOK; + } + if (0 == ci_data_pool.chunk_size) + { + ACDB_ERR("Error[%d]: Unable to retrieve graph ckvs. " + "Datapool chunk is empty.", status); + return status; + } + } + + //The KV Lookup Table uses GLB BUF 1 + ACDB_CLEAR_BUFFER(glb_buf_1); + lookup.size = sizeof(glb_buf_1); + lookup.lookup_table = (AcdbKeyVectorLutEntry*)&glb_buf_1; + + data_pool_offset = ci_data_pool.chunk_offset + sg_list_offset; + status = FileManReadBuffer(&sg_list_header, + sizeof(SgListHeader), &data_pool_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read the subgraph" + " list header", status); + return status; + } + + if (!ignore_voice_ckv) + { + offset = ci_vcpm_cal.chunk_offset; + status = FileManReadBuffer(&sg_vcpm_caldata_header, + sizeof(AcdbVcpmSubgraphCalHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: VCPM Subgraph Caldata header.", status); + return status; + } + } + + + // Loop through each subgraph and combine all the key vectors into a list + for (uint32_t i = 0; i < sg_list_header.num_subgraphs; i++) + { + + status = FileManReadBuffer(&sg_obj, sizeof(SgListObjHeader), + &data_pool_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read the subgraph" + " object header", status); + return status; + } + + //Skip over subgraph destinations + data_pool_offset += sg_obj.num_subgraphs * sizeof(uint32_t); + + //Get Voice CKVs for a voice subgraph + if (!ignore_voice_ckv) + { + sg_vcpm_data_offset = offset; + status = GetVcpmSubgraphCalTable(sg_vcpm_caldata_header.num_subgraphs, + sg_obj.subgraph_id, &sg_vcpm_data_offset, &sg_cal_tbl_header); + if (AR_SUCCEEDED(status)) + { + status = GetAllVoiceCKVVariations(&lookup, &sg_vcpm_data_offset, + &sg_cal_tbl_header, &blob_offset, expected_size, rsp); + if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: Failed to get Voice CKVs for " + "Subgraph(0x%x)", status); + return status; + } + + continue; + } + } + + //Get Audio CKVs for a subgraph + sg_entry_header.subgraph_id = sg_obj.subgraph_id; + status = SearchSubgraphCalLut2(&sg_entry_header, &ckv_list_offset); + if (AR_ENOTEXIST == status) + { + ACDB_DBG("Warning[%d]: Unable to find audio ckv table for " + "for Subgraph(0x%x). Skipping..", status, sg_obj.subgraph_id); + continue; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to find audio ckv table for " + "for Subgraph(0x%x).", status, sg_obj.subgraph_id); + return status; + } + + //Search List of Offsets for matching CKV + for (uint32_t j = 0; j < sg_entry_header.num_ckv_entries; j++) + { + status = FileManReadBuffer(&e, sizeof(AcdbCalKeyTblEntry), + &ckv_list_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: CKV key table and" + " value table offsets", status); + return status; + } + + status = GetAllAudioCKVVariations( + &lookup, &e, &blob_offset, expected_size, rsp); + if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: CKV key table and" + " value table offsets", status); + return status; + } + } + } + + return status; +} + +/** +* \brief +* Search for the first occurance of a +* tuple using the Subgraph ID as a search key and returns the file +* offset of the first occurrance. +* +* \param[in/out] sg_tag_entry: Tag Key Data Table entry in the +* format of +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t TagKeyTableFindFirstOfSubgraphID(SubgraphTagLutEntry *sg_tag_entry, uint32_t* file_offset) +{ + int32_t status = AR_EOK; + //uint32_t offset = 0; + ChunkInfo ci_tag_key_tbl = { 0 }; + + //Binary Search based on Subgraph id + uint32_t search_index_count = 1; + uint32_t sz_gsl_cal_lut = 0; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + if (IsNull(sg_tag_entry) || IsNull(file_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameters is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_tag_key_tbl.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_KEYTABLE; + status = ACDB_GET_CHUNK_INFO(&ci_tag_key_tbl); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get Module Tag Key Table Chunk", + status); + return status; + } + + sz_gsl_cal_lut = ci_tag_key_tbl.chunk_size - sizeof(uint32_t); + + //Setup Table Information + table_info.table_offset = ci_tag_key_tbl.chunk_offset + sizeof(uint32_t); + table_info.table_size = sz_gsl_cal_lut; + table_info.table_entry_size = sizeof(SubgraphTagLutEntry); + + //Setup Search Information + search_info.num_search_keys = search_index_count; + search_info.num_structure_elements = + (sizeof(SubgraphTagLutEntry) / sizeof(uint32_t)); + search_info.table_entry_struct = sg_tag_entry; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Failed to find Subgraph ID(0x%x)", sg_tag_entry->sg_id); + return status; + } + + *file_offset = ci_tag_key_tbl.chunk_offset + + sizeof(uint32_t) //Number of entries + + search_info.entry_offset; + + ACDB_CLEAR_BUFFER(glb_buf_1); + + return status; +} + +int32_t FindTagKeyList(uint32_t tag_id, uint32_t* dpo) +{ + int32_t status = AR_EOK; + ChunkInfo ci_tag_key_list_lut = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + TagKeyListEntry tag_key_list_entry = { 0 }; + + if (IsNull(dpo)) + { + ACDB_ERR("Error[%d]: One or more input parameters is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_tag_key_list_lut.chunk_id = ACDB_CHUNKID_MODULE_TAG_KEY_LIST_LUT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool, &ci_tag_key_list_lut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get Module Tag Key Table Chunk", + status); + return status; + } + + tag_key_list_entry.tag_id = tag_id; + + //Setup Table Information + table_info.table_offset = + ci_tag_key_list_lut.chunk_offset + sizeof(uint32_t); + table_info.table_size = ci_tag_key_list_lut.chunk_size + - sizeof(uint32_t); + table_info.table_entry_size = sizeof(TagKeyListEntry); + + //Setup Search Information + search_info.num_search_keys = 1;//Binary Search based on Tag id + search_info.num_structure_elements = + (sizeof(TagKeyListEntry) / sizeof(uint32_t)); + search_info.table_entry_struct = &tag_key_list_entry; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Failed to find Tag ID(0x%x)", tag_id); + return status; + } + + //Key Table format: [Table Size, Num Keys, KeyID+] + *dpo = ci_data_pool.chunk_offset + tag_key_list_entry.key_list_offset + + sizeof(uint32_t);//Skip size + ACDB_CLEAR_BUFFER(glb_buf_1); + + return status; +} + +/** +* \brief +* Retrieves all the audio cal key vector combinations for a set of keys given +* the offset of the Key ID and Key Value tables +* +* \depends +* Makes use of GLB_BUF_3 to store key vector data +* +* \param[in/out] lookup: Keeps track of key vectors already found +* Key ID and Key Value tables +* \param[in] cal_key_table_entry: An entry that holds the offsets to the +* Key ID and Key Value tables +* \param[in/out] blob_offset: current offset in the rsp +* \param[in] expected_size: the expected size of the rsp.list_size +* \param[out] rsp: The Key Vector List to be populated +* +* \return 0 on success, and non-zero on failure +*/ +int32_t GetAllTKVVariations(SubgraphTagLutEntry *sg_tag_entry, + uint32_t *blob_offset, uint32_t expected_size, AcdbTagKeyVectorList *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_keys = 0; + ChunkInfo ci_tag_data_lut_tbl = { 0 }; + AcdbOp op = ACDB_OP_NONE; + KeyTableHeader key_value_table_header = { 0 }; + uint32_t *key_id_list = NULL; + uint32_t *key_value_list = NULL; + uint32_t *tkv = NULL; + + op = IsNull(rsp->key_vector_list) ? ACDB_OP_GET_SIZE : ACDB_OP_GET_DATA; + + ci_tag_data_lut_tbl.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_LUT; + + status = ACDB_GET_CHUNK_INFO(&ci_tag_data_lut_tbl); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get chunk info for: " + "Tag Key List/Data tables or Datapool.", AR_EBADPARAM); + return status; + } + + status = FindTagKeyList(sg_tag_entry->tag_id, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to find Tag(0x%x)", + AR_EBADPARAM, sg_tag_entry->tag_id); + return status; + } + + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of keys.", status); + return status; + } + + if (num_keys != 0) + { + status = FileManReadBuffer(&glb_buf_3[0], + num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key ID List", status); + return status; + } + } + + offset = ci_tag_data_lut_tbl.chunk_offset + + sg_tag_entry->offset; + status = FileManReadBuffer(&key_value_table_header, + sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of values " + "and lut entries.", status); + return status; + } + + if (num_keys != key_value_table_header.num_keys) + { + ACDB_ERR("Error[%d]: Number of keys and values are" + " different!", AR_EFAILED); + return AR_EFAILED; + } + //GLB_BUF_3 stores the key vector IDs followed by the Values + //Ex. [K1 K2 K2 V1 V2 V3] + key_id_list = &glb_buf_3[0]; + key_value_list = &glb_buf_3[num_keys]; + tkv = &glb_buf_3[num_keys * 2]; + + for (uint32_t i = 0; i < key_value_table_header.num_entries; i++) + { + if (num_keys != 0) + { + status = FileManReadBuffer(key_value_list, + num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key Value List.", status); + return status; + } + } + + //Skip Def and Dot offsets + offset += 2 * sizeof(uint32_t); + + rsp->num_key_vectors++; + rsp->list_size += (sizeof(sg_tag_entry->tag_id) + sizeof(num_keys) + + num_keys * sizeof(AcdbKeyValuePair)); + + if (op == ACDB_OP_GET_SIZE) continue; + + //Write Key Vector + status = AcdbZip1(num_keys, key_id_list, + num_keys, key_value_list, + num_keys * 2, tkv); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to zip key id and" + " key value list.", status); + return status; + } + + //Write Tag ID + if (*blob_offset + + sizeof(uint32_t) > expected_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->key_vector_list + *blob_offset, + sizeof(uint32_t), &sg_tag_entry->tag_id, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + //Write num keys + if (*blob_offset + + sizeof(uint32_t) > expected_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->key_vector_list + *blob_offset, + sizeof(uint32_t), &num_keys, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + if (num_keys == 0) continue; + + //Write Key Vector + if (*blob_offset + + num_keys * sizeof(AcdbKeyValuePair) > expected_size) + { + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->key_vector_list + *blob_offset, + num_keys * sizeof(AcdbKeyValuePair), + tkv, num_keys * sizeof(AcdbKeyValuePair)); + *blob_offset += num_keys * sizeof(AcdbKeyValuePair); + } + + ACDB_CLEAR_BUFFER(glb_buf_3); + return status; +} + +/** +* \brief +* Builds a list of tag key vectors using the subgraphs defined in a graph +* +* \depends +* Makes use of GLB_BUF_2 to keep track of tags that were found +* +* \param[in] sg_list_offset: Offset of the subgraph list +* \param[out] rsp: The Key Vector List to be populated +* +* \return 0 on success, and non-zero on failure +*/ +int32_t BuildTagKeyVectorList( + AcdbTagKeyVectorList *rsp, uint32_t sg_list_offset) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t data_pool_offset = 0; + uint32_t blob_offset = 0; + uint32_t end_offset = 0; + //The expected size of rps.key_vector_list set by client + uint32_t expected_size = 0; + ChunkInfo ci_data_pool = { 0 }; + ChunkInfo ci_tag_data_lut = { 0 }; + ChunkInfo ci_tag_key_tbl = { 0 }; + SgListHeader sg_list_header = { 0 }; + SgListObjHeader sg_obj = { 0 }; + SubgraphTagLutEntry sg_tag_entry = { 0 }; + AcdbUintList found_tags = { 0 }; + bool_t skip_tag = FALSE; + + if (IsNull(rsp)) + { + ACDB_ERR("Error[%d]: The input parameter rsp is null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (!IsNull(rsp->key_vector_list)) + { + expected_size = rsp->list_size; + rsp->list_size = 0; + rsp->num_key_vectors = 0; + } + + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + ci_tag_data_lut.chunk_id = ACDB_CHUNKID_MODULE_TAG_KEY_LIST_LUT; + ci_tag_key_tbl.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_KEYTABLE; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool, + &ci_tag_data_lut, &ci_tag_key_tbl); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve chunk info for: " + "data pool or tag data.", status); + return status; + } + + data_pool_offset = ci_data_pool.chunk_offset + sg_list_offset; + status = FileManReadBuffer(&sg_list_header, + sizeof(SgListHeader), &data_pool_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read the subgraph" + " list header", status); + return status; + } + + //Setup list of found tags using GLB_BUFFER_2 + found_tags.list = &glb_buf_2[0]; + + // Loop through each subgraph and combine all the key vectors into a list + for (uint32_t i = 0; i < sg_list_header.num_subgraphs; i++) + { + status = FileManReadBuffer(&sg_obj, sizeof(SgListObjHeader), + &data_pool_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read the subgraph" + " object header", status); + return status; + } + + sg_tag_entry.sg_id = sg_obj.subgraph_id; + + //Skip over subgraph destinations + data_pool_offset += sg_obj.num_subgraphs * sizeof(uint32_t); + + status = TagKeyTableFindFirstOfSubgraphID(&sg_tag_entry, &offset); + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + ACDB_DBG("Error[%d]: No module tags found in Subgraph(0x%x)." + " Skipping..", status, sg_tag_entry.sg_id); + status = AR_EOK; + continue; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Subgraph(0x%x) Tag entry" + " in Module Tag Key Table.", status, sg_tag_entry.sg_id); + return status; + } + + end_offset = ci_tag_key_tbl.chunk_offset + ci_tag_key_tbl.chunk_size; + while (offset < end_offset) + { + status = FileManReadBuffer(&sg_tag_entry, + sizeof(SubgraphTagLutEntry), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Subgraph Tag entry" + " in Module Tag Key Table.", status); + return status; + } + + if (sg_tag_entry.sg_id != sg_obj.subgraph_id) + break; + + /* Skip a tag if we already found the same tag in a + * subgraph. Tags are required to have the same tag key vector, + * so we avoid adding duplicate tag key vectors by skipping the + * tags already found.*/ + for (size_t j = 0; j < found_tags.count; j++) + { + if (found_tags.list[j] == sg_tag_entry.tag_id) + { + skip_tag = TRUE; + break; + } + skip_tag = FALSE; + } + + if (skip_tag) continue; + + status = GetAllTKVVariations(&sg_tag_entry, + &blob_offset, expected_size, rsp); + if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: Failed to get TKVs for " + "Subgraph(0x%x) & Tag(0x%x)", status); + return status; + } + + if (AR_SUCCEEDED(status)) + found_tags.list[found_tags.count++] = sg_tag_entry.tag_id; + } + } + + return status; +} + +/** +* \brief +* Retrieves a list of Tag or Calibration Key Vectors given a GKV +* +* \param[in] kv_type: the type of key vector to get data for +* \param[in] AcdbGraphKeyVector: the graph key vector to get keys vectors from +* \param[out] rsp: the Key Vector List to be populated +* \param[out] rsp_size: the size of the kv_list_rsp structure +* +* \return 0 on success, and non-zero on failure +*/ +int32_t GetUsecaseKeyVectorList(KeyVectorType kv_type, AcdbGraphKeyVector *gkv, + void *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + void *kv_list = NULL; + AcdbGraphKeyVector graph_kv = { 0 }; + acdb_graph_info_t graph_info = { 0 }; + + if (IsNull(gkv) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null:" + " GKV or Response", status); + return AR_EBADPARAM; + } + + if (gkv->num_keys > ACDB_MAX_KEY_COUNT) + return AR_EBADPARAM; + + switch (kv_type) + { + case CAL_KEY_VECTOR: + if (rsp_size < sizeof(AcdbKeyVectorList)) + { + ACDB_ERR("Error[%d]: The size of the response structure is less " + "than %d bytes", status, sizeof(AcdbKeyVectorList)); + return AR_EBADPARAM; + } + + kv_list = ((AcdbKeyVectorList*)rsp)->key_vector_list; + break; + case TAG_KEY_VECTOR: + if (rsp_size < sizeof(AcdbTagKeyVectorList)) + { + ACDB_ERR("Error[%d]: The size of the response structure is less " + "than %d bytes", status, sizeof(AcdbTagKeyVectorList)); + return AR_EBADPARAM; + } + + kv_list = ((AcdbTagKeyVectorList*)rsp)->key_vector_list; + break; + default: + break; + } + + if (IsNull(kv_list)) + { + /* Print only during the size querry,i.e the first time this + * api is called */ + ACDB_DBG("Retrieving subgraph list for the following" + " graph key vector:"); + LogKeyVector(gkv, GRAPH_KEY_VECTOR); + } + + graph_kv.num_keys = gkv->num_keys; + graph_kv.graph_key_vector = (AcdbKeyValuePair*)&glb_buf_3[0]; + ACDB_MEM_CPY_SAFE(&glb_buf_3[0], gkv->num_keys * sizeof(AcdbKeyValuePair), + gkv->graph_key_vector, gkv->num_keys * sizeof(AcdbKeyValuePair)); + + //Sort Key Vector by Key IDs(position 0 of AcdbKeyValuePair) + status = AcdbSort2(gkv->num_keys * sizeof(AcdbKeyValuePair), + graph_kv.graph_key_vector, sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort graph key vector.", status); + return status; + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_GKV, + &graph_kv, sizeof(AcdbGraphKeyVector), + &graph_info, sizeof(acdb_graph_info_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to find the graph key vector", status); + return status; + } + + switch (kv_type) + { + case CAL_KEY_VECTOR: + status = BuildCalKeyVectorList( + (AcdbKeyVectorList*)rsp, graph_info.sg_list_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to build calibration key vector list", + status); + return status; + } + break; + case TAG_KEY_VECTOR: + status = BuildTagKeyVectorList( + (AcdbTagKeyVectorList*)rsp, graph_info.sg_list_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to build tag key vector list", + status); + return status; + } + break; + default: + break; + } + + return status; +} + +int32_t AcdbCmdGetGraphCalKeyVectors(AcdbGraphKeyVector *gkv, + AcdbKeyVectorList *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + + status = GetUsecaseKeyVectorList(CAL_KEY_VECTOR, gkv, rsp, rsp_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured " + "while retrieving CKV list", status); + return status; + } + + return status; +} + +int32_t AcdbCmdGetGraphTagKeyVectors(AcdbGraphKeyVector *gkv, + AcdbTagKeyVectorList *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + + status = GetUsecaseKeyVectorList(TAG_KEY_VECTOR, gkv, rsp, rsp_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured.", status); + return status; + } + + return status; +} + +/** +* \brief +* Retrieves all the graph key vector combinations for a set of keys given +* the offset of the Graph Key Value table +* +* \depends +* GLB_BUF_3 is used to store gkv data +* +* \param[in] graph_keys: A list of graph Key IDs +* \param[in] gkv_lut_offset: An entry that holds the offset to the +* Graph Key Value look up table +* \param[in/out] blob_offset: offset within the rsp.key_vector_list +* \param[in] expected_size: The expected size of rsp.key_vector_list +* \param[out] rsp: The Key Vector List to be populated +* \return 0 on success, and non-zero on failure +*/ +int32_t GetAllGraphKvVariations( + AcdbUintList *graph_keys, uint32_t gkv_lut_offset, + uint32_t *blob_offset, uint32_t expected_size, AcdbKeyVectorList *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t value_list_size = 0; + KeyTableHeader key_table_header = { 0 }; + ChunkInfo ci_key_value_table = { 0 }; + //AcdbOp op = ACDB_OP_NONE; + uint32_t *key_value_list = NULL; + uint32_t *gkv = NULL; + + if (IsNull(rsp)) + { + ACDB_ERR("Error[%d]: The input response parameter is null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_key_value_table.chunk_id = ACDB_CHUNKID_GKVLUTTBL; + status = ACDB_GET_CHUNK_INFO(&ci_key_value_table); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve Graph Key LUT Chunk.", + status); + return status; + } + + offset = ci_key_value_table.chunk_offset + gkv_lut_offset; + status = FileManReadBuffer(&key_table_header, + sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key table header.", + status); + return status; + } + + if (graph_keys->count != key_table_header.num_keys) + { + ACDB_ERR("Error[%d]: There is a mismatch between the length " + "of the input key id list and the number of keys in the GKV LUT.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + //Only includes size of value list + value_list_size = key_table_header.num_keys + * sizeof(uint32_t); + /* Recalculate list_size when getting data + num entries x (#keys + sizeof(KeyValuePairList)) */ + rsp->list_size += key_table_header.num_entries + * ((uint32_t)sizeof(uint32_t) + 2UL * value_list_size); + rsp->num_key_vectors += key_table_header.num_entries; + + if (IsNull(rsp->key_vector_list)) return status; + + key_value_list = &glb_buf_3[0]; + gkv = &glb_buf_3[key_table_header.num_keys]; + + for (uint32_t i = 0; i < key_table_header.num_entries; i++) + { + //read value list + status = FileManReadBuffer(key_value_list, + key_table_header.num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key Value List.", status); + return status; + } + + //Skip SG List and Data offsets + offset += 2 * sizeof(uint32_t); + + status = AcdbZip1(key_table_header.num_keys, graph_keys->list, + key_table_header.num_keys, key_value_list, + key_table_header.num_keys * 2, gkv); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to zip key id and" + " key value list.", status); + return status; + } + + //Write key vector to buffer + + // Write num keys + if (*blob_offset + sizeof(uint32_t) > expected_size) + { + ACDB_ERR("Error[%d]: Unable to write number of keys. " + "The actual key vector list size is greater than" + " the expected size %d bytes.", + AR_ENEEDMORE, expected_size); + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(rsp->key_vector_list + *blob_offset, sizeof(uint32_t), + &graph_keys->count, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + // Write key vector + if (*blob_offset + 2 * value_list_size > expected_size) + { + ACDB_ERR("Error[%d]: Unable to write key vector. " + "The actual key vector list size is greater than" + " the expected size %d bytes.", + AR_ENEEDMORE, expected_size); + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE( + rsp->key_vector_list + *blob_offset, 2UL * (size_t)value_list_size, + gkv , 2UL * (size_t)value_list_size); + + *blob_offset += 2 * value_list_size; + } + + return status; +} + +int32_t AcdbCmdGetSupportedGraphKeyVectors(AcdbUintList *key_id_list, + AcdbKeyVectorList *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_key_tables = 0; + uint32_t key_table_size = 0; + uint32_t key_table_entry_size = 0; + uint32_t num_gkvs_found = 0; + uint32_t num_keys_found = 0; + uint32_t entry_index = 0; + uint32_t blob_offset = 0; + uint32_t expected_size = 0;//Expected size of rsp.key_vector_list + ChunkInfo ci_key_id_table = { 0 }; + KeyTableHeader key_table_header = { 0 }; + AcdbUintList graph_keys = { 0 }; + + if (IsNull(key_id_list) || IsNull(rsp)) + { + ACDB_ERR("Error[%d]: The gkv input parameter is null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (rsp_size < sizeof(AcdbKeyVectorList)) + { + ACDB_ERR("Error[%d]: The response structure size is less than %d", + AR_EBADPARAM, sizeof(AcdbKeyVectorList)); + return AR_EBADPARAM; + } + + if (rsp->list_size == 0 && !IsNull(rsp->key_vector_list)) + { + ACDB_ERR("Error[%d]: The key vector list size is zero, " + "but the key vector list is not null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (!IsNull(rsp->key_vector_list)) + { + //Recalculate list size and #kvs when gettig data + expected_size = rsp->list_size; + rsp->list_size = 0; + rsp->num_key_vectors = 0; + } + + /* GLB_BUF_2 stores a graph key table entry [key1,key2,... lutOffset] + * graph_keys will point to the key id list + */ + graph_keys.list = &glb_buf_2[0]; + + ci_key_id_table.chunk_id = ACDB_CHUNKID_GKVKEYTBL; + status = ACDB_GET_CHUNK_INFO(&ci_key_id_table); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve Graph Key ID Chunk.", + status); + return status; + } + + offset = ci_key_id_table.chunk_offset; + status = FileManReadBuffer(&num_key_tables, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of GKV Key ID tables.", + status); + return status; + } + + for (uint32_t i = 0; i < num_key_tables; i++) + { + status = FileManReadBuffer(&key_table_header, + sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key table header.", + status); + return status; + } + + key_table_entry_size = key_table_header.num_keys + * sizeof(uint32_t) + + sizeof(uint32_t); + key_table_size = key_table_header.num_entries + * key_table_entry_size; + graph_keys.count = key_table_header.num_keys; + + /* If there are less keys than the provided keys, the GKV + * does not support the capability(ies) that are needed */ + if (key_table_header.num_keys < key_id_list->count) + { + offset += key_table_size; + continue; + } + else + { + //Read key vector and see if it contains the provided keys + + for (uint32_t k = 0; k < key_table_header.num_entries; k++) + { + num_keys_found = 0; + + //Read Graph Keys + status = FileManReadBuffer(&glb_buf_2, key_table_entry_size, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of GKV Key ID tables.", + status); + return status; + } + + + for (uint32_t j = 0; j < key_id_list->count; j++) + { + if (AR_SUCCEEDED(AcdbDataBinarySearch2( + graph_keys.list, + key_table_header.num_keys * sizeof(uint32_t), + &key_id_list->list[j], 1, 1, &entry_index))) + { + num_keys_found++; + } + } + + if (num_keys_found == key_id_list->count) + { + //Go to LUT and collect all the Key Combinations + status = GetAllGraphKvVariations( + &graph_keys, glb_buf_2[graph_keys.count], + &blob_offset, expected_size, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get all GKV " + "variations for:", + status); + + LogKeyIDs(&graph_keys, GRAPH_KEY_VECTOR); + return status; + } + + num_gkvs_found++; + } + } + } + } + + if (!num_gkvs_found) + { + ACDB_ERR("Error[%d]: Failed to find data. No graph key vector supports" + " all the provided keys:",AR_ENOTEXIST); + + for (uint32_t i = 0; i < key_id_list->count; i++) + { + ACDB_ERR("Graph Key: 0x%x", key_id_list->list[i]); + } + return AR_ENOTEXIST; + } + + return status; +} + +/** +* \brief +* Retrieves all the driver key vector combinations for a set of +* keys given the offset of the Key and Value tables +* +* \depends +* GLB_BUF_3 is used to store kv data +* +* \param[in] cal_key_table_entry: An entry that holds the offsets to the +* Key ID and Key Value tables +* \param[in/out] blob_offset: current offset in the rsp +* \param[in] expected_size: the expected size of the rsp.list_size +* \param[out] rsp: The Key Vector List to be populated +* +* \return 0 on success, and non-zero on failure +*/ +int32_t GetAllDriverKvVariations( + acdb_driver_cal_lut_entry_t *cal_lut_entry, uint32_t *blob_offset, + uint32_t expected_size, AcdbKeyVectorList *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t value_list_size = 0; + uint32_t num_keys = 0; + KeyTableHeader key_table_header = { 0 }; + //AcdbOp op = ACDB_OP_NONE; + uint32_t *key_list = NULL; + uint32_t *value_list = NULL; + uint32_t *driver_kv = NULL; + ChunkInfo gsl_cal_key_tbl = { 0 }; + ChunkInfo gsl_cal_lut_tbl = { 0 }; + + gsl_cal_key_tbl.chunk_id = ACDB_CHUNKID_GSL_CALKEY_TBL; + gsl_cal_lut_tbl.chunk_id = ACDB_CHUNKID_GSL_CALDATA_TBL; + status = ACDB_GET_CHUNK_INFO(&gsl_cal_key_tbl, &gsl_cal_lut_tbl); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get GSL Key Table or" + " GSL Value Table Chunk", status); + return status; + } + + if (IsNull(rsp)) + { + ACDB_ERR("Error[%d]: The input response parameter is null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + offset = gsl_cal_key_tbl.chunk_offset + + cal_lut_entry->offset_calkey_table; + + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of keys.", status); + return status; + } + + if (num_keys != 0) + { + status = FileManReadBuffer(&glb_buf_3[0], + num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key ID List", status); + return status; + } + } + + offset = gsl_cal_lut_tbl.chunk_offset + + cal_lut_entry->offset_caldata_table; + status = FileManReadBuffer(&key_table_header, + sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key table header.", + status); + return status; + } + + if (num_keys != key_table_header.num_keys) + { + ACDB_ERR("Error[%d]: There is a mismatch between the length " + "of the key id list and the number of keys in the " + "Driver Key LUT.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + //Only includes size of value list + value_list_size = key_table_header.num_keys + * sizeof(uint32_t); + /* Recalculate list_size when getting data + num entries x (#keys + sizeof(KeyValuePairList)) */ + rsp->list_size += key_table_header.num_entries + * ((uint32_t)sizeof(uint32_t) + 2UL * value_list_size); + rsp->num_key_vectors += key_table_header.num_entries; + + if (IsNull(rsp->key_vector_list)) return status; + + key_list = &glb_buf_3[0]; + value_list = &glb_buf_3[key_table_header.num_keys]; + driver_kv = &glb_buf_3[2 * key_table_header.num_keys]; + + for (uint32_t i = 0; i < key_table_header.num_entries; i++) + { + //Read value list + status = FileManReadBuffer(value_list, + key_table_header.num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key Value List.", status); + return status; + } + + //Skip SG List and Data offsets + offset += 2 * sizeof(uint32_t); + + status = AcdbZip1(key_table_header.num_keys, key_list, + key_table_header.num_keys, value_list, + key_table_header.num_keys * 2, driver_kv); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to zip key id and" + " key value list.", status); + return status; + } + + //Write key vector to buffer + + // Write num keys + if (*blob_offset + sizeof(uint32_t) > expected_size) + { + ACDB_ERR("Error[%d]: Unable to write number of keys. " + "The actual key vector list size is greater than" + " the expected size %d bytes.", + AR_ENEEDMORE, expected_size); + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE(rsp->key_vector_list + *blob_offset, sizeof(uint32_t), + &num_keys, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + // Write key vector + if (*blob_offset + 2 * value_list_size > expected_size) + { + ACDB_ERR("Error[%d]: Unable to write key vector. " + "The actual key vector list size is greater than" + " the expected size %d bytes.", + AR_ENEEDMORE, expected_size); + return AR_ENEEDMORE; + } + + ACDB_MEM_CPY_SAFE( + rsp->key_vector_list + *blob_offset, 2UL * (size_t)value_list_size, + driver_kv , 2UL * (size_t)value_list_size); + *blob_offset += 2 * value_list_size; + } + + return status; +} + +int32_t AcdbCmdGetDriverModuleKeyVectors( + uint32_t module_id, AcdbKeyVectorList *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t blob_offset = 0; + uint32_t expected_size = 0; + uint32_t end_gsl_cal_lut_offset = 0; + acdb_driver_cal_lut_entry_t cal_lut_entry = { 0 }; + ChunkInfo gsl_cal_lut = { 0 }; + + if (IsNull(rsp)) + { + ACDB_ERR("Error[%d]: The input response parameter is null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (rsp_size < sizeof(AcdbKeyVectorList)) + { + ACDB_ERR("Error[%d]: The response structure size is less than %d", + AR_EBADPARAM, sizeof(AcdbKeyVectorList)); + return AR_EBADPARAM; + } + + if (rsp->list_size == 0 && !IsNull(rsp->key_vector_list)) + { + ACDB_ERR("Error[%d]: The key vector list size is zero, " + "but the key vector list is not null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + /* Algorithm + * 1. Find the first occurance of the Module ID in the GSL Cal LUT + * 2. Use the offset of that entry to find remaining + * entries + * 3. zip key id list and value list and write to reponse buffer + */ + cal_lut_entry.mid = module_id; + + status = acdb_ctx_man_ioctl( + ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_DRIVER_MODULE, + &cal_lut_entry, sizeof(cal_lut_entry), + &offset, sizeof(uint32_t)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: No key vectors found for driver module(0x%x)" + , status, module_id); + return status; + } + + gsl_cal_lut.chunk_id = ACDB_CHUNKID_GSL_CAL_LUT; + status = ACDB_GET_CHUNK_INFO(&gsl_cal_lut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get GSL Cal LUT Chunk", status); + return status; + } + + if (!IsNull(rsp->key_vector_list)) + { + //Recalculate list size and #kvs when gettig data + expected_size = rsp->list_size; + rsp->list_size = 0; + rsp->num_key_vectors = 0; + } + + end_gsl_cal_lut_offset = gsl_cal_lut.chunk_offset + + gsl_cal_lut.chunk_size; + + while(offset < end_gsl_cal_lut_offset) + { + status = FileManReadBuffer(&cal_lut_entry, sizeof(acdb_driver_cal_lut_entry_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read GSL Cal LUT entry" + " of entries.", status); + return status; + } + + if (cal_lut_entry.mid != module_id) break; + + status = GetAllDriverKvVariations( + &cal_lut_entry, &blob_offset, expected_size, rsp); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get all key vector variations." + , status); + return status; + } + } + + return status; +} + +int32_t SearchSubgraphCalLut( + uint32_t req_subgraph_id, uint32_t sz_ckv_entry_list, + AcdbCalKeyTblEntry *ckv_entry_list, uint32_t *num_entries) +{ + int32_t status = AR_EOK; + bool_t sg_found = FALSE; + uint32_t num_subgraphs = 0; + uint32_t num_ckv_tbl_entries = 0; + uint32_t subgraph_id = 0; + uint32_t offset = 0; + ChunkInfo ci_calsglut = { 0 }; + + if (IsNull(ckv_entry_list)) + { + ACDB_ERR("Error[%d]: The provided input parameter(s) are null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + //Search for Persist/Non-persist/Global-persist caldata in ACDB files + + ci_calsglut.chunk_id = ACDB_CHUNKID_CALSGLUT; + status = ACDB_GET_CHUNK_INFO(&ci_calsglut); + if (AR_FAILED(status)) return status; + + offset = ci_calsglut.chunk_offset; + status = FileManReadBuffer(&num_subgraphs, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of subgraphs.", status); + return status; + } + + for (uint32_t i = 0; i < num_subgraphs; i++) + { + status = FileManReadBuffer(&glb_buf_3[0], 2 * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read subgraph and number of entries.", status); + return status; + } + + subgraph_id = glb_buf_3[0]; + num_ckv_tbl_entries = glb_buf_3[1]; + + if (subgraph_id == req_subgraph_id) + { + sg_found = TRUE; + //Read number of Entries + *num_entries = num_ckv_tbl_entries; + + if (num_ckv_tbl_entries == 0) + { + ACDB_CLEAR_BUFFER(glb_buf_3); + ACDB_ERR("Error[%d]: Subgraph(%x) does not have CKV table entries.", + AR_ENOTEXIST, subgraph_id); + return AR_ENOTEXIST; + } + + if (sz_ckv_entry_list < num_ckv_tbl_entries * sizeof(uint32_t)) + { + return AR_ENEEDMORE; + } + + status = FileManReadBuffer(ckv_entry_list, + num_ckv_tbl_entries * sizeof(AcdbCalKeyTblEntry), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read CKV table entries for Subgraph(%x)", + status, subgraph_id); + return status; + } + + break; + } + else + { + //List + offset += 2 * sizeof(uint32_t) * num_ckv_tbl_entries; + } + } + + if (!sg_found) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Could not find calibration data for Subgraph(%x)", + status, req_subgraph_id); + } + + ACDB_CLEAR_BUFFER(glb_buf_3); + + return status; +} + +int32_t SearchSubgraphCalLut2(AcdbSgCalLutHeader *sg_lut_entry_header, + uint32_t *ckv_entry_list_offset) +{ + int32_t status = AR_EOK; + bool_t sg_found = FALSE; + uint32_t num_subgraphs = 0; + uint32_t offset = 0; + ChunkInfo ci_calsglut = { 0 }; + AcdbSgCalLutHeader entry_header = { 0 }; + + if (IsNull(sg_lut_entry_header) || IsNull(ckv_entry_list_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameter(s) are null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_calsglut.chunk_id = ACDB_CHUNKID_CALSGLUT; + status = ACDB_GET_CHUNK_INFO(&ci_calsglut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get Subgraph Calibration" + " Lookup table chunk info."); + return status; + } + + offset = ci_calsglut.chunk_offset; + status = FileManReadBuffer(&num_subgraphs, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of subgraphs.", status); + return status; + } + + for (uint32_t i = 0; i < num_subgraphs; i++) + { + status = FileManReadBuffer(&entry_header, + sizeof(AcdbSgCalLutHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read subgraph lookup" + " table entry header.", status); + return status; + } + + if (entry_header.subgraph_id == sg_lut_entry_header->subgraph_id) + { + sg_found = TRUE; + + if (entry_header.num_ckv_entries == 0) + { + ACDB_CLEAR_BUFFER(glb_buf_3); + ACDB_DBG("Warning[%d]: Subgraph(0x%x) does not" + " does not have CKVs", + AR_ENOTEXIST, entry_header.subgraph_id); + return AR_ENOTEXIST; + } + sg_lut_entry_header->num_ckv_entries = + entry_header.num_ckv_entries; + *ckv_entry_list_offset = offset; + break; + } + else + { + //List + offset += 2 * sizeof(uint32_t) + * entry_header.num_ckv_entries; + } + } + + if (!sg_found) + { + status = AR_ENOTEXIST; + ACDB_ERR("Error[%d]: Unable to find calibration data for Subgraph(0x%x)", + status, sg_lut_entry_header->subgraph_id); + } + + return status; +} + +/** +* \brief +* Matches the requeset CKV with the Key ID and Key Value Tables. Returns +* the offsets to the DEF, DOT(used for non-persistent/persistent and +* DOT2(used for global-persistent) tables +* \param[in] req: Request containing the subgraph, module instance, parameter, and CKV +* \param[in] offset_key_table: Offset of Key ID table +* \param[in] offset_cal_lut: Offset of Key Value LUT +* \param[out] ckv_lut_entry: Offsets to DEF, DOT, and DOT2 for the input request +* \return 0 on success, and non-zero on failure +*/ +int32_t SearchForMatchingCalKeyVector(AcdbParameterCalData *req, + uint32_t offset_key_table, uint32_t offset_cal_lut, + AcdbCkvLutEntryOffsets* ckv_lut_entry) +{ + int32_t status = AR_EOK; + bool_t found = FALSE; + uint32_t offset = 0; + uint32_t num_keys = 0; + uint32_t num_values = 0; + uint32_t num_lut_entries = 0; + ChunkInfo ci_calkeytbl = { 0 }; + ChunkInfo ci_callut = { 0 }; + + if (IsNull(req) || IsNull(ckv_lut_entry)) + { + ACDB_ERR("The input request, DEF offset, or DOT offset are null"); + return AR_EBADPARAM; + } + + ci_calkeytbl.chunk_id = ACDB_CHUNKID_CALKEYTBL; + ci_callut.chunk_id = ACDB_CHUNKID_CALDATALUT; + + status = ACDB_GET_CHUNK_INFO(&ci_calkeytbl, &ci_callut); + if (AR_FAILED(status)) return status; + + //Get Key List + offset = ci_calkeytbl.chunk_offset + offset_key_table; + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of keys.", status); + return status; + } + + if (req->cal_key_vector.num_keys != num_keys) + { + return AR_ENOTEXIST; + } + + if (num_keys != 0) + { + status = FileManReadBuffer(&glb_buf_3[0], num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key ID List", status); + return status; + } + + //Sort Key Vector by Key IDs(position 0 of AcdbKeyValuePair) + status = AcdbSort2(num_keys * sizeof(AcdbKeyValuePair), + req->cal_key_vector.graph_key_vector, sizeof(AcdbKeyValuePair), 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to sort input request key vector.", status); + return status; + } + + if (!CompareKeyVectorIds(req->cal_key_vector, glb_buf_2, glb_buf_3, num_keys)) + { + return AR_ENOTEXIST; + } + } + + offset = ci_callut.chunk_offset + offset_cal_lut; + status = FileManReadBuffer(&glb_buf_3[0], 2 * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of values and lut entries.", status); + return status; + } + + num_values = glb_buf_3[0]; + num_lut_entries = glb_buf_3[1]; + + if (num_keys != num_values) + { + ACDB_ERR("Error[%d]: Number of keys and values are different!", AR_EFAILED); + return AR_EFAILED; + } + + //Compare CKV Values and get + for (uint32_t i = 0; i < num_lut_entries; i++) + { + if (num_values == 0) + { + found = TRUE; + status = FileManReadBuffer(ckv_lut_entry, sizeof(AcdbCkvLutEntryOffsets), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read ckv lut entry.", status); + return status; + } + + break; + } + + status = FileManReadBuffer(&glb_buf_3[0], num_values * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Key Value List.", status); + return status; + } + + if (CompareKeyVectorValues(req->cal_key_vector, glb_buf_2, glb_buf_3, num_keys)) + { + found = TRUE; + status = FileManReadBuffer(ckv_lut_entry, sizeof(AcdbCkvLutEntryOffsets), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read ckv lut entry offsets.", status); + return status; + } + + break; + } + else + { + // + offset += sizeof(AcdbCkvLutEntryOffsets); + } + } + + if (!found) + { + ACDB_ERR("Error[%d]: No matching calibration key vector was found", AR_ENOTEXIST); + status = AR_ENOTEXIST; + } + + ACDB_CLEAR_BUFFER(glb_buf_2); + ACDB_CLEAR_BUFFER(glb_buf_3); + return status; +} + +/** +* \brief +* Retrieve calibration data for a parameter from the data pool +* \param[int] req: Request containing the subgraph, module instance, parameter, and CKV +* \param[in/out] rsp: A data blob containg calibration data +* \param[in] offset_pair: calibration data def and dot offsets +* \return 0 on success, and non-zero on failure +*/ +int32_t BuildParameterCalDataBlob(AcdbParameterCalData *req, AcdbBlob *rsp, + AcdbDefDotPair *offset_pair) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t param_size = 0; + uint32_t error_code = 0; + uint32_t param_dot_offset = 0; + uint32_t data_offset = 0; + uint32_t blob_offset = 0; + uint32_t num_iid_pid_entries = 0; + uint32_t entry_index = 0; + ChunkInfo ci_caldef = { 0 }; + ChunkInfo ci_caldot = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbModIIDParamIDPair iid_pid_pair = { 0 }; + + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("The input request, or response are null"); + return AR_EBADPARAM; + } + + ci_caldef.chunk_id = ACDB_CHUNKID_CALDATADEF; + ci_caldot.chunk_id = ACDB_CHUNKID_CALDATADOT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + + status = ACDB_GET_CHUNK_INFO(&ci_caldef, &ci_caldot, &ci_data_pool); + if (AR_FAILED(status)) return status; + + offset = ci_caldef.chunk_offset + offset_pair->offset_def; + + status = FileManReadBuffer(&num_iid_pid_entries, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of entries.", status); + return status; + } + + status = FileManReadBuffer(&glb_buf_3[0], num_iid_pid_entries * sizeof(AcdbModIIDParamIDPair), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read List of .", status); + return status; + } + + iid_pid_pair.module_iid = req->module_iid; + iid_pid_pair.parameter_id = req->parameter_id; + + if (SEARCH_ERROR == AcdbDataBinarySearch2((void*)&glb_buf_3, + num_iid_pid_entries * sizeof(AcdbModIIDParamIDPair), + &iid_pid_pair, 2, + (int32_t)(sizeof(AcdbModIIDParamIDPair) / sizeof(uint32_t)), + &entry_index)) + { + //MID PID not found + return AR_ENOTEXIST; + } + else + { + offset = ci_caldot.chunk_offset + offset_pair->offset_dot; + + /* Calculation for DOT offset of pair + * + * Offset of + Number of + Offset of the desired DOT entry based on + * DOT DOT entries index of in DEF + */ + param_dot_offset = offset + sizeof(uint32_t) + sizeof(uint32_t) * (uint32_t)( + entry_index / (sizeof(AcdbModIIDParamIDPair) / sizeof(uint32_t))); + + status = FileManReadBuffer(&data_offset, sizeof(uint32_t), ¶m_dot_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read data pool offset from DOT.", status); + return status; + } + + offset = ci_data_pool.chunk_offset + data_offset; + + status = FileManReadBuffer(¶m_size, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read param size from data pool.", status); + return status; + } + + rsp->buf_size = sizeof(AcdbModIIDParamIDPair) + 2 * sizeof(uint32_t) + param_size; + + //Write Module IID, and Parameter ID + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, sizeof(AcdbModIIDParamIDPair), + &iid_pid_pair, sizeof(AcdbModIIDParamIDPair)); + blob_offset += sizeof(AcdbModIIDParamIDPair); + + //Write Parameter Size + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, sizeof(uint32_t), + ¶m_size, sizeof(uint32_t)); + blob_offset += sizeof(uint32_t); + + //Write Error code + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, sizeof(uint32_t), + &error_code, sizeof(uint32_t)); + blob_offset += sizeof(uint32_t); + + //Write Payload + if (param_size != 0) + { + status = FileManReadBuffer((uint8_t*)rsp->buf + blob_offset, + param_size, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read param payload of %d bytes.", + status, param_size); + return status; + } + } + } + + return status; +} + +int32_t SearchForMatchingVoiceCalKeyValues(AcdbParameterCalData *req, + AcdbVcpmCalDataObj *cal_data_obj, uint32_t *table_offset) +{ + int32_t status = AR_EOK; + uint32_t file_offset = *table_offset; + uint32_t offset = 0; + uint32_t num_keys = 0; + ChunkInfo ci_vcpm_cal_lut = { 0 }; + + if (IsNull(req) || IsNull(cal_data_obj) || IsNull(table_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_vcpm_cal_lut.chunk_id = ACDB_CHUNKID_VCPM_CALDATA_LUT; + + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_cal_lut); + if (AR_FAILED(status)) return status; + + status = FileManReadBuffer(cal_data_obj, + sizeof(AcdbVcpmCalDataObj), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Cal " + "Data Object Header.", status); + return status; + } + + offset = ci_vcpm_cal_lut.chunk_offset + cal_data_obj->offset_vcpm_ckv_lut; + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of voice keys.", status); + return status; + } + + if (num_keys != req->cal_key_vector.num_keys) + { + //Go to Next Cal Data Obj + *table_offset = file_offset + + (cal_data_obj->num_data_offsets * sizeof(uint32_t)); + return AR_ENOTEXIST; + } + + if (num_keys != 0) + { + offset += sizeof(uint32_t);//num_entries is always 1 + status = FileManReadBuffer(&glb_buf_1, num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to Voice Key IDs.", status); + return status; + } + + if (FALSE == CompareKeyVectorValues( + req->cal_key_vector, glb_buf_3, glb_buf_1, num_keys)) + { + //Go to Next Cal Data Obj + *table_offset = file_offset + + (cal_data_obj->num_data_offsets * sizeof(uint32_t)); + return AR_ENOTEXIST; + } + } + + *table_offset = file_offset; + + return status; +} + +int32_t SearchForMatchingVoiceCalKeyIDs(AcdbParameterCalData *req, + AcdbVcpmCkvDataTable *cal_data_table, uint32_t *table_offset) +{ + int32_t status = AR_EOK; + uint32_t file_offset = *table_offset; + uint32_t offset = 0; + uint32_t num_keys = 0; + ChunkInfo ci_vcpm_cal_key = { 0 }; + + if (IsNull(req) || IsNull(cal_data_table) || IsNull(table_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_vcpm_cal_key.chunk_id = ACDB_CHUNKID_VCPM_CALKEY_TABLE; + + status = ACDB_GET_CHUNK_INFO(&ci_vcpm_cal_key); + if (AR_FAILED(status)) return status; + + status = FileManReadBuffer(cal_data_table, + sizeof(AcdbVcpmCkvDataTable), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read CKV " + "Data Table Header.", status); + return status; + } + + offset = ci_vcpm_cal_key.chunk_offset + + cal_data_table->offset_voice_key_table; + status = FileManReadBuffer(&num_keys, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of voice keys.", status); + return status; + } + + if (num_keys != req->cal_key_vector.num_keys) + { + //Go to Next CKV Data Table + *table_offset = file_offset + + sizeof(uint32_t) //table size + + cal_data_table->table_size + - sizeof(AcdbVcpmCkvDataTable); + return AR_ENOTEXIST; + } + + if (num_keys != 0) + { + status = FileManReadBuffer(&glb_buf_1, num_keys * sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to Voice Key IDs.", status); + return status; + } + + if (FALSE == CompareKeyVectorIds( + req->cal_key_vector, glb_buf_3, glb_buf_1, num_keys)) + { + //Go to Next CKV Data Table + *table_offset = file_offset + + sizeof(uint32_t) //table size + + cal_data_table->table_size + - sizeof(AcdbVcpmCkvDataTable); + return AR_ENOTEXIST; + } + } + + *table_offset = file_offset; + + return status; +} + +int32_t GetVoiceParameterCalData(AcdbParameterCalData *req, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t i = 0; + uint32_t file_offset = 0; + uint32_t blob_offset = 0; + uint32_t param_size = 0; + uint32_t error_code = 0; + uint32_t id_pair_table_size = 0; + uint32_t data_pool_offset = 0; + uint32_t data_pool_offset_index = 0; + ChunkInfo ci_vcpm_cal = { 0 }; + ChunkInfo ci_vcpm_cal_key = { 0 }; + ChunkInfo ci_vcpm_cal_lut = { 0 }; + ChunkInfo ci_vcpm_cal_def = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbVcpmSubgraphCalHeader subgraph_cal_header = { 0 }; + AcdbVcpmSubgraphCalTable subgraph_cal_table_header = { 0 }; + AcdbVcpmCkvDataTable cal_data_table = { 0 }; + AcdbVcpmCalDataObj cal_data_obj = { 0 }; + AcdbMiidPidPair id_pair = { 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + ci_vcpm_cal.chunk_id = ACDB_CHUNKID_VCPM_CAL_DATA; + ci_vcpm_cal_key.chunk_id = ACDB_CHUNKID_VCPM_CALKEY_TABLE; + ci_vcpm_cal_lut.chunk_id = ACDB_CHUNKID_VCPM_CALDATA_LUT; + ci_vcpm_cal_def.chunk_id = ACDB_CHUNKID_VCPM_CALDATA_DEF; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + + status = ACDB_GET_CHUNK_INFO( + &ci_vcpm_cal, &ci_vcpm_cal_lut, + &ci_vcpm_cal_key, &ci_vcpm_cal_def, + &ci_data_pool); + if (AR_FAILED(status)) return status; + + file_offset = ci_vcpm_cal.chunk_offset; + status = FileManReadBuffer(&subgraph_cal_header, + sizeof(AcdbVcpmSubgraphCalHeader), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read Module Header.", status); + return status; + } + + //Search for the matching VCPM Subgraph Cal Data Table + status = GetVcpmSubgraphCalTable(subgraph_cal_header.num_subgraphs, + req->subgraph_id, &file_offset, &subgraph_cal_table_header); + if (AR_FAILED(status)) + { + return status; + } + + //Search for matching key vector then find iid,pid and get voice cal data + for (i = 0; i < subgraph_cal_table_header.num_ckv_data_table; i++) + { + status = SearchForMatchingVoiceCalKeyIDs( + req, &cal_data_table, &file_offset); + + if (AR_FAILED(status) && status != AR_ENOTEXIST) + return status; + else if (AR_SUCCEEDED(status)) break; + } + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to find matching key vector.", status); + return status; + } + + for (i = 0; i < cal_data_table.num_caldata_obj; i++) + { + status = SearchForMatchingVoiceCalKeyValues( + req, &cal_data_obj, &file_offset); + + if (AR_FAILED(status) && status != AR_ENOTEXIST) + return status; + else if (AR_SUCCEEDED(status)) break; + } + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to find matching key vector.", status); + return status; + } + + /* Binary Search through to find index of . Use the + * index to calculate the Cal Data Object data pool offset get to the + * data pool offset */ + id_pair_table_size = + cal_data_obj.num_data_offsets * sizeof(AcdbMiidPidPair); + + id_pair.module_iid = req->module_iid; + id_pair.parameter_id = req->parameter_id; + + //Setup Table Information + table_info.table_offset = ci_vcpm_cal_def.chunk_offset + + cal_data_obj.offset_cal_def + sizeof(uint32_t);//Skip num id pairs + table_info.table_size = id_pair_table_size; + table_info.table_entry_size = sizeof(AcdbMiidPidPair); + + //Setup Search Information + search_info.num_search_keys = 2;//IID, PID + search_info.num_structure_elements = + (sizeof(AcdbMiidPidPair) / sizeof(uint32_t)); + search_info.table_entry_struct = &id_pair; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Failed to find Module Instance ID(0x%x) " + "Parameter ID(0x%x)", id_pair.module_iid, id_pair.parameter_id); + return status; + } + + data_pool_offset_index = search_info.entry_index; + file_offset += data_pool_offset_index * sizeof(uint32_t); + + //Get parameter data from the data pool + status = FileManReadBuffer(&data_pool_offset, + sizeof(uint32_t), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read global " + "data pool offset.", status); + return status; + } + + file_offset = ci_data_pool.chunk_offset + data_pool_offset; + status = FileManReadBuffer(¶m_size, sizeof(uint32_t), &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read parameter size.", status); + return status; + } + + rsp->buf_size = sizeof(AcdbMiidPidPair) + + 2 * sizeof(uint32_t) + param_size; + + //Write Module IID, and Parameter ID + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, + sizeof(AcdbMiidPidPair), &id_pair, sizeof(AcdbMiidPidPair)); + blob_offset += sizeof(AcdbMiidPidPair); + + //Write Parameter Size + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, sizeof(uint32_t), + ¶m_size, sizeof(uint32_t)); + blob_offset += sizeof(uint32_t); + + //Write Error code + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, sizeof(uint32_t), + &error_code, sizeof(uint32_t)); + blob_offset += sizeof(uint32_t); + + if (param_size != 0) + { + status = FileManReadBuffer((uint8_t*)rsp->buf + blob_offset, + param_size, &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read parameter payload.", status); + return status; + } + blob_offset += param_size; + } + + return status; +} + +/** +* \brief +* Get calibration data for one parameter +* \param[int] req: Request containing the subgraph, module instance, parameter, and CKV +* \param[in/out] rsp: A data blob containg calibration data +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbGetParameterCalData(AcdbParameterCalData *req, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + AcdbCalKeyTblEntry *cal_key_entry_list = NULL; + AcdbCkvLutEntryOffsets ckv_lut_entry = { 0 }; + uint32_t num_entries = 0; + if (IsNull(req) || IsNull(rsp)) + { + ACDB_ERR("The input request and/or response is null"); + return AR_EBADPARAM; + } + //Search for Voice Subgraph Calibration Data + status = GetVoiceParameterCalData(req, rsp); + if (AR_FAILED(status) && status != AR_ENOTEXIST) + { + return status; + } + else if (AR_SUCCEEDED(status)) return status; + + //Find Subgraph and Possible CKV offsets + cal_key_entry_list = (AcdbCalKeyTblEntry*)&glb_buf_1[0]; + + status = SearchSubgraphCalLut(req->subgraph_id, sizeof(glb_buf_1), + cal_key_entry_list, &num_entries); + if (AR_FAILED(status)) + { + return status; + } + + //Search List of Offsets for matching CKV + for (uint32_t i = 0; i < num_entries; i++) + { + AcdbCalKeyTblEntry e = cal_key_entry_list[i]; + status = SearchForMatchingCalKeyVector(req, + e.offset_cal_key_tbl, e.offset_cal_lut, &ckv_lut_entry); + if (AR_SUCCEEDED(status)) break; + } + + if (AR_FAILED(status)) + { + //Either CKV not found or another error occured + ACDB_ERR("Error[%d]: Could not find a matcing CKV.", status); + return status; + } + + //Use offset from CKV LUT to find Module Calibration + status = BuildParameterCalDataBlob(req, rsp, + (AcdbDefDotPair*)(void*)&ckv_lut_entry); + + return status; +} + +/** +* \brief +* Retrieve tag data for a parameter from the data pool +* \param[int] req: Request containing the subgraph, module instance, parameter, and module tag +* \param[in/out] rsp: A data blob containg tag data +* \param[in] offset_pair: Tag data def and dot offsets +* \return 0 on success, and non-zero on failure +*/ +int32_t BuildParameterTagDataBlob(AcdbParameterTagData *req, AcdbBlob *rsp, AcdbDefDotPair *offset_pair) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t blob_offset = 0; + uint32_t data_offset = 0; + uint32_t param_size = 0; + uint32_t error_code = 0; + uint32_t param_dot_offset = 0; + uint32_t entry_index = 0; + uint32_t num_iid_pid_entries = 0; + AcdbModIIDParamIDPair iid_pid_pair = { 0 }; + ChunkInfo ci_tag_data_def = { 0 }; + ChunkInfo ci_tag_data_dot = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + + if (IsNull(req) || IsNull(offset_pair)) + { + ACDB_ERR("Error[%d]: The input request, response, or offset pair is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci_tag_data_def.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_DEF; + ci_tag_data_dot.chunk_id = ACDB_CHUNKID_MODULE_TAGDATA_DOT; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + + status = ACDB_GET_CHUNK_INFO( + &ci_tag_data_def, &ci_tag_data_dot, &ci_data_pool); + + offset = ci_tag_data_def.chunk_offset + offset_pair->offset_def; + status = FileManReadBuffer(&num_iid_pid_entries, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read number of tagged entries.", status); + return status; + } + + status = FileManReadBuffer(&glb_buf_3[0], num_iid_pid_entries * sizeof(AcdbModIIDParamIDPair), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read List of .", status); + return status; + } + + iid_pid_pair.module_iid = req->module_iid; + iid_pid_pair.parameter_id = req->parameter_id; + + if (SEARCH_ERROR == AcdbDataBinarySearch2((void*)&glb_buf_3, + num_iid_pid_entries * sizeof(AcdbModIIDParamIDPair), + &iid_pid_pair, 2, + (int32_t)(sizeof(AcdbModIIDParamIDPair) / sizeof(uint32_t)), + &entry_index)) + { + //MID PID not found + return AR_ENOTEXIST; + } + else + { + offset = ci_tag_data_dot.chunk_offset + offset_pair->offset_dot; + + /* Calculation for DOT offset of pair + * + * Offset of + Number of + Offset of the desired DOT entry based on + * DOT DOT entries index of in DEF + */ + param_dot_offset = offset + sizeof(uint32_t) + sizeof(uint32_t) * (uint32_t)( + entry_index / (sizeof(AcdbModIIDParamIDPair) / sizeof(uint32_t))); + + status = FileManReadBuffer(&data_offset, sizeof(uint32_t), ¶m_dot_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read data pool offset from DOT.", status); + return status; + } + + offset = ci_data_pool.chunk_offset + data_offset; + + status = FileManReadBuffer(¶m_size, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read param size from data pool.", status); + return status; + } + + rsp->buf_size = sizeof(AcdbModIIDParamIDPair) + 2 * sizeof(uint32_t) + param_size; + + //Write Module IID, and Parameter ID + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, sizeof(AcdbModIIDParamIDPair), + &iid_pid_pair, sizeof(AcdbModIIDParamIDPair)); + blob_offset += sizeof(AcdbModIIDParamIDPair); + + //Write Parameter Size + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, sizeof(uint32_t), + ¶m_size, sizeof(uint32_t)); + blob_offset += sizeof(uint32_t); + + //Write Error code + ACDB_MEM_CPY_SAFE((uint8_t*)rsp->buf + blob_offset, sizeof(uint32_t), + &error_code, sizeof(uint32_t)); + blob_offset += sizeof(uint32_t); + + //Write Payload + status = FileManReadBuffer((uint8_t*)rsp->buf + blob_offset, + param_size, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read param payload of %d bytes.", + status, param_size); + return status; + } + } + + return status; +} + +/** +* \brief +* Get Tag data for one parameter +* \param[int] req: Request containing the subgraph, module instance, parameter, and module tag +* \param[in/out] rsp: A data blob containg tag data +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbGetParameterTagData(AcdbParameterTagData *req, AcdbBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t offset_tag_data_tbl = 0; + AcdbSgIdModuleTag sg_module_tag = { 0 }; + AcdbDefDotPair offset_pair = { 0 }; + + status = AcdbSort2( + req->module_tag.tag_key_vector.num_keys * sizeof(AcdbKeyValuePair), + req->module_tag.tag_key_vector.graph_key_vector, + sizeof(AcdbKeyValuePair), 0); + + status = TagDataSearchKeyTable(req->subgraph_id, req->module_tag.tag_id, + &offset_tag_data_tbl); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to search for Subgraph(%x) Tag(%x)", + status, req->subgraph_id, req->module_tag.tag_id); + return status; + } + + sg_module_tag.module_tag = req->module_tag; + sg_module_tag.num_sg_ids = 1; + sg_module_tag.sg_ids = &req->subgraph_id; + + status = TagDataSearchLut(&sg_module_tag.module_tag.tag_key_vector, + offset_tag_data_tbl, &offset_pair); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to search tag data LUT for Subgraph(%x) Tag(%x)", + status, req->subgraph_id, req->module_tag.tag_id); + return status; + } + + status = BuildParameterTagDataBlob(req, rsp, &offset_pair); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to build tag data blob for Subgraph(%x) Tag(%x)", + status, req->subgraph_id, req->module_tag.tag_id); + } + + return status; +} diff --git a/acdb/src/acdb_context_mgr.c b/acdb/src/acdb_context_mgr.c new file mode 100644 index 0000000..2594763 --- /dev/null +++ b/acdb/src/acdb_context_mgr.c @@ -0,0 +1,630 @@ +/** +*============================================================================= +* \file acdb_contet_mgr.c +* +* \brief +* The handle manager that maintains handles to different aml layers +* such as the file manager, delta file manager, and delta data heap +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ +#include "ar_osal_error.h" +#include "acdb_context_mgr.h" +#include "acdb_parser.h" +#include "acdb_data_proc.h" +#include "acdb_utility.h" + +/* --------------------------------------------------------------------------- +* Macros +*--------------------------------------------------------------------------- */ + +#define ACDB_MAX_ACDB_FILES 16 + +#define ACDB_BIT_SET(value, bit) (value &= ~(1 << bit)) +#define ACDB_BIT_UNSET(value, bit) (value |= ~(0xFFFFFFFE << bit)) +#define ACDB_SUBGRAPH_TO_VM_ID(sg_id) ((sg_id & 0x0F000000) >> 24) + +/* --------------------------------------------------------------------------- +* Types +*--------------------------------------------------------------------------- */ + +typedef struct _acdb_man_context_t AcdbCtxManContext; +struct _acdb_man_context_t +{ + ar_osal_mutex_t acdb_client_lock; + ar_osal_mutex_t ctx_man_lock; + /**< a bit field representing the available file slots. + 0 = taken, 1 = open */ + //uint32_t active_db_slots; + /**< The index of the database that the filemanager is + currently pointing to */ + acdb_context_handle_t *active_db; + /**< Current Number of databases being managed */ + uint32_t database_count; + /**< Maintains handle info about each loaded database */ + acdb_context_handle_t *database_info[ACDB_MAX_ACDB_FILES]; +}; + +typedef struct acdb_man_subgraph_location_t acdb_man_subgraph_location_t; +struct acdb_man_subgraph_location_t +{ + uint32_t subgraph_id; + acdb_context_handle_t* handle; +}; + +/* --------------------------------------------------------------------------- +* Global Variables +*--------------------------------------------------------------------------- */ + +static AcdbCtxManContext acdb_ctx_man_context; + +/**< NOTE: In the case where setting the active handle for a list of subgraphs +* results in more that one subgraph belonging to a different file: +* +* subgraphID + db handle (location that subgraph was found) */ +//static acdb_man_subgraph_location_t subgraph_location_cache[20]; + +/* --------------------------------------------------------------------------- +* Private functions +*--------------------------------------------------------------------------- */ + +int32_t acdb_ctx_man_init(void) +{ + int32_t status = AR_EOK; + + if (!acdb_ctx_man_context.acdb_client_lock) + { + status = ar_osal_mutex_create(&acdb_ctx_man_context.acdb_client_lock); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: failed to create acdb client mutex", + status); + } + } + + if (!acdb_ctx_man_context.ctx_man_lock) + { + status = ar_osal_mutex_create(&acdb_ctx_man_context.ctx_man_lock); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: failed to create context manager mutex", + status); + } + } + + //acdb_ctx_man_context.active_db_slots = 0xFFFFFFFF; + + return status; +} + +int32_t acdb_ctx_man_add_database(acdb_context_handle_t *handle) +{ + int32_t status = AR_EOK; + uint32_t index = 0; + acdb_context_handle_t *db_ctx = NULL; + + for (index = 0; index < MAX_ACDB_FILE_COUNT; index++) + { + if (IsNull(acdb_ctx_man_context.database_info[index])) + break; + } + + if (MAX_ACDB_FILE_COUNT == index) + index--; + + acdb_ctx_man_context.database_info[index] = + ACDB_MALLOC(acdb_context_handle_t, 1); + + if (IsNull(acdb_ctx_man_context.database_info[index])) + return AR_ENOMEMORY; + + ACDB_MUTEX_LOCK(acdb_ctx_man_context.ctx_man_lock); + db_ctx = acdb_ctx_man_context.database_info[index]; + + ar_mem_set(db_ctx, 0, sizeof(acdb_context_handle_t)); + + db_ctx->vm_id = handle->vm_id; + db_ctx->database_index = index; + db_ctx->file_manager_handle = handle->file_manager_handle; + db_ctx->delta_manager_handle = handle->delta_manager_handle; + db_ctx->heap_handle = handle->heap_handle; + + //ACDB_BIT_SET(acdb_ctx_man_context.active_db_slots, index); + acdb_ctx_man_context.database_count++; + if (1 == acdb_ctx_man_context.database_count) + acdb_ctx_man_context.active_db = + acdb_ctx_man_context.database_info[index]; + ACDB_MUTEX_UNLOCK(acdb_ctx_man_context.ctx_man_lock); + + return status; +} + +int32_t acdb_ctx_man_remove_database(acdb_handle_t *handle) +{ + int32_t status = AR_EOK; + // uint32_t db_index = 0; + acdb_context_handle_t* ctx_handle = NULL; + uint32_t vm_id = 0; + + if (IsNull(handle)) + return AR_EBADPARAM; + + vm_id = ACDB_HANDLE_TO_UINT(handle); + for (uint32_t i = 0; i < acdb_ctx_man_context.database_count; i++) + { + ctx_handle = acdb_ctx_man_context.database_info[i]; + + if (IsNull(ctx_handle)) + continue; + + if (vm_id == acdb_ctx_man_context.database_info[i]->vm_id) + { + // db_index = ctx_handle->database_index; + acdb_ctx_man_context.database_info[i] = NULL; + break; + } + } + + ACDB_FREE(ctx_handle); + + ACDB_MUTEX_LOCK(acdb_ctx_man_context.ctx_man_lock); + + // ACDB_BIT_UNSET(acdb_ctx_man_context.active_db_slots, db_index); + + if (acdb_ctx_man_context.database_count > 0) + { + acdb_ctx_man_context.database_count--; + } + + ACDB_MUTEX_UNLOCK(acdb_ctx_man_context.ctx_man_lock); + + return status; +} + +int32_t acdb_ctx_man_reset(void) +{ + int32_t status = AR_EOK; + acdb_context_handle_t *db_info = NULL; + acdb_handle_t acdb_handle = NULL; + + for (uint32_t i = 0; i < acdb_ctx_man_context.database_count; i++) + { + db_info = acdb_ctx_man_context.database_info[i]; + + if (IsNull(db_info)) + continue; + + acdb_handle = (acdb_handle_t)(uintptr_t)db_info->vm_id; + status = acdb_ctx_man_remove_database(&acdb_handle); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to remove data base at index %d", + status, db_info->vm_id); + status = AR_EFAILED; + } + } + + ar_osal_mutex_destroy(acdb_ctx_man_context.ctx_man_lock); + ar_osal_mutex_destroy(acdb_ctx_man_context.acdb_client_lock); + ar_mem_set(&acdb_ctx_man_context, 0, sizeof(AcdbCtxManContext)); + return status; +} + +int32_t acdb_ctx_man_get_acdb_client_handle(uint32_t acdb_handle, + acdb_handle_t *db_handle) +{ + if (IsNull(db_handle)) + return AR_EBADPARAM; + + for (uint32_t i = 0; i < acdb_ctx_man_context.database_count; i++) + { + if (acdb_handle == acdb_ctx_man_context.database_info[i]->vm_id) + { + *db_handle = ACDB_UINT_TO_HANDLE(acdb_handle); + return AR_EOK; + } + } + + return AR_ENOTEXIST; +} + +int32_t acdb_ctx_man_get_context_handle(uint32_t acdb_handle, + acdb_context_handle_t **ctx_handle) +{ + int32_t status = AR_EOK; + bool_t found = FALSE; + + if (IsNull(ctx_handle)) + return AR_EBADPARAM; + + for (uint32_t i = 0; i < acdb_ctx_man_context.database_count; i++) + { + if (acdb_handle == acdb_ctx_man_context.database_info[i]->vm_id) + { + *ctx_handle = acdb_ctx_man_context.database_info[i]; + found = TRUE; + break; + } + } + + if (!found) + return AR_ENOTEXIST; + + return status; +} + +int32_t acdb_ctx_man_get_context_handle_using_index(uint32_t db_index, + acdb_context_handle_t** ctx_handle) +{ + int32_t status = AR_EOK; + + if (IsNull(ctx_handle)) + return AR_EBADPARAM; + + if(db_index > acdb_ctx_man_context.database_count) + return AR_EBADPARAM; + + *ctx_handle = acdb_ctx_man_context.database_info[db_index]; + + if (IsNull(*ctx_handle)) + { + ACDB_ERR("Error[%d]: No database context was found at " + "index %d", db_index); + return AR_ENOTEXIST; + } + + return status; +} + +int32_t acdb_ctx_man_set_context_handle(acdb_handle_t *handle) +{ + int32_t status = AR_EOK; + uint32_t vm_id = 0; + + vm_id = ACDB_HANDLE_TO_UINT(handle); + for (uint32_t i = 0; i < acdb_ctx_man_context.database_count; i++) + { + if (vm_id != acdb_ctx_man_context.database_info[i]->vm_id) + continue; + + acdb_ctx_man_context.active_db = + acdb_ctx_man_context.database_info[i]; + break; + } + + return status; +} + +int32_t acdb_ctx_man_set_context_handle_using_index(uint32_t db_index) +{ + int32_t status = AR_EOK; + + if (db_index > acdb_ctx_man_context.database_count) + return AR_EBADPARAM; + + acdb_ctx_man_context.active_db = + acdb_ctx_man_context.database_info[db_index]; + + if (IsNull(acdb_ctx_man_context.active_db)) + { + ACDB_ERR("Error[%d]: No database context was found at " + "index %d", db_index); + return AR_ENOTEXIST; + } + + return status; +} + +int32_t acdb_ctx_man_set_handle_using_gkv( + AcdbGraphKeyVector* gkv, acdb_graph_info_t* graph_info) +{ + int32_t status = AR_ENOTEXIST; + uint32_t gkv_lut_offset = 0; + + if (IsNull(gkv) || IsNull(graph_info)) + { + return AR_EBADPARAM; + } + + for (uint32_t i = 0; i < acdb_ctx_man_context.database_count; i++) + { + acdb_ctx_man_context.active_db = + acdb_ctx_man_context.database_info[i]; + + status = DataProcSearchGkvKeyTable(gkv, &gkv_lut_offset); + if (AR_ENOTEXIST == status) + continue; + else if (AR_FAILED(status)) + { + return status; + } + + status = DataProcSearchGkvLut(gkv, gkv_lut_offset, graph_info); + if (AR_ENOTEXIST == status) + continue; + else if (AR_FAILED(status)) + { + return status; + } + + return status; + } + + ACDB_DBG("Error[%d]: Unable to set active database." + "Graph key vector not found in any file", status); + + return status; +} + +int32_t acdb_ctx_man_set_handle_using_subgraph( + AcdbUintList* subgraph_id_list) +{ + uint32_t status = AR_EOK; + uint32_t vm_id = 0; + uint32_t subgraph_id = 0; + uint32_t num_subgraphs_found = 0; + AcdbRange sg_range = { 0 }; + AcdbSharedSubgraphGuidTable shared_sg_guid_table = { 0 }; + + /* if a subgraph is shared, it can exist in one file plus 1 or more other + * files. This means that it is possible for it to be outside the subgraph + * id range. if the shared subgraph is outside the range, check the files + * import/export shared subgraph properties to make sure its in the + * current file */ + + if (acdb_ctx_man_context.database_count == 1) + { + acdb_ctx_man_context.active_db = + acdb_ctx_man_context.database_info[0]; + return AR_EOK; + } + + if (IsNull(subgraph_id_list) || IsNull(subgraph_id_list->list) || + 0 == subgraph_id_list->count) + { + return AR_EBADPARAM; + } + + for (uint32_t i = 0; i < acdb_ctx_man_context.database_count; i++) + { + num_subgraphs_found = 0; + acdb_ctx_man_context.active_db = + acdb_ctx_man_context.database_info[i]; + + if (1 == subgraph_id_list->count) + { + vm_id = ACDB_SUBGRAPH_TO_VM_ID(subgraph_id_list->list[0]); + + if (vm_id == acdb_ctx_man_context.database_info[i]->vm_id) + { + return AR_EOK; + } + } + else + { + status = DataProcGetIdRange( + ACDB_GPROP_SUBGRAPH_ID_RANGE, &sg_range); + if (AR_FAILED(status)) + { + return status; + } + + for (uint32_t j = 0; j < subgraph_id_list->count; j++) + { + subgraph_id = subgraph_id_list->list[j]; + if (DataProcIsValueInRange(subgraph_id, sg_range)) + { + num_subgraphs_found++; + } + else + { + //check imports + status = DataProcGetSharedSubgraphGuidTable( + ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS, + &shared_sg_guid_table); + if (AR_FAILED(status)) + { + return status; + } + + if (DataProcDoesSharedSubgraphExist( + subgraph_id, &shared_sg_guid_table)) + { + num_subgraphs_found++; + } + } + + if (num_subgraphs_found == 0) + break; + } + } + + if (num_subgraphs_found == subgraph_id_list->count) + { + return AR_EOK; + } + } + + /* The active context can only be set to one database. The acdb sw + * apis will fail to find subgraphs if subgraphs exist accross different files. + * For example: SG1 is defined in file 1, SG2 and SG3 are defined in File 2. + * If the context were set to file 1, acdb sw wont be able to find SG2 and SG3. + */ + ACDB_DBG("Error[%d]: Unable to set active database." + "Not all subgraphs were found in the same file", AR_ENOTEXIST); + + return AR_ENOTEXIST; +} + +int32_t acdb_ctx_man_set_handle_using_driver_module( + acdb_driver_cal_lut_entry_t *cal_lut_entry, + uint32_t *cal_lut_entry_offset) +{ + int32_t status = AR_EOK; + + for (uint32_t i = 0; i < acdb_ctx_man_context.database_count; i++) + { + acdb_ctx_man_context.active_db = + acdb_ctx_man_context.database_info[i]; + + status = DriverDataFindFirstOfModuleID( + cal_lut_entry, cal_lut_entry_offset); + if (AR_SUCCEEDED(status)) + { + return AR_EOK; + } + } + + ACDB_DBG("Error[%d]: Unable to set active database. " + "Driver module 0x%x not found in any file", + status, cal_lut_entry->mid); + + return status; +} + +/* --------------------------------------------------------------------------- +* Public Functions +*--------------------------------------------------------------------------- */ + +acdb_context_handle_t *acdb_ctx_man_get_active_handle(void) +{ + return acdb_ctx_man_context.active_db; +} + +ar_osal_mutex_t acdb_ctx_man_get_client_lock(void) +{ + return acdb_ctx_man_context.acdb_client_lock; +} + +uint32_t acdb_ctx_man_get_database_count(void) +{ + return acdb_ctx_man_context.database_count; +} + +int32_t acdb_ctx_man_ioctl(uint32_t cmd_id, + void* req, + uint32_t req_size, + void* rsp, + uint32_t rsp_size) +{ + int32_t status = AR_EOK; + + switch (cmd_id) + { + case ACDB_CTX_MAN_CMD_INIT: + status = acdb_ctx_man_init(); + break; + case ACDB_CTX_MAN_CMD_ADD_DATABASE: + if (req == NULL || req_size != sizeof(acdb_context_handle_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_add_database((acdb_context_handle_t*)req); + break; + case ACDB_CTX_MAN_CMD_REMOVE_DATABASE: + if (req == NULL || req_size != sizeof(acdb_handle_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_remove_database((acdb_handle_t*)req); + break; + case ACDB_CTX_MAN_CMD_RESET: + status = acdb_ctx_man_reset(); + break; + case ACDB_CTX_MAN_CMD_GET_AVAILABLE_FILE_SLOTS: + if (rsp == NULL || rsp_size != sizeof(uint32_t)) + { + return AR_EBADPARAM; + } + + *(uint32_t*)rsp = ACDB_MAX_ACDB_FILES + - acdb_ctx_man_context.database_count; + break; + case ACDB_CTX_MAN_CMD_GET_ACDB_CLIENT_HANDLE: + if (req == NULL || req_size != sizeof(uint32_t) || + rsp == NULL || rsp_size != sizeof(acdb_handle_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_get_acdb_client_handle( + *(uint32_t*)req, (acdb_handle_t*)rsp); + break; + case ACDB_CTX_MAN_CMD_GET_CONTEXT_HANDLE: + if (req == NULL || req_size != sizeof(uint32_t) || + rsp == NULL || rsp_size != sizeof(acdb_context_handle_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_get_context_handle(*(uint32_t*)req, rsp); + break; + case ACDB_CTX_MAN_CMD_GET_CONTEXT_HANDLE_USING_INDEX: + if (req == NULL || req_size != sizeof(uint32_t) || + rsp == NULL || rsp_size != sizeof(acdb_context_handle_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_get_context_handle_using_index( + *(uint32_t*)req, rsp); + break; + case ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE: + if (req == NULL || req_size != sizeof(acdb_handle_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_set_context_handle((acdb_handle_t*)req); + break; + case ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_INDEX: + if (req == NULL || req_size != sizeof(uint32_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_set_context_handle_using_index( + *(uint32_t*)req); + break; + case ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_GKV: + if (req == NULL || req_size != sizeof(AcdbGraphKeyVector) || + rsp == NULL || rsp_size != sizeof(acdb_graph_info_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_set_handle_using_gkv( + (AcdbGraphKeyVector*)req, (acdb_graph_info_t*)rsp); + break; + case ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_SUBGRAPHS: + if (req == NULL || req_size != sizeof(AcdbUintList)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_set_handle_using_subgraph( + (AcdbUintList*)req); + break; + case ACDB_CTX_MAN_CMD_SET_CONTEXT_HANDLE_USING_DRIVER_MODULE: + if (req == NULL || req_size != sizeof(acdb_driver_cal_lut_entry_t) || + rsp == NULL || rsp_size != sizeof(uint32_t)) + { + return AR_EBADPARAM; + } + + status = acdb_ctx_man_set_handle_using_driver_module( + (acdb_driver_cal_lut_entry_t*)req, (uint32_t*)rsp); + break; + default: + status = AR_EUNSUPPORTED; + break; + } + + return status; +} diff --git a/acdb/src/acdb_data_proc.c b/acdb/src/acdb_data_proc.c new file mode 100644 index 0000000..7b94862 --- /dev/null +++ b/acdb/src/acdb_data_proc.c @@ -0,0 +1,2527 @@ +/** +*============================================================================= +* \file acdb_data_proc.c +* +* \brief +* Processes data for the ACDB SW commands. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#include "acdb_data_proc.h" +#include "acdb_parser.h" +#include "acdb_heap.h" +#include "acdb_common.h" +#include "acdb_delta_file_mgr.h" + +/** +* \brief AcdbBlobToCalData +* Copies one module calibration from AcdbBlob to AcdbDeltaModuleCalData +* at some offset in AcdbBlob. +* \param[in/out] caldata: Calibration data in the format of delta data that +* must be freed in acdb_heap. calblob is copied to caldata +* \param[int] calblob: Module calibration blob passed in from the client +* \param[in/out] blob_offset: Offset within the blob +*/ +int32_t AcdbBlobToCalData(bool_t ignore_error_code, + AcdbDeltaModuleCalData *caldata, const AcdbBlob calblob, + uint32_t *blob_offset) +{ + if (*blob_offset > calblob.buf_size) + { + return AR_EBADPARAM; + } + + ACDB_MEM_CPY_SAFE(&caldata->module_iid, sizeof(uint32_t), + (uint8_t*)calblob.buf + *blob_offset, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + if (*blob_offset > calblob.buf_size) + { + ACDB_ERR("Unable to parse past module iid. " + "Blob offset %d is greater than the blob size %d", + *blob_offset, calblob.buf_size); + return AR_EFAILED; + } + + ACDB_MEM_CPY_SAFE(&caldata->param_id, sizeof(uint32_t), + (uint8_t*)calblob.buf + *blob_offset, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + if (*blob_offset > calblob.buf_size) + { + ACDB_ERR("Unable to parse past parameter id. " + "Blob offset %d is greater than the blob size %d", + *blob_offset, calblob.buf_size); + return AR_EFAILED; + } + + ACDB_MEM_CPY_SAFE(&caldata->param_size, sizeof(uint32_t), + (uint8_t*)calblob.buf + *blob_offset, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + if (*blob_offset > calblob.buf_size) + { + ACDB_ERR("Unable to parse past parameter size. " + "Blob offset %d is greater than the blob size %d", + *blob_offset, calblob.buf_size); + return AR_EFAILED; + } + + if (!ignore_error_code) + *blob_offset += sizeof(uint32_t); + + if (*blob_offset > calblob.buf_size) + { + ACDB_ERR("Unable to parse past error code. " + "Blob offset %d is greater than the blob size %d", + *blob_offset, calblob.buf_size); + return AR_EFAILED; + } + + caldata->param_payload = ACDB_MALLOC(uint8_t, caldata->param_size); + + if (!IsNull(caldata->param_payload)) + { + ACDB_MEM_CPY_SAFE(caldata->param_payload, (size_t)caldata->param_size, + (uint8_t*)calblob.buf + *blob_offset, (size_t)caldata->param_size); + *blob_offset += caldata->param_size; + if (!ignore_error_code) + *blob_offset += ACDB_PADDING_8_BYTE(caldata->param_size); + } + else + { + ACDB_ERR("Error[%d]: Unable to allocate %d bytes for " + "iid 0x%x pid 0x%x", AR_ENOMEMORY, + caldata->param_size, caldata->module_iid, caldata->param_id); + return AR_ENOMEMORY; + } + + return AR_EOK; +} + +void CalDataToAcdbBlob(AcdbDeltaModuleCalData *caldata, AcdbBlob calblob, uint32_t *blob_offset) +{ + if (*blob_offset < calblob.buf_size) + { + ACDB_MEM_CPY_SAFE(calblob.buf + *blob_offset, sizeof(uint32_t), + &caldata->module_iid, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE(calblob.buf + *blob_offset, sizeof(uint32_t), + &caldata->param_id, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE(calblob.buf + *blob_offset, sizeof(uint32_t), + &caldata->param_size, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + if (!IsNull(caldata->param_payload)) + { + ACDB_MEM_CPY_SAFE((uint8_t*)calblob.buf + *blob_offset, (size_t)caldata->param_size, + caldata->param_payload, (size_t)caldata->param_size); + *blob_offset += caldata->param_size; + } + } +} + +void FreeCalData(AcdbDeltaModuleCalData **caldata) +{ + ACDB_FREE((*caldata)->param_payload); + ACDB_FREE(*caldata); + *caldata = NULL; +} + +int32_t DataProcGetSubgraphProcIidMap(uint32_t subgraph_id, AcdbSubgraphPdmMap* subgraph_proc_iid_map) +{ + uint32_t status = AR_EOK; + uint32_t offset = 0; + ChunkInfo ci = { 0 }; + uint32_t subgraph_count = 0; + //Header: + size_t sz_subgraph_obj_header = 3 * sizeof(uint32_t); + + if (IsNull(subgraph_proc_iid_map)) + { + ACDB_ERR("Error[%d]: subgraph proc domain module map parameter is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci.chunk_id = ACDB_CHUNKID_SG_IID_MAP; + status = ACDB_GET_CHUNK_INFO(&ci); + if (AR_EOK != status) return status; + + offset = ci.chunk_offset; + status = FileManReadBuffer(&subgraph_count, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read subgraph count", status); + return status; + } + + for (uint32_t i = 0; i < subgraph_count; i++) + { + status = FileManReadBuffer((void*)subgraph_proc_iid_map, sz_subgraph_obj_header, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read subgraph proc domain map " + "header for subgraph 0x%x", status, subgraph_id); + return AR_EFAILED; + } + + if (subgraph_id != subgraph_proc_iid_map->subgraph_id) + { + offset += subgraph_proc_iid_map->size; + status = AR_ENOTEXIST; + continue; + } + + status = FileManGetFilePointer2((void**)&subgraph_proc_iid_map->proc_info, offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get pointer to proc domain module list info", status); + return AR_EFAILED; + } + + status = AR_EOK; + break; + } + + if (AR_FAILED(status)) + { + ar_mem_set((void*)subgraph_proc_iid_map, 0, sizeof(AcdbSubgraphPdmMap)); + } + + return status; +} + +/** +* \brief DoesSubgraphContainModule +* Checks if a module is contained in a subgraph +* \param[in] subgraph_id: The subgraph to search for +* \param[in] module_iid: The module instance to check for +* \param[in] status: ar error status +* \return TRUE if found, FALSE otherwise +*/ +bool_t DoesSubgraphContainModule(uint32_t subgraph_id, uint32_t module_iid, int32_t *status) +{ + uint32_t offset = 0; + AcdbProcDomainModuleList* proc_domain_module_list = NULL; + AcdbModuleInstance* module_instance_list = NULL; + + AcdbSubgraphPdmMap subgraph_proc_domain_map = { 0 }; + + *status = DataProcGetSubgraphProcIidMap(subgraph_id, &subgraph_proc_domain_map); + if (AR_EOK != *status) return FALSE; + + while (offset < subgraph_proc_domain_map.size) + { + proc_domain_module_list = (AcdbProcDomainModuleList*)((uint8_t*)subgraph_proc_domain_map.proc_info + offset); + offset += sizeof(AcdbProcDomainModuleList) + + proc_domain_module_list->module_count * sizeof(AcdbModuleInstance); + + module_instance_list = (AcdbModuleInstance*)((uint8_t*)&proc_domain_module_list->module_count + sizeof(uint32_t)); + + for (uint32_t i = 0; i < proc_domain_module_list->module_count; i++) + { + if (module_iid == module_instance_list[i].mid_iid) + { + return TRUE; + } + } + } + + return FALSE; +} + +int32_t DataProcGetProcDomainForModule(AcdbSubgraphPdmMap* subgraph_proc_domain_map, uint32_t module_iid, uint32_t* proc_domain_id) +{ + uint32_t offset = 0; + AcdbProcDomainModuleList* proc_domain_module_list = NULL; + AcdbModuleInstance* module_instance_list = NULL; + + while (offset < subgraph_proc_domain_map->size) + { + proc_domain_module_list = (AcdbProcDomainModuleList*)((uint8_t*)subgraph_proc_domain_map->proc_info + offset); + offset += sizeof(AcdbProcDomainModuleList) + + proc_domain_module_list->module_count * sizeof(AcdbModuleInstance); + + module_instance_list = (AcdbModuleInstance*)((uint8_t*)&proc_domain_module_list->module_count + sizeof(uint32_t)); + + for (uint32_t i = 0; i < proc_domain_module_list->module_count; i++) + { + if (module_iid == module_instance_list[i].mid_iid) + { + *proc_domain_id = proc_domain_module_list->proc_domain_id; + return AR_EOK; + } + } + } + + return AR_ENOTEXIST; +} + +int32_t IsPidGlobalyPersistent(uint32_t pid) +{ + //Acdb File Manager will handle selecting the correct ACDB file to read from + //ar_fhandle fhandle = NULL; + + uint32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t cal_id_count = 0; + uint32_t search_index = 0; + uint32_t *glb_persist_pid_map = NULL; + ChunkInfo ci = { 0 }; + //Header: + size_t sz_cal_id_obj_header = 3 * sizeof(uint32_t); + + CalibrationIdMap cal_id_obj; + + cal_id_obj.cal_id = 0; + cal_id_obj.param_id = pid; + cal_id_obj.cal_data_offset = 0; + + //ACDB_CLEAR_BUFFER(glb_buf_1); + + ci.chunk_id = ACDB_CHUNKID_GLB_PID_PERSIST_MAP; + status = ACDB_GET_CHUNK_INFO(&ci); + if (AR_EOK != status) return status; + + offset = ci.chunk_offset; + status = FileManReadBuffer(&cal_id_count, sizeof(uint32_t), &offset); + if (AR_EOK != status) return status; + + if (cal_id_count == 0) + { + ACDB_ERR("Cannot determine global persistence of Parameter(%x). " + "The number of Calibration Identifiers is zero.", pid); + return AR_ENOTEXIST; + } + + glb_persist_pid_map = ACDB_MALLOC(uint32_t, 3 * cal_id_count); + + status = FileManReadBuffer(glb_persist_pid_map, cal_id_count * sz_cal_id_obj_header, &offset); + if (AR_EOK != status) goto end; + + if (AR_EOK != AcdbDataBinarySearch2( + glb_persist_pid_map/*glb_buf_1*/, cal_id_count * sz_cal_id_obj_header, + &cal_id_obj, 1, sizeof(CalibrationIdMap)/sizeof(uint32_t), + &search_index)) + { + status = AR_ENOTEXIST; + } + +end: + + ACDB_FREE(glb_persist_pid_map); + + return status; +} + +int32_t IsPidPersistent(uint32_t pid) +{ + int32_t status = AR_EOK; + uint32_t num_pids = 0; + uint32_t offset = 0; + uint32_t search_index = 0; + uint32_t *persist_pid_map = NULL; + ChunkInfo ci = { 0 }; + + ci.chunk_id = ACDB_CHUNKID_PIDPERSIST; + status = ACDB_GET_CHUNK_INFO(&ci); + if (AR_EOK != status) return status; + + offset = ci.chunk_offset; + status = FileManGetFilePointer1( + (void**)&persist_pid_map, sizeof(uint32_t), &offset); + if (AR_EOK != status) return status; + + num_pids = *persist_pid_map; + if (num_pids == 0) + { + return AR_ENOTEXIST; + } + + status = FileManGetFilePointer1( + (void**)&persist_pid_map, num_pids * sizeof(uint32_t), &offset); + if (AR_EOK != status) return status; + + if (AR_EOK != AcdbDataBinarySearch2( + persist_pid_map, num_pids * sizeof(uint32_t), + &pid, 1, 1, + &search_index)) + { + status = AR_ENOTEXIST; + } + + return status; +} + +int32_t DataProcGetPersistenceType(uint32_t pid, AcdbDataPersistanceType *persistence_type) +{ + int32_t status = AR_EOK; + + if (IsNull(persistence_type)) + return AR_EBADPARAM; + + status = IsPidPersistent(pid); + if (AR_SUCCEEDED(status)) + { + *persistence_type = ACDB_DATA_PERSISTENT; + return status; + } + + //PID not found in Persistent Map so its either Non-persist or global + if(status == AR_ENOTEXIST) + { + status = IsPidGlobalyPersistent(pid); + if (AR_SUCCEEDED(status)) + { + *persistence_type = ACDB_DATA_GLOBALY_PERSISTENT; + return status; + } + else if (status == AR_ENOTEXIST) + { + *persistence_type = ACDB_DATA_NON_PERSISTENT; + status = AR_EOK; + return status; + } + } + + *persistence_type = ACDB_DATA_UNKNOWN; + ACDB_ERR("Error[%d] - Unable to determine the persistence type of Parameter(0x%x)", status, pid); + return status; +} + +/** +* \brief ConvertSetCalDataReqToMap +* Converts the input request into a format usable by the +* delta file manager. +* \param[in] req_key_vector: The key vector passed in by the client. The +* request key vector can be AcdbGraphKeyVector or AcdbModuleTag +* \param[in] key_vector_type: The type of key vector used in the requeset(CKV, TKV, etc...) +* \param[in] param_data: The subgraph param data to set to the heap +* \return a map pointer on success, Null on failure +*/ +acdb_delta_data_map_t *ConvertSetCalDataReqToMap( + void *req_key_vector, KeyVectorType key_vector_type, + AcdbSubgraphParamData* param_data, int32_t *status) +{ + AcdbBlob calblob; + uint32_t blob_offset = 0; + uint32_t subgraph_id = 0; + uint32_t num_sg_ids = 0; + uint32_t *sg_id_list = NULL; + LinkedListNode *node = NULL; + AcdbDeltaSubgraphData *subgraph_data = NULL; + AcdbGraphKeyVector *key_vector = NULL; + acdb_delta_data_map_t *map = + ACDB_MALLOC(acdb_delta_data_map_t, 1); + + calblob.buf = NULL; + calblob.buf_size = 0; + + *status = AR_EOK; + + if (IsNull(map)) + { + *status = AR_ENOMEMORY; + return NULL; + } + + ACDB_CLEAR_BUFFER(*map); + map->map_size = 0; + map->key_vector_type = key_vector_type; + switch (key_vector_type) + { + case TAG_KEY_VECTOR: + map->key_vector_data = ACDB_MALLOC(AcdbModuleTag, 1); + if (IsNull((AcdbModuleTag*)map->key_vector_data)) + { + *status = AR_ENOMEMORY; + ACDB_FREE(map); + return NULL; + } + + ((AcdbModuleTag*)map->key_vector_data)->tag_id = + ((AcdbModuleTag*)req_key_vector)->tag_id; + key_vector = &((AcdbModuleTag*)map->key_vector_data)->tag_key_vector; + + key_vector->num_keys = + ((AcdbModuleTag*)req_key_vector)->tag_key_vector.num_keys; + + key_vector->graph_key_vector = + ACDB_MALLOC(AcdbKeyValuePair, + key_vector->num_keys); + + if (IsNull(key_vector->graph_key_vector)) + { + *status = AR_ENOMEMORY; + ACDB_FREE(map); + return NULL; + } + + ACDB_MEM_CPY_SAFE( + key_vector->graph_key_vector, + key_vector->num_keys * sizeof(AcdbKeyValuePair), + ((AcdbModuleTag*)req_key_vector)->tag_key_vector.graph_key_vector, + key_vector->num_keys * sizeof(AcdbKeyValuePair)); + + break; + case CAL_KEY_VECTOR: + key_vector = ACDB_MALLOC(AcdbGraphKeyVector, 1); + if (IsNull(key_vector)) + { + *status = AR_ENOMEMORY; + ACDB_FREE(map); + return NULL; + } + + key_vector->graph_key_vector = NULL; + map->key_vector_data = key_vector; + + key_vector->num_keys = + ((AcdbGraphKeyVector*)req_key_vector)->num_keys; + + if (key_vector->num_keys) + { + key_vector->graph_key_vector = + ACDB_MALLOC(AcdbKeyValuePair, + key_vector->num_keys); + + if (IsNull(key_vector->graph_key_vector)) + { + *status = AR_ENOMEMORY; + ACDB_FREE(key_vector); + ACDB_FREE(map); + return NULL; + } + + ACDB_MEM_CPY_SAFE( + key_vector->graph_key_vector, + key_vector->num_keys * sizeof(AcdbKeyValuePair), + ((AcdbGraphKeyVector*)req_key_vector)->graph_key_vector, + key_vector->num_keys * sizeof(AcdbKeyValuePair)); + } + break; + default: + break; + } + + num_sg_ids = param_data->subgraph_id_list.count; + sg_id_list = param_data->subgraph_id_list.list; + + calblob.buf_size = param_data->data_size; + calblob.buf = param_data->data; + + map->num_subgraphs = num_sg_ids; + ACDB_CLEAR_BUFFER(map->subgraph_data_list); + + for (uint32_t i = 0; i < num_sg_ids; i++) + { + subgraph_id = sg_id_list[i]; + + subgraph_data = ACDB_MALLOC(AcdbDeltaSubgraphData, 1); + + if (IsNull(subgraph_data)) + { + *status = AR_ENOMEMORY; + break; + } + + ACDB_CLEAR_BUFFER(subgraph_data->non_global_data); + ACDB_CLEAR_BUFFER(subgraph_data->global_data); + + node = AcdbListCreateNode(subgraph_data); + if (IsNull(node)) + { + *status = AR_ENOMEMORY; + break; + } + + AcdbListAppend(&map->subgraph_data_list, node); + + subgraph_data->subgraph_id = subgraph_id; + subgraph_data->subgraph_data_size = 0; + + blob_offset = 0; + + //Parse Cal Blob and map the subgraph to its modules + while (blob_offset < calblob.buf_size) + { + if (blob_offset > calblob.buf_size) + { + ACDB_ERR("Error[%d]: cal data blob offset %d is larger " + "than blob size %d", *status, blob_offset, calblob.buf_size); + *status = AR_EFAILED; + break; + } + + AcdbDeltaModuleCalData *caldata = + ACDB_MALLOC(AcdbDeltaModuleCalData, 1); + + if (IsNull(caldata)) + { + *status = AR_ENOMEMORY; + break; + } + + *status = AcdbBlobToCalData(param_data->ignore_error_code, + caldata, calblob, &blob_offset); + if (AR_FAILED(*status)) + { + *status = AR_ENOMEMORY; + break; + } + + if (TRUE == DoesSubgraphContainModule(subgraph_id, + caldata->module_iid, status) && AR_EOK == *status) + { + LinkedListNode *caldata_node = AcdbListCreateNode(caldata); + + //Non Global(Persistent and Non-Persistent) + subgraph_data->non_global_data.data_size += + 3 * sizeof(uint32_t) + caldata->param_size; + + AcdbListAppend( + &subgraph_data->non_global_data.cal_data_list, + caldata_node); + + //todo: uncomment this functionality when global persist is supported + //if (AR_EOK == IsPidGlobalyPersistent(caldata->param_id)) + //{ + // //Global (Globaly Persistent) + // subgraph_data->global_data.data_size += + // 3 * sizeof(uint32_t) + caldata->param_size; + + // AcdbListAppend( + // &subgraph_data->global_data.cal_data_list, + // caldata_node); + //} + //else + //{ + //Non Global(Persistent and Non-Persistent) + //subgraph_data->non_global_data.data_size += + // 3 * sizeof(uint32_t) + caldata->param_size; + + //AcdbListAppend( + // &subgraph_data->non_global_data.cal_data_list, + // caldata_node); + //} + } + else + { + //ACDB_DBG("Subgraph(0x%x) does not contain Module Instance(0x%x).", subgraph_id, caldata->module_iid); + FreeCalData(&caldata); + } + } + + if (AR_FAILED(*status)) + { + ACDB_ERR("Error[%d]: Unable to create delta data " + "for subgraph 0x%x", *status, subgraph_id); + break; + } + + subgraph_data->subgraph_data_size = + subgraph_data->non_global_data.data_size + + subgraph_data->global_data.data_size; + + map->map_size += subgraph_data->subgraph_data_size; + } + + if (AR_EOK != *status) + { + acdb_heap_free_map(map); + map = NULL; + } + else + { + map->map_size += map->num_subgraphs * sizeof(uint32_t); + } + + subgraph_data = NULL; + node = NULL; + + return map; +} + +int32_t UpdateHeap(acdb_delta_data_map_t *req_map) +{ + int32_t status = AR_EOK; + acdb_delta_data_map_t *heap_map = NULL; + AcdbGraphKeyVector* key_vector = NULL; + + if (IsNull(req_map)) + { + ACDB_ERR("Failed to convert Set Data request to map"); + return status; + } + + switch (req_map->key_vector_type) + { + case TAG_KEY_VECTOR: + key_vector = + &((AcdbModuleTag*)req_map->key_vector_data)->tag_key_vector; + + if (IsNull(key_vector)) + { + ACDB_ERR("The request Tag Key Vector is null"); + return AR_EBADPARAM; + } + break; + case CAL_KEY_VECTOR: + key_vector = + (AcdbGraphKeyVector*)req_map->key_vector_data; + + if (IsNull(key_vector)) + { + ACDB_ERR("The request Calibration Key Vector is null"); + return AR_EBADPARAM; + } + break; + default: + break; + } + + if (IsNull(key_vector)) + { + ACDB_ERR("The request Key Vector is null"); + return AR_EBADPARAM; + } + + status = acdb_heap_ioctl( + ACDB_HEAP_CMD_GET_MAP, + (uint8_t*)key_vector, sizeof(AcdbGraphKeyVector), + (uint8_t*)&heap_map, sizeof(acdb_delta_data_map_t)); + + key_vector = NULL; + + if (AR_ENOTEXIST == status) + { + /** + * Scenario 1 - Add New CKV-to-Subgraph Map to Heap + * KV is not in the heap, so skip the comparison and write it to the heap + */ + status = acdb_heap_ioctl(ACDB_HEAP_CMD_ADD_MAP, + (uint8_t*)req_map, sizeof(acdb_delta_data_map_t), + NULL, 0); + } + else + { + /** + * Scenario 2 & 3 + * Update the subgraph data list for an existing map as well as update + * module calibration for an existing subgraph. + * Heap subgraph list is being modified. Any subgraph entry found is + * moved to the end of the heap maps subgraph list + */ + LinkedListNode *heap_sg_data_node = heap_map->subgraph_data_list.p_head; + LinkedListNode *req_sg_data_node = req_map->subgraph_data_list.p_head; + AcdbDeltaSubgraphData *heap_sg_data = NULL; + AcdbDeltaSubgraphData *req_sg_data = NULL; + LinkedListNode *heap_prev = NULL; + LinkedListNode *req_prev = NULL; + LinkedListNode *dont_care = NULL; + bool_t is_new_sg = FALSE; + + while (!IsNull(req_sg_data_node)) + { + req_sg_data = (AcdbDeltaSubgraphData*)req_sg_data_node->p_struct; + + if (IsNull(heap_sg_data_node)) + { + status = AR_EFAILED; + break; + } + + do + { + if (heap_sg_data_node == dont_care) + { + is_new_sg = TRUE; + break; + } + + heap_sg_data = (AcdbDeltaSubgraphData*)heap_sg_data_node->p_struct; + + if ((heap_sg_data->subgraph_id == req_sg_data->subgraph_id) && + req_sg_data->subgraph_data_size == 0) + { + break; + } + else if (heap_sg_data->subgraph_id == req_sg_data->subgraph_id) + { + //Perform Calibration Data Diff + is_new_sg = FALSE; + AcdbDeltaModuleCalData *heap_caldata = NULL; + AcdbDeltaModuleCalData *req_caldata = NULL; + LinkedListNode *heap_caldata_node = NULL; + LinkedListNode *req_caldata_node = NULL; + LinkedListNode *req_caldata_prev = NULL; + bool_t found = FALSE; + + heap_caldata_node = heap_sg_data->non_global_data.cal_data_list.p_head; + req_caldata_node = req_sg_data->non_global_data.cal_data_list.p_head; + if (IsNull(heap_caldata_node)) + { + ACDB_ERR("heap_caldata_node is null for subgraph_id: %u", heap_sg_data->subgraph_id); + continue; + } + if (IsNull(req_caldata_node)) + { + ACDB_ERR("req_caldata_node is null for subgraph_id: %u", req_sg_data->subgraph_id); + continue; + } + do + { + found = FALSE; + req_caldata = (AcdbDeltaModuleCalData*)req_caldata_node->p_struct; + do + { + heap_caldata = (AcdbDeltaModuleCalData*)heap_caldata_node->p_struct; + + // Compare + if (0 == ACDB_MEM_CMP(heap_caldata, req_caldata, 2 * sizeof(uint32_t))) + { + /* Replace the old parameter data with then new parameter data by + * subtracting the old parameters size and freeing its data */ + + // Remove old param data from heap map + heap_map->map_size -= heap_caldata->param_size; + heap_sg_data->subgraph_data_size -= heap_caldata->param_size; + heap_sg_data->non_global_data.data_size -= heap_caldata->param_size; + + //Add request maps data size + heap_map->map_size += req_caldata->param_size; + heap_sg_data->subgraph_data_size += req_caldata->param_size; + heap_sg_data->non_global_data.data_size += req_caldata->param_size; + + ACDB_FREE(heap_caldata->param_payload); + heap_caldata->param_payload = req_caldata->param_payload; + heap_caldata->param_size = req_caldata->param_size; + + req_caldata->param_payload = NULL; + req_caldata->param_size = 0; + + found = TRUE; + break; + } + + } while (TRUE != AcdbListSetNext(&heap_caldata_node)); + + if (!found) + { + AcdbListRemove(&req_sg_data->non_global_data.cal_data_list, req_caldata_prev, req_caldata_node); + AcdbListAppend(&heap_sg_data->non_global_data.cal_data_list, req_caldata_node); + + //Update Map Size and Subgraph data size + heap_sg_data->non_global_data.data_size += req_sg_data->non_global_data.data_size; + heap_sg_data->subgraph_data_size += req_sg_data->non_global_data.data_size; + heap_map->map_size += req_sg_data->non_global_data.data_size; + + if (IsNull(req_prev)) + { + //If the head is removed and added to the new list, + //reset the request subgraph node to the new head + req_caldata_node = req_sg_data->non_global_data.cal_data_list.p_head; + } + else + { + req_caldata_node = req_caldata_prev; + } + } + + heap_caldata_node = heap_sg_data->non_global_data.cal_data_list.p_head; + req_caldata_prev = req_caldata_node; + } while (TRUE != AcdbListSetNext(&req_caldata_node)); + + if (dont_care == NULL) + { + dont_care = heap_sg_data_node; + } + + AcdbListMoveToEnd(&heap_map->subgraph_data_list, &heap_sg_data_node, &heap_prev); + break; + } + else + { + is_new_sg = TRUE; + } + + heap_prev = heap_sg_data_node; + + } while (TRUE != AcdbListSetNext(&heap_sg_data_node)); + + //Add any subgraphs that were not found in the heap here + if (is_new_sg) + { + heap_map->map_size += sizeof(req_sg_data->subgraph_id) + req_sg_data->subgraph_data_size; + heap_map->num_subgraphs++; + + AcdbListRemove(&req_map->subgraph_data_list, req_prev, req_sg_data_node); + AcdbListAppend(&heap_map->subgraph_data_list, req_sg_data_node); + is_new_sg = FALSE; + + if (dont_care == NULL) + { + dont_care = req_sg_data_node; + } + if (IsNull(req_prev)) + { + //If the head is removed and added to the new list, + //reset the request subgraph node to the new head + req_sg_data_node = req_map->subgraph_data_list.p_head; + heap_sg_data_node = heap_map->subgraph_data_list.p_head; + continue; + } + else + { + req_sg_data_node = req_prev; + } + } + + req_prev = req_sg_data_node; + heap_sg_data_node = heap_map->subgraph_data_list.p_head; + req_sg_data_node = req_sg_data_node->p_next; + } + + //Free Request Map + acdb_heap_free_map(req_map); + req_map = NULL; + } + + return status; +} + +int32_t DataProcSetMapToHeap(acdb_delta_data_map_t *map) +{ + int32_t status = AR_EOK; + + status = UpdateHeap(map); + + return status; +} + + +int32_t SetSubraphData(void *req, KeyVectorType key_vector_type, + AcdbSubgraphParamData *subgraph_param_data) +{ + int32_t status = AR_EOK; + acdb_delta_data_map_t *req_map = NULL; + AcdbGraphKeyVector* key_vector = NULL; + + switch (key_vector_type) + { + case TAG_KEY_VECTOR: + key_vector = &((AcdbModuleTag*)req)->tag_key_vector; + + if (IsNull(key_vector)) + { + ACDB_ERR("The request Tag Key Vector is null"); + return AR_EBADPARAM; + } + break; + case CAL_KEY_VECTOR: + key_vector = ((AcdbGraphKeyVector*)req); + + if (IsNull(key_vector)) + { + ACDB_ERR("The request Calibration Key Vector is null"); + return AR_EBADPARAM; + } + break; + default: + break; + } + + if (IsNull(key_vector)) + { + ACDB_ERR("The request Key Vector is null"); + return AR_EBADPARAM; + } + + status = AcdbSort2(key_vector->num_keys * sizeof(AcdbKeyValuePair), + key_vector->graph_key_vector, sizeof(AcdbKeyValuePair), 0); + + req_map = ConvertSetCalDataReqToMap(req, key_vector_type, + subgraph_param_data, &status); + + if (IsNull(req_map) || AR_FAILED(status)) + { + ACDB_ERR("Failed to convert Set Data request to map"); + return status; + } + + status = UpdateHeap(req_map); + + return status; +} + +int32_t DataProcSetCalData(AcdbGraphKeyVector* cal_key_vector, + AcdbSubgraphParamData* subgraph_param_data) +{ + return SetSubraphData(cal_key_vector, CAL_KEY_VECTOR, + subgraph_param_data); +} + +int32_t DataProcSetTagData(AcdbModuleTag* module_tag, + AcdbSubgraphParamData* subgraph_param_data) +{ + return SetSubraphData(module_tag, TAG_KEY_VECTOR, + subgraph_param_data); +} + +int32_t GetSubgraphCalDataFromHeap( + AcdbDataPersistanceType persist_type, AcdbDataClient client, + AcdbGraphKeyVector* key_vector, + uint32_t subgraph_id, uint32_t module_iid, uint32_t param_id, + bool_t is_offloaded_param, bool_t should_write_iid_pid, + uint32_t* blob_offset, AcdbBlob* blob) +{ + int32_t status = AR_EOK; + int32_t error_code = 0; + uint32_t padded_param_size = 0; + uint32_t tmp_param_size = 0; + uint32_t caldata_size = 0; + uint32_t padding = 0; + uint32_t tmp_blob_offset = 0; + bool_t found = FALSE; + acdb_delta_data_map_t* heap_map = NULL; + LinkedListNode* sg_data_node = NULL; + AcdbDeltaSubgraphData* sg_data = NULL; + status = acdb_heap_ioctl( + ACDB_HEAP_CMD_GET_MAP, + (uint8_t*)key_vector, sizeof(AcdbGraphKeyVector), + (uint8_t*)&heap_map, sizeof(acdb_delta_data_map_t)); + + if (AR_EOK != status) return status; + + sg_data_node = heap_map->subgraph_data_list.p_head; + + //Resolve persist type if its unknown + if (persist_type == ACDB_DATA_UNKNOWN || + persist_type == ACDB_DATA_DONT_CARE) + { + /* TODO: replace this check with DataProcGetPersistenceType(...) + * when global persistence is supported */ + persist_type = IsPidPersistent(param_id) == AR_EOK ? + ACDB_DATA_PERSISTENT : ACDB_DATA_NON_PERSISTENT; + } + + do + { + sg_data = (AcdbDeltaSubgraphData*)sg_data_node->p_struct; + + if (subgraph_id == sg_data->subgraph_id) + { + LinkedListNode* cur_node = NULL; + AcdbDeltaModuleCalData* caldata = NULL; + + switch (persist_type) + { + case ACDB_DATA_GLOBALY_PERSISTENT: + { + cur_node = sg_data->global_data.cal_data_list.p_head; + } + break; + case ACDB_DATA_PERSISTENT: + case ACDB_DATA_NON_PERSISTENT: + { + cur_node = sg_data->non_global_data.cal_data_list.p_head; + } + break; + default: + return AR_EBADPARAM; + } + + while (cur_node != NULL) + { + caldata = (AcdbDeltaModuleCalData*)cur_node->p_struct; + + if (caldata->module_iid != module_iid || + caldata->param_id != param_id) + { + status = AR_ENOTEXIST; + cur_node = cur_node->p_next; + continue; + } + + //Collect only persistent data + if (ACDB_DATA_PERSISTENT == persist_type && + AR_EOK != IsPidPersistent(caldata->param_id)) + { + cur_node = cur_node->p_next; + } + + //Collect only non-persistent data + if (ACDB_DATA_NON_PERSISTENT == persist_type && + AR_EOK == IsPidPersistent(caldata->param_id)) + { + cur_node = cur_node->p_next; + } + + //Collect only globaly persistent data + if (ACDB_DATA_GLOBALY_PERSISTENT == persist_type && + AR_EOK != IsPidGlobalyPersistent(caldata->param_id)) + { + cur_node = cur_node->p_next; + } + + + status = AR_EOK; + //accumulate size + + /* + When ARCT requests for calibration from the heap, padding is not requried. + When ACDB Clients requests for calibration data, padding is requried since the + DSP requires 8 byte alignment. + */ + switch (client) + { + case ACDB_DATA_ACDB_CLIENT: + + if (is_offloaded_param) + { + AcdbPayload offloaded_caldata = { 0 }; + + if (blob->buf == NULL) + tmp_blob_offset = blob->buf_size; + else + tmp_blob_offset = *blob_offset; + + tmp_blob_offset += sizeof(AcdbDspModuleHeader); + offloaded_caldata.size = caldata->param_size; + offloaded_caldata.payload = caldata->param_payload; + + status = GetOffloadedParameterData( &offloaded_caldata, + &tmp_param_size, blob, &tmp_blob_offset); + + padded_param_size = + ACDB_ALIGN_8_BYTE(tmp_param_size); + padding = 0; + + if (blob->buf != NULL) + { + tmp_param_size = caldata->param_size; + caldata->param_size = padded_param_size; + } + } + else + { + padded_param_size = ACDB_ALIGN_8_BYTE( + caldata->param_size); + padding = padded_param_size + - caldata->param_size; + } + break; + + case ACDB_DATA_ATS_CLIENT: + padded_param_size = caldata->param_size; + padding = 0; + break; + default: + break; + } + + if (should_write_iid_pid) + caldata_size = sizeof(AcdbDspModuleHeader) + + padded_param_size; + else + caldata_size = 2 * sizeof(uint32_t) // param size and error code + + padded_param_size; + + //AcdbDeltaModuleCalData to AcdbBlob + if (blob->buf != NULL) + { + if (client == ACDB_DATA_ATS_CLIENT) + { + blob->buf_size += caldata_size; + } + + if (should_write_iid_pid) + { + //Copy MID, PID + if (blob->buf_size < (*blob_offset + 2 * sizeof(uint32_t))) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE(blob->buf + *blob_offset, 2 * sizeof(uint32_t), + caldata, 2 * sizeof(uint32_t)); + *blob_offset += 2 * sizeof(uint32_t); + } + + //Copy Param Size + if (blob->buf_size < (*blob_offset + sizeof(uint32_t))) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE(blob->buf + *blob_offset, sizeof(uint32_t), + &caldata->param_size, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + + //Insert error code + if (blob->buf_size < (*blob_offset + sizeof(error_code))) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE( + blob->buf + *blob_offset, sizeof(error_code), + &error_code, sizeof(error_code)); + *blob_offset += sizeof(error_code); + + if (is_offloaded_param && client == ACDB_DATA_ACDB_CLIENT) + { + caldata->param_size = tmp_param_size; + *blob_offset = tmp_blob_offset; + return status; + } + + //Payload + if (blob->buf_size < (*blob_offset + caldata->param_size)) + return AR_ENEEDMORE; + + ACDB_MEM_CPY_SAFE( + blob->buf + *blob_offset, caldata->param_size, + caldata->param_payload, caldata->param_size); + *blob_offset += caldata->param_size; + + //Add Padding + if (padding != 0) + { + memset((uint8_t*)blob->buf + *blob_offset, 0, padding); + *blob_offset += padding; + } + } + else + { + //Moudle IID, Param ID, Param Size, Error Code, Payload + blob->buf_size += caldata_size; + *blob_offset += caldata_size; + } + + found = TRUE; + break; + } + } + + if (TRUE == found) break; + + } while (TRUE != AcdbListSetNext(&sg_data_node)); + + if (!found) status = AR_ENOTEXIST; + + return status; +} + +int32_t GetSubgraphCalData( + AcdbDataPersistanceType persist_type, AcdbDataClient client, + AcdbGraphKeyVector* key_vector, + uint32_t subgraph_id, uint32_t module_iid, uint32_t param_id, + bool_t is_offloaded_param, uint32_t* blob_offset, AcdbBlob* blob) +{ + int32_t status = AR_EOK; + + status = GetSubgraphCalDataFromHeap( + persist_type, + client, + key_vector, + subgraph_id, + module_iid, + param_id, + is_offloaded_param, TRUE, blob_offset, blob); + + return status; +} + +int32_t DataProcGetHeapSubgraphCalData(acdb_heap_request_t* request) +{ + if (IsNull(request)) + { + ACDB_ERR("Error[%d]: The function input parameter is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + return GetSubgraphCalDataFromHeap( + request->persist_type, + request->client, + request->key_vector, + request->subgraph_id, + request->module_iid, + request->param_id, + request->is_offloaded_param, + request->should_write_iid_pid, + &request->blob_offset, + request->blob); +} + +int32_t DataProcGetHeapInfo(AcdbBufferContext *rsp) +{ + int32_t status = AR_EOK; + status = acdb_heap_ioctl(ACDB_HEAP_CMD_GET_HEAP_INFO, + NULL, 0, (uint8_t*)rsp, sizeof(AcdbBufferContext)); + + if (AR_FAILED(status)) + { + ACDB_ERR("Failed to get key vector and map info from the heap") + } + return status; +} + +int32_t WriteCalDataToBuffer(LinkedListNode *caldata_head, AcdbBlob* blob, uint32_t *blob_offset) +{ + int32_t status = AR_EOK; + AcdbDeltaModuleCalData *caldata = NULL; + LinkedListNode *cur_node = caldata_head; + uint32_t offset = *blob_offset; + + if (IsNull(caldata_head)) return AR_ENOTEXIST; + + while (!IsNull(cur_node)) + { + caldata = (AcdbDeltaModuleCalData*)cur_node->p_struct; + + status = AR_EOK; + + CalDataToAcdbBlob(caldata, *blob, &offset); + + cur_node = cur_node->p_next; + } + + *blob_offset = offset; + cur_node = NULL; + return status; +} + +int32_t DataProcGetHeapData(AcdbGraphKeyVector *key_vector, AcdbBufferContext* rsp, uint32_t *blob_offset) +{ + int32_t status = AR_EOK; + acdb_delta_data_map_t *heap_map = NULL; + LinkedListNode *sg_data_node = NULL; + AcdbDeltaSubgraphData *sg_data = NULL; + AcdbGraphKeyVector *heap_map_key_vector = NULL; + AcdbBlob blob = { 0 }; + uint32_t offset = *blob_offset; + blob.buf = rsp->buf; + blob.buf_size = rsp->size; + + status = acdb_heap_ioctl( + ACDB_HEAP_CMD_GET_MAP, + (uint8_t*)key_vector, sizeof(AcdbGraphKeyVector), + (uint8_t*)&heap_map, sizeof(acdb_delta_data_map_t)); + + if (AR_ENOTEXIST == status) + { + ACDB_ERR("No heap entry found for the provided key vector.") + return status; + } + + heap_map_key_vector = get_key_vector_from_map(heap_map); + if (IsNull(heap_map_key_vector)) + { + ACDB_ERR("Error[%d]: Map retrieved from heap is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + //Write Heap map to buffer + + //Write Key Vector + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(heap_map_key_vector->num_keys), + &heap_map_key_vector->num_keys, + sizeof(heap_map_key_vector->num_keys)); + offset += sizeof(heap_map_key_vector->num_keys); + + uint32_t sz_key_vector = heap_map_key_vector->num_keys * sizeof(AcdbKeyValuePair); + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sz_key_vector, + heap_map_key_vector->graph_key_vector, + sz_key_vector); + offset += sz_key_vector; + + //Write Map Size + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(heap_map->map_size), + &heap_map->map_size, sizeof(heap_map->map_size)); + offset += sizeof(heap_map->map_size); + + //Write Number of Subgraphs Data Objs + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(heap_map->num_subgraphs), + &heap_map->num_subgraphs, sizeof(heap_map->num_subgraphs)); + offset += sizeof(heap_map->num_subgraphs); + + //Write Subgraph Data Objs + sg_data_node = heap_map->subgraph_data_list.p_head; + + do + { + sg_data = (AcdbDeltaSubgraphData*)sg_data_node->p_struct; + + //Write Subgraph ID + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(sg_data->subgraph_id), + &sg_data->subgraph_id, sizeof(sg_data->subgraph_id)); + offset += sizeof(sg_data->subgraph_id); + + //Write Subgraph Data Size + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(sg_data->subgraph_data_size), + &sg_data->subgraph_data_size, sizeof(sg_data->subgraph_data_size)); + offset += sizeof(sg_data->subgraph_data_size); + + //Write Calibration Data (Same code for Global and Non Global Data) + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(sg_data->non_global_data.data_size), + &sg_data->non_global_data.data_size, sizeof(sg_data->non_global_data.data_size)); + offset += sizeof(sg_data->non_global_data.data_size); + + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(sg_data->non_global_data.cal_data_list.length), + &sg_data->non_global_data.cal_data_list.length, sizeof(sg_data->non_global_data.cal_data_list.length)); + offset += sizeof(sg_data->non_global_data.cal_data_list.length); + + //blob.buf = &rsp->buf[offset]; + + status = WriteCalDataToBuffer( + sg_data->non_global_data.cal_data_list.p_head, + &blob, &offset); + + if (AR_SUCCEEDED(status)) + { + *blob_offset += offset; + } + else + { + ACDB_DBG("There is no non-global subgraph calibration data in the heap entry"); + status = AR_EOK; + } + + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(sg_data->global_data.data_size), + &sg_data->global_data.data_size, sizeof(sg_data->global_data.data_size)); + offset += sizeof(sg_data->global_data.data_size); + + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(sg_data->global_data.cal_data_list.length), + &sg_data->global_data.cal_data_list.length, sizeof(sg_data->global_data.cal_data_list.length)); + offset += sizeof(sg_data->global_data.cal_data_list.length); + + status = WriteCalDataToBuffer( + sg_data->global_data.cal_data_list.p_head, + &blob, &offset); + + if (AR_SUCCEEDED(status)) + { + *blob_offset += offset; + } + else + { + ACDB_DBG("There is no global subgraph calibration data in the heap entry"); + status = AR_EOK; + } + + } while (TRUE != AcdbListSetNext(&sg_data_node)); + + *blob_offset = offset; + + return status; +} + +int32_t GetPartitionInfo(AcdbTableInfo *table_info, uint32_t scratch_buf_size, + uint32_t* num_partitions, uint32_t *partition_size) +{ + if (IsNull(table_info) || IsNull(num_partitions) || IsNull(partition_size)) + { + ACDB_ERR("Either table info, number of partitions, or partition size is null"); + return AR_EBADPARAM; + } + + if (table_info->table_size > scratch_buf_size) + { + //Determine partition size which is the max readable size based on the scratch buffer + *partition_size = (uint32_t)( + scratch_buf_size - (scratch_buf_size % table_info->table_entry_size) + ); + *num_partitions = (uint32_t)AcdbCeil(table_info->table_size, *partition_size); + } + else + { + *num_partitions = 1; + *partition_size = table_info->table_size; + } + + return AR_EOK; +} + +int32_t AcdbPartitionBinarySearch(AcdbTableInfo *table_info, + AcdbPartitionSearchInfo *part_info) +{ + int32_t status = AR_EOK; + uint32_t entry_index = 0; + uint32_t actual_index = 0; + uint32_t part_offset = 0; + uint32_t file_offset = 0; + Partition part = { 0 }; + uint32_t num_parts = 0; + uint32_t partition_size = 0; + + if (IsNull(table_info) || IsNull(part_info)) + { + return AR_EBADPARAM; + } + + //No data in the table + if (0 == table_info->table_size) + return AR_ENOTEXIST; + + status = GetPartitionInfo(table_info, part_info->scratch_space.buf_size, + &num_parts, &partition_size); + + part.offset = table_info->table_offset; + part.size = partition_size; + + for (uint32_t j = 0; j < num_parts; j++) + { + file_offset = part.offset; + status = FileManReadBuffer(part_info->scratch_space.buf, + part.size, &file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Unable to read Partition[%d][size: %d bytes, offset: 0x%x]", + j, part.offset, part.size); + return AR_EFAILED; + } + + part.offset += partition_size; + + //Binary Search + if (SEARCH_ERROR == AcdbDataBinarySearch2( + part_info->scratch_space.buf, + part.size, + part_info->table_entry_struct, + part_info->num_search_keys, + part_info->num_structure_elements, + &entry_index)) + { + //Nothing found in Partition X so continue + status = AR_ENOTEXIST; + continue; + } + else + { + //Found entry + part_offset = j * part.size; + actual_index = part_offset / sizeof(uint32_t) + entry_index; + actual_index /= part_info->num_structure_elements; + part_info->entry_index = actual_index; + part_info->entry_offset = entry_index * sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE( + part_info->table_entry_struct, + table_info->table_entry_size, + ((uint8_t*)part_info->scratch_space.buf) + part_info->entry_offset, + table_info->table_entry_size); + + status = AR_EOK; + break; + } + } + + return status; +} + +int32_t AcdbTableBinarySearch( + AcdbTableInfo *table_info, AcdbTableSearchInfo *part_info) +{ + int32_t status = AR_EOK; + uint32_t entry_index = 0; + acdb_fm_file_ptr_req_t fm_file_ptr_req = { 0 }; + + void *table_ptr = NULL; + if (IsNull(table_info) || IsNull(part_info)) + { + return AR_EBADPARAM; + } + + //No data in the table + if (0 == table_info->table_size) + return AR_ENOTEXIST; + + fm_file_ptr_req.handle_override = table_info->handle_override; + fm_file_ptr_req.offset = table_info->table_offset; + status = FileManGetDbPointer(&fm_file_ptr_req); + table_ptr = fm_file_ptr_req.file_ptr; + + if (SEARCH_ERROR == AcdbDataBinarySearch2( + table_ptr, + table_info->table_size, + part_info->table_entry_struct, + part_info->num_search_keys, + part_info->num_structure_elements, + &entry_index)) + { + //Nothing found in the table + return AR_ENOTEXIST; + } + + part_info->entry_index = entry_index / part_info->num_structure_elements; + part_info->entry_offset = entry_index * sizeof(uint32_t); + + ACDB_MEM_CPY_SAFE( + part_info->table_entry_struct, + table_info->table_entry_size, + ((uint8_t*)table_ptr) + part_info->entry_offset, + table_info->table_entry_size); + + return status; +} + +int32_t GetAcdbProperty(AcdbProperty *prop) +{ + int32_t status = AR_EOK; + uint32_t entry_count = 0; + //uint32_t offset = 0; + ChunkInfo ci_gprop = { 0 }; + ChunkInfo ci_data_pool = { 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + AcdbPropertyEntry entry = { 0 }; + acdb_fm_read_req_t read_req = { 0 }; + acdb_fm_file_ptr_req_t get_file_ptr_req = { 0 }; + + ci_gprop.chunk_id = ACDB_CHUNKID_GLOBAL_PROP; + ci_gprop.handle_override = prop->handle_override; + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + ci_data_pool.handle_override = prop->handle_override; + + status = ACDB_GET_CHUNK_INFO(&ci_gprop, &ci_data_pool); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Failed to read one or more chunks", status); + return status; + } + + read_req.handle_override = prop->handle_override; + read_req.dst_buffer = &entry_count; + read_req.read_size = sizeof(uint32_t); + read_req.offset = ci_gprop.chunk_offset; + //offset = ci_gprop.chunk_offset; + status = FileManDbReadAndSeek(&read_req); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to get property table entry count", + status); + return status; + } + + entry.property_id = prop->property_id; + //Setup Table Information (skip table entry count) + table_info.table_offset = read_req.offset; + table_info.table_size = ci_gprop.chunk_size - sizeof(uint32_t); + table_info.table_entry_size = sizeof(AcdbPropertyEntry); + table_info.handle_override = prop->handle_override; + + //Setup Search Information + search_info.num_search_keys = 1; + search_info.num_structure_elements = + (sizeof(AcdbPropertyEntry) / sizeof(uint32_t)); + search_info.table_entry_struct = &entry; + + status = AcdbTableBinarySearch(&table_info, &search_info); + + if (AR_FAILED(status) && status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: Property(%s) not found.", + status, &prop->property_id); + return status; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: An error occured while searching " + "for Property(%s).", status, &prop->property_id); + return status; + } + + read_req.dst_buffer = &prop->size; + read_req.read_size = sizeof(uint32_t); + read_req.offset = ci_data_pool.chunk_offset + entry.offset_property_data; + status = FileManDbReadAndSeek(&read_req); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get property size for Property(%s)", + status, &prop->property_id); + return status; + } + get_file_ptr_req.handle_override = prop->handle_override; + get_file_ptr_req.offset = read_req.offset; + + status = FileManGetDbPointer(&get_file_ptr_req); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get property data for Property(%s)", + status, &prop->property_id); + return status; + } + prop->property_data = (uint8_t*)get_file_ptr_req.file_ptr; + + return status; +} + +int32_t IsOffloadedParam(uint32_t param_id, AcdbUintList *offloaded_param_list) +{ + if (IsNull(offloaded_param_list)) + return AR_ENOTEXIST; + + for (uint32_t i = 0; i < offloaded_param_list->count; i++) + { + if (param_id == offloaded_param_list->list[i]) + return AR_EOK; + } + + return AR_ENOTEXIST; +} + +int32_t GetOffloadedParamList(AcdbUintList *offloaded_param_list) +{ + int32_t status = AR_EOK; + AcdbProperty prop = { 0 }; + + prop.property_id = ACDB_GPROP_OFFLOADED_PARAM_INFO; + status = GetAcdbProperty(&prop); + if (AR_FAILED(status)) + { + offloaded_param_list->count = 0; + offloaded_param_list->list = NULL; + return status; + } + + offloaded_param_list->count = *(uint32_t*)prop.property_data; + offloaded_param_list->list = ((uint32_t*)prop.property_data + 1); + + return status; +} + +int32_t GetOffloadedParameterData( + AcdbPayload *caldata, uint32_t *paramSize, + AcdbBlob *rsp, uint32_t *blob_offset) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + AcdbOffloadedParamHeader header = { 0 }; + size_t data_size = 0; + uint32_t padding = 0; + uint32_t path_length = 0; + char_t* path = NULL; + bool_t is_relative_path = FALSE; + + if (IsNull(caldata) || IsNull(paramSize) || IsNull(rsp) || IsNull(blob_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameters is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (caldata->size <= 0 || caldata->payload == NULL) + { + ACDB_ERR("Error[%d]: The input calibration data is null or empty", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + //Parse AcdbOffloadedParamHeader from parameter payload + ACDB_MEM_CPY_SAFE(&header, sizeof(header), caldata->payload, sizeof(header)); + offset += sizeof(header); + + //Parse payload: Should contain [path length, path] + path_length = *(uint32_t*)(caldata->payload + offset); + if (path_length > 0) + { + path = (char_t*)caldata->payload + offset + sizeof(uint32_t); + + //Check for relative path or full path + if(path_length > 2 && !( + (path[0] == '/') || + (path[1] == ':' && path[2] == '\\') + )) + { + /* Relative Path: Merge acdb directory path with offloaded file name + * Ex. "../path/to/acdb/" + "offloaded_file.bin" + */ + char_t *tmp_path = NULL; + acdb_path_256_t *path_info = NULL; + uint32_t tmp_path_length = 0; + is_relative_path = TRUE; + + status = AcdbFileManGetAcdbDirectoryPath(&path_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get acdb directory path to" + " merge with relative path %s", status, path); + return status; + } + + tmp_path_length = path_length + path_info->path_len; + tmp_path = ACDB_MALLOC(char_t, tmp_path_length); + + if (IsNull(tmp_path)) + { + return AR_ENOMEMORY; + } + + ACDB_STR_CPY_SAFE(tmp_path, tmp_path_length, + path_info->path, path_info->path_len); + ACDB_STR_CPY_SAFE(tmp_path + path_info->path_len, + path_length, path, path_length); + + path = tmp_path; + path_length = tmp_path_length; + tmp_path = NULL; + } + } + + if (path != NULL && path[0] != '\0' && path_length > 0) + { + status = FileManReadFileToBuffer( + path, &data_size, NULL, rsp->buf_size); + if (AR_FAILED(status)) + { + status = AR_EOK; + ACDB_ERR("Error[%d]: Unable to read file size for" + " offloaded parameter. Does the file exist?" + " The data section will be zeroed out", AR_ENOTEXIST); + data_size = padding = 0; + } + + //perform alignment before writing data + if ((*blob_offset + offset) % header.alignment && data_size > 0) + { + //padding here is for offloaded data front-padding + padding = header.alignment + - (*blob_offset + offset) % header.alignment; + header.data_offset = padding; + + if (!IsNull(rsp->buf) && rsp->buf_size > 0) + { + if (offset > rsp->buf_size) + { + status = AR_ENEEDMORE; + ACDB_ERR("Error[%d]: Buffer is not large enough " + "to set offloaded parameter padding.\n", status); + goto end; + } + ar_mem_set((void*)((uint8_t*)rsp->buf + offset + *blob_offset), + 0, padding); + } + } + } + else + { + status = AR_EOK; + if(IsNull(rsp->buf)) + ACDB_DBG( + "Warning[%d]: No file data to load for offloaded parameter." + "Does the file exist? The data section will be zeroed out." + , status); + data_size = padding = 0; + } + + //Update Parameter Size + *paramSize = (uint32_t)sizeof(header) + padding + (uint32_t)data_size; + header.data_size = (uint32_t)data_size; + + //8 byte aligned padding + padding = ACDB_PADDING_8_BYTE(*paramSize); + //*paramSize = ACDB_ALIGN_8_BYTE(*paramSize); + + if (IsNull(rsp->buf) || rsp->buf_size == 0) + goto end; + + //Write Data + if (sizeof(header) > rsp->buf_size) + { + status = AR_ENEEDMORE; + ACDB_ERR("Error[%d]: Buffer is not large enough " + "to copy offloaded parameter header.\n", status); + goto end; + } + + offset = 0; + //Write Header + ACDB_MEM_CPY_SAFE(rsp->buf + offset + *blob_offset, sizeof(header), + &header, sizeof(header)); + offset += sizeof(header); + *blob_offset += sizeof(header); + + if ((uint32_t)data_size > rsp->buf_size - offset) + { + status = AR_ENEEDMORE; + ACDB_ERR("Error[%d]: Buffer is not large enough " + "to copy offloaded parameter data.\n", status); + goto end; + } + + if (path != NULL && path[0] != '\0' && data_size > 0) + { + status = FileManReadFileToBuffer(path, &data_size, + (uint8_t*)rsp->buf + *blob_offset + header.data_offset, + rsp->buf_size); + if ((uint32_t)data_size > 0UL && AR_SUCCEEDED(status)) + { + *blob_offset += header.data_offset + (uint32_t)data_size; + } + } + else + { + *blob_offset += header.data_offset + (uint32_t)data_size; + } + + //Write 8 byte aligned padding + if (padding) + { + ar_mem_set((void*)((uint8_t*)rsp->buf + *blob_offset), 0, padding); + *blob_offset += padding; + } + +end: + if (is_relative_path) + { + if (path) ACDB_FREE(path); + } + + return status; +} + +int32_t DataProcGetHwAccelSubgraphInfo(AcdbHwAccelSubgraphInfo* info) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_subgraphs = 0; + ChunkInfo ci_hasi = { 0 }; + AcdbHwAccelSubgraphInfo *subgraph_info = NULL; + + ci_hasi.chunk_id = ACDB_CHUNKID_HW_ACCEL_SUBGRAPH_INFO; + status = ACDB_GET_CHUNK_INFO(&ci_hasi); + if (AR_FAILED(status)) + { + return status; + } + + //Todo: make this a linear search for now. add a search function that + //determines how to search based on the number of elements + + offset = ci_hasi.chunk_offset; + + status = FileManReadBuffer(&num_subgraphs, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to read HW Accel " + "Subgraph Info subgraph count", status); + return status; + } + + status = FileManGetFilePointer2((void**)&subgraph_info, offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to get HW Accel Subgraph Info", + status); + return status; + } + + for (uint32_t i = 0; i < num_subgraphs; i++) + { + if (subgraph_info[i].subgraph_id == info->subgraph_id) + { + info->subgraph_id = subgraph_info[i].subgraph_id; + info->mem_type = subgraph_info[i].mem_type; + info->module_list_offset = subgraph_info[i].module_list_offset; + return AR_EOK; + } + } + + return AR_ENOTEXIST; +} + +int32_t DataProcIsHwAccelParam(uint32_t module_list_offset, + uint32_t module_iid, uint32_t param_id) +{ + int32_t status = AR_EOK; + uint32_t num_params = AR_EOK; + uint32_t offset = AR_EOK; + AcdbMiidPidPair *module_param_list = NULL; + ChunkInfo ci_data_pool = { 0 }; + + ci_data_pool.chunk_id = ACDB_CHUNKID_DATAPOOL; + status = ACDB_GET_CHUNK_INFO(&ci_data_pool); + if (AR_FAILED(status)) + { + return status; + } + + /* Skip 4 byte data size */ + offset = ci_data_pool.chunk_offset + + module_list_offset + sizeof(uint32_t); + + status = FileManReadBuffer(&num_params, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to read HW Accel " + "Subgraph Info subgraph count", status); + return status; + } + + status = FileManGetFilePointer2((void**)&module_param_list, offset); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to get HW Accel Subgraph Info", + status); + return status; + } + + for (uint32_t i = 0; i < num_params; i++) + { + if (module_iid == module_param_list[i].module_iid && + param_id == module_param_list[i].parameter_id) + return AR_EOK; + } + + return AR_ENOTEXIST; +} + +int32_t DataProcGetVmId(uint32_t *vm_id) +{ + int32_t status = AR_EOK; + AcdbProperty prop = { 0 }; + + if (IsNull(vm_id)) + return AR_EBADPARAM; + + prop.property_id = ACDB_GPROP_VIRTUAL_MACHINE_ID; + prop.handle_override = ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER; + status = GetAcdbProperty(&prop); + + if (AR_SUCCEEDED(status)) + { + *vm_id = *(uint32_t*)prop.property_data; + } + + return status; +} + +bool_t DataProcIsValueInRange(uint32_t id, AcdbRange range) +{ + return range.min <= id && id <= range.max; +} + +int32_t DataProcGetIdRange(AcdbGlobalProperty range_property_id, + AcdbRange *id_range) +{ + int32_t status = AR_EOK; + AcdbProperty prop = { 0 }; + + switch (range_property_id) + { + case ACDB_GPROP_SUBGRAPH_ID_RANGE: + break; + default: + status = AR_EBADPARAM; + break; + } + + if (AR_FAILED(status)) + return status; + + prop.property_id = range_property_id; + status = GetAcdbProperty(&prop); + + if (AR_SUCCEEDED(status)) + { + id_range->min = *(uint32_t*)prop.property_data; + id_range->max = *(uint32_t*)(prop.property_data + sizeof(uint32_t)); + } + + return status; +} + +int32_t DataProcGetSharedSubgraphGuid(uint32_t subgraph_id, + AcdbGlobalProperty im_ex_shared_subgraph_property_id, + uint8_t* guid) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + bool_t found = FALSE; + AcdbSharedSubgraphGuidTable subgraph_guid_table = { 0 }; + AcdbSharedSubgraphDataGuid *subgraph_guid_entry = NULL; + AcdbProperty im_ex_shared_sugraph_property = { 0 }; + + if (IsNull(guid)) + { + return status; + } + + switch (im_ex_shared_subgraph_property_id) + { + case ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS: + case ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS: + break; + default: + status = AR_EBADPARAM; + break; + } + + if (AR_FAILED(status)) + return status; + + im_ex_shared_sugraph_property.handle_override = + ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER; + im_ex_shared_sugraph_property.property_id = + im_ex_shared_subgraph_property_id; + + status = GetAcdbProperty(&im_ex_shared_sugraph_property); + if (AR_EOK != status) + { + return status; + } + + subgraph_guid_table.num_subgraphs = + *(uint32_t*)im_ex_shared_sugraph_property.property_data; + + offset += sizeof(uint32_t); + subgraph_guid_table.guid_entries = (AcdbSharedSubgraphDataGuid*) + (im_ex_shared_sugraph_property.property_data + offset); + + for (uint32_t i = 0; i < subgraph_guid_table.num_subgraphs; i++) + { + subgraph_guid_entry = &subgraph_guid_table.guid_entries[i]; + + if (subgraph_guid_entry->subgraph_id == subgraph_id) + { + found = TRUE; + break; + } + } + + if (!found) + { + return AR_ENOTEXIST; + } + + ar_mem_cpy(guid, ACDB_GUID_BYTE_LENGTH, + &subgraph_guid_entry->guid, ACDB_GUID_BYTE_LENGTH); + + return status; +} + +int32_t DataProcGetSharedSubgraphGuidTable( + AcdbGlobalProperty im_ex_shared_subgraph_property_id, + AcdbSharedSubgraphGuidTable *guid_table) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + AcdbProperty import_export_shared_sugraph_property = { 0 }; + + if (IsNull(guid_table)) + { + return AR_EBADPARAM; + } + + switch (im_ex_shared_subgraph_property_id) + { + case ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS: + case ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS: + break; + default: + status = AR_EBADPARAM; + break; + } + + if (AR_FAILED(status)) + return status; + + import_export_shared_sugraph_property.property_id = + im_ex_shared_subgraph_property_id; + + status = GetAcdbProperty(&import_export_shared_sugraph_property); + if (AR_FAILED(status)) + { + return status; + } + + guid_table->num_subgraphs = + *(uint32_t*)import_export_shared_sugraph_property.property_data; + + offset += sizeof(uint32_t); + guid_table->guid_entries = (AcdbSharedSubgraphDataGuid*) + (import_export_shared_sugraph_property.property_data + offset); + + return status; +} + +bool_t DataProcDoesSharedSubgraphExist(uint32_t subgraph_id, + AcdbSharedSubgraphGuidTable *guid_table) +{ + if (IsNull(guid_table) || 0 == guid_table->num_subgraphs) + return FALSE; + + for (uint32_t i = 0; i < guid_table->num_subgraphs; i++) + { + if (guid_table->guid_entries[i].subgraph_id == subgraph_id) + { + return TRUE; + } + } + + return FALSE; +} + +int32_t DataProcGetSubgraphPdmMap(AcdbSubgraphPdmMap* map) +{ + uint32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t subgraph_count = 0; + uint32_t found_count = 0; + //Header: + size_t sz_subgraph_obj_header = 3 * sizeof(uint32_t); + ChunkInfo ci = { 0 }; + AcdbSubgraphPdmMap found_map = { 0 }; + + if (IsNull(map)) + { + ACDB_DBG("Error[%d]: The input subgraph proc domain to module" + " instance map is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + ci.chunk_id = ACDB_CHUNKID_SG_IID_MAP; + status = ACDB_GET_CHUNK_INFO(&ci); + if (AR_EOK != status) return status; + + offset = ci.chunk_offset; + status = FileManReadBuffer(&subgraph_count, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read subgraph count", status); + return status; + } + + for (uint32_t i = 0; i < subgraph_count; i++) + { + status = FileManReadBuffer(&found_map, + sz_subgraph_obj_header, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read subgraph count", status); + goto end; + } + + if (found_map.subgraph_id == map->subgraph_id) + { + map->proc_count = found_map.proc_count; + map->size = found_map.size; + if (found_map.size <= 0) continue; + + status = FileManGetFilePointer1((void **)&map->proc_info, found_map.size, &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read processor info", status); + goto end; + } + + found_count++; + break; + } + else + { + offset += map->size; + } + } + +end: + status = (0 == found_count) ? AR_ENOTEXIST : status; + + if (AR_FAILED(status)) + { + map->proc_info = NULL; + } + + return status; +} + +int32_t DataProcSearchGkvKeyTable( + AcdbGraphKeyVector *gkv, uint32_t *gkv_lut_offset) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_key_tables = 0; + uint32_t key_table_size = 0; + uint32_t key_table_entry_size = 0; + bool_t found = FALSE; + ChunkInfo ci_key_id_table = { 0 }; + KeyTableHeader key_table_header = { 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + if (IsNull(gkv) || IsNull(gkv_lut_offset)) + { + ACDB_ERR("Error[%d]: The gkv input parameter is null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (gkv->num_keys >= GLB_BUF_2_LENGTH / 2) + { + ACDB_ERR("Error[%d]: The number of keys %d is greater " + "than the max buffer element count %d", + AR_EBADPARAM, gkv->num_keys, GLB_BUF_2_LENGTH / 2); + return AR_EBADPARAM; + } + + ci_key_id_table.chunk_id = ACDB_CHUNKID_GKVKEYTBL; + status = ACDB_GET_CHUNK_INFO(&ci_key_id_table); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve Graph Key ID Chunk.", + status); + return status; + } + + offset = ci_key_id_table.chunk_offset; + status = FileManReadBuffer(&num_key_tables, sizeof(uint32_t), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read number of GKV Key ID tables.", + status); + return status; + } + + if (num_key_tables > ci_key_id_table.chunk_size) + { + ACDB_ERR("Error[%d]: Number of GKV tables %d is greater than the table size %d.", + AR_EFAILED, num_key_tables, ci_key_id_table.chunk_size); + return AR_EFAILED; + } + + for (uint32_t i = 0; i < num_key_tables; i++) + { + status = FileManReadBuffer(&key_table_header, + sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key table header.", + status); + return status; + } + + key_table_entry_size = key_table_header.num_keys + * sizeof(uint32_t) + + sizeof(uint32_t); + key_table_size = key_table_header.num_entries + * key_table_entry_size; + + if (key_table_header.num_keys != gkv->num_keys) + { + offset += key_table_size; + } + else + { + //GLB BUF 2 stores Key IDs + for (uint32_t j = 0; j < gkv->num_keys; j++) + { + glb_buf_2[j] = gkv->graph_key_vector[j].key; + } + + //Setup Table Information + table_info.table_offset = offset; + table_info.table_size = key_table_size; + table_info.table_entry_size = key_table_entry_size; + + //Setup Search Information + search_info.num_search_keys = key_table_header.num_keys; + search_info.num_structure_elements = + key_table_header.num_keys + 1;//key_ids + GKVLUT Offset + search_info.table_entry_struct = &glb_buf_2; + + status = AcdbTableBinarySearch(&table_info, &search_info); + + if (AR_FAILED(status)) + { + //ACDB_DBG("Error[%d]: Unable to find graph key vector. " + // "No matching key IDs were found", status); + return status; + } + + *gkv_lut_offset = glb_buf_2[gkv->num_keys]; + + found = TRUE; + return status; + } + } + + if (!found) + { + //ACDB_DBG("Error[%d]: Unable to find graph key vector. " + // "There are no key vectors with %d keys", AR_ENOTEXIST, + // gkv->num_keys); + return AR_ENOTEXIST; + } + + return status; +} + +int32_t DataProcSearchGkvLut(AcdbGraphKeyVector* gkv, + uint32_t gkv_lut_offset, + acdb_graph_info_t *graph_info) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t key_table_size = 0; + uint32_t key_table_entry_size = 0; + ChunkInfo ci_key_value_table = { 0 }; + KeyTableHeader key_table_header = { 0 }; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + if (IsNull(gkv) || IsNull(graph_info)) + { + ACDB_ERR("Error[%d]: One or more input parameter(s) are null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (gkv->num_keys + 1 >= GLB_BUF_2_LENGTH / 2) + { + ACDB_ERR("Error[%d]: The number of keys %d is greater " + "than the max buffer element count %d", + AR_EBADPARAM, gkv->num_keys, GLB_BUF_2_LENGTH / 2); + return AR_EBADPARAM; + } + + ci_key_value_table.chunk_id = ACDB_CHUNKID_GKVLUTTBL; + status = ACDB_GET_CHUNK_INFO(&ci_key_value_table); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to retrieve Graph Key Lookup Chunk.", + status); + return status; + } + + offset = ci_key_value_table.chunk_offset + gkv_lut_offset; + status = FileManReadBuffer(&key_table_header, + sizeof(KeyTableHeader), &offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key table header.", + status); + return status; + } + + //Value List + SG List offset + SG Data Offset + key_table_entry_size = key_table_header.num_keys + * sizeof(uint32_t) + + 2 * sizeof(uint32_t); + key_table_size = key_table_header.num_entries + * key_table_entry_size; + + if (key_table_header.num_keys != gkv->num_keys) + { + ACDB_DBG("Error[%d]: The lookup table key count does not " + "match the input key vector key count.", + AR_ENOTEXIST); + return AR_ENOTEXIST; + } + else + { + //GLB BUF 2 stores Key Values + for (uint32_t j = 0; j < gkv->num_keys; j++) + { + glb_buf_2[j] = gkv->graph_key_vector[j].value; + } + + //Setup Table Information + table_info.table_offset = offset; + table_info.table_size = key_table_size; + table_info.table_entry_size = key_table_entry_size; + + //Setup Search Information + search_info.num_search_keys = key_table_header.num_keys; + search_info.num_structure_elements = + key_table_header.num_keys + 2;//Values + List Offset + Data Offset + search_info.table_entry_struct = &glb_buf_2; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Unable to find graph key vector. " + "No matching values were found", status); + return status; + } + + graph_info->sg_list_offset = glb_buf_2[gkv->num_keys]; + graph_info->sg_prop_data_offset = glb_buf_2[gkv->num_keys + 1]; + } + + return status; +} + +/** +* \brief +* Search for the first occurance of a tuple using the Module ID as a search key and +* returns the file offset of the first occurrance. +* +* \param[in/out] cal_lut_entry: GSL Calibration Lookuptable entry in the +* format of +* \param[out] cal_lut_entry_offset: The starting offset of one or more +* entries for the MID +* specified in cal_lut_entry.mid +* +* \return AR_EOK on success, non-zero otherwise +*/ +int32_t DriverDataFindFirstOfModuleID( + acdb_driver_cal_lut_entry_t* cal_lut_entry, uint32_t* cal_lut_entry_offset) +{ + int32_t status = AR_EOK; + ChunkInfo gsl_cal_lut = { 0 }; + + //Lookup Table + //Binary Search based on MID + uint32_t search_index_count = 1; + uint32_t sz_gsl_cal_lut = 0; + AcdbTableInfo table_info = { 0 }; + AcdbTableSearchInfo search_info = { 0 }; + + if (IsNull(cal_lut_entry) || IsNull(cal_lut_entry_offset)) + { + ACDB_ERR("Error[%d]: One or more input parameters is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + gsl_cal_lut.chunk_id = ACDB_CHUNKID_GSL_CAL_LUT; + status = ACDB_GET_CHUNK_INFO(&gsl_cal_lut); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to get GSL Calibration Data Chunk", status); + return status; + } + + sz_gsl_cal_lut = gsl_cal_lut.chunk_size - sizeof(uint32_t); + + //Setup Table Information + table_info.table_offset = gsl_cal_lut.chunk_offset + sizeof(uint32_t); + table_info.table_size = sz_gsl_cal_lut; + table_info.table_entry_size = sizeof(acdb_driver_cal_lut_entry_t); + + //Setup Search Information + search_info.num_search_keys = search_index_count; + search_info.num_structure_elements = + (sizeof(acdb_driver_cal_lut_entry_t) / sizeof(uint32_t)); + search_info.table_entry_struct = cal_lut_entry; + + status = AcdbTableBinarySearch(&table_info, &search_info); + if (AR_FAILED(status)) + { + return status; + } + + *cal_lut_entry_offset = gsl_cal_lut.chunk_offset + + sizeof(uint32_t) //Number of entries + + search_info.entry_offset; + + ACDB_CLEAR_BUFFER(glb_buf_1); + + return status; +} diff --git a/acdb/src/acdb_delta_file_mgr.c b/acdb/src/acdb_delta_file_mgr.c new file mode 100644 index 0000000..22ff52f --- /dev/null +++ b/acdb/src/acdb_delta_file_mgr.c @@ -0,0 +1,869 @@ +/** +*============================================================================= +* \file acdb_delta_file_mgr.c +* +* \brief +* Contains the implementation of the delta acdb file manager +* interface. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +#include "ar_osal_error.h" +#include "ar_osal_file_io.h" +#include "acdb_delta_file_mgr.h" +#include "acdb_init_utility.h" +#include "acdb_common.h" +#include "acdb_heap.h" +#include "acdb_data_proc.h" +#include "acdb_utility.h" +#include "acdb_context_mgr.h" + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ +#define INF 4294967295U + +/**< A File Manager macro that simplifies accessing the database info within the + * File Manager context structure. + * + * Specify the index of the database info to retrieve + * + * NOTE: This macro is mainly used in for loops when cycling through + * databases info entries + */ +#define ACDB_DFM_DB_INFO_AT_INDEX(index) acdb_delta_file_man_context \ +.database_info[index] + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ + +typedef struct _acdb_delta_file_man_database_info_t +AcdbDeltaFileManDatabaseInfo; +struct _acdb_delta_file_man_database_info_t { + /**< The virtual machine id used by the database */ + uint32_t vm_id; + /**< Index of the delta file in the delta file manager file list */ + uint32_t file_index; + /**< Index of the associated acdb file in the acdb file manager file list */ + uint32_t acdb_file_index; + /**< A flag indicating whether the delta file is updated */ + uint32_t is_updated; + /**< A flag that determines the existance of the delta file */ + uint32_t exists; + /**< The size of the delta file */ + uint32_t file_size; + /**< File handle for the delta file */ + ar_fhandle file_handle; + /**< File path to the delta file */ + acdb_path_t delta_file_path; + /**< Delta file version information */ + acdb_delta_file_version_t file_info; +}; + +typedef struct _acdb_delta_file_man_context_t AcdbDeltaFileManContext; +struct _acdb_delta_file_man_context_t +{ + ar_osal_mutex_t delta_lock; + uint32_t database_count; + AcdbDeltaFileManDatabaseInfo *database_info[MAX_ACDB_FILE_COUNT]; +}; + +/* --------------------------------------------------------------------------- +* Static Variable Definitions +*--------------------------------------------------------------------------- */ + +/**< Maintains a list of AcdbDeltaFileManContext.*/ +static AcdbDeltaFileManContext acdb_delta_file_man_context; + +/**< Manages the state of the delta persistence.*/ +static AcdbDeltaPersistState acdb_delta_persist_state; + +/* --------------------------------------------------------------------------- +* Private Functions +*--------------------------------------------------------------------------- */ + +int32_t AcdbDeltaInit(void) +{ + int32_t status = AR_EOK; + + if (!acdb_delta_file_man_context.delta_lock) + { + status = ar_osal_mutex_create(&acdb_delta_file_man_context.delta_lock); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: failed to create acdb client mutex", + status); + } + } + return status; +} +int32_t AcdbDeltaAddDatabase(AcdbDeltaFileManFileInfo *info, + acdb_delta_file_man_handle_t *handle) +{ + int32_t status = AR_EOK; + uint32_t index = 0; + AcdbDeltaFileManDatabaseInfo* db_info = NULL; + + if (info == NULL) + { + ACDB_ERR("Error[%d]: delta info is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (acdb_delta_file_man_context.database_count >= MAX_ACDB_FILE_COUNT) + { + ACDB_ERR("Error[%d]: Max delta acdb file count exceeded. " + "The max is %d. The current count is %d", + AR_EBADPARAM, acdb_delta_file_man_context.database_count + 1); + return AR_EBADPARAM; + } + + ACDB_MUTEX_LOCK(acdb_delta_file_man_context.delta_lock); + + for (index = 0; index < MAX_ACDB_FILE_COUNT; index++) + { + if (IsNull(acdb_delta_file_man_context.database_info[index])) + break; + } + + if (MAX_ACDB_FILE_COUNT == index) + index--; + + acdb_delta_file_man_context.database_info[index] = + ACDB_MALLOC(AcdbDeltaFileManDatabaseInfo, 1); + + db_info = acdb_delta_file_man_context.database_info[index]; + + ar_mem_set(db_info, 0, sizeof(AcdbDeltaFileManDatabaseInfo)); + acdb_delta_file_man_context.database_count++; + + db_info->vm_id = info->vm_id; + db_info->file_index = index; + db_info->acdb_file_index = info->acdb_file_index; + db_info->file_info = info->file_info; + db_info->is_updated = FALSE; + db_info->exists = info->exists; + db_info->file_size = info->file_size; + db_info->file_handle = info->file_handle; + db_info->delta_file_path.path_length = + info->delta_file_path.path_length; + db_info->delta_file_path.path = + info->delta_file_path.path; + + *handle = db_info; + ACDB_MUTEX_UNLOCK(acdb_delta_file_man_context.delta_lock); + + return status; +} + +int32_t AcdbDeltaRemoveDatabase(acdb_delta_file_man_handle_t *dfm_handle) +{ + int32_t status = AR_EOK; + AcdbDeltaFileManDatabaseInfo *db_info = NULL; + + if (IsNull(dfm_handle)) + return AR_EBADPARAM; + + db_info = (AcdbDeltaFileManDatabaseInfo*)dfm_handle; + + if (IsNull(db_info)) + return AR_EBADPARAM; + + ACDB_DFM_DB_INFO_AT_INDEX(db_info->acdb_file_index) = NULL; + + db_info->exists = FALSE; + db_info->file_size = 0; + + if (!IsNull(db_info->file_handle)) + { + (void)ar_fclose(db_info->file_handle); + db_info->file_handle = NULL; + } + + ACDB_FREE(db_info->delta_file_path.path); + ACDB_FREE(db_info); + + ACDB_MUTEX_LOCK(acdb_delta_file_man_context.delta_lock); + + if (acdb_delta_file_man_context.database_count > 0) + acdb_delta_file_man_context.database_count--; + + ACDB_MUTEX_UNLOCK(acdb_delta_file_man_context.delta_lock); + + return status; +} + +int32_t AcdbDeltaDataCmdReset(void) +{ + int32_t status = AR_EOK; + AcdbDeltaFileManDatabaseInfo* db_info = NULL; + + for (uint32_t i = 0; i < acdb_delta_file_man_context + .database_count; i++) + { + db_info = ACDB_DFM_DB_INFO_AT_INDEX(i); + + if (IsNull(db_info)) + continue; + + status = AcdbDeltaRemoveDatabase( + (acdb_delta_file_man_handle_t)db_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to remove delta database" + " data at index %d", status, i); + status = AR_EFAILED; + } + } + + ar_osal_mutex_destroy(acdb_delta_file_man_context.delta_lock); + ar_mem_set(&acdb_delta_file_man_context, 0, + sizeof(AcdbDeltaFileManContext)); + + return status; +} +int32_t AcdbDeltaDataCmdGetDeltaVersion(uint32_t findex, uint32_t *delta_major, uint32_t *delta_minor) +{ + int32_t result = AR_EOK; + uint32_t offset = 0; + size_t bytes_read = 0; + + if (findex >= acdb_delta_file_man_context.database_count) + { + ACDB_ERR("Error[%d]: " + "The file index %d is larger than the total file count %d", + AR_EBADPARAM, findex, acdb_delta_file_man_context.database_count) + return AR_EBADPARAM; + } + + //todo: push this file parsing logic down to the delta file parser + + if (acdb_delta_file_man_context.database_info[findex]->exists == TRUE && acdb_delta_file_man_context.database_info[findex]->file_handle != NULL) + { + offset = 0; + if (acdb_delta_file_man_context.database_info[findex]->file_size > sizeof(AcdbDeltaFileHeader) + sizeof(uint32_t)) + { + int ret = ar_fseek(acdb_delta_file_man_context.database_info[findex]->file_handle, offset, AR_FSEEK_BEGIN); + if (ret != 0) + { + ACDB_ERR("AcdbDeltaDataCmdGetDeltaVersion() failed, file seek to %d was unsuccessful", offset); + return AR_EFAILED; + } + ret = ar_fread(acdb_delta_file_man_context.database_info[findex]->file_handle, &delta_major, sizeof(uint32_t), &bytes_read); + if (ret != 0) + { + ACDB_ERR("AcdbDeltaDataCmdGetDeltaVersion() failed, delta_major read was unsuccessful"); + return AR_EFAILED; + } + offset += sizeof(uint32_t); // curDeltafilemajor + ret = ar_fseek(acdb_delta_file_man_context.database_info[findex]->file_handle, offset, AR_FSEEK_BEGIN); + if (ret != 0) + { + ACDB_ERR("AcdbDeltaDataCmdGetDeltaVersion() failed, file seek to %d was unsuccessful", offset); + return AR_EFAILED; + } + ret = ar_fread(acdb_delta_file_man_context.database_info[findex]->file_handle, &delta_minor, sizeof(uint32_t), &bytes_read); + if (ret != 0) + { + ACDB_ERR("AcdbDeltaDataCmdGetDeltaVersion() failed, delta_minor read was unsuccessful"); + return AR_EFAILED; + } + offset += sizeof(uint32_t); // curDeltafileminor + } + } + + return result; +} + +int32_t AcdbDeltaDataCmdSave(void) +{ + int32_t status = AR_EOK; + ar_fhandle *fhandle = NULL; + uint32_t fsize = 0; + uint32_t fdata_size = 0; ; + LinkedList *p_map_list = NULL; + LinkedList map_list = { 0 }; + LinkedListNode *cur_node = NULL; + //acdb_path_256_t file_name_info = { 0 }; + acdb_delta_data_map_t *map = NULL; + AcdbInitUtilDeltaInfo delta_info = { 0 }; + acdb_context_handle_t *context_handle = NULL; + AcdbDeltaFileManDatabaseInfo *db_info = NULL; + + context_handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(context_handle) || IsNull(context_handle->delta_manager_handle)) + { + ACDB_ERR("Warning[%d]: Unable to save delta file. There is no delta file", + AR_EHANDLE); + return AR_EOK; + } + + /* Check if heap contains any data. If not, do nothing and return */ + p_map_list = &map_list; + + status = acdb_heap_ioctl(ACDB_HEAP_CMD_GET_MAP_LIST, NULL, 0, + (uint8_t*)&p_map_list, sizeof(LinkedList)); + if (AR_EOK != status) goto end; + + cur_node = p_map_list->p_head; + + if(cur_node == NULL) + { + ACDB_ERR("Warning[%d]: No data to write. The heap is empty", + AR_EHANDLE); + status = AR_EOK; + goto end; + } + + db_info = (AcdbDeltaFileManDatabaseInfo*) + context_handle->delta_manager_handle; + + fhandle = &db_info->file_handle; + + /* Close and delete old delta file */ + ar_fclose(*fhandle); + + status = ar_fdelete(db_info->delta_file_path.path); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to delete delta file", status); + goto end; + } + + /* Create new delta file and set ar_fhandle to acdb_delta_file_man_context + * at findex. Check to see if file exists otherwise create it */ + delta_info.properties.file_access_io_flag = ACDB_FUNC_IO_IN; + delta_info.properties.file_access = AR_FOPEN_WRITE_ONLY; + delta_info.delta_path = db_info->delta_file_path; + + status = AcdbInitUtilGetDeltaInfo2( + &db_info->delta_file_path, &delta_info.properties); + if (AR_FAILED(status)) + { + ACDB_ERR_MSG_1("Unable to create a new delta acdb file", status); + goto end; + } + + fsize = delta_info.properties.file_size; + delta_info.properties.file_access = AR_FOPEN_READ_ONLY_WRITE; + + status = AcdbInitUtilOpenDeltaFile(&delta_info, fhandle); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to open delta file", status); + goto end; + } + + db_info->file_handle = *fhandle; + + /* Write the header first as a place holder. We'll update this after + * determining the number of maps and size of the data */ + status = acdb_delta_parser_write_file_header( + db_info->file_handle, + &db_info->file_info, 0, 0); + + if (AR_FAILED(status)) goto end; + + /* Write the map data to the file */ + while (cur_node != NULL) + { + map = ((acdb_delta_data_map_t*)cur_node->p_struct); + status = acdb_delta_parser_write_map(*fhandle, map); + if (AR_EOK != status) break; + cur_node = cur_node->p_next; + } + + /* Seek back to the begining of the file to update the header */ + status = ar_fseek(*fhandle, 0, AR_FSEEK_BEGIN); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to seek delta file", status); + goto end; + } + + fsize = (uint32_t)ar_fsize(*fhandle); + fdata_size = fsize - sizeof(AcdbDeltaFileHeader) + sizeof(uint32_t); + + status = acdb_delta_parser_write_file_header( + db_info->file_handle, + &db_info->file_info, fdata_size, p_map_list->length); + + if (AR_EOK != status) goto end; + + db_info->is_updated = TRUE; + db_info->file_size = fsize; + +end: + AcdbListClear(p_map_list); + p_map_list = NULL; + + return status; +} +int32_t AcdbDeltaInitHeap(acdb_context_handle_t *handle) +{ + int32_t status = AR_EOK; + uint32_t foffset = sizeof(AcdbDeltaFileHeader); + acdb_delta_data_map_t *map = NULL; + AcdbDeltaFileManDatabaseInfo *db_info = NULL; + acdb_heap_map_handle_info_t map_handle_info = { 0 }; + + /* todo: read entire delta file into memory, close file, + * and write that memory into the heap format */ + + if (IsNull(handle)) + return AR_EBADPARAM; + + db_info = (AcdbDeltaFileManDatabaseInfo*)handle->delta_manager_handle; + + if (IsNull(db_info)) + return AR_EHANDLE; + + map_handle_info.handle = handle->heap_handle; + while (foffset < db_info->file_size) + { + map = ACDB_MALLOC(acdb_delta_data_map_t, 1); + map_handle_info.map = map; + + if (IsNull(map)) + { + ACDB_ERR("Error[%d]: Failed to allocate memory " + "for delta data map.", status); + status = AR_ENOMEMORY; + break; + } + + ACDB_CLEAR_BUFFER(*map); + + status = acdb_delta_parser_read_map( + db_info->file_handle, &foffset, map); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read map " + "from the *.acdbdelta file.", status); + break; + } + + status = acdb_heap_ioctl(ACDB_HEAP_CMD_ADD_MAP_USING_HANDLE, + &map_handle_info, sizeof(acdb_delta_data_map_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to add map to the heap.", status); + break; + } + } + + if (AR_FAILED(status)) + { + uint32_t status2 = acdb_heap_ioctl(ACDB_HEAP_CMD_CLEAR_DATABASE_HEAP, + handle->heap_handle, sizeof(acdb_heap_handle_t), NULL, 0); + if (AR_FAILED(status2)) + { + ACDB_ERR("Error[%d]: Unable to clear the heap.", status2); + } + } + + return status; +} + +int32_t AcdbDeltaUpdateHeap(acdb_context_handle_t* handle) +{ + int32_t status = AR_EOK; + uint32_t foffset = sizeof(AcdbDeltaFileHeader); + acdb_delta_data_map_t* map = NULL; + AcdbDeltaFileManDatabaseInfo* db_info = NULL; + + if (IsNull(handle)) + return AR_EBADPARAM; + + db_info = (AcdbDeltaFileManDatabaseInfo*)handle->delta_manager_handle; + + if (IsNull(db_info)) + return AR_EHANDLE; + + while (foffset < db_info->file_size) + { + map = ACDB_MALLOC(acdb_delta_data_map_t, 1); + + if (IsNull(map)) + { + ACDB_ERR("Error[%d]: Failed to allocate memory " + "for delta data map.", status); + status = AR_ENOMEMORY; + break; + } + + ACDB_CLEAR_BUFFER(*map); + + status = acdb_delta_parser_read_map( + db_info->file_handle, &foffset, map); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read map " + "from the *.acdbdelta file.", status); + break; + } + + status = DataProcSetMapToHeap(map); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set map to the heap.", status); + break; + } + } + + if (AR_EOK != status) + { + status = acdb_heap_ioctl(ACDB_HEAP_CMD_CLEAR_DATABASE_HEAP, + handle->heap_handle, sizeof(acdb_heap_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to clear the heap.", status); + } + } + + return status; +} + +int32_t AcdbDeltaDeleteFile(uint32_t database_index) +{ + int32_t status = AR_EOK; + ar_fhandle *fhandle = NULL; + acdb_path_256_t file_name_info = { 0 }; + + if (database_index >= acdb_delta_file_man_context.database_count) + { + ACDB_ERR("Error[%d]: " + "The file index %d is larger than the total file count %d", + AR_EBADPARAM, database_index, acdb_delta_file_man_context.database_count) + return AR_EBADPARAM; + } + + fhandle = &ACDB_DFM_DB_INFO_AT_INDEX(database_index)->file_handle; + + memset(&file_name_info.path[0], 0, ACDB_MAX_PATH_LENGTH); + file_name_info.path_len = 0; + status = acdb_file_man_ioctl(ACDB_FILE_MAN_GET_FILE_NAME, + &database_index, sizeof(uint32_t), + &file_name_info, sizeof(file_name_info)); + + //Close and delete old delta file + status = ar_fclose(*fhandle); + if (AR_EOK != status) + { + ACDB_ERR("Error[%d]: Failed to close delta file", status); + return status; + } + + status = AcdbInitUtilDeleteDeltaFileData( + file_name_info.path, file_name_info.path_len, + &ACDB_DFM_DB_INFO_AT_INDEX(database_index)->delta_file_path); + + if (AR_EOK != status) return status; + + ACDB_DFM_DB_INFO_AT_INDEX(database_index)->exists = FALSE; + ACDB_DFM_DB_INFO_AT_INDEX(database_index)->is_updated = FALSE; + + return status; +} + +int32_t AcdbDeltaDataSwapDelta(AcdbDeltaDataSwapInfo *swap_info) +{ + int32_t status = AR_EOK; + AcdbDeltaFileManDatabaseInfo *db_info = NULL; + AcdbInitUtilDeltaInfo delta_info = { 0 }; + acdb_path_256_t file_name_info = { 0 }; + acdb_path_t delta_dir = { 0 }; + + if (IsNull(swap_info)) + { + ACDB_ERR("Error[%d]: The swap info input parameter is null", + AR_EBADPARAM) + return AR_EBADPARAM; + } + + if (swap_info->file_index >= acdb_delta_file_man_context.database_count) + { + ACDB_ERR("Error[%d]: " + "The file index %d is larger than the total file count %d", + AR_EBADPARAM, swap_info->file_index, + acdb_delta_file_man_context.database_count) + return AR_EBADPARAM; + } + + db_info = ACDB_DFM_DB_INFO_AT_INDEX(swap_info->file_index); + + /* Close the previous delta file and open/create the new file */ + status = ar_fclose(db_info->file_handle); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to close %s ", status, + db_info->delta_file_path.path); + return status; + } + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_GET_FILE_NAME, + &db_info->acdb_file_index, sizeof(uint32_t), + &file_name_info, sizeof(file_name_info)); + + //Open/Create rw_delta file + delta_info.properties.file_access_io_flag = ACDB_FUNC_IO_IN; + delta_info.properties.file_access = swap_info->file_access; + + delta_dir.path_length = swap_info->path_info.path_len; + delta_dir.path = &swap_info->path_info.path[0]; + + status = AcdbInitUtilGetDeltaInfo( + &file_name_info.path[0], file_name_info.path_len, + &delta_dir, &delta_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to get read/write delta file info", status); + return status; + } + + status = AcdbInitUtilOpenDeltaFile( + &delta_info, &db_info->file_handle); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to open read/write delta file", status); + return status; + } + + ACDB_FREE(db_info->delta_file_path.path); + db_info->file_size = delta_info.properties.file_size; + db_info->delta_file_path = delta_info.delta_path; + + return status; +} + +int32_t AcdbDeltaDataIsFileAtPath(AcdbDeltaDataSwapInfo *swap_info) +{ + int32_t status = AR_EOK; + AcdbDeltaFileManDatabaseInfo *delta_finfo = NULL; + AcdbInitUtilDeltaInfo delta_info = { 0 }; + acdb_path_256_t file_name_info = { 0 }; + acdb_path_t delta_dir = { 0 }; + + if (IsNull(swap_info)) + { + ACDB_ERR("Error[%d]: The swap info input parameter is null", + AR_EBADPARAM) + return AR_EBADPARAM; + } + + if (swap_info->file_index >= + acdb_delta_file_man_context.database_count) + { + ACDB_ERR("Error[%d]: " + "The file index %d is larger than the total file count %d", + AR_EBADPARAM, swap_info->file_index, + acdb_delta_file_man_context.database_count) + return AR_EBADPARAM; + } + + delta_finfo = ACDB_DFM_DB_INFO_AT_INDEX(swap_info->file_index); + delta_info.properties.file_access_io_flag = ACDB_FUNC_IO_IN; + delta_info.properties.file_access = swap_info->file_access; + + delta_dir.path_length = swap_info->path_info.path_len; + delta_dir.path = &swap_info->path_info.path[0]; + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_GET_FILE_NAME, + &delta_finfo->acdb_file_index, sizeof(uint32_t), + &file_name_info, sizeof(file_name_info)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to get acdb file name at file index %d", + status, delta_finfo->acdb_file_index); + return status; + } + + status = AcdbInitUtilGetDeltaInfo( + &file_name_info.path[0], file_name_info.path_len, + &delta_dir, &delta_info); + if (AR_ENOTEXIST == status) + { + ACDB_ERR("Error[%d]: " + "The delta file %s does not exist", + status, delta_info.delta_path.path); + goto end; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Failed to open read/write delta file", status); + goto end; + } + +end: + ACDB_FREE(delta_info.delta_path.path); + + return status; +} + +/* --------------------------------------------------------------------------- +* Public Functions +*--------------------------------------------------------------------------- */ + +int32_t acdb_delta_data_is_persist_enabled(void) +{ + return (int32_t)acdb_delta_persist_state; +} + +int32_t acdb_delta_data_ioctl(uint32_t cmd_id, + void *req, uint32_t req_size, + void *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + + switch (cmd_id) + { + case ACDB_DELTA_DATA_CMD_INIT: + { + status = AcdbDeltaInit(); + break; + } + case ACDB_DELTA_DATA_CMD_ADD_DATABASE: + { + if (req == NULL || req_size != sizeof(AcdbDeltaFileManFileInfo) || + rsp == NULL || rsp_size != sizeof(acdb_delta_file_man_handle_t)) + { + return AR_EBADPARAM; + } + status = AcdbDeltaAddDatabase((AcdbDeltaFileManFileInfo *)req, + (acdb_delta_file_man_handle_t*)rsp); + } + break; + case ACDB_DELTA_DATA_CMD_REMOVE_DATABASE: + { + if (req == NULL || req_size != sizeof(acdb_delta_file_man_handle_t)) + { + return AR_EBADPARAM; + } + status = AcdbDeltaRemoveDatabase((acdb_delta_file_man_handle_t*)req); + } + break; + case ACDB_DELTA_DATA_CMD_ENABLE_PERSISTENCE: + { + if (req == NULL || req_size != sizeof(AcdbDeltaPersistState)) + { + return AR_EBADPARAM; + } + + acdb_delta_persist_state = *(AcdbDeltaPersistState*)req; + } + break; + case ACDB_DELTA_DATA_CMD_RESET: + { + status = AcdbDeltaDataCmdReset(); + } + break; + case ACDB_DELTA_DATA_CMD_GET_FILE_VERSION: + { + uint32_t delta_major = 0; + uint32_t delta_minor = 0; + uint32_t *pDeltafile_index = NULL; + acdb_delta_file_version_t *deltaVersion = + ACDB_MALLOC(acdb_delta_file_version_t, 1); + + if (deltaVersion == NULL) + { + ACDB_FREE(deltaVersion); + return AR_ENOMEMORY; + } + + if (IsNull(req) || req_size != sizeof(uint32_t)) + { + ACDB_FREE(deltaVersion); + return AR_EBADPARAM; + } + + pDeltafile_index = (uint32_t *)req; + status = AcdbDeltaDataCmdGetDeltaVersion( + *pDeltafile_index, &delta_major, &delta_minor); + deltaVersion->major = delta_major; + deltaVersion->minor = delta_minor; + + ACDB_MEM_CPY_SAFE(rsp, sizeof(acdb_delta_file_version_t), + deltaVersion, sizeof(acdb_delta_file_version_t)); + ACDB_FREE(deltaVersion); + status = AR_EOK; + } + break; + case ACDB_DELTA_DATA_CMD_INIT_HEAP: + { + if (IsNull(req) || req_size != sizeof(acdb_context_handle_t)) + { + return AR_EBADPARAM; + } + + status = AcdbDeltaInitHeap((acdb_context_handle_t*)req); + } + break; + case ACDB_DELTA_DATA_CMD_UPDATE_HEAP: + { + if (IsNull(req) || req_size != sizeof(acdb_context_handle_t)) + { + return AR_EBADPARAM; + } + + status = AcdbDeltaUpdateHeap((acdb_context_handle_t*)req); + } + break; + case ACDB_DELTA_DATA_CMD_SAVE: + { + status = AcdbDeltaDataCmdSave(); + } + break; + case ACDB_DELTA_DATA_CMD_DELETE_ALL_FILES: + { + status = AcdbDeltaDeleteFile(0);//todo: check this last + } + break; + case ACDB_DELTA_DATA_CMD_GET_FILE_COUNT: + { + if (IsNull(rsp) || rsp_size != sizeof(uint32_t)) + { + return AR_EBADPARAM; + } + + *(uint32_t*)rsp = acdb_delta_file_man_context.database_count; + } + break; + case ACDB_DELTA_DATA_CMD_SWAP_DELTA: + { + if (IsNull(req) || req_size != sizeof(AcdbDeltaDataSwapInfo)) + { + return AR_EBADPARAM; + } + + status = AcdbDeltaDataSwapDelta((AcdbDeltaDataSwapInfo*)req); + } + break; + case ACDB_DELTA_DATA_CMD_IS_FILE_AT_PATH: + { + if (IsNull(req) || req_size != sizeof(AcdbDeltaDataSwapInfo)) + { + return AR_EBADPARAM; + } + + status = AcdbDeltaDataIsFileAtPath((AcdbDeltaDataSwapInfo*)req); + } + break; + default: + status = AR_EUNSUPPORTED; + ACDB_ERR("Error[%d]: Unsupported command %08X", status, cmd_id); + } + + return status; +} diff --git a/acdb/src/acdb_delta_parser.c b/acdb/src/acdb_delta_parser.c new file mode 100644 index 0000000..e7d4334 --- /dev/null +++ b/acdb/src/acdb_delta_parser.c @@ -0,0 +1,718 @@ +/** +*============================================================================= +* \file acdb_delta_parser.c +* +* \brief +* Contains the implementation of the Acdb Delta Parser/Generator. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- + * Include Files + *--------------------------------------------------------------------------- */ +#include "ar_osal_error.h" +#include "ar_osal_file_io.h" + +#include "acdb_delta_parser.h" +#include "acdb_parser.h" +#include "acdb_common.h" +#include "acdb_types.h" +#include "acdb_heap.h" + + /* --------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + *--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- + * Type Declarations + *--------------------------------------------------------------------------- */ + +int32_t file_seek_read( + ar_fhandle fhandle, void* p_buf, size_t read_size, uint32_t *offset) +{ + int32_t status = AR_EOK; + size_t bytes_read = 0; + + status = ar_fseek(fhandle, *offset, AR_FSEEK_BEGIN); + + if (AR_EOK != status) return status; + + status = ar_fread(fhandle, p_buf, read_size, &bytes_read); + + *offset += (uint32_t)bytes_read; + + return status; +} + +int32_t acdb_delta_parser_read_file_header( + ar_fhandle fhandle, AcdbDeltaFileHeader *file_header) +{ + uint32_t offset = 0; + + if (AR_EOK != file_seek_read(fhandle, file_header, + sizeof(AcdbDeltaFileHeader), &offset)) + { + return AR_EFAILED; + } + + return AR_EOK; +} + +int32_t acdb_delta_parser_verify_file_version( + AcdbDeltaFileHeader *header) +{ + int32_t status = ACDB_PARSE_SUCCESS;//ACDB_PARSE_INVALID_FILE + + //File version must not be higher than the Software File Version + + if ((header->delta_major == 1 && header->delta_minor == 0) // || + /*(header->major == ?? && header->minor == ??)*/) + { + status = ACDB_PARSE_SUCCESS; + } + else + { + ACDB_ERR("Unsupported delta file version %d.%d.%d", + header->delta_major, header->delta_minor, header->delta_revision); + status = ACDB_PARSE_INVALID_FILE; + } + + return status; +} + +/* --------------------------------------------------------------------------- + * Public Function + *--------------------------------------------------------------------------- */ + +int32_t acdb_delta_parser_is_file_valid( + ar_fhandle fhandle, uint32_t file_size) +{ + int32_t status = ACDB_PARSE_SUCCESS; + AcdbDeltaFileHeader file_header; + + if (fhandle == NULL) + { + ACDB_ERR("Error[%d]: The file handle is null", AR_EHANDLE); + return ACDB_PARSE_INVALID_FILE; + } + + if (file_size < sizeof(AcdbDeltaFileHeader)) + { + ACDB_ERR("Error[%d]: The delta file size %d bytes is less than than" + " file header %d bytes", AR_EBADPARAM, file_size, + sizeof(AcdbDeltaFileHeader)); + return ACDB_PARSE_INVALID_FILE; + } + + if (AR_EOK != acdb_delta_parser_read_file_header(fhandle, &file_header)) + { + ACDB_ERR("Error[%d]: Failed to read delta file header.", AR_EFAILED); + return ACDB_PARSE_INVALID_FILE; + } + + if (file_header.file_data_size > file_size) + { + ACDB_ERR("Error[%d]: The file data size is larger than the " + "actual file size.", AR_EFAILED); + return ACDB_PARSE_INVALID_FILE; + } + + if (ACDB_PARSE_SUCCESS != + acdb_delta_parser_verify_file_version(&file_header)) + { + return ACDB_PARSE_INVALID_FILE; + } + + /* File data size should be at least 4 bytes (for the map count) for an empty delta file */ + if(file_header.file_data_size == 0) + { + ACDB_ERR("Error[%d]: The delta file data size of %d bytes is incorrect." + " It should be %d bytes for an empty file", + AR_EFAILED, + file_header.file_data_size, + sizeof(uint32_t));//map_count + return ACDB_PARSE_INVALID_FILE; + } + else if (file_header.file_data_size > sizeof(uint32_t) && + file_size != file_header.file_data_size + (sizeof(AcdbDeltaFileHeader) - sizeof(uint32_t))) + { + ACDB_ERR("Error[%d]: The delta file data size of %d is incorrect." + " It should be %d bytes", + AR_EFAILED, + file_header.file_data_size, + file_size - (sizeof(AcdbDeltaFileHeader) - sizeof(uint32_t))); + return ACDB_PARSE_INVALID_FILE; + } + + return status; +} + +int32_t acdb_delta_parser_get_file_version( + ar_fhandle fhandle, uint32_t file_size, + acdb_delta_file_version_t* delta_finfo) +{ + AcdbDeltaFileHeader file_header; + + if (file_size < (sizeof(AcdbDeltaFileHeader))) + { + ACDB_ERR("AcdbDeltaFileGetSWVersion() failed, delta acdb file size = %d is less than AcdbDeltaFileHeader", file_size); + return AR_EBADPARAM; + } + + if (AR_EOK != acdb_delta_parser_read_file_header(fhandle, &file_header)) + { + ACDB_ERR("failed with error code %d. Failed to read delta file header.") + return AR_EFAILED; + } + + delta_finfo->major = file_header.delta_major; + delta_finfo->minor = file_header.delta_minor; + delta_finfo->revision = file_header.delta_revision; + delta_finfo->cpl_info = file_header.acdb_cpl_info; + + return AR_EOK; +} + +int32_t acdb_delta_parser_read_delta_param_data( + ar_fhandle fhandle, AcdbDeltaPersistanceData *persistance_data, + uint32_t *offset) +{ + int32_t status = AR_EOK; + uint32_t bytes_read = *offset; + uint32_t persistance_data_size = 0; + uint32_t file_size = 0; + AcdbDeltaModuleCalData *caldata = NULL; + + file_size = (uint32_t)ar_fsize(fhandle); + + status = file_seek_read(fhandle, &persistance_data->data_size, + sizeof(uint32_t), &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read total delta param data size", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (persistance_data->data_size > file_size) + { + ACDB_ERR("Error[%d]: The total delta param data size %d is greater " + "than the file size %d", + AR_EBADPARAM, persistance_data->data_size, file_size); + return AR_EBADPARAM; + } + + ACDB_CLEAR_BUFFER(persistance_data->cal_data_list); + + while (persistance_data_size < persistance_data->data_size) + { + caldata = ACDB_MALLOC(AcdbDeltaModuleCalData, 1); + if (IsNull(caldata)) + { + status = AR_ENOMEMORY; + ACDB_ERR("Error[%d]: Not enoug memory to allocate delta " + "param header", status); + break; + } + + ar_mem_set(caldata, 0, sizeof(AcdbDeltaModuleCalData)); + + //Read Instance ID, Param ID, Param Size + status = file_seek_read(fhandle, caldata, + 3 * sizeof(uint32_t), &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read delta param header " + "", status); + break; + } + + if (caldata->param_size > persistance_data->data_size) + { + status = AR_EFAILED; + ACDB_ERR("Error[%d]: The param size %d for iid,pid <0x%x, 0x%x>" + " is greater than the aggragate delta param delta" + " data size %d", + status, caldata->param_size, caldata->module_iid, + caldata->param_id, persistance_data->data_size); + break; + } + + // Read payload + if (caldata->param_size > 0) + { + caldata->param_payload = ACDB_MALLOC( + uint8_t, caldata->param_size); + if (IsNull(caldata->param_payload)) + { + status = AR_ENOMEMORY; + ACDB_ERR("Error[%d]: Not enoug memory to allocate delta " + "param payload", status); + break; + } + + status = file_seek_read(fhandle, caldata->param_payload, + caldata->param_size, &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read delta " + "param payload", status); + break; + } + } + + LinkedListNode *node = AcdbListCreateNode(caldata); + + AcdbListAppend(&persistance_data->cal_data_list, node); + + persistance_data_size += 3 * sizeof(uint32_t) + caldata->param_size; + + caldata = NULL; + } + + if (AR_FAILED(status)) + { + if(!IsNull(caldata)) + ACDB_FREE(caldata->param_payload); + ACDB_FREE(caldata); + } + else + *offset = bytes_read; + + return status; +} + +int32_t acdb_delta_parser_read_map( + ar_fhandle fhandle, uint32_t *offset, + acdb_delta_data_map_t *map) +{ + int32_t status = AR_EOK; + uint32_t kv_pair_count = 0; + uint32_t bytes_read = *offset; + AcdbModuleTag* module_tag = NULL; + AcdbGraphKeyVector* key_vector = NULL; + uint32_t file_size = 0; + + if (map == NULL) + { + return AR_EBADPARAM; + } + + file_size = (uint32_t)ar_fsize(fhandle); + + status = file_seek_read(fhandle, &map->key_vector_type, + sizeof(uint32_t), &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key vector type", status); + return status; + } + + //Read Module Tag or Graph Key Vector depending on key vector type + switch (map->key_vector_type) + { + case TAG_KEY_VECTOR: + module_tag = ACDB_MALLOC(AcdbModuleTag, 1); + if (IsNull(module_tag)) + { + status = AR_ENOMEMORY; + ACDB_ERR_MSG_1("Unable to allocate memory for module tag", status); + return status; + } + + map->key_vector_data = (void*)module_tag; + + status = file_seek_read(fhandle, &module_tag->tag_id, sizeof(uint32_t), &bytes_read); + if (AR_EOK != status) + { + ACDB_FREE(module_tag); + ACDB_ERR_MSG_1("Unable to read module tag", status); + return status; + } + + key_vector = &module_tag->tag_key_vector; + if (IsNull(key_vector)) + { + status = AR_EBADPARAM; + ACDB_FREE(module_tag); + ACDB_ERR_MSG_1("Tag Key Vector is null", status); + return status; + } + + break; + case CAL_KEY_VECTOR: + key_vector = ACDB_MALLOC(AcdbGraphKeyVector, 1); + if (IsNull(key_vector)) + { + status = AR_ENOMEMORY; + ACDB_ERR_MSG_1("Unable to allocate memory for Calibration Key Vector", status); + return status; + } + + map->key_vector_data = (void*)key_vector; + break; + default: + break; + } + + if (IsNull(key_vector)) + { + ACDB_ERR("The Map Key vector is null"); + return AR_EBADPARAM; + } + + ACDB_CLEAR_BUFFER(*key_vector); + + status = file_seek_read(fhandle, &kv_pair_count, + sizeof(uint32_t), &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read key vector length", + status); + return status; + } + + if (kv_pair_count > ACDB_MAX_KEY_COUNT) + { + ACDB_ERR("Error[%d]: The key vector length %d is larger than " + "the max %d", kv_pair_count, ACDB_MAX_KEY_COUNT); + return AR_EBADPARAM; + } + + key_vector->num_keys = kv_pair_count; + + if (kv_pair_count > 0) + { + key_vector->graph_key_vector = ACDB_MALLOC( + AcdbKeyValuePair, kv_pair_count * sizeof(AcdbKeyValuePair)); + + status = file_seek_read(fhandle, key_vector->graph_key_vector, + kv_pair_count * sizeof(AcdbKeyValuePair), &bytes_read); + if (AR_FAILED(status)) + { + if (!IsNull(key_vector->graph_key_vector)) + { + ACDB_FREE(key_vector->graph_key_vector); + } + + ACDB_ERR("Error[%d]: Unable to read key vector", + status); + return status; + } + } + + module_tag = NULL; + key_vector = NULL; + + status = file_seek_read(fhandle, &map->map_size, + sizeof(uint32_t), &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read map size", + status); + return status; + } + + if (map->map_size > file_size) + { + ACDB_ERR("Error[%d]: The map size %d is larger than " + "the file size %d", map->map_size, file_size); + return AR_EBADPARAM; + } + + status = file_seek_read(fhandle, &map->num_subgraphs, + sizeof(uint32_t), &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read subgraph count", + status); + return status; + } + + if (map->num_subgraphs > file_size) + { + ACDB_ERR("Error[%d]: The subgraph count %d is greater than " + "the file size %d", map->num_subgraphs, file_size); + return AR_EBADPARAM; + } + + LinkedListNode *sg_data_node = NULL; + AcdbDeltaSubgraphData *sg_data = NULL; + + ACDB_CLEAR_BUFFER(map->subgraph_data_list); + + for (uint32_t i = 0; i < map->num_subgraphs; i++) + { + sg_data = ACDB_MALLOC(AcdbDeltaSubgraphData, 1); + if (IsNull(sg_data)) + { + status = AR_ENOMEMORY; + ACDB_ERR("Error[%d]: Not enoug memory to allocate delta " + "param data", status); + break; + } + + ar_mem_set(sg_data, 0, sizeof(AcdbDeltaSubgraphData)); + + status = file_seek_read(fhandle, sg_data, + 2 * sizeof(uint32_t), &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read subgraph data header", + status); + break; + } + + status = acdb_delta_parser_read_delta_param_data( + fhandle, &sg_data->non_global_data, &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read regular/shared param " + "data for subgraph 0x%x", status, sg_data->subgraph_id); + break; + } + + status = acdb_delta_parser_read_delta_param_data( + fhandle, &sg_data->global_data, &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read global param " + "data for subgraph 0x%x", status, sg_data->subgraph_id); + break; + } + + sg_data_node = AcdbListCreateNode(sg_data); + AcdbListAppend(&map->subgraph_data_list, sg_data_node); + } + + if (AR_FAILED(status)) + { + acdb_heap_free_subgraph_data(sg_data); + acdb_heap_free_map(map); + return status; + } + + *offset = bytes_read; + + sg_data_node = NULL; + sg_data = NULL; + return status; +} + +int32_t acdb_delta_parser_write_file_header( + ar_fhandle fhandle, acdb_delta_file_version_t* delta_finfo, + uint32_t fdata_size, uint32_t map_count) +{ + size_t bytes_written = 0; + AcdbDeltaFileHeader file_header; + file_header.delta_major = ACDB_DELTA_FILE_VERSION_MAJOR; + file_header.delta_minor = ACDB_DELTA_FILE_VERSION_MINOR; + file_header.delta_revision = ACDB_DELTA_FILE_REVISION; + + file_header.acdb_major = delta_finfo->major; + file_header.acdb_minor = delta_finfo->minor; + file_header.acdb_revision = delta_finfo->revision; + file_header.acdb_cpl_info = delta_finfo->cpl_info; + file_header.file_data_size = fdata_size; + file_header.map_count = map_count; + + int32_t status = ar_fwrite(fhandle, &file_header, sizeof(AcdbDeltaFileHeader), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write the *.acdbdelta file header", status); + return AR_EFAILED; + } + + return AR_EOK; +} + +int32_t acdb_delta_parser_write_delta_data( + ar_fhandle fhandle, AcdbDeltaPersistanceData *persist_data) +{ + int32_t status = AR_EOK; + size_t bytes_written = 0; + AcdbDeltaModuleCalData cal_data; + + status = ar_fwrite(fhandle, &persist_data->data_size, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write global/non-global data size.", status); + return AR_EFAILED; + } + + if (persist_data->data_size == 0) + { + return AR_EOK; + } + + LinkedListNode *cur_node = persist_data->cal_data_list.p_head; + while (!IsNull(cur_node)) + { + cal_data = *((AcdbDeltaModuleCalData*)cur_node->p_struct); + + status = ar_fwrite(fhandle, &cal_data.module_iid, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write Module Instance ID.", status); + return AR_EFAILED; + } + + status = ar_fwrite(fhandle, &cal_data.param_id, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write Parameter ID.", status); + return AR_EFAILED; + } + + status = ar_fwrite(fhandle, &cal_data.param_size, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write Parameter Size.", status); + return AR_EFAILED; + } + + status = ar_fwrite(fhandle, (uint8_t*)cal_data.param_payload, (size_t)cal_data.param_size, &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write Parameter Payload.", status); + return AR_EFAILED; + } + + cur_node = cur_node->p_next; + } + + return AR_EOK; +} + +int32_t acdb_delta_parser_write_map( + ar_fhandle fhandle, acdb_delta_data_map_t *map) +{ + int32_t status = AR_EOK; + AcdbModuleTag* module_tag = NULL; + AcdbGraphKeyVector* key_vector = NULL; + if (IsNull(map)) return AR_EBADPARAM; + + uint32_t i = 0; + size_t bytes_written = 0; + + status = ar_fwrite(fhandle, &map->key_vector_type, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write key vector type", status); + return AR_EFAILED; + } + + //Write Module Tag or Graph Key Vector depending on KV type + switch (map->key_vector_type) + { + case TAG_KEY_VECTOR: + module_tag = ((AcdbModuleTag*)map->key_vector_data); + status = ar_fwrite(fhandle, &module_tag->tag_id, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write module tag", status); + return AR_EFAILED; + } + + key_vector = &module_tag->tag_key_vector; + + if (IsNull(key_vector)) + { + ACDB_ERR("Map Tag Key Vector is null"); + return AR_EBADPARAM; + } + break; + case CAL_KEY_VECTOR: + key_vector = ((AcdbGraphKeyVector*)map->key_vector_data); + + if (IsNull(key_vector)) + { + ACDB_ERR("Map Calibration Key Vector is null"); + return AR_EBADPARAM; + } + break; + default: + break; + } + + if (IsNull(key_vector)) + { + ACDB_ERR("The Map Key Vector is null"); + return AR_EBADPARAM; + } + + status = ar_fwrite(fhandle, &key_vector->num_keys, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write number of cal key vector key pairs", status); + return AR_EFAILED; + } + + for (i = 0; i < key_vector->num_keys; i++) + { + status = ar_fwrite(fhandle, &key_vector->graph_key_vector[i], sizeof(AcdbKeyValuePair), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write the calibration key vector", status); + return AR_EFAILED; + } + } + + status = ar_fwrite(fhandle, &map->map_size, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write map size", status); + return AR_EFAILED; + } + + status = ar_fwrite(fhandle, &map->num_subgraphs, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write number of subgraph", status); + return AR_EFAILED; + } + + LinkedListNode *sg_data_node = map->subgraph_data_list.p_head; + AcdbDeltaSubgraphData *sg_data = NULL; + + do + { + sg_data = (AcdbDeltaSubgraphData*)sg_data_node->p_struct; + + status = ar_fwrite(fhandle, &sg_data->subgraph_id, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write the subgraph ID", status); + return AR_EFAILED; + } + + status = ar_fwrite(fhandle, &sg_data->subgraph_data_size, sizeof(uint32_t), &bytes_written); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write the subgraph data size", status); + return AR_EFAILED; + } + + status = acdb_delta_parser_write_delta_data(fhandle, &sg_data->non_global_data); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write non-global persistance data", status); + return AR_EFAILED; + } + + status = acdb_delta_parser_write_delta_data(fhandle, &sg_data->global_data); + if (AR_EOK != status) + { + ACDB_ERR_MSG_1("Unable to write global persistance data", status); + return AR_EFAILED; + } + + } while (TRUE != AcdbListSetNext(&sg_data_node)); + + return AR_EOK; +} diff --git a/acdb/src/acdb_file_mgr.c b/acdb/src/acdb_file_mgr.c new file mode 100644 index 0000000..024845b --- /dev/null +++ b/acdb/src/acdb_file_mgr.c @@ -0,0 +1,2125 @@ +/** +*============================================================================= +* \file acdb_file_mgr.c +* +* \brief +* This file contains the implementation of the acdb file manager +* interfaces. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- +* Include Files +*--------------------------------------------------------------------------- */ + +#include +#include "acdb_context_mgr.h" +#include "acdb_file_mgr.h" +#include "acdb_parser.h" +#include "acdb_init_utility.h" +#include "acdb_init.h" +#include "ar_osal_error.h" +#include "ar_osal_file_io.h" +#include "acdb_common.h" +#include "acdb_data_proc.h" + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ + +/**< + * A File Manager macro that simplifies accessing the database info within the + * File Manager context structure. + * + * This macro represents the database info at the current index set in + * acdb_file_man_context.database_index + * + * NOTE: The acdb_file_man_context.database_index must me non-zero and initialized + * before using this macro + */ +#define ACDB_FM_DB_INFO acdb_file_man_context \ +.database_info[acdb_file_man_context.database_index] + +/**< + * A File Manager macro that simplifies accessing the database info within the + * File Manager context structure. + * + * Specify the index of the database info to retrieve + * + * NOTE: This macro is mainly used in for loops when cycling through + * databases info entries + */ +#define ACDB_FM_DB_INFO_AT_INDEX(index) acdb_file_man_context \ +.database_info[index] + + /**< + * A File Manager macro that simplifies accessing the workspace info within the + * File Manager context structure. + * + * Specify the index of the workspace info to retrieve + * + * NOTE: This macro is mainly used in for loops when cycling through + * workspace info entries + */ +#define ACDB_FM_WS_INFO_AT_INDEX(index) acdb_file_man_context \ +.workspace_info[index] + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ + +typedef enum { + ACDB_FM_FILE_OP_OPEN, + ACDB_FM_FILE_OP_CLOSE, +}AcdbFileManFileOp; + +typedef enum { + ACDB_PATH_TYPE_NONE = -1, + ACDB_PATH_TYPE_QWSP_FILE = 0, + ACDB_PATH_TYPE_ACDB_FILE, + ACDB_PATH_TYPE_WRITEABLE_DIRECTORY, + ACDB_PATH_TYPE_DELTA_DIRECTORY +} AcdbPathType; + +/**< Indicates if AcdbFileManDbPathInfo or AcdbFileManDbPathInfoV2 +should be used */ +typedef enum { + /**< Use AcdbFileManDbPathInfo */ + ACDB_FM_DB_PATH_INFO_VERSION_1 = 1, + /**< Use AcdbFileManDbPathInfoV2 */ + ACDB_FM_DB_PATH_INFO_VERSION_2 = 2 +}AcdbDatabasePathInfoVersion; + +typedef struct _acdb_file_man_workspace_info_t AcdbFileManWorkspaceInfo; +struct _acdb_file_man_workspace_info_t { + /**< The virtual machine id used by the database */ + uint32_t vm_id; + /**< The workspace file handle */ + ar_fhandle file_handle; + /**< The size of the workspace file */ + uint32_t file_size; + /**< The path to the workspace file */ + acdb_path_256_t workspace_file; +}; + +typedef struct _acdb_file_man_database_info_t AcdbFileManDatabaseInfo; +struct _acdb_file_man_database_info_t { + /**< The virtual machine id used by the database */ + uint32_t vm_id; + /**< The database index */ + uint32_t file_index; + /**< The databases file type */ + AcdbFileType file_type; + /**< The file handle to the database */ + ar_fhandle file_handle; + /**< The size of the database file */ + uint32_t database_cache_size; + /**< A pointer to the database file cached in memory */ + void* database_cache; + /**< The path to the database file */ + acdb_path_256_t database_file; + /**< The path where the database files reside */ + acdb_path_256_t database_directory; + /**< The path to the writable directory used for database operations */ + acdb_path_256_t writable_directory; +}; + +typedef struct _acdb_file_man_context_t AcdbFileManContext; +struct _acdb_file_man_context_t +{ + ar_osal_mutex_t file_man_lock; + /**< The index of the database that the filemanager is + currently pointing to */ + int32_t database_index; + /**< The index of the newly added database */ + int32_t latest_database_index; + /**< Number of databases being managed */ + int32_t database_count; + /**< Number of workspace files being managed */ + int32_t workspace_count; + /**< Maintains context info about each loaded database */ + AcdbFileManDatabaseInfo *database_info[ACDB_MAX_ACDB_FILES]; + /**< Maintains context info about each loaded database */ + AcdbFileManWorkspaceInfo *workspace_info[ACDB_MAX_ACDB_FILES]; +}; + +typedef struct acdb_file_man_db_path_info_v2_t +{ + /**< The type of path (either a file or directory) */ + AcdbPathType path_type; + /**< The size of the file. If path_type is a directory this + should be zero */ + uint32_t file_size; + /**< The length of the path (either file or directory)*/ + uint32_t path_length; + /**< The path string */ + char_t *path; +}AcdbFileManDbPathInfoV2; + +typedef struct acdb_file_man_db_path_info_t +{ + /**< The size of the file. If path_type is a directory this + should be zero */ + uint32_t file_size; + /**< The length of the path (either file or directory)*/ + uint32_t path_length; + /**< The path string */ + char_t* path; +}AcdbFileManDbPathInfo; + +/* --------------------------------------------------------------------------- +* Global Data Definitions +*--------------------------------------------------------------------------- */ +static AcdbFileManContext acdb_file_man_context; + +/* --------------------------------------------------------------------------- +* Static Variable Definitions +*--------------------------------------------------------------------------- */ +int32_t AcdbFileManRemoveDatabase(acdb_file_man_handle_t* fm_handle); + +/** +* \brief +* 1. Comparing Imports to Exports +* Checks for the existance of imports in the newly added +* database compared to the exports in existing databases +* +* 2. Comparing Exports to Imports +* Checks for the existance of exports in the newly added +* database compared to the imports in existing databases +* +* If subgraphs are found between the new database and the +* existing databases in 1. and 2. their GUIDs will be +* compared. Validation fails if they do not match. +* +* \param[in] im_ex_shared_sg_property_id: +* The imported or exported shared subgraph property ID +* 1. For option 1 this will be ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS. +* 2. For option 2 this will be ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS. +* \param[out] im_ex_shared_sg_property: +* The imported or exports shared subgraph property +* 1. For option 1 this property will have data for +* ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS. +* 2. For option 2 this property will have data for +* ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS. +* \return 0 on success, and non-zero on failure +*/ +int32_t AcdbFileManValidateImExShSubgraphs( + AcdbGlobalProperty im_ex_shared_sg_property_id, + AcdbProperty* im_ex_shared_sg_property); + +/* --------------------------------------------------------------------------- +* Function Declarations and Definitions +*--------------------------------------------------------------------------- */ + +int32_t AcdbFileManSetFileIndex(int32_t file_index) +{ + if (file_index < -1 || file_index > acdb_file_man_context.database_count) + return AR_EBADPARAM; + + acdb_file_man_context.database_index = file_index; + return AR_EOK; +} + +int32_t AcdbFileManValidateImExShSubgraphs( + AcdbGlobalProperty im_ex_shared_sg_property_id, + AcdbProperty *im_ex_shared_sg_property) +{ + int32_t status = AR_EOK; + AcdbFileManDatabaseInfo *new_db_info = NULL; + AcdbFileManDatabaseInfo *existing_db_info_2 = NULL; + AcdbSharedSubgraphGuidTable subgraph_guid_table = { 0 }; + AcdbSharedSubgraphDataGuid* subgraph_guid = NULL; + uint8_t guid[ACDB_GUID_BYTE_LENGTH] = { 0 }; + + if (IsNull(im_ex_shared_sg_property)) + return AR_EBADPARAM; + + subgraph_guid_table.num_subgraphs = + *(uint32_t*)im_ex_shared_sg_property->property_data; + + //Exit if there are no imports/exports + if (subgraph_guid_table.num_subgraphs == 0) + return AR_EOK; + + subgraph_guid_table.guid_entries = (AcdbSharedSubgraphDataGuid*) + (im_ex_shared_sg_property->property_data + + sizeof(uint32_t)); + + new_db_info = ACDB_FM_DB_INFO_AT_INDEX( + acdb_file_man_context.latest_database_index); + + if(IsNull(new_db_info)) + return AR_EBADPARAM; + + for (int32_t i = 0; i < acdb_file_man_context.database_count; i++) + { + if (i == acdb_file_man_context.latest_database_index) + continue; + + existing_db_info_2 = ACDB_FM_DB_INFO_AT_INDEX(i); + if (IsNull(existing_db_info_2)) + continue; + + AcdbFileManSetFileIndex(i); + + for (uint32_t j = 0; j < subgraph_guid_table.num_subgraphs; j++) + { + subgraph_guid = &subgraph_guid_table.guid_entries[j]; + + status = DataProcGetSharedSubgraphGuid(subgraph_guid->subgraph_id, + im_ex_shared_sg_property_id, &guid[0]); + + if (status == AR_ENOTEXIST) + { + /* Either property doesnt exist or shared subgraph doesnt exist */ + status = AR_EOK; + continue; + } + + if (0 != ar_mem_cmp( + &subgraph_guid->guid[0], &guid[0], + ACDB_GUID_BYTE_LENGTH)) + { + status = AR_EFAILED; + ACDB_ERR("Error[%d]: There is a difference in subgraph data" + " for shared subgraph 0x%x between new VM-%d " + "and existing VM-%d", status, subgraph_guid->subgraph_id, + new_db_info->vm_id, existing_db_info_2->vm_id); + return status; + } + } + } + + return status; +} + +int32_t AcdbFileManValidateSharedSubgraphs(void) +{ + int32_t status = AR_EOK; + bool_t has_exports = FALSE; + bool_t has_imports = FALSE; + AcdbProperty imported_shared_sg_property = { 0 }; + AcdbProperty exported_shared_sg_property = { 0 }; + + imported_shared_sg_property.property_id = + ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS; + imported_shared_sg_property.handle_override = + ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER; + exported_shared_sg_property.property_id = + ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS; + exported_shared_sg_property.handle_override = + ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER; + + AcdbFileManSetFileIndex(acdb_file_man_context.latest_database_index); + + status = GetAcdbProperty(&imported_shared_sg_property); + if (AR_FAILED(status) && AR_ENOTEXIST != status) + return status; + + has_imports = AR_SUCCEEDED(status); + + status = GetAcdbProperty(&exported_shared_sg_property); + if (AR_FAILED(status) && AR_ENOTEXIST != status) + return status; + + has_exports = AR_SUCCEEDED(status); + status = AR_EOK; + + if (has_imports) + { + status = AcdbFileManValidateImExShSubgraphs( + ACDB_GPROP_EXPORTED_SHARED_SUBGRAPHS, + &imported_shared_sg_property); + } + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed comparing shared subgraphs: imports " + "in new database to exports in existing database(s) ", status); + return status; + } + + if (has_exports) + { + status = AcdbFileManValidateImExShSubgraphs( + ACDB_GPROP_IMPORTED_SHARED_SUBGRAPHS, + &exported_shared_sg_property); + } + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed comparing shared subgraphs: exports " + "in new database to imports in existing database(s) ", status); + return status; + } + + return status; +} + +/* --------------------------------------------------------------------------- +* helper functions that dont use any of the global variables +*--------------------------------------------------------------------------- */ + +/** +* \brief +* Retrieves the file name from the given path. +* Ex. path - c:\my\file.acdb file name - file.acdb +* +* \param[in] fpath: the file path to get the file name from +* \param[in] fpath_len: length of fpath +* \param[in/out] fname: the output file name +* \param[out] fname_len: length of the filename +* +* \return none +*/ +int32_t GetFileNameFromPath(char_t* fpath, uint32_t fpath_len, char_t* fname, uint32_t *fname_len) +{ + if (fpath == NULL || fpath_len == 0) + { + ACDB_ERR("Error[%d]: The input file path is empty", AR_EBADPARAM); + return AR_EBADPARAM; + } + else + { + //Delta file path is provided, so form the full path + //Ex. ..\acdb_data + \ + acdb_data.acdb + delta + uint32_t char_index = fpath_len; + + /* Detect windows\linux style path prefixes + Absolute Paths + Ex. C:\acdb_data\ar_acdb.acdb + Ex. /acdb_data/ar_acdb.acdb + Relative paths + Ex. ..\acdb_data\ar_acdb.acdb + Ex. ../acdb_data/ar_acdb.acdb + */ + //if (!((fpath[0] == '.' && fpath[1] == '.') || + // (fpath[1] == ':' && fpath[2] == '\\') || + // (fpath[1] == ':' && fpath[2] == '/') || + // fpath[0] == '/')) + //{ + // char_index = 0; + //} + + while (--char_index > 0) + { + if (fpath[char_index] == '\\' || + fpath[char_index] == '/') + { + char_index++; + break; + } + } + + fname = &fpath[char_index]; + if (IsNull(fname)) + { + ACDB_ERR("Error[%d]: Unable to retrieve file name from %s", AR_EBADPARAM, fpath); + return AR_EBADPARAM; + } + + *fname_len = fpath_len - char_index; + } + + return AR_EOK; +} + +int32_t AcdbFileManGetDirectoryFromFilePath(const char* fpath, uint32_t fpath_len, acdb_path_256_t *path_info) +{ + int32_t status = AR_EOK; + uint32_t last_slash_index = fpath_len; + + if (fpath == NULL || fpath_len == 0) + { + ACDB_ERR("Error[%d]: The input file path is empty", AR_EBADPARAM); + return AR_EBADPARAM; + } + + /* Detect windows\linux style path prefixes + Absolute Paths + Ex. C:\acdb_data\ar_acdb.acdb + Ex. /acdb_data/ar_acdb.acdb + Relative paths + Ex. ..\acdb_data\ar_acdb.acdb + Ex. ../acdb_data/ar_acdb.acdb + */ + + while (--last_slash_index > 0) + { + if (fpath[last_slash_index] == '\\' || + fpath[last_slash_index] == '/') + { + last_slash_index++; + break; + } + } + + path_info->path_len = last_slash_index; + status = ar_strcpy(path_info->path, sizeof(path_info->path), + fpath, path_info->path_len); + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to extract directory path from %s", + AR_EBADPARAM, fpath); + return status; + } + + return AR_EOK; +} + +/* --------------------------------------------------------------------------- +* functions that use the global variables +*--------------------------------------------------------------------------- */ + +int32_t AcdbFileManInit(void) +{ + int32_t status = AR_EOK; + + if (!acdb_file_man_context.file_man_lock) + { + status = ar_osal_mutex_create(&acdb_file_man_context.file_man_lock); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: failed to create acdb client mutex", + status); + } + } + return status; +} + +int32_t AcdbFileManGetAcdbDirectoryPath(acdb_path_256_t **path_info) +{ + int32_t status = AR_EOK; + acdb_context_handle_t *handle = NULL; + AcdbFileManDatabaseInfo *db = NULL; + + if (IsNull(path_info)) + return AR_EBADPARAM; + + handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(handle) || IsNull(handle->file_manager_handle)) + return AR_EHANDLE; + + db = (AcdbFileManDatabaseInfo*)handle->file_manager_handle; + + *path_info = &db->database_directory; + + return status; +} + +int32_t AcdbFileManAddAcdb(int32_t index, uint32_t *vm_id, + AcdbFileManFileInfo *file_info) +{ + int32_t status = AR_EOK; + AcdbFileManDatabaseInfo *db_info = NULL; + + if (IsNull(file_info) || IsNull(vm_id) || MAX_ACDB_FILE_COUNT == index) + return AR_EBADPARAM; + + ACDB_FM_DB_INFO_AT_INDEX(index) = + ACDB_MALLOC(AcdbFileManDatabaseInfo, 1); + + db_info = ACDB_FM_DB_INFO_AT_INDEX(index); + if (IsNull(db_info)) + return AR_ENOMEMORY; + + ar_mem_set(db_info, 0, + sizeof(AcdbFileManDatabaseInfo)); + + db_info->file_index = index; + db_info->database_cache = file_info->file.buffer; + db_info->database_cache_size = file_info->file.size; + db_info->file_handle = file_info->file_handle; + db_info->file_type = file_info->file_type; + db_info->database_file.path_len = file_info->path_length; + ACDB_MEM_CPY_SAFE( + &db_info->database_file.path[0], file_info->path_length, + file_info->path, file_info->path_length); + + status = AcdbFileManGetDirectoryFromFilePath(file_info->path, + file_info->path_length, &db_info->database_directory); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get acdb directory from path %s", + AR_EBADPARAM, &file_info->path); + return AR_EBADPARAM; + } + + if (AR_FAILED(DataProcGetVmId(vm_id))) + { + ACDB_INFO("Warning[%d]: Using default VM ID for %s", + status, file_info->path); + *vm_id = ACDB_CTX_MAN_DEFAULT_DB_HANDLE; + } + + db_info->vm_id = *vm_id; + + if (acdb_file_man_context.database_count > 1) + { + status = AcdbFileManValidateSharedSubgraphs(); + if (AR_FAILED(status)) + { + AcdbFileManRemoveDatabase( + (acdb_file_man_handle_t*)db_info); + } + } + return status; +} + +int32_t AcdbFileManAddQwsp(int32_t index, + AcdbFileManFileInfo* file_info) +{ + AcdbFileManWorkspaceInfo* ws_info = NULL; + if (IsNull(file_info) || MAX_ACDB_FILE_COUNT == index) + return AR_EBADPARAM; + + ACDB_FM_WS_INFO_AT_INDEX(index) = + ACDB_MALLOC(AcdbFileManWorkspaceInfo, 1); + + ws_info = ACDB_FM_WS_INFO_AT_INDEX(index); + if (IsNull(ws_info)) + return AR_ENOMEMORY; + + ar_mem_set(ACDB_FM_WS_INFO_AT_INDEX(index), 0, + sizeof(AcdbFileManWorkspaceInfo)); + + ws_info->file_size = file_info->file.size; + ws_info->file_handle = file_info->file_handle; + ws_info->workspace_file.path_len = + file_info->path_length; + ACDB_MEM_CPY_SAFE( + &ws_info->workspace_file.path[0], file_info->path_length, + file_info->path, file_info->path_length); + + return AR_EOK; +} + +int32_t AcdbFileManAddDatabase(acdb_file_man_data_files_t *db_files, + acdb_file_man_context_handle_t *fm_ctx_handle) +{ + int32_t status = AR_EOK; + uint32_t vm_id = 0; + uint32_t index = 0; + AcdbFileManFileInfo *db_file = NULL; + + if (IsNull(db_files) || IsNull(fm_ctx_handle)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null.", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (db_files->num_files > ACDB_MAX_FILE_ADD_LIMIT) + { + ACDB_ERR("Error[%d]: The size of the file set is more than %d", + AR_ENORESOURCE, ACDB_MAX_FILE_ADD_LIMIT); + return AR_EBADPARAM; + } + + if (acdb_file_man_context.database_count == ACDB_MAX_ACDB_FILES) + { + ACDB_ERR("Error[%d]: Max number of files is %d", + AR_ENORESOURCE, ACDB_MAX_ACDB_FILES); + return AR_ENORESOURCE; + } + + ACDB_MUTEX_LOCK(acdb_file_man_context.file_man_lock); + + for (uint32_t i = 0; i < db_files->num_files; i++) + { + db_file = db_files->file_info[i]; + + //check for duplicate *.acdb file here using strstr. make sure the same file cannot be added twice + for (int32_t j = 0; j < acdb_file_man_context.database_count; j++) + { + AcdbFileManDatabaseInfo* fm_db_info = ACDB_FM_DB_INFO_AT_INDEX(j); + + if (NULL == ar_strstr(&fm_db_info->database_file.path[0], &db_file->path[0])) + continue; + else + { + ACDB_ERR("Error[%d]: The database file %s already exists", AR_EALREADY, + db_file->path); + return AR_EALREADY; + } + } + + for (index = 0; index < MAX_ACDB_FILE_COUNT; index++) + { + if (ACDB_FILE_TYPE_DATABASE == db_file->file_type && + IsNull(acdb_file_man_context.database_info[index])) + { + acdb_file_man_context.database_count++; + acdb_file_man_context.database_index = index; + acdb_file_man_context.latest_database_index = index; + break; + } + else if (ACDB_FILE_TYPE_WORKSPACE == db_file->file_type && + IsNull(acdb_file_man_context.workspace_info[index])) + { + acdb_file_man_context.workspace_count++; + break; + } + } + + if (MAX_ACDB_FILE_COUNT == index) + index--; + + switch (db_file->file_type) + { + case ACDB_FILE_TYPE_DATABASE: + status = AcdbFileManAddAcdb(index, &vm_id, db_file); + break; + case ACDB_FILE_TYPE_WORKSPACE: + status = AcdbFileManAddQwsp(index, db_file); + break; + default: + break; + } + + if (AR_FAILED(status)) + break; + } + + if (AR_SUCCEEDED(status)) + { + fm_ctx_handle->vm_id = vm_id; + fm_ctx_handle->file_man_handle = ACDB_FM_DB_INFO_AT_INDEX(index); + } + + ACDB_MUTEX_UNLOCK(acdb_file_man_context.file_man_lock); + return status; +} + +int32_t AcdbFileManRemoveDatabase(acdb_file_man_handle_t *fm_handle) +{ + int32_t status = AR_EOK; + uint32_t db_index = 0; + bool_t had_workspace = 0; + AcdbFileManDatabaseInfo *db_info = NULL; + AcdbFileManWorkspaceInfo *ws_info = NULL; + + if (IsNull(fm_handle)) + return AR_EBADPARAM; + + db_info = (AcdbFileManDatabaseInfo*)fm_handle; + if (IsNull(db_info)) + return AR_EBADPARAM; + + db_index = db_info->file_index; + ACDB_FM_DB_INFO_AT_INDEX(db_index) = NULL; + ws_info = ACDB_FM_WS_INFO_AT_INDEX(db_info->file_index); + if (!IsNull(db_info->file_handle)) + (void)ar_fclose(db_info->file_handle); + + acdb_buffer_t in_mem_file; + in_mem_file.buffer = db_info->database_cache; + in_mem_file.size = db_info->database_cache_size; + AcbdInitUnloadInMemFile(&in_mem_file); + + ACDB_FREE(db_info); + + if (!IsNull(ws_info)) + { + ACDB_FM_WS_INFO_AT_INDEX(db_index) = NULL; + if(!IsNull(ws_info->file_handle)) + (void)ar_fclose(ws_info->file_handle); + ACDB_FREE(ws_info); + had_workspace = TRUE; + } + + ACDB_MUTEX_LOCK(acdb_file_man_context.file_man_lock); + + if (acdb_file_man_context.database_count > 0) + { + acdb_file_man_context.database_count--; + + if (had_workspace) + acdb_file_man_context.workspace_count--; + } + + ACDB_MUTEX_UNLOCK(acdb_file_man_context.file_man_lock); + + return status; +} + +int32_t AcdbFileManReset(void) +{ + int32_t status = AR_EOK; + AcdbFileManDatabaseInfo* db_info = NULL; + + for (int32_t i = 0; i < ACDB_MAX_ACDB_FILES; i++) + { + db_info = ACDB_FM_DB_INFO_AT_INDEX(i); + + if (IsNull(db_info)) + continue; + + status = AcdbFileManRemoveDatabase((acdb_file_man_handle_t)db_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to close %s", status, + ACDB_FM_DB_INFO->database_file.path); + status = AR_EFAILED; + } + } + + ar_osal_mutex_destroy(acdb_file_man_context.file_man_lock); + ar_mem_set(&acdb_file_man_context, 0, sizeof(AcdbFileManContext)); + acdb_file_man_context.database_index = -1; + return status; +} + +int32_t AcdbFileManGetVmIdFromFileName(AcdbFile *acdb_file, uint32_t *vm_id) +{ + int32_t status = AR_ENOTEXIST; + AcdbFileManDatabaseInfo* db_info = NULL; + + if (IsNull(acdb_file) || IsNull(vm_id)) + { + return AR_EBADPARAM; + } + + for (int32_t i = 0; i < acdb_file_man_context.database_count; i++) + { + db_info = ACDB_FM_DB_INFO_AT_INDEX(i); + + if (IsNull(db_info)) + continue; + + if (!ACDB_FIND_STR(acdb_file->fileName, db_info->database_file.path)) + continue; + + status = AR_EOK; + *vm_id = db_info->vm_id; + } + + return status; +} + +int32_t AcdbFileManGetFileName(int32_t *findex, acdb_path_256_t *file_name_info) +{ + int32_t status = AR_EOK; + + size_t dst_str_size = sizeof(file_name_info->path); + size_t src_str_size = + ACDB_FM_DB_INFO_AT_INDEX(*findex)->database_file.path_len; + + if (src_str_size > dst_str_size) + { + ACDB_ERR("Error[%d]: Unable to copy file name. Source(%s) is " + "longer than Destination(%s)", AR_EBADPARAM, src_str_size, + dst_str_size); + return AR_EBADPARAM; + } + + if (IsNull(findex) || IsNull(file_name_info)) + { + ACDB_ERR("Error[%d]: The input parameter(s) are null") + return AR_EBADPARAM; + } + + if (*findex < acdb_file_man_context.database_count) + { + if (src_str_size >= ACDB_MAX_PATH_LENGTH) + { + ACDB_ERR("Error[%d]: Acdb file name legnth " + "is longer than 256 characters"); + return AR_EBADPARAM; + } + + status = ACDB_STR_CPY_SAFE(file_name_info->path, dst_str_size, + ACDB_FM_DB_INFO_AT_INDEX(*findex)->database_file.path, + src_str_size); + + if (AR_EOK != status) return status; + + file_name_info->path_len = + ACDB_FM_DB_INFO_AT_INDEX(*findex)->database_file.path_len; + } + else + { + ACDB_ERR("Error[%d]: The file index is greater than the file count"); + return AR_EBADPARAM; + } + + return status; +} + +int32_t AcdbFileManQwspFileIO( + AcdbFileManWorkspaceInfo *ws_info, AcdbFileManFileOp file_op) +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + + if (IsNull(ws_info)) + { + ACDB_ERR("Error[%d]: Workspace file info is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + switch (file_op) + { + case ACDB_FM_FILE_OP_OPEN: + status = ar_fopen(&fhandle, ws_info->workspace_file.path, + AR_FOPEN_READ_ONLY); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to open the workspace file", status); + } + + ws_info->file_handle = fhandle; + ws_info->file_size = (uint32_t)ar_fsize(ws_info->file_handle); + + break; + case ACDB_FM_FILE_OP_CLOSE: + status = ar_fclose(ws_info->file_handle); + ws_info->file_handle = NULL; + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to close the workspace file", status); + } + //Clear handle in case close is called again + ws_info->file_handle = NULL; + break; + default: + break; + } + + return status; +} + +int32_t AcdbFileManSetQwspPathInfo( + AcdbDatabasePathInfoVersion version, + void* file_info, void* path_info) +{ + int32_t status = AR_EOK; + AcdbFileManWorkspaceInfo* ws_info = NULL; + + ws_info = (AcdbFileManWorkspaceInfo*)file_info; + + if (IsNull(ws_info)) + return AR_ENOTEXIST; + + switch (version) + { + case ACDB_FM_DB_PATH_INFO_VERSION_1: + ((AcdbFileManDbPathInfo*)path_info)->file_size = + ws_info->file_size; + ((AcdbFileManDbPathInfo*)path_info)->path_length = + ws_info->workspace_file.path_len; + ((AcdbFileManDbPathInfo*)path_info)->path = + &ws_info->workspace_file.path[0]; + break; + case ACDB_FM_DB_PATH_INFO_VERSION_2: + ((AcdbFileManDbPathInfoV2*)path_info)->file_size = + ws_info->file_size; + ((AcdbFileManDbPathInfoV2*)path_info)->path_type = + ACDB_PATH_TYPE_QWSP_FILE; + ((AcdbFileManDbPathInfoV2*)path_info)->path_length = + ws_info->workspace_file.path_len; + ((AcdbFileManDbPathInfoV2*)path_info)->path = + &ws_info->workspace_file.path[0]; + break; + default: + status = AR_EBADPARAM; + break; + } + + return status; +} + +int32_t AcdbFileManSetAcdbPathInfo( + AcdbDatabasePathInfoVersion version, + void* file_info, void* path_info) +{ + int32_t status = AR_EOK; + AcdbFileManDatabaseInfo* db_info = NULL; + + db_info = (AcdbFileManDatabaseInfo*)file_info; + + if (IsNull(db_info)) + return AR_ENOTEXIST; + + switch (version) + { + case ACDB_FM_DB_PATH_INFO_VERSION_1: + ((AcdbFileManDbPathInfo*)path_info)->file_size = + db_info->database_cache_size; + ((AcdbFileManDbPathInfo*)path_info)->path_length = + db_info->database_file.path_len; + ((AcdbFileManDbPathInfo*)path_info)->path = + &db_info->database_file.path[0]; + break; + case ACDB_FM_DB_PATH_INFO_VERSION_2: + ((AcdbFileManDbPathInfoV2*)path_info)->file_size = + db_info->database_cache_size; + ((AcdbFileManDbPathInfoV2*)path_info)->path_type = + ACDB_PATH_TYPE_ACDB_FILE; + ((AcdbFileManDbPathInfoV2*)path_info)->path_length = + db_info->database_file.path_len; + ((AcdbFileManDbPathInfoV2*)path_info)->path = + &db_info->database_file.path[0]; + break; + default: + status = AR_EBADPARAM; + break; + } + + return status; +} + +int32_t AcdbFileManWriteLoadedFileInfo( + AcdbDatabasePathInfoVersion version, + AcdbPathType path_type, void *file_info, + AcdbFileManBlob *rsp, uint32_t *blob_offset) +{ + int32_t status = AR_EOK; + uint32_t path_info_struct_size = 0; + acdb_buffer_t path_info_struct = { 0 }; + acdb_path_t db_file = { 0 }; + AcdbFileManDbPathInfoV2 db_path_info_v2 = { 0 }; + AcdbFileManDbPathInfo db_path_info_v1 = { 0 }; + AcdbFileManDatabaseInfo* db_info = NULL; + AcdbFileManWorkspaceInfo* ws_info = NULL; + + if (IsNull(file_info) || IsNull(rsp) || IsNull(blob_offset)) + return AR_EBADPARAM; + + switch (version) + { + case ACDB_FM_DB_PATH_INFO_VERSION_1: + path_info_struct.buffer = (void*)&db_path_info_v1; + path_info_struct_size = sizeof(db_path_info_v1) - sizeof(intptr_t); + break; + case ACDB_FM_DB_PATH_INFO_VERSION_2: + path_info_struct.buffer = (void*)&db_path_info_v2; + path_info_struct_size = sizeof(db_path_info_v2) - sizeof(size_t); + break; + default: + status = AR_EBADPARAM; + break; + } + + switch (path_type) + { + case ACDB_PATH_TYPE_QWSP_FILE: + ws_info = (AcdbFileManWorkspaceInfo*)file_info; + if (IsNull(ws_info)) return AR_ENOTEXIST; + + status = AcdbFileManSetQwspPathInfo( + version, file_info, path_info_struct.buffer); + break; + case ACDB_PATH_TYPE_ACDB_FILE: + db_info = (AcdbFileManDatabaseInfo*)file_info; + if (IsNull(db_info)) return AR_ENOTEXIST; + + status = AcdbFileManSetAcdbPathInfo( + version, file_info, path_info_struct.buffer); + break; + case ACDB_PATH_TYPE_WRITEABLE_DIRECTORY: + db_info = (AcdbFileManDatabaseInfo*)file_info; + if (IsNull(db_info)) return AR_ENOTEXIST; + if (0 == db_info->writable_directory.path_len) return AR_ENOTEXIST; + db_path_info_v2.file_size = 0; + db_path_info_v2.path_type = ACDB_PATH_TYPE_WRITEABLE_DIRECTORY; + db_path_info_v2.path_length = db_info->writable_directory.path_len; + db_path_info_v2.path = &db_info->writable_directory.path[0]; + break; + default: + status = AR_EBADPARAM; + break; + } + + if (AR_FAILED(status)) + return status; + + switch (version) + { + case ACDB_FM_DB_PATH_INFO_VERSION_1: + db_file.path_length = db_path_info_v1.path_length; + db_file.path = db_path_info_v1.path; + + ACDB_MEM_CPY_SAFE(rsp->buf + *blob_offset, sizeof(AcdbPathType), + &db_path_info_v1.file_size, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + ACDB_MEM_CPY_SAFE(rsp->buf + *blob_offset, sizeof(AcdbPathType), + &db_path_info_v1.path_length, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + break; + case ACDB_FM_DB_PATH_INFO_VERSION_2: + db_file.path_length = db_path_info_v2.path_length; + db_file.path = db_path_info_v2.path; + + ACDB_MEM_CPY_SAFE(rsp->buf + *blob_offset, sizeof(AcdbPathType), + &db_path_info_v2.path_type, sizeof(AcdbPathType)); + *blob_offset += sizeof(AcdbPathType); + ACDB_MEM_CPY_SAFE(rsp->buf + *blob_offset, sizeof(uint32_t), + &db_path_info_v2.file_size, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + ACDB_MEM_CPY_SAFE(rsp->buf + *blob_offset, sizeof(uint32_t), + &db_path_info_v2.path_length, sizeof(uint32_t)); + *blob_offset += sizeof(uint32_t); + break; + default: + break; + } + + ACDB_MEM_CPY_SAFE(rsp->buf + *blob_offset, db_file.path_length, + db_file.path, db_file.path_length); + *blob_offset += db_file.path_length; + + return status; +} + +int32_t AcdbFileManGetHostDatabaseFileInfo(AcdbFileManBlob* rsp) +{ + int32_t status = AR_EOK; + uint32_t sz_file_info_rsp = 0; + uint32_t offset = 0; + uint32_t offset_file_count = 0; + int32_t i = 0; + int32_t file_count = 0; + AcdbFileManDatabaseInfo *db_info = NULL; + AcdbFileManWorkspaceInfo *ws_info = NULL; + + /* + The format of the output is: + + +-----------------------------+ + | #files | + +-----------------------------+ + +-----------------------------+ + | fsize | fnamelength | fname | File #1 + +-----------------------------+ + ... + ... + +-----------------------------+ + | fsize | fnamelength | fname | File #N + +-----------------------------+ + */ + + if (acdb_file_man_context.database_count <= 0) + { + ACDB_ERR("Error[%d]: No database file found at index %d", + AR_ENORESOURCE, i); + return AR_ENORESOURCE; + } + + ws_info = ACDB_FM_WS_INFO_AT_INDEX(i); + db_info = ACDB_FM_DB_INFO_AT_INDEX(i); + + sz_file_info_rsp += sizeof(file_count); + + if (!IsNull(ws_info)) + { + status = AcdbFileManQwspFileIO(ws_info, ACDB_FM_FILE_OP_OPEN); + if (AR_FAILED(status)) return status; + + status = AcdbFileManQwspFileIO(ws_info, ACDB_FM_FILE_OP_CLOSE); + if (AR_FAILED(status)) return status; + + // workspace file + sz_file_info_rsp += sizeof(AcdbFileManDbPathInfo) + - sizeof(intptr_t); + sz_file_info_rsp += ws_info->workspace_file.path_len; + } + else + { + ACDB_DBG("Warning: No workspace file found for database in %s", + &db_info->database_directory.path[0]); + } + + if (!IsNull(db_info)) + { + // acdb file + sz_file_info_rsp += sizeof(AcdbFileManDbPathInfo) + - sizeof(intptr_t); + sz_file_info_rsp += db_info->database_file.path_len; + } + + if (sz_file_info_rsp > rsp->size) + { + ACDB_ERR("Error[%d]: There isnt enough memory to " + "copy file information", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + offset_file_count = 0; + + ws_info = ACDB_FM_WS_INFO_AT_INDEX(i); + db_info = ACDB_FM_DB_INFO_AT_INDEX(i); + file_count = 0; + + if (!IsNull(ws_info) && !IsNull(db_info)) + ws_info->vm_id = db_info->vm_id; + else + { + ACDB_ERR("Error[%d]: The workspace/database info param are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + //Skip writing file_count and write it after determining file_count + offset_file_count = offset; + offset += sizeof(uint32_t); + + status = AcdbFileManWriteLoadedFileInfo( + ACDB_FM_DB_PATH_INFO_VERSION_1, + ACDB_PATH_TYPE_QWSP_FILE, + (void*)ws_info, rsp, &offset); + file_count += AR_SUCCEEDED(status) ? 1 : 0; + + status = AcdbFileManWriteLoadedFileInfo( + ACDB_FM_DB_PATH_INFO_VERSION_1, + ACDB_PATH_TYPE_ACDB_FILE, + (void*)db_info, rsp, &offset); + file_count += AR_SUCCEEDED(status) ? 1 : 0; + + ACDB_MEM_CPY_SAFE( + rsp->buf + offset_file_count, sizeof(uint32_t), + &file_count, sizeof(uint32_t)); + + status = AR_EOK; + + rsp->bytes_filled = sz_file_info_rsp; + + return status; +} + +int32_t AcdbFileManGetAllDatabasesFileInfo(AcdbFileManBlob* rsp) +{ + /* + * The format of the output is: + * +-------------------------------------+ + * | #files sets | + * +-------------------------------------+ + * +-------------------------------------+ + * | acdb handle | _ + * +-------------------------------------+ | + * +-------------------------------------+ | + * | # files | | + * +-------------------------------------+ | + * +-------------------------------------+ | File Set #N + * | path type | fsize | path len | path | | + * +-------------------------------------+ | + * | ... | + * +-------------------------------------+ | + * | path type | fsize | path len | path | _| + * +-------------------------------------+ + * . + * . + * +-------------------------------------+ + * | acdb handle | _ + * +-------------------------------------+ | + * +-------------------------------------+ | + * | # files | | + * +-------------------------------------+ | + * +-------------------------------------+ | File Set #N + * | path type | fsize | path len | path | | + * +-------------------------------------+ | + * | ... | + * +-------------------------------------+ | + * | path type | fsize | path len | path | _| + * +-------------------------------------+ + */ + + int32_t status = AR_EOK; + uint32_t sz_file_info_rsp = 0; + uint32_t offset = 0; + uint32_t offset_file_count = 0; + int32_t i = 0; + int32_t file_count = 0; + int32_t fileset_count = 0; + uint32_t acdb_handle = 0; + AcdbFileManDatabaseInfo* db_info = NULL; + AcdbFileManWorkspaceInfo* ws_info = NULL; + AcdbFileManDbPathInfoV2 db_path_info = { 0 }; + + sz_file_info_rsp += sizeof(fileset_count); + fileset_count = acdb_file_man_context.database_count; + + for (i = 0; i < acdb_file_man_context.database_count; i++) + { + ws_info = ACDB_FM_WS_INFO_AT_INDEX(i); + db_info = ACDB_FM_DB_INFO_AT_INDEX(i); + + sz_file_info_rsp += sizeof(acdb_handle); + sz_file_info_rsp += sizeof(file_count); + + if (!IsNull(ws_info)) + { + status = AcdbFileManQwspFileIO(ws_info, ACDB_FM_FILE_OP_OPEN); + if (AR_FAILED(status)) return status; + + status = AcdbFileManQwspFileIO(ws_info, ACDB_FM_FILE_OP_CLOSE); + if (AR_FAILED(status)) return status; + + // workspace file + sz_file_info_rsp += sizeof(db_path_info) - sizeof(intptr_t); + sz_file_info_rsp += ws_info->workspace_file.path_len; + } + else + { + ACDB_DBG("Warning: No workspace file found for database in %s", + &db_info->database_directory.path[0]); + } + + if (!IsNull(db_info)) + { + // acdb file + sz_file_info_rsp += sizeof(db_path_info) - sizeof(intptr_t); + sz_file_info_rsp += db_info->database_file.path_len; + + // writable directory + if (db_info->writable_directory.path_len > 0) + { + sz_file_info_rsp += sizeof(db_path_info) - sizeof(intptr_t); + sz_file_info_rsp += db_info->writable_directory.path_len; + } + } + else + { + ACDB_ERR("Error[%d]: No database file found at index %d", + AR_ENORESOURCE, i); + return AR_ENORESOURCE; + } + } + + if (sz_file_info_rsp > rsp->size) + { + ACDB_ERR("Error[%d]: There isnt enough memory to " + "copy file information", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + + ACDB_MEM_CPY_SAFE( + rsp->buf, sizeof(uint32_t), + &fileset_count, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + offset_file_count = 0; + for (i = 0; i < acdb_file_man_context.database_count; i++) + { + ws_info = ACDB_FM_WS_INFO_AT_INDEX(i); + db_info = ACDB_FM_DB_INFO_AT_INDEX(i); + file_count = 0; + + if (!IsNull(ws_info) && !IsNull(db_info)) + ws_info->vm_id = db_info->vm_id; + else if(IsNull(ws_info) && IsNull(db_info)) + { + ACDB_ERR("Error[%d]: The workspace/database info param are null", + AR_EBADPARAM); + status = AR_EBADPARAM; + break; + } + + acdb_handle = db_info->vm_id; + ACDB_MEM_CPY_SAFE( + rsp->buf + offset, sizeof(uint32_t), + &acdb_handle, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + //Skip writing file_count and write it after determining file_count + offset_file_count = offset; + offset += sizeof(uint32_t); + + status = AcdbFileManWriteLoadedFileInfo( + ACDB_FM_DB_PATH_INFO_VERSION_2, + ACDB_PATH_TYPE_QWSP_FILE, + (void*)ws_info, rsp, &offset); + file_count += AR_SUCCEEDED(status) ? 1 : 0; + + status = AcdbFileManWriteLoadedFileInfo( + ACDB_FM_DB_PATH_INFO_VERSION_2, + ACDB_PATH_TYPE_ACDB_FILE, + (void*)db_info, rsp, &offset); + file_count += AR_SUCCEEDED(status) ? 1 : 0; + + status = AcdbFileManWriteLoadedFileInfo( + ACDB_FM_DB_PATH_INFO_VERSION_2, + ACDB_PATH_TYPE_WRITEABLE_DIRECTORY, + (void*)db_info, rsp, &offset); + file_count += AR_SUCCEEDED(status) ? 1 : 0; + + ACDB_MEM_CPY_SAFE( + rsp->buf + offset_file_count, sizeof(uint32_t), + &file_count, sizeof(uint32_t)); + + status = AR_EOK; + } + + rsp->bytes_filled = sz_file_info_rsp; + + return status; +} + +int32_t AcdbFileManGetQwspFileData(AcdbFileManWorkspaceInfo* ws_info, + AcdbFileManGetFileDataReq* req, AcdbFileManBlob *rsp) +{ + int32_t status = AR_EOK; + size_t data_copy_size = 0; + size_t bytes_read = 0; + + if (IsNull(req) | IsNull(ws_info) | IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (ws_info->file_size < req->file_offset) + { + ACDB_ERR("Error[%d]: The provided offset is past the end of the file", + AR_EBADPARAM); + return AR_EBADPARAM; + } + if ((ws_info->file_size - req->file_offset) < req->file_data_len) + { + data_copy_size = (size_t)(ws_info->file_size - req->file_offset); + } + else + { + data_copy_size = (size_t)req->file_data_len; + } + + status = AcdbFileManQwspFileIO(ws_info, ACDB_FM_FILE_OP_OPEN); + if (AR_FAILED(status)) return status; + + status = ar_fseek(ws_info->file_handle, + req->file_offset, AR_FSEEK_BEGIN); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to seek to file offset %d", + status, req->file_offset); + goto end; + } + + status = ar_fread(ws_info->file_handle, + (void*)rsp->buf, data_copy_size, &bytes_read); + if (bytes_read != data_copy_size) + { + ACDB_DBG("Expected to read %d bytes, but read %d bytes", + data_copy_size, bytes_read); + goto end; + } + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read data for %s", + status, ws_info->workspace_file.path); + goto end; + } + +end: + + AcdbFileManQwspFileIO(ws_info, ACDB_FM_FILE_OP_CLOSE); + rsp->bytes_filled = (uint32_t)data_copy_size; + return status; +} + +int32_t AcdbFileManGetAcdbFileData(AcdbFileManDatabaseInfo *db_info, + AcdbFileManGetFileDataReq* req, AcdbFileManBlob *rsp) +{ + int32_t status = AR_EOK; + size_t data_copy_size = 0; + + if (IsNull(req) | IsNull(db_info) | IsNull(rsp)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (db_info->database_cache_size < req->file_offset) + { + ACDB_ERR("Error[%d]: The provided offset is past the end of the file", + AR_EBADPARAM); + return AR_EBADPARAM; + } + if ((db_info->database_cache_size - req->file_offset) < req->file_data_len) + { + data_copy_size = (size_t)(db_info->database_cache_size + - req->file_offset); + } + else + { + data_copy_size = (size_t)req->file_data_len; + } + + status = acdb_fm_read_db_mem((acdb_file_man_handle_t)db_info, rsp->buf, + data_copy_size, &req->file_offset); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to read data from %s", + status, db_info->database_file.path); + return status; + } + + rsp->bytes_filled = (uint32_t)data_copy_size; + return status; +} + +int32_t AcdbFileManGetDatabaseFileSet( + AcdbFileManGetFileDataReq* req, AcdbFileManBlob* rsp) +{ + int32_t status = AR_EOK; + char_t* fname = NULL; + uint32_t fname_len = 0; + char_t* path = NULL; + uint32_t path_len = 0; + uint32_t db_count = acdb_file_man_context.database_count; + bool_t found_handle = false; + AcdbFileManDatabaseInfo* db_info = NULL; + AcdbFileManWorkspaceInfo* ws_info = NULL; + AcdbPathType path_type = ACDB_PATH_TYPE_NONE; + const char* WKSP_FILE_NAME_EXT = ".qwsp"; + const char* ACDB_FILE_NAME_EXT = ".acdb"; + + if (req == NULL || rsp == NULL) + { + ACDB_ERR("Error[%d]: One or more input parameter(s) are null"); + return AR_EBADPARAM; + } + + for (uint32_t i = 0; i < db_count; i++) + { + db_info = ACDB_FM_DB_INFO_AT_INDEX(i); + ws_info = ACDB_FM_WS_INFO_AT_INDEX(i); + + found_handle = db_info->vm_id == req->acdb_handle; + + if (found_handle) + break; + } + + if (!found_handle) + { + ACDB_ERR("Error[%d]: The provided handle is invalid. " + "No matching database was found.", AR_EHANDLE); + return AR_EHANDLE; + } + + if (!IsNull(ACDB_FIND_STR((char_t*)req->file_name, WKSP_FILE_NAME_EXT))) + { + path_type = ACDB_PATH_TYPE_QWSP_FILE; + path = &ws_info->workspace_file.path[0]; + path_len = ws_info->workspace_file.path_len; + } + else if (!IsNull(ACDB_FIND_STR((char_t*)req->file_name, ACDB_FILE_NAME_EXT))) + { + path_type = ACDB_PATH_TYPE_ACDB_FILE; + path = &db_info->database_file.path[0]; + path_len = db_info->database_file.path_len; + } + else + { + ACDB_ERR("Error[%d]: Unknown file extension for file: %s. ", + AR_EHANDLE, req->file_name); + return AR_EBADPARAM; + } + + status = GetFileNameFromPath(path, path_len, fname, &fname_len); + + fname = &path[path_len - fname_len]; + + if (AR_FAILED(status) || fname == NULL) + { + ACDB_ERR("Error[%d]: Failed to get file name from path", status); + return status; + } + + if (IsNull(strstr((char*)fname, (char*)req->file_name))) + { + ACDB_ERR("Error[%d]: Unknown file %s. The file name %s does not match %s", + AR_ENOTEXIST, req->file_name, req->file_name, fname); + return AR_ENOTEXIST; + } + + status = AR_EOK; + + switch (path_type) + { + case ACDB_PATH_TYPE_QWSP_FILE: + status = AcdbFileManGetQwspFileData(ws_info, req, rsp); + break; + case ACDB_PATH_TYPE_ACDB_FILE: + status = AcdbFileManGetAcdbFileData(db_info, req, rsp); + break; + default: + ACDB_ERR("Error[%d]: The file type for %s is unknown", + AR_EUNEXPECTED, db_info->database_file.path); + return AR_EUNEXPECTED; + break; + } + + db_info = NULL; + ws_info = NULL; + + return status; +} + +int32_t AcdbFileManSetWritablePath( + acdb_file_man_writable_path_info_t* info) +{ + AcdbFileManDatabaseInfo* db_info = NULL; + + if (IsNull(info)) + return AR_EBADPARAM; + + db_info = (AcdbFileManDatabaseInfo*)info->handle; + + if (IsNull(db_info)) + return AR_EHANDLE; + + ACDB_MEM_CPY_SAFE( + &db_info->writable_directory.path[0], + info->writable_path.path_length, + info->writable_path.path, info->writable_path.path_length); + + db_info->writable_directory.path_len = info->writable_path.path_length; + + return AR_EOK; +} + +int32_t AcdbFileManGetWritablePath( + acdb_file_man_writable_path_info_256_t *info) +{ + int32_t status = AR_EOK; + AcdbFileManDatabaseInfo *db_info = NULL; + + if (IsNull(info)) + return AR_EBADPARAM; + + db_info = (AcdbFileManDatabaseInfo*)info->handle; + + if (IsNull(db_info)) + return AR_EHANDLE; + + info->writable_path.path_len = + db_info->writable_directory.path_len; + ACDB_MEM_CPY_SAFE( + &info->writable_path.path[0], + db_info->writable_directory.path_len, + &db_info->writable_directory.path[0], + db_info->writable_directory.path_len); + + return status; +} + +/* --------------------------------------------------------------------------- +* Public functions +*--------------------------------------------------------------------------- */ + +int32_t FileSeekRead(void* buffer, size_t read_size, uint32_t* offset) +{ + if (-1 == acdb_file_man_context.database_index) + return AR_ENORESOURCE; + int32_t status = AR_EOK; + size_t bytes_read = 0; + + status = ar_fseek(ACDB_FM_DB_INFO->file_handle, + *offset, AR_FSEEK_BEGIN); + + if (AR_FAILED(status)) return status; + + status = ar_fread(ACDB_FM_DB_INFO->file_handle, + buffer, read_size, &bytes_read); + + *offset += (uint32_t)bytes_read; + + return status; +} + +int32_t FileManReadFileToBuffer(const char_t* fname, size_t* fsize, uint8_t* fbuffer, uint32_t fbuffer_size) +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t bytes_read = 0; + + if (fname == NULL) + { + return AR_EBADPARAM; + } + else + { + status = ar_fopen(&fhandle, fname, AR_FOPEN_READ_ONLY); + if (AR_FAILED(status) || fhandle == NULL) + { + ACDB_ERR("Error[%d]: Unable to open file: %s", status, fname); + return status; + } + + *fsize = (uint32_t)ar_fsize(fhandle); + + if (fbuffer == NULL) + { + ar_fclose(fhandle); + return AR_EOK; + } + + if (*fsize > fbuffer_size) + { + ar_fclose(fhandle); + ACDB_ERR("Error[%d]: File size (%d bytes) is more " + "than buffer size (%d bytes)", + AR_EBADPARAM, *fsize, fbuffer_size); + return AR_EBADPARAM; + } + + status = ar_fread(fhandle, (void*)fbuffer, *fsize, &bytes_read); + if (AR_FAILED(status) || fhandle == NULL) + { + ar_fclose(fhandle); + ACDB_ERR("Error[%d]: Unable to read file: %s", status, fname); + return status; + } + + if (bytes_read != *fsize) + { + status = AR_EBADPARAM; + ACDB_ERR("Error[%d]: The bytes read (%d bytes) is not equal to " + "the requested read size (%d bytes)", + status, bytes_read, *fsize); + } + + ar_fclose(fhandle); + } + return status; +} + +/* --------------------------------------------------------------------------- +* Public functions: Database Read Operations +*--------------------------------------------------------------------------- */ + +int32_t acdb_get_db_chunk(acdb_file_man_handle_t handle, + uint32_t chunk_id, uint32_t* chunk_offset, uint32_t* chunk_size) +{ + if (IsNull(handle) || IsNull(chunk_offset) || IsNull(chunk_size)) + return AR_EBADPARAM; + + AcdbFileManDatabaseInfo* db = (AcdbFileManDatabaseInfo*)handle; + + int32_t status = acdb_parser_get_chunk( + db->database_cache, + db->database_cache_size, + chunk_id, chunk_offset, chunk_size); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Failed to get information for Chunk[0x%x]", + status, chunk_id); + return status; + } + + if (*chunk_size <= 0) + { + ACDB_DBG("Warning[%d]: Chunk[0x%x] is empty", AR_ENOTEXIST, chunk_id); + return AR_ENOTEXIST; + } + + return AR_EOK; +} + +int32_t acdb_fm_get_db_chunks(uint32_t count, ...) +{ + int32_t status = AR_EOK; + va_list args; + ChunkInfo* ci = NULL; + acdb_context_handle_t * ctx_handle = NULL; + acdb_file_man_handle_t fm_handle = NULL; + va_start(args, count); + + for (uint32_t i = 0; i < count; i++) + { + ci = va_arg(args, ChunkInfo*); + + if (IsNull(ci)) + return AR_EBADPARAM; + + switch (ci->handle_override) + { + case ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER: + fm_handle = ACDB_FM_DB_INFO; + break; + case ACDB_FM_HANDLE_OVERRIDE_CTX_MANAGER: + default: + ctx_handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(ctx_handle)) + return AR_EHANDLE; + + fm_handle = ctx_handle->file_manager_handle; + break; + } + + if (IsNull(fm_handle)) + return AR_EHANDLE; + + status = acdb_get_db_chunk(fm_handle, + ci->chunk_id, &ci->chunk_offset, &ci->chunk_size); + if (AR_FAILED(status)) + { + return status; + } + } + + va_end(args); + return status; +} + +int32_t acdb_file_seek_read(acdb_file_man_handle_t handle, + void* buffer, size_t read_size, uint32_t* offset) +{ + int32_t status = AR_EOK; + size_t bytes_read = 0; + AcdbFileManDatabaseInfo *db = NULL; + + if (IsNull(handle) || IsNull(buffer) || IsNull(offset)) + return AR_EBADPARAM; + + db = (AcdbFileManDatabaseInfo*)handle; + + status = ar_fseek(db->file_handle, + *offset, AR_FSEEK_BEGIN); + + if (AR_FAILED(status)) return status; + + status = ar_fread(db->file_handle, + buffer, read_size, &bytes_read); + + *offset += (uint32_t)bytes_read; + + return status; +} + +int32_t acdb_fm_read_db_mem(acdb_file_man_handle_t handle, + void* buffer, size_t read_size, uint32_t* offset) +{ + int32_t status = AR_EOK; + AcdbFileManDatabaseInfo* db = NULL; + uint8_t* buffer_ptr = NULL; + + if (read_size == 0) + return status; + + if (IsNull(handle) || IsNull(buffer) || IsNull(offset)) + return AR_EBADPARAM; + + db = (AcdbFileManDatabaseInfo*)handle; + buffer_ptr = (uint8_t*)db->database_cache; + + buffer_ptr += *offset; + + if ((*offset >= db->database_cache_size) || + (read_size > (db->database_cache_size - *offset))) + { + ACDB_ERR("Error[%d]: offset[%u] readsize[%zu] database_cache_size[%u] " + "read beyond database cache bounds", AR_EBADPARAM, *offset, + read_size, db->database_cache_size); + return AR_EBADPARAM; + } + + status = ar_mem_cpy(buffer, read_size, buffer_ptr, read_size); + if (AR_FAILED(status)) return status; + + *offset += (uint32_t)read_size; + + return status; +} + +int32_t acdb_fm_get_db_mem_ptr(acdb_file_man_handle_t handle, + void** file_ptr, size_t data_size, uint32_t* offset) +{ + int32_t status = AR_EOK; + AcdbFileManDatabaseInfo* db = NULL; + + if (IsNull(handle) || IsNull(file_ptr) || IsNull(offset)) + return AR_EBADPARAM; + + db = (AcdbFileManDatabaseInfo*)handle; + + if ((*offset >= db->database_cache_size) || + (data_size > (db->database_cache_size - *offset))) + { + ACDB_ERR("Error[%d]: offset[%u] datasize[%zu] database_cache_size[%u] " + "read beyond database cache bounds", AR_EBADPARAM, *offset, + data_size, db->database_cache_size); + return AR_EBADPARAM; + } + + *file_ptr = (uint8_t*)db->database_cache + *offset; + *offset += (uint32_t)data_size; + + return status; +} + +int32_t acdb_fm_get_db_mem_ptr_2(acdb_file_man_handle_t handle, + void** file_ptr, uint32_t offset) +{ + int32_t status = AR_EOK; + void* addr_start = NULL; + void* addr_end = NULL; + AcdbFileManDatabaseInfo* db = NULL; + + if (IsNull(handle) || IsNull(file_ptr)) + return AR_EBADPARAM; + + db = (AcdbFileManDatabaseInfo*)handle; + addr_start = db->database_cache; + addr_end = (uint8_t*)db->database_cache + + db->database_cache_size; + + if((uint8_t*)addr_start + offset > (uint8_t*)addr_end) + return AR_EBADPARAM; + + *file_ptr = (uint8_t*)db->database_cache + offset; + + return status; +} + +int32_t FileManReadBuffer(void* buffer, size_t read_size, uint32_t* offset) +{ + acdb_context_handle_t* ctx_handle = NULL; + + ctx_handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(ctx_handle)) + return AR_EHANDLE; + + return acdb_fm_read_db_mem(ctx_handle->file_manager_handle, + buffer, read_size, offset); +} + +int32_t FileManGetFilePointer1(void** file_ptr, size_t data_size, uint32_t* offset) +{ + acdb_context_handle_t* handle = NULL; + + handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(handle)) + return AR_EHANDLE; + + return acdb_fm_get_db_mem_ptr(handle->file_manager_handle, + file_ptr, data_size, offset); +} + +int32_t FileManGetFilePointer2(void** file_ptr, uint32_t offset) +{ + acdb_context_handle_t* handle = NULL; + + handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(handle)) + return AR_EHANDLE; + + return acdb_fm_get_db_mem_ptr_2(handle->file_manager_handle, + file_ptr, offset); +} + +int32_t FileManDbReadAndSeek(acdb_fm_read_req_t *req) +{ + acdb_context_handle_t* ctx_handle = NULL; + acdb_file_man_handle_t fm_handle = NULL; + + switch (req->handle_override) + { + case ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER: + fm_handle = ACDB_FM_DB_INFO; + break; + case ACDB_FM_HANDLE_OVERRIDE_CTX_MANAGER: + default: + ctx_handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(ctx_handle)) + return AR_EHANDLE; + + fm_handle = ctx_handle->file_manager_handle; + break; + } + + return acdb_fm_read_db_mem(fm_handle, + req->dst_buffer, req->read_size, &req->offset); +} + +int32_t FileManGetDbPointerAndSeek(acdb_fm_file_ptr_req_t *req) +{ + acdb_context_handle_t* ctx_handle = NULL; + acdb_file_man_handle_t fm_handle = NULL; + + switch (req->handle_override) + { + case ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER: + fm_handle = ACDB_FM_DB_INFO; + break; + case ACDB_FM_HANDLE_OVERRIDE_CTX_MANAGER: + default: + ctx_handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(ctx_handle)) + return AR_EHANDLE; + + fm_handle = ctx_handle->file_manager_handle; + break; + } + + return acdb_fm_get_db_mem_ptr(fm_handle, + &req->file_ptr, req->data_size, &req->offset); +} + +int32_t FileManGetDbPointer(acdb_fm_file_ptr_req_t *req) +{ + acdb_context_handle_t* ctx_handle = NULL; + acdb_file_man_handle_t fm_handle = NULL; + + switch (req->handle_override) + { + case ACDB_FM_HANDLE_OVERRIDE_FILE_MANAGER: + fm_handle = ACDB_FM_DB_INFO; + break; + case ACDB_FM_HANDLE_OVERRIDE_CTX_MANAGER: + default: + ctx_handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(ctx_handle)) + return AR_EHANDLE; + + fm_handle = ctx_handle->file_manager_handle; + break; + } + + return acdb_fm_get_db_mem_ptr_2(fm_handle, + &req->file_ptr, req->offset); +} + +int32_t acdb_file_man_ioctl(uint32_t cmd_id, + void *req, uint32_t req_size, + void *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + switch (cmd_id) + { + case ACDB_FILE_MAN_INIT: + { + status = AcdbFileManInit(); + break; + } + case ACDB_FILE_MAN_ADD_DATABASE: + { + if (req == NULL || req_size != sizeof(acdb_file_man_data_files_t) || + rsp == NULL || rsp_size != sizeof(acdb_file_man_context_handle_t)) + { + return AR_EBADPARAM; + } + status = AcdbFileManAddDatabase( + (acdb_file_man_data_files_t*)req, + (acdb_file_man_context_handle_t*)rsp); + break; + } + case ACDB_FILE_MAN_REMOVE_DATABASE: + { + if (req == NULL || req_size != sizeof(acdb_file_man_handle_t)) + { + return AR_EBADPARAM; + } + status = AcdbFileManRemoveDatabase( + (acdb_file_man_handle_t*)req); + break; + } + case ACDB_FILE_MAN_RESET: + { + status = AcdbFileManReset(); + break; + } + case ACDB_FILE_MAN_GET_VM_ID_FROM_FILE_NAME: + { + if (req == NULL || req_size != sizeof(AcdbFile) || + rsp == NULL || rsp_size != sizeof(uint32_t)) + { + return AR_EBADPARAM; + } + status = AcdbFileManGetVmIdFromFileName( + (AcdbFile*)req, (uint32_t*)rsp); + break; + } + case ACDB_FILE_MAN_SET_WRITABLE_PATH: + { + if (req == NULL || + req_size != sizeof(acdb_file_man_writable_path_info_t)) + { + return AR_EBADPARAM; + } + status = AcdbFileManSetWritablePath( + (acdb_file_man_writable_path_info_t*)req); + break; + } + case ACDB_FILE_MAN_GET_FILE_NAME: + { + if (req == NULL || req_size != sizeof(uint32_t) || + rsp == NULL || rsp_size != sizeof(acdb_path_256_t)) + { + return AR_EBADPARAM; + } + + status = AcdbFileManGetFileName( + (int32_t*)req, (acdb_path_256_t*)rsp); + break; + } + case ACDB_FILE_MAN_GET_HOST_DATABASE_FILE_SET_INFO: + { + if (rsp == NULL || rsp_size != sizeof(AcdbFileManBlob)) + { + return AR_EBADPARAM; + } + + status = AcdbFileManGetHostDatabaseFileInfo( + (AcdbFileManBlob*)rsp); + break; + } + case ACDB_FILE_MAN_GET_ALL_DATABASE_FILE_SETS: + { + if (rsp == NULL || rsp_size != sizeof(AcdbFileManBlob)) + { + return AR_EBADPARAM; + } + + status = AcdbFileManGetAllDatabasesFileInfo( + (AcdbFileManBlob*)rsp); + break; + } + case ACDB_FILE_MAN_GET_DATABASE_FILE_SET: + { + if (req == NULL || req_size == 0 || + rsp == NULL || rsp_size != sizeof(AcdbFileManBlob)) + { + return AR_EBADPARAM; + } + + status = AcdbFileManGetDatabaseFileSet( + (AcdbFileManGetFileDataReq*)req, + (AcdbFileManBlob*)rsp); + break; + } + case ACDB_FILE_MAN_GET_WRITABLE_PATH: + { + if (req == NULL || + req_size != sizeof(acdb_file_man_writable_path_info_256_t)) + { + return AR_EBADPARAM; + } + + status = AcdbFileManGetWritablePath(req); + break; + } + default: + status = AR_EUNSUPPORTED; + ACDB_ERR("Error[%d]: Unsupported Command[%08X]", status, cmd_id); + } + return status; +} diff --git a/acdb/src/acdb_heap.c b/acdb/src/acdb_heap.c new file mode 100644 index 0000000..8819e75 --- /dev/null +++ b/acdb/src/acdb_heap.c @@ -0,0 +1,1425 @@ +/** +*============================================================================== +* \file acdb_heap.h +* +* \brief +* Manages the calibration data set by ACDB SW clients in RAM. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================== +*/ + +#include +#include "acdb_heap.h" +#include "acdb_common.h" +#include "acdb_context_mgr.h" +#include "acdb_types.h" + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ + +#define ACDB_MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define ACDB_MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define HEX_DIGITS 8 +#define ACDB_MAX_ACDB_FILES 16 + +/**< A File Manager macro that simplifies accessing the database info within the + * File Manager context structure. + * + * This macro represents the database info at the current index set in + * acdb_file_man_context.database_index + * + * NOTE: The acdb_file_man_context.database_index must me non-zero and initialized + * before using this macro + */ +#define ACDB_HEAP_DB_INFO acdb_heap_context \ +.heap_info[acdb_heap_context.active_heap_index] + + /**< A File Manager macro that simplifies accessing the database info within the + * File Manager context structure. + * + * Specify the index of the database info to retrieve + * + * NOTE: This macro is mainly used in for loops when cycling through + * databases info entries + */ +#define ACDB_HEAP_DB_INFO_AT_INDEX(index) acdb_heap_context \ +.heap_info[index] + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ + +typedef struct _acdb_heap_info_t AcdbHeapInfo; +struct _acdb_heap_info_t +{ + /**< The virtual machine id used by the database */ + uint32_t vm_id; + /**< The index of the associated database */ + int32_t database_index; + /**< Root of the associated tree */ + AcdbTreeNode* root; +}; + +typedef struct _acdb_heap_context_t AcdbHeapContext; +struct _acdb_heap_context_t +{ + ar_osal_mutex_t heap_lock; + /**< The index of the heap currently being accessed */ + int32_t active_heap_index; + /**< Number of active delta data heaps */ + int32_t heap_count; + /**< List of heap information */ + AcdbHeapInfo *heap_info[MAX_ACDB_FILE_COUNT]; +}; + +/* --------------------------------------------------------------------------- +* Static Variable Definitions +*--------------------------------------------------------------------------- */ + +static AcdbHeapContext acdb_heap_context; + +/* --------------------------------------------------------------------------- +* Function Prototypes +*--------------------------------------------------------------------------- */ + +int32_t acdb_heap_clear(acdb_heap_handle_t handle); + +/* --------------------------------------------------------------------------- +* Helper functions +*--------------------------------------------------------------------------- */ + +/** +* \breif +* Converts a key vector to a string. +* Caller is responsible for freeing the returned string pointer +* +* \return pointer to key vector string on succes, null on failure +*/ +char *acdb_heap_key_vector_to_string( + const AcdbGraphKeyVector *key_vector, size_t *sz_str_key_vector) +{ + /* Example + Format : ... + Input : <0xA, 0x1><0xB, 0x1><0xC, 0x1> + Output : 'A1B1C1' in Big Endian + */ + if (IsNull(key_vector)) return NULL; + + uint32_t offset = 0; + //Max Key Vector String length = 8 * 2 * key_vector->num_keys; + size_t str_size = 0; + //8 Hex Digits in 32-bit integer * 2 members in + uint32_t sz_str_kv_pair = 16 + 1; + char tmp[16 + 1] = ""; + char *key_vector_str = NULL; + + for (uint32_t i = 0; i < key_vector->num_keys; i++) + { + if (0 > ar_sprintf(tmp, sz_str_kv_pair, "%08x%08x", + key_vector->graph_key_vector[i].key, + key_vector->graph_key_vector[i].value)) + { + return NULL; + } + str_size += ar_strlen(tmp, (size_t)sz_str_kv_pair); + } + + str_size += 1;// '\0' + + key_vector_str = ACDB_MALLOC(char, str_size); + if (IsNull(key_vector_str)) return NULL; + memset(key_vector_str, 0, str_size); + + for (uint32_t i = 0; i < key_vector->num_keys; i++) + { + if (key_vector_str + offset < key_vector_str + str_size) + { + if (0 > ar_sprintf(key_vector_str + offset, sz_str_kv_pair, + "%08x%08x", + key_vector->graph_key_vector[i].key, + key_vector->graph_key_vector[i].value)) + { + ACDB_FREE(key_vector_str); + return NULL; + } + offset = (uint32_t)ar_strlen(key_vector_str, str_size); + } + } + + *sz_str_key_vector = offset; + return key_vector_str; +} + +/** +* \breif +* Get Calibration or Tag Key Vector from the KV to Subgraph Map +* +* \param[in/out] map: map to extract key vector from +* \return pointer to key vector +*/ +AcdbGraphKeyVector *get_key_vector_from_map( + acdb_delta_data_map_t* map) +{ + AcdbGraphKeyVector *kv = NULL; + + if (IsNull(map)) + return NULL; + + if (IsNull(map->key_vector_data)) + return NULL; + + switch (map->key_vector_type) + { + case TAG_KEY_VECTOR: + kv = &((AcdbModuleTag*)map->key_vector_data)->tag_key_vector; + break; + case CAL_KEY_VECTOR: + kv = ((AcdbGraphKeyVector*)map->key_vector_data); + break; + default: + break; + } + + return kv; +} + +bool_t acdb_tree_is_leaf(AcdbTreeNode *tnode) +{ + if (tnode == NULL) + return FALSE; + + //or if the depth of the node is zero + + //No left or right subtrees, but has a parent, so it must be a leaf + if (IsNull(tnode->left) && IsNull(tnode->right) && + !IsNull(tnode->parent)) + { + return TRUE; + } + return FALSE; +} + +bool_t acdb_tree_is_tree_empty(AcdbTreeNode *root) +{ + if (IsNull(root) || + (IsNull(root->p_struct) && + IsNull(root->left) && + IsNull(root->right) && + IsNull(root->parent))) + { + return TRUE; + } + return FALSE; +} + +bool_t acdb_tree_is_tree(AcdbTreeNode *tnode) +{ + return !acdb_tree_is_leaf(tnode); +} + +bool_t acdb_tree_is_balanced(AcdbTreeNode *tnode, int32_t *factor) +{ + //difference = right.depth - left.depth + //-1 - left heavy + // 0 - balanced + // 1 - right heavy + int32_t diff = 0; + + //if both left and right are non-null this is the equivalent of + //diff = tnode->right->depth - tnode->left->depth; + if (!acdb_tree_is_leaf(tnode)) + { + if (!IsNull(tnode->right)) + { + diff += tnode->right->depth; + } + if (!IsNull(tnode->left)) + { + diff += -1 * tnode->left->depth; + } + } + + *factor = diff; + + if (diff < -1 || diff > 1) + return FALSE; + + return TRUE; +} + +void acdb_tree_update_depth(AcdbTreeNode *tnode) +{ + AcdbTreeNode *p_cur_node; + p_cur_node = tnode; + + while (p_cur_node != NULL) + { + if (IsNull(p_cur_node)) + { + break; + } + + if (!acdb_tree_is_leaf(p_cur_node) && !IsNull(p_cur_node)) + { + if (IsNull(p_cur_node->right)) + { + p_cur_node->depth = 1 + p_cur_node->left->depth; + } + else if (IsNull(p_cur_node->left)) + { + p_cur_node->depth = 1 + p_cur_node->right->depth; + } + else + { + p_cur_node->depth = 1 + ACDB_MAX(p_cur_node->left->depth, p_cur_node->right->depth); + } + } + else if (acdb_tree_is_leaf(p_cur_node) && !IsNull(p_cur_node)) + { + p_cur_node->depth = 1; + } + + p_cur_node = p_cur_node->parent; + } + + p_cur_node = NULL; +} + +int32_t acdb_tree_direction(AcdbTreeNode *p_x, AcdbTreeNode *p_y) +{ + if (IsNull(p_x) || IsNull(p_y)) + { + return TREE_DIR_NONE; + } + if (IsNull(p_x->p_struct) || IsNull(p_y->p_struct)) + { + return TREE_DIR_NONE; + } + + int32_t direction = strcmp( + ((KVSubgraphMapBin*)p_x->p_struct)->str_key_vector, + ((KVSubgraphMapBin*)p_y->p_struct)->str_key_vector); + + if (direction < 0) + { + return TREE_DIR_LEFT; + } + else if (direction > 0) + { + return TREE_DIR_RIGHT; + } + + return TREE_DIR_NONE; +} + +void acdb_tree_rotate_right(AcdbTreeNode *p_a, AcdbTreeNode *p_c) +{ + //Left heavy means right rotation + //rotate right + // a + // b => b + //c c a + + AcdbTreeNode *p_b = p_c->parent; + + p_b->parent = p_a->parent; + p_a->parent = p_b; + + if (!IsNull(p_b->right)) + { + p_b->right->parent = p_a; + } + + p_a->left = p_b->right; + p_b->right = p_a; + + if (TREE_DIR_LEFT == acdb_tree_direction(p_b, p_b->parent)) + { + p_b->parent->left = p_b; + } + else if (TREE_DIR_RIGHT == acdb_tree_direction(p_b, p_b->parent)) + { + p_b->parent->right = p_b; + } + + acdb_tree_update_depth(p_a); + acdb_tree_update_depth(p_c); +} + +void acdb_tree_rotate_left(AcdbTreeNode *p_a, AcdbTreeNode *p_c) +{ + //Right heavy means left rotation + //rotate left + //a + // b => b + // c a c + AcdbTreeNode *p_b = p_c->parent; + + p_b->parent = p_a->parent; + p_a->parent = p_b; + + if (!IsNull(p_b->left)) + { + p_b->left->parent = p_a; + } + + p_a->right = p_b->left; + p_b->left = p_a; + + if (TREE_DIR_LEFT == acdb_tree_direction(p_b, p_b->parent)) + { + p_b->parent->left = p_b; + } + else if (TREE_DIR_RIGHT == acdb_tree_direction(p_b, p_b->parent)) + { + p_b->parent->right = p_b; + } + + acdb_tree_update_depth(p_a); + acdb_tree_update_depth(p_c); +} + +void acdb_tree_rotate(AcdbTreeNode *p_a, AcdbTreeNode *p_c, int32_t factor) +{ + //a - grand parent + //b - parent + //c - child + AcdbTreeNode *p_b = p_c->parent; + + //Single Rotation (Left, Right) + if (factor < -1 && TREE_DIR_LEFT == acdb_tree_direction(p_c, p_b)) + { + acdb_tree_rotate_right(p_a, p_c); + } + else if (factor > 1 && TREE_DIR_RIGHT == acdb_tree_direction(p_c, p_b)) + { + acdb_tree_rotate_left(p_a, p_c); + } + + //Double Rotation (Left-Right, Right-Left) + else if (factor < -1 && TREE_DIR_RIGHT == acdb_tree_direction(p_c, p_b)) + { + //Left heavy means right rotation + //Left-Right, rotate left, the rotate right + // a a + // b => c => c + // c b b a + //rotate_left(p_b, p_c); + + p_c->parent = p_b->parent; + p_b->parent = p_c; + p_a->left = p_c; + + p_b->right = p_c->left; + p_c->left = p_b; + + acdb_tree_rotate_right(p_a, p_b); + } + else if (factor > 1 && TREE_DIR_LEFT == acdb_tree_direction(p_c, p_b)) + { + //Right heavy means left rotation + //Right-Left, rotate right, the rotate left + //a a + // b => c => c + //c b a b + //rotate_right(p_b, p_c); + + p_c->parent = p_b->parent; + p_b->parent = p_c; + p_a->right = p_c; + + p_b->left = p_c->right; + p_c->right = p_b; + + acdb_tree_rotate_left(p_a, p_b); + } +} + +int32_t acdb_stack_push(LinkedList* stack, LinkedListNode* node) +{ + if (stack->length == 0) + { + stack->p_head = node; + + stack->p_tail = node; + + stack->length++; + } + else + { + //get what head is currently pointing to and point it to the inserted bin_node + //stack->p_head->p_next = node; + + node->p_next = stack->p_head; + //set the inserted bin_node to tail + stack->p_head = node; + + stack->length++; + } + + return 0; +} + +int32_t acdb_stack_pop(LinkedList* stack, LinkedListNode** node) +{ + //(*node)->p_struct = stack->p_head->p_struct; + *node = stack->p_head; + + if (!IsNull(stack->p_head->p_next)) + { + stack->p_head = stack->p_head->p_next; + } + else + { + stack->p_head = NULL; + stack->p_tail = NULL; + } + + if (stack->length != 0) + { + stack->length--; + } + + return 0; +} + +KVSubgraphMapBin *acdb_heap_create_map_bin(void) +{ + KVSubgraphMapBin *bin = ACDB_MALLOC(KVSubgraphMapBin, 1); + + if (IsNull(bin)) + return NULL; + + bin->str_key_vector_size = 0; + bin->str_key_vector = NULL; + bin->map = NULL; + + return bin; +} + +AcdbTreeNode *acdb_heap_create_tree_node(void *p_struct) +{ + AcdbTreeNode *bin_node = ACDB_MALLOC(AcdbTreeNode, 1); + + if (IsNull(bin_node)) + return NULL; + + bin_node->depth = 1; + bin_node->left = NULL; + bin_node->right = NULL; + bin_node->parent = NULL; + bin_node->p_struct = p_struct; + + return bin_node; +} + +LinkedListNode *acdb_heap_create_list_node(void *p_struct) +{ + LinkedListNode *lnode = ACDB_MALLOC(LinkedListNode, 1); + + if (lnode == NULL) return NULL; + + lnode->p_next = NULL; + lnode->p_struct = p_struct; + + return lnode; +} + +void acdb_heap_free_persistance_data( + AcdbDeltaPersistanceData *persistance_data) +{ + if (IsNull(persistance_data)) return; + + AcdbDeltaModuleCalData *p_cal_data = NULL; + LinkedListNode *cur_node = persistance_data->cal_data_list.p_head; + + while (!(IsNull(cur_node))) + { + if (!IsNull(cur_node->p_struct)) + { + p_cal_data = ((AcdbDeltaModuleCalData*)cur_node->p_struct); + ACDB_FREE((uint8_t*)p_cal_data->param_payload); + ACDB_FREE(p_cal_data); + } + + cur_node = cur_node->p_next; + } + + AcdbListClear(&persistance_data->cal_data_list); + + p_cal_data = NULL; + cur_node = NULL; +} + +void acdb_heap_free_key_vector_data(KeyVectorType key_vector_type, + void* key_vector_data) +{ + AcdbKeyValuePair* kv_pair = NULL; + if (IsNull(key_vector_data)) return; + + switch (key_vector_type) + { + case TAG_KEY_VECTOR: + kv_pair = ((AcdbModuleTag*) + key_vector_data)->tag_key_vector.graph_key_vector; + + if(!IsNull(kv_pair)) ACDB_FREE(kv_pair); + + break; + case CAL_KEY_VECTOR: + kv_pair = ((AcdbGraphKeyVector*) + key_vector_data)->graph_key_vector; + + if (!IsNull(kv_pair)) ACDB_FREE(kv_pair); + + break; + default: + return; + } + + ACDB_FREE(key_vector_data); +} + +void acdb_heap_free_subgraph_data(AcdbDeltaSubgraphData* subgraph_data) +{ + if (IsNull(subgraph_data)) return; + + acdb_heap_free_persistance_data(&subgraph_data->non_global_data); + acdb_heap_free_persistance_data(&subgraph_data->global_data); + ACDB_FREE(subgraph_data); +} + +void acdb_heap_free_map(acdb_delta_data_map_t *map) +{ + if (IsNull(map)) return; + + //AcdbDeltaModuleCalData *p_cal_data = NULL; + LinkedListNode *sg_data_node = NULL; + AcdbDeltaSubgraphData *sg_data = NULL; + + sg_data_node = map->subgraph_data_list.p_head; + + do + { + if (IsNull(sg_data_node)) break; + + sg_data = (AcdbDeltaSubgraphData*)sg_data_node->p_struct; + acdb_heap_free_persistance_data(&sg_data->non_global_data); + acdb_heap_free_persistance_data(&sg_data->global_data); + ACDB_FREE(sg_data); + + } while (TRUE != AcdbListSetNext(&sg_data_node)); + + AcdbListClear(&map->subgraph_data_list); + + acdb_heap_free_key_vector_data(map->key_vector_type, map->key_vector_data); + ACDB_FREE(map); +} + +void acdb_heap_free_bin(KVSubgraphMapBin **bin) +{ + acdb_heap_free_map((*bin)->map); + ACDB_FREE((*bin)->str_key_vector); + ACDB_FREE(*bin); + *bin = NULL; +} + +/** +* \breif acdb_heap_insert +* Insert a node into the tree +* +* \return 0 on succes, non-zero on failure +*/ +int32_t acdb_heap_insert(acdb_heap_handle_t handle, AcdbTreeNode *tnode) +{ + int32_t factor = 0; + AcdbTreeNode *t = NULL; + AcdbTreeNode *u = NULL; + AcdbHeapInfo* db_heap = NULL; + + if (IsNull(handle)) + return AR_EHANDLE; + + db_heap = (AcdbHeapInfo*)handle; + t = db_heap->root; + + if (TRUE == acdb_tree_is_tree_empty(t)) + { + db_heap->root = tnode; + return 0; + } + + while (TRUE) + { + if (TREE_DIR_LEFT == acdb_tree_direction(tnode, t)) + { + if (t->left == NULL) + { + t->left = tnode; + tnode->parent = t; + acdb_tree_update_depth(t); + break; + } + else + { + t = t->left; + } + } + else if (TREE_DIR_RIGHT == acdb_tree_direction(tnode, t)) + { + if (t->right == NULL) + { + t->right = tnode; + tnode->parent = t; + acdb_tree_update_depth(t); + break; + } + else + { + t = t->right; + } + } + else + { + break; + } + } + + //Check balance and rotate when nessesary. Set the new root + u = tnode; + while (t != NULL) + { + if (acdb_tree_is_balanced(t, &factor)) + { + if (t->parent == NULL) + { + db_heap->root = t; + } + + if (t->depth - u->depth >= 2) + { + u = u->parent; + } + + t = t->parent; + } + else + { + //t - grandparent + // - parent + //u - child + acdb_tree_rotate(t, u, factor); + } + } + + return AR_EOK; +} + +//int32_t acdb_heap_remove(TreeNode *tnode) +//{ +// int32_t status = AR_ENOTIMPL; +// //the reverse of insert +// //copy the same code but instead of inserting the node, ACDB_FREE the memory associated with the node +// return status; +//} + +int32_t acdb_heap_get_bin(acdb_heap_handle_t handle, + size_t size_str_key_vector, + char* str_key_vector, KVSubgraphMapBin **bin) +{ + int32_t status = AR_EOK; + int32_t tree_dir = TREE_DIR_NONE; + AcdbTreeNode *t = NULL; + AcdbTreeNode tnode; + KVSubgraphMapBin tmp_bin; + AcdbHeapInfo* db_heap = NULL; + + if (IsNull(handle)) + return AR_EHANDLE; + + db_heap = (AcdbHeapInfo*)handle; + t = db_heap->root; + + if (TRUE == acdb_tree_is_tree_empty(t)) + { + return AR_ENOTEXIST; + } + + tmp_bin.str_key_vector = str_key_vector; + tmp_bin.str_key_vector_size = (uint32_t)(size_str_key_vector); + tnode.depth = 1; + tnode.left = NULL; + tnode.right = NULL; + tnode.parent = NULL; + tnode.p_struct = &tmp_bin; + + while (TRUE) + { + tree_dir = acdb_tree_direction(&tnode, t); + + switch (tree_dir) + { + case TREE_DIR_LEFT: + { + if (t->left == NULL) + { + status = AR_ENOTEXIST; + break; + } + + t = t->left; + break; + } + case TREE_DIR_RIGHT: + { + if (t->right == NULL) + { + status = AR_ENOTEXIST; + break; + } + + t = t->right; + break; + } + case TREE_DIR_NONE: + { + *bin = (KVSubgraphMapBin*)t->p_struct; + break; + } + default: + break; + } + + if (TREE_DIR_NONE == tree_dir || + AR_EOK != status) break; + } + + tmp_bin.str_key_vector = NULL; + tmp_bin.str_key_vector_size = 0; + t = NULL; + + return status; +} + +/* --------------------------------------------------------------------------- +* IOCTL Command Functions +*--------------------------------------------------------------------------- */ + +int32_t acdb_heap_init(void) +{ + int32_t status = AR_EOK; + + if (!acdb_heap_context.heap_lock) + { + status = ar_osal_mutex_create(&acdb_heap_context.heap_lock); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: failed to create acdb client mutex", + status); + } + } + return status; +} + +int32_t acdb_heap_add_database(uint32_t vm_id, acdb_heap_handle_t *handle) +{ + int32_t status = AR_EOK; + int32_t index = 0; + + ACDB_MUTEX_LOCK(acdb_heap_context.heap_lock); + + /* find next avalible slot */ + for (index = 0; index < MAX_ACDB_FILE_COUNT; index++) + { + if (IsNull(acdb_heap_context.heap_info[index])) + break; + } + + if (MAX_ACDB_FILE_COUNT == index) + index--; + + acdb_heap_context.heap_count++; + acdb_heap_context.heap_info[index] = ACDB_MALLOC(AcdbHeapInfo, 1); + + ACDB_MUTEX_UNLOCK(acdb_heap_context.heap_lock); + + ar_mem_set(acdb_heap_context.heap_info[index], 0, sizeof(AcdbHeapInfo)); + + acdb_heap_context.heap_info[index]->vm_id = vm_id; + + *handle = acdb_heap_context.heap_info[index]; + return status; +} + +int32_t acdb_heap_remove_database(acdb_heap_handle_t *handle) +{ + int32_t status = AR_EOK; + AcdbHeapInfo* db_heap = NULL; + + if (IsNull(handle)) + return AR_EHANDLE; + + db_heap = (AcdbHeapInfo*)handle; + + if (IsNull(db_heap)) + return AR_EBADPARAM; + + status = acdb_heap_clear((acdb_heap_handle_t)db_heap); + if (AR_FAILED(status)) + { + ACDB_DBG("Error[%d]: Failed to clear heap for VM ID %d", + status, db_heap->vm_id); + } + + acdb_heap_context.heap_info[db_heap->database_index] = NULL; + ACDB_FREE(db_heap); + + ACDB_MUTEX_LOCK(acdb_heap_context.heap_lock); + + if(acdb_heap_context.heap_count > 0) + acdb_heap_context.heap_count--; + + ACDB_MUTEX_UNLOCK(acdb_heap_context.heap_lock); + + return status; +} + +int32_t acdb_heap_add_delta_data_map( + bool_t should_use_active_handle, + acdb_heap_map_handle_info_t* info) +{ + int32_t status = AR_EOK; + size_t size_str_key_vector = 0; + char_t* str_key_vector = NULL; + AcdbTreeNode* bin_node = NULL; + KVSubgraphMapBin* bin = NULL; + AcdbGraphKeyVector *map_key_vector = NULL; + acdb_context_handle_t *ctx_handle = NULL; + acdb_heap_handle_t heap_handle = NULL; + + if (IsNull(info)) + return AR_EBADPARAM; + + ctx_handle = acdb_ctx_man_get_active_handle(); + + if (should_use_active_handle && IsNull(ctx_handle)) + return AR_EHANDLE; + + heap_handle = should_use_active_handle? + ctx_handle->heap_handle: info->handle; + + if (IsNull(heap_handle)) + return AR_EHANDLE; + + map_key_vector = get_key_vector_from_map(info->map); + + if (IsNull(map_key_vector)) + return AR_EBADPARAM; + + str_key_vector = acdb_heap_key_vector_to_string( + map_key_vector, &size_str_key_vector); + + /* Check to see if Tree has the appropriate bin + * Locate bin and append to linked list */ + status = acdb_heap_get_bin(heap_handle, + size_str_key_vector, str_key_vector, &bin); + if (AR_SUCCEEDED(status)) + { + goto end; + } + else + { + //Create new bin and insert into tree + bin = acdb_heap_create_map_bin(); + if (IsNull(bin)) + { + status = AR_ENOMEMORY; + goto end; + } + + bin_node = acdb_heap_create_tree_node(bin); + if (IsNull(bin_node)) + { + status = AR_ENOMEMORY; + goto end; + } + + bin->str_key_vector = str_key_vector; + bin->str_key_vector_size = (uint32_t)(size_str_key_vector); + bin->map = info->map; + + acdb_heap_insert(heap_handle, bin_node); + status = AR_EOK; + } + +end: + if (AR_FAILED(status)) + { + ACDB_FREE(bin_node); + ACDB_FREE(bin); + ACDB_FREE(str_key_vector); + } + + return status; +} + +int32_t acdb_heap_get_ckv_subgraph_map( + const AcdbGraphKeyVector *cal_key_vector, + acdb_delta_data_map_t** map) +{ + int32_t status = AR_EOK; + KVSubgraphMapBin *bin = NULL; + AcdbGraphKeyVector *map_key_vector = NULL; + acdb_delta_data_map_t *tmp_map = NULL; + size_t size_str_key_vector = 0; + acdb_context_handle_t* handle = NULL; + char* str_key_vector = NULL; + + handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(handle) || IsNull(handle->heap_handle)) + return AR_EHANDLE; + + str_key_vector = acdb_heap_key_vector_to_string( + cal_key_vector, &size_str_key_vector); + + status = acdb_heap_get_bin(handle->heap_handle, + size_str_key_vector, str_key_vector, &bin); + + if (AR_EOK != status) + { + //ACDB_ERR("Key Vector not found in heap"); + //LogKeyVector(cal_key_vector); + goto end; + } + + tmp_map = (acdb_delta_data_map_t*)bin->map; + + if (IsNull(tmp_map->key_vector_data)) + { + if (!IsNull(str_key_vector)) + ACDB_DBG("Map key vector data is null for " + "Key Vector<%s>", str_key_vector); + status = AR_ENOTEXIST; + goto end; + } + + switch (tmp_map->key_vector_type) + { + case TAG_KEY_VECTOR: + map_key_vector = &((AcdbModuleTag*)tmp_map->key_vector_data)->tag_key_vector; + break; + case CAL_KEY_VECTOR: + map_key_vector = ((AcdbGraphKeyVector*)tmp_map->key_vector_data); + break; + default: + if (!IsNull(str_key_vector)) + ACDB_DBG("Unable to determine Key Vector type " + "for Key Vector<%s>", str_key_vector); + status = AR_ENOTEXIST; + goto end; + } + + //Compare Sorted Key Vectors and values + if (0 == ACDB_MEM_CMP( + cal_key_vector->graph_key_vector, + map_key_vector->graph_key_vector, + map_key_vector->num_keys * sizeof(AcdbKeyValuePair))) + { + *map = tmp_map; + tmp_map = NULL; + } + + if (IsNull(*map)) + { + if(!IsNull(str_key_vector)) + ACDB_DBG("KV Map does not exist for " + "Key Vector<%s>", str_key_vector); + status = AR_ENOTEXIST; + } + + end: + if (!IsNull(str_key_vector)) + { + ACDB_FREE(str_key_vector); + str_key_vector = NULL; + } + + return status; +} + +/** +* \brief acdb_heap_get_map_list +* Returns an aggregated list of all the maps in the tree using an +* inoder tree traversal(Left, Root, Right). Each node in map_list must be freed by caller. +* \param[out] map_list: A linked list of CKV Bin linked lists +* +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t acdb_heap_get_map_list(LinkedList **map_list) +{ + int32_t status = AR_EOK; + AcdbTreeNode *cur_node = NULL; + LinkedListNode *item_node = NULL; + LinkedList stack = { 0 }; + acdb_context_handle_t* handle = NULL; + AcdbHeapInfo* db_heap = NULL; + + handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(handle) || IsNull(handle->heap_handle)) + return AR_EHANDLE; + + db_heap = (AcdbHeapInfo*)handle->heap_handle; + cur_node = db_heap->root; + + if (IsNull(*map_list)) return AR_EBADPARAM; + + while (cur_node != NULL || stack.length != 0) + { + if (!IsNull(cur_node)) + { + item_node = acdb_heap_create_list_node(cur_node); + if (IsNull(item_node)) + { + return AR_ENOMEMORY; + } + acdb_stack_push(&stack, item_node); + cur_node = cur_node->left; + continue; + } + + if (IsNull(cur_node) && stack.length > 0) + { + acdb_stack_pop(&stack, &item_node); + cur_node = (AcdbTreeNode*)item_node->p_struct; + ACDB_FREE(item_node); + + //Collect Key Vector Subgraph Maps and add/append to list + LinkedListNode *node = acdb_heap_create_list_node( + ((KVSubgraphMapBin*)cur_node->p_struct)->map); + if (IsNull(node)) + { + return AR_ENOMEMORY; + } + AcdbListAppend(*map_list, node); + cur_node = cur_node->right; + } + } + + return status; +} + +/** +* \brief acdb_heap_clear +* Clears all heap data in an inoder fashion +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t acdb_heap_clear(acdb_heap_handle_t handle) +{ + AcdbTreeNode *cur_node = NULL; + AcdbTreeNode *tmp_node = NULL; + AcdbHeapInfo *db_heap = NULL; + LinkedListNode *item_node = NULL; + LinkedList stack = { 0 }; + + if (IsNull(handle)) + return AR_EHANDLE; + + db_heap = (AcdbHeapInfo*)handle; + cur_node = db_heap->root; + + while (cur_node != NULL || stack.length != 0) + { + if (!IsNull(cur_node)) + { + item_node = acdb_heap_create_list_node(cur_node); + if (IsNull(item_node)) + { + return AR_ENOMEMORY; + } + acdb_stack_push(&stack, item_node); + cur_node = cur_node->left; + continue; + } + + if (IsNull(cur_node) && stack.length > 0) + { + acdb_stack_pop(&stack, &item_node); + cur_node = (AcdbTreeNode*)item_node->p_struct; + + KVSubgraphMapBin **bin = (KVSubgraphMapBin**)(&(cur_node->p_struct)); + acdb_heap_free_bin(bin); + //acdb_heap_free_bin(&(CkvSubgraphMapBin*)cur_node->p_struct); + + //Free stack nodes + ACDB_FREE(item_node); + + //Free Tree nodes + tmp_node = cur_node->right; + ACDB_FREE(cur_node); + cur_node = tmp_node; + } + } + + db_heap->root = NULL; + + return AR_EOK; +} + +int32_t acdb_heap_reset(void) +{ + int32_t status = AR_EOK; + AcdbHeapInfo *db_info = NULL; + + for (int32_t i = 0; i < ACDB_MAX_ACDB_FILES; i++) + { + db_info = ACDB_HEAP_DB_INFO_AT_INDEX(i); + + if (IsNull(db_info)) + continue; + + status = acdb_heap_remove_database((acdb_heap_handle_t)db_info); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to remove database heap at index %d", + status, i); + status = AR_EFAILED; + } + } + + ar_osal_mutex_destroy(acdb_heap_context.heap_lock); + ar_mem_set(&acdb_heap_context, 0, sizeof(AcdbHeapContext)); + acdb_heap_context.active_heap_index = -1; + return status; +} + +/** +* \brief acdb_heap_get_heap_info +* Performs an inorder traversal of the heap and collects information + about each heap node in an. This includes: +* 1. Key Vector +* 2. Key Vector Type (CKV or TKV) +* 3. Calibration data size +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t acdb_heap_get_heap_info(AcdbBufferContext *rsp) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t num_nodes = 0; + AcdbTreeNode *cur_node = NULL; + LinkedListNode* item_node = NULL; + LinkedList stack = { 0 }; + acdb_context_handle_t* handle = NULL; + AcdbHeapInfo* db_heap = NULL; + + handle = acdb_ctx_man_get_active_handle(); + + if (IsNull(handle) || IsNull(handle->heap_handle)) + return AR_EHANDLE; + + db_heap = (AcdbHeapInfo*)handle->heap_handle; + + if (IsNull(db_heap)) + return AR_EHANDLE; + + cur_node = db_heap->root; + + //Make room to write number of heap nodes at the end of the function + offset += sizeof(num_nodes); + + if (IsNull(rsp)) return AR_EBADPARAM; + + while (cur_node != NULL || stack.length != 0) + { + if (!IsNull(cur_node)) + { + item_node = acdb_heap_create_list_node(cur_node); + if (IsNull(item_node)) + { + return AR_ENOMEMORY; + } + acdb_stack_push(&stack, item_node); + cur_node = cur_node->left; + continue; + } + + if (IsNull(cur_node) && stack.length > 0) + { + acdb_stack_pop(&stack, &item_node); + cur_node = (AcdbTreeNode*)item_node->p_struct; + ACDB_FREE(item_node); + + KVSubgraphMapBin* bin = (KVSubgraphMapBin*)cur_node->p_struct; + + num_nodes++; + + char* next_int = bin->str_key_vector; + char tmp[HEX_DIGITS + 1]; + uint32_t num_keys = 0; + + offset += sizeof(num_keys);//Make room to write number of keys + /** Get Key Vector + * This loop will write key followed by value for each key value pair. + * The str_key_vector is in the form A0000000A0000001B0000000B0000001 where + * key1.ID = A0000000 key1.Value = A0000001 + * key2.ID = B0000000 key2.Value = B0000001 + */ + while (*next_int != '\0') + { + ACDB_MEM_CPY_SAFE(&tmp[0], HEX_DIGITS, next_int, HEX_DIGITS);//8 bytes for 8 hex digits + + uint32_t key = 0;//(uint32_t)strtoul(&tmp[0], NULL, 16); + + ar_sscanf(&tmp[0], "%08x", &key); + next_int += HEX_DIGITS; + + //write to rsp buf + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(key), &key, sizeof(key)); + offset += sizeof(key); + num_keys++; + } + + next_int = NULL; + num_keys = num_keys / 2; + ACDB_MEM_CPY_SAFE(&rsp->buf[offset - (num_keys * sizeof(AcdbKeyValuePair) + sizeof(num_keys))], + sizeof(num_keys), &num_keys, sizeof(num_keys)); + + //Get Size of map + acdb_delta_data_map_t *map = + (acdb_delta_data_map_t*)bin->map; + + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(map->map_size), &map->map_size, sizeof(map->map_size)); + offset += sizeof(map->map_size); + + //Determine type of Key Vector + uint32_t kv_type = map->key_vector_type; + ACDB_MEM_CPY_SAFE(&rsp->buf[offset], sizeof(kv_type), &kv_type, sizeof(kv_type)); + offset += sizeof(kv_type); + + cur_node = cur_node->right; + } + } + + ACDB_MEM_CPY_SAFE(rsp->buf, sizeof(num_nodes), &num_nodes, sizeof(num_nodes)); + + rsp->bytes_filled = offset; + return status; +} +/** +*============================================================================== +* Public functions +*============================================================================== +*/ +int32_t acdb_heap_ioctl(uint32_t cmd_id, + void *req, uint32_t req_size, + void *rsp, uint32_t rsp_size) +{ + int32_t status = AR_EOK; + + switch (cmd_id) + { + case ACDB_HEAP_CMD_INIT: + { + status = acdb_heap_init(); + break; + } + case ACDB_HEAP_CMD_ADD_DATABASE: + if (IsNull(req) || req_size < sizeof(uint32_t) || + IsNull(rsp) || rsp_size < sizeof(acdb_heap_handle_t)) + return AR_EBADPARAM; + + status = acdb_heap_add_database( + *(uint32_t*)req, (acdb_heap_handle_t*)rsp); + break; + + case ACDB_HEAP_CMD_REMOVE_DATABASE: + if (IsNull(req) || req_size < sizeof(acdb_heap_handle_t)) + return AR_EBADPARAM; + + status = acdb_heap_remove_database((acdb_heap_handle_t*)req); + break; + case ACDB_HEAP_CMD_RESET: + status = acdb_heap_reset(); + break; + case ACDB_HEAP_CMD_CLEAR_DATABASE_HEAP: + { + if (IsNull(req) || req_size < sizeof(acdb_heap_handle_t)) + return AR_EBADPARAM; + + status = acdb_heap_clear((acdb_heap_handle_t)req); + break; + } + case ACDB_HEAP_CMD_ADD_MAP: + { + if (IsNull(req) || req_size < sizeof(acdb_delta_data_map_t)) + return AR_EBADPARAM; + + acdb_heap_map_handle_info_t info = + { + NULL, + (acdb_delta_data_map_t*)req + }; + status = acdb_heap_add_delta_data_map(TRUE, &info); + break; + } + case ACDB_HEAP_CMD_ADD_MAP_USING_HANDLE: + { + if (IsNull(req) || req_size < sizeof(acdb_heap_map_handle_info_t)) + return AR_EBADPARAM; + + status = acdb_heap_add_delta_data_map(FALSE, + (acdb_heap_map_handle_info_t*)req); + break; + } + case ACDB_HEAP_CMD_REMOVE_MAP: + { + //Similar to Get Map but frees the memory associated with the map + break; + } + case ACDB_HEAP_CMD_GET_MAP: + { + if (IsNull(req) || req_size < sizeof(AcdbGraphKeyVector) || + IsNull(rsp) || rsp_size < sizeof(acdb_delta_data_map_t)) + return AR_EBADPARAM; + + status = acdb_heap_get_ckv_subgraph_map( + (AcdbGraphKeyVector*)req, + (acdb_delta_data_map_t**)rsp); + + break; + } + case ACDB_HEAP_CMD_GET_MAP_LIST: + { + if (IsNull(rsp) || rsp_size < sizeof(LinkedList)) + return AR_EBADPARAM; + + status = acdb_heap_get_map_list((LinkedList**)rsp); + break; + } + + case ACDB_HEAP_CMD_GET_HEAP_INFO: + { + if (IsNull(rsp) || rsp_size < sizeof(AcdbBufferContext)) + return AR_EBADPARAM; + + status = acdb_heap_get_heap_info((AcdbBufferContext*)rsp); + break; + } + default: + break; + } + return status; +} diff --git a/acdb/src/acdb_init.c b/acdb/src/acdb_init.c new file mode 100644 index 0000000..e103b25 --- /dev/null +++ b/acdb/src/acdb_init.c @@ -0,0 +1,627 @@ +/** +*============================================================================= +* \file acdb_init.c +* +* \brief +* Handles the initialization and de-initialization of ACDB SW. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ +#include "acdb_init.h" +#include "acdb_init_utility.h" +#include "acdb_parser.h" +#include "acdb_delta_parser.h" +#include "acdb_common.h" +#include "acdb_context_mgr.h" +#include "acdb_file_mgr.h" +#include "acdb_delta_file_mgr.h" +#include "acdb_heap.h" + +/* --------------------------------------------------------------------------- +* Global Data Definitions +*--------------------------------------------------------------------------- */ + +const char* WKSP_FILE_NAME_EXT = ".qwsp"; +const char* ACDB_FILE_NAME_EXT = ".acdb"; + +/* --------------------------------------------------------------------------- +* helper functions +*--------------------------------------------------------------------------- */ + +bool_t AcdbInitDoSwVersionsMatch(acdb_file_version_t* acdb_finfo, + acdb_delta_file_version_t* acdb_delta_finfo) +{ + if ((acdb_finfo->major == acdb_delta_finfo->major) && + (acdb_finfo->minor == acdb_delta_finfo->minor) && + (acdb_finfo->revision == acdb_delta_finfo->revision) && + (acdb_finfo->cpl_info == INF || + acdb_finfo->cpl_info == acdb_delta_finfo->cpl_info)) + { + return TRUE; + } + return FALSE; +} + +void AcdbInitUnloadAcdbFile(AcdbFileManFileInfo* acdb_file_info) +{ + if (!IsNull(acdb_file_info->file_handle)) + { + (void)ar_fclose(acdb_file_info->file_handle); + } + + acdb_file_info->file_handle = NULL; + ACDB_FREE(acdb_file_info->file.buffer); + acdb_file_info->file.buffer = NULL; +} + +void AcdbInitUnloadDeltaFile(AcdbDeltaFileManFileInfo* delta_file_info) +{ + if (!IsNull(delta_file_info->file_handle)) + { + (void)ar_fclose(delta_file_info->file_handle); + } + + delta_file_info->file_handle = NULL; + delta_file_info->exists = FALSE; + delta_file_info->file_size = 0; + + ACDB_FREE(delta_file_info->delta_file_path.path); +} + +int32_t AcdbInitLoadAcdbFile(AcdbFileManFileInfo *acdb_cmd_finfo, + acdb_file_version_t *acdb_finfo) +{ + int32_t status = AR_EOK; + ar_fhandle *fhandle = &acdb_cmd_finfo->file_handle; + acdb_header_v1_t header_v1 = { 0 }; + + if (ACDB_FIND_STR(acdb_cmd_finfo->path, WKSP_FILE_NAME_EXT) != NULL) + { + /* The workspace file is only opened when ARCT(or other ACDB client) + * connects and querries for file information + */ + acdb_cmd_finfo->file_type = ACDB_FILE_TYPE_WORKSPACE; + } + else if (ACDB_FIND_STR(acdb_cmd_finfo->path, ACDB_FILE_NAME_EXT) != NULL) + { + acdb_cmd_finfo->file_type = ACDB_FILE_TYPE_DATABASE; + + status = AcdbInitUtilGetFileData( + acdb_cmd_finfo->path, fhandle, + &acdb_cmd_finfo->file + ); + + if (AR_FAILED(status) || IsNull(fhandle)) + return status; + + status = acdb_parser_validate_file( + &acdb_cmd_finfo->file); + if (AR_FAILED(status)) + return status; + + status = acdb_parser_get_acdb_header_v1( + &acdb_cmd_finfo->file, + &header_v1); + + acdb_finfo->major = header_v1.file_version.major; + acdb_finfo->minor = header_v1.file_version.minor; + acdb_finfo->revision = header_v1.file_version.revision; + acdb_finfo->cpl_info = header_v1.file_version.cpl_info; + + AcdbLogFileInfo(&header_v1); + } + else + { + //Provided file is not an acdb or workspace file + ACDB_ERR("Error[%d]: %s is not a *.qwsp or *.acdb file.", + AR_EBADPARAM, acdb_cmd_finfo->path); + return AR_EBADPARAM; + } + + fhandle = NULL; + return status; +} + +int32_t AcdbInitLoadDeltaFile(AcdbFileManFileInfo *acdb_cmd_finfo, + acdb_file_version_t *acdb_file_version, acdb_path_t *delta_dir, + AcdbDeltaFileManFileInfo *delta_finfo) +{ + int32_t status = AR_EOK; + AcdbInitUtilDeltaInfo delta_info = { 0 }; + ar_fhandle *fhandle = &delta_finfo->file_handle; + + delta_info.properties.file_access_io_flag = ACDB_FUNC_IO_OUT; + status = AcdbInitUtilGetDeltaInfo( + acdb_cmd_finfo->path, + acdb_cmd_finfo->path_length, + delta_dir, &delta_info); + if (AR_FAILED(status)) + { + fhandle = NULL; + delta_finfo->exists = FALSE; + return status; + } + + status = AcdbInitUtilOpenDeltaFile(&delta_info, fhandle); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to open the delta file %s", + status, delta_info.delta_path.path); + goto unload_file; + } + + /* The delta file manager will be responsible for freeing the memory + associated with delta_finfo->delta_file_path.path*/ + delta_finfo->delta_file_path = delta_info.delta_path; + + /* Validate the delta file only if it exists. Otherwise bypass + * validation. */ + if (AR_FOPEN_WRITE_ONLY != delta_info.properties.file_access + && delta_info.properties.file_size > 0) + { + if (ACDB_PARSE_SUCCESS != acdb_delta_parser_is_file_valid( + *fhandle, delta_info.properties.file_size)) + { + status = AR_EFAILED; + goto unload_file; + } + + status = acdb_delta_parser_get_file_version( + *fhandle, delta_info.properties.file_size, + &delta_finfo->file_info); + if (AR_FAILED(status)) + { + goto unload_file; + } + + if (!AcdbInitDoSwVersionsMatch( + acdb_file_version, &delta_finfo->file_info)) + { + goto unload_file; + } + + AcdbLogDeltaFileVersion( + delta_finfo->file_info.major, + delta_finfo->file_info.minor, + delta_finfo->file_info.revision, + delta_finfo->file_info.cpl_info + ); + } + + delta_finfo->exists = TRUE; + delta_finfo->file_size = delta_info.properties.file_size; + delta_finfo->acdb_file_index = acdb_cmd_finfo->file_index; + + /* Set the acdb file version to new delta files */ + if (AR_FOPEN_WRITE_ONLY == delta_info.properties.file_access + && delta_finfo->file_size == 0) + { + ACDB_MEM_CPY_SAFE(&delta_finfo->file_info, sizeof(acdb_file_version_t), + acdb_file_version, sizeof(acdb_file_version_t)); + } + +unload_file: + if(AR_FAILED(status)) + AcdbInitUnloadDeltaFile(delta_finfo); + + return status; +} + +/* --------------------------------------------------------------------------- +* ioctl command implementations +*--------------------------------------------------------------------------- */ + +int32_t acdb_init_layers(void) +{ + int32_t status = AR_EOK; + + ACDB_PKT_LOG_INIT(); + + status = AcdbARHeapInit(); + if (AR_FAILED(status)) + { + return status; + } + + AcdbLogSwVersion( + ACDB_SOFTWARE_VERSION_MAJOR, + ACDB_SOFTWARE_VERSION_MINOR, + ACDB_SOFTWARE_VERSION_REVISION, + ACDB_SOFTWARE_VERSION_CPLINFO); + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_INIT, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to initialize context manager.", status); + return status; + } + status = acdb_file_man_ioctl(ACDB_FILE_MAN_INIT, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to initialize file manager.", status); + return status; + + } + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_INIT, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to initialize delta file manager.", status); + return status; + + } + status = acdb_heap_ioctl(ACDB_HEAP_CMD_INIT, NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to initialize heap manager.", status); + return status; + + } + + return status; +} + +int32_t acdb_init_add_database(acdb_init_database_paths_t *database_paths, + acdb_handle_t *acdb_handle) +{ + int32_t status = AR_EOK; + uint32_t i = 0, j = 0; + uint32_t remaining_file_slots = 0; + uint32_t num_data_files = 0; + bool_t should_ignore_delta_file = FALSE; + bool_t is_writable_path_avalible = FALSE; + acdb_file_version_t acdb_file_version = { 0 }; + AcdbFileManFileInfo *fm_file_info = NULL; + AcdbDeltaFileManFileInfo *dfm_file_info = NULL; + acdb_context_handle_t ctx_handle = { 0 }; + acdb_file_man_context_handle_t fm_ctx_handle = { 0 }; + acdb_file_man_data_files_t fm_db_files = { 0 }; + acdb_file_man_writable_path_info_t writable_path_info = { 0 }; + + if (IsNull(database_paths) || database_paths->num_files == 0) + { + ACDB_ERR("Error[%d]: No database files were provided.", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (database_paths->num_files > ACDB_MAX_FILE_ADD_LIMIT) + { + ACDB_ERR("Error[%d]: The max number of files that can be initalized " + "is %d: one *.qwsp and one *.acdb", AR_EBADPARAM, + ACDB_MAX_FILE_ADD_LIMIT); + return AR_EBADPARAM; + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_GET_AVAILABLE_FILE_SLOTS, + NULL, 0, (uint8_t*)&remaining_file_slots, sizeof(uint32_t)); + if (AR_FAILED(status) || remaining_file_slots < database_paths->num_files) + { + ACDB_ERR("Error[%d]: Only %d/%d file slots available.", AR_ENORESOURCE, + remaining_file_slots, MAX_ACDB_FILE_COUNT); + status = AR_ENORESOURCE; + goto end; + } + + is_writable_path_avalible = !IsNull(database_paths->writable_path.path); + + fm_db_files.num_files = database_paths->num_files; + fm_file_info = ACDB_MALLOC( + AcdbFileManFileInfo, database_paths->num_files); + dfm_file_info = ACDB_MALLOC( + AcdbDeltaFileManFileInfo, database_paths->num_files); + if (IsNull(fm_file_info) || IsNull(dfm_file_info)) + { + ACDB_ERR("Error[%d]: Unable to allocate memory to store " + "acdb data file information", AR_ENOMEMORY); + goto end; + } + + ar_mem_set(fm_file_info, 0, sizeof(AcdbFileManFileInfo) + * database_paths->num_files); + ar_mem_set(dfm_file_info, 0, sizeof(AcdbDeltaFileManFileInfo) + * database_paths->num_files); + + for (i = 0; i < database_paths->num_files; i++) + { + fm_file_info[i].file_index = i; + fm_file_info[i].path_length = + database_paths->acdb_data_files[i].path_length; + fm_file_info[i].path = + database_paths->acdb_data_files[i].path; + + fm_db_files.file_info[i] = &fm_file_info[i]; + + status = AcdbInitLoadAcdbFile(&fm_file_info[i], &acdb_file_version); + if (AR_FAILED(status)) + { + for (j = 0; j < database_paths->num_files; j++) + { + AcdbInitUnloadAcdbFile(&fm_file_info[j]); + AcdbInitUnloadDeltaFile(&dfm_file_info[j]); + } + + ACDB_ERR_MSG_1("Acdb initialization failed.", AR_EFAILED); + status = AR_EFAILED; + goto end; + } + + if (ACDB_FILE_TYPE_WORKSPACE == fm_file_info[i].file_type) continue; + + num_data_files++; + + /* Load delta file */ + if (is_writable_path_avalible) + { + status = AcdbInitLoadDeltaFile( + &fm_file_info[i], &acdb_file_version, + &database_paths->writable_path, &dfm_file_info[i]); + + should_ignore_delta_file = + AR_FAILED(status) || !dfm_file_info[i].exists ? TRUE : FALSE; + } + } + + if (num_data_files == 0) + { + ACDB_ERR("Error[%d]: No *.acdb files were found.", AR_ENORESOURCE); + status = AR_ENORESOURCE; + goto end; + } + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_ADD_DATABASE, + &fm_db_files, sizeof(acdb_file_man_data_files_t), + &fm_ctx_handle, sizeof(fm_ctx_handle)); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to add database file " + "set (*.qwsp/*.acdb).", status); + goto end; + } + + uint32_t findex = 0; + for (i = 0; i < database_paths->num_files; i++) + { + if (ACDB_FILE_TYPE_WORKSPACE == fm_file_info[i].file_type) + continue; + + status = acdb_heap_ioctl(ACDB_HEAP_CMD_ADD_DATABASE, + (uint8_t*)&fm_ctx_handle.vm_id, sizeof(uint32_t), + (uint8_t*)&ctx_handle.heap_handle, sizeof(acdb_heap_handle_t)); + + if (is_writable_path_avalible && !should_ignore_delta_file) + { + dfm_file_info[i].vm_id = fm_ctx_handle.vm_id; + dfm_file_info[i].acdb_file_index = findex; + + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_ADD_DATABASE, + &dfm_file_info[i], sizeof(AcdbDeltaFileManFileInfo), + &ctx_handle.delta_manager_handle, sizeof(acdb_delta_file_man_handle_t)); + if (AR_EOK != status) + { + /*if we fail to add the delta file, remove it from memory and continue */ + AcdbInitUnloadDeltaFile(&dfm_file_info[i]); + ACDB_ERR_MSG_1("Failed to initialize delta acdb files.", + status); + goto end; + } + } + + ctx_handle.vm_id = fm_ctx_handle.vm_id; + ctx_handle.file_manager_handle = fm_ctx_handle.file_man_handle; + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_ADD_DATABASE, + (void*)&ctx_handle, sizeof(acdb_context_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + //the context manager should not fail. This is a serious error + ACDB_ERR("Error[%d]: Unable to update context manager " + "with new database", status); + goto end; + } + + /* Load the contents of the delta file into the heap */ + + if (is_writable_path_avalible && !should_ignore_delta_file) + { + uint32_t delta_status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_INIT_HEAP, + &ctx_handle, sizeof(acdb_context_handle_t), + NULL, 0); + if (AR_EOK != delta_status) + { + ACDB_ERR("Warning[%d]: Unable to load delta file into heap", delta_status); + status = delta_status; + } + } + + if (is_writable_path_avalible) + { + /* The delta file path serves two purposes: + * 1. to store the delta files + * 2. to store temporary files generated by ATS clients (e.g ARCT) + * The delta file path will be set as the temporary file path managed + * by the File Manager + */ + writable_path_info.handle = ctx_handle.file_manager_handle; + writable_path_info.writable_path = database_paths->writable_path; + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_SET_WRITABLE_PATH, + &writable_path_info, sizeof(acdb_file_man_writable_path_info_t), + NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to set temporary file path using " + "the delta file path. Skipping..", status); + status = AR_EOK; + } + } + else + { + ACDB_DBG("Unable to set temporary file path using " + "the delta file path. No path was provided. Skipping.."); + } + + findex++; + } + + if (acdb_handle) + { + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_GET_ACDB_CLIENT_HANDLE, + &fm_ctx_handle.vm_id, sizeof(uint32_t), + acdb_handle, sizeof(acdb_handle_t)); + } + +end: + + ACDB_FREE(fm_file_info); + ACDB_FREE(dfm_file_info); + return status; +} + +int32_t acdb_init_remove_database(acdb_handle_t *acdb_handle) +{ + int32_t status = AR_EOK; + acdb_context_handle_t *ctx_handle = NULL; + uint32_t vm_id = 0; + + if (IsNull(acdb_handle)) + return AR_EHANDLE; + + vm_id = ACDB_HANDLE_TO_UINT(acdb_handle); + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_GET_CONTEXT_HANDLE, + &vm_id, sizeof(uint32_t), + &ctx_handle, sizeof(acdb_context_handle_t)); + + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to get context handle", status); + return status; + } + + /* Try to remove database data even if removing data + * from one layers fails */ + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_REMOVE_DATABASE, + ctx_handle->file_manager_handle, + sizeof(acdb_file_man_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to remove " + "database data from file manager.", status); + } + + //Does the added database have delta data? if so, remove the delta data + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_REMOVE_DATABASE, + ctx_handle->delta_manager_handle, + sizeof(acdb_delta_file_man_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to remove " + "database data from delta file manager.", status); + } + + status = acdb_heap_ioctl(ACDB_HEAP_CMD_REMOVE_DATABASE, + ctx_handle->heap_handle, sizeof(acdb_heap_handle_t), + NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to remove " + "database data from heap manager.", status); + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_REMOVE_DATABASE, + acdb_handle, sizeof(acdb_handle_t), NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to remove " + "database data from context manager.", status); + } + + return status; +} + +int32_t acdb_init_reset(void) +{ + int32_t status = AR_EOK; + + status = acdb_file_man_ioctl(ACDB_FILE_MAN_RESET, + NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to reset " + "file manager.", status); + } + + status = acdb_delta_data_ioctl(ACDB_DELTA_DATA_CMD_RESET, + NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to reset " + "delta file manager.", status); + } + + status = acdb_heap_ioctl(ACDB_HEAP_CMD_RESET, + NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to reset " + "heap manager.", status); + } + + status = acdb_ctx_man_ioctl(ACDB_CTX_MAN_CMD_RESET, + NULL, 0, NULL, 0); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to reset " + "context manager.", status); + } + + ACDB_PKT_LOG_DEINIT(); + + status = AcdbARHeapDeinit(); + if (AR_FAILED(status)) + { + return status; + } + + return status; +} + +int32_t acdb_init_ioctl(uint32_t cmd_id, + void* req, uint32_t req_size, + void* rsp, uint32_t rsp_size) +{ + __UNREFERENCED_PARAM(rsp); + __UNREFERENCED_PARAM(rsp_size); + + int32_t status = AR_EOK; + + switch (cmd_id) + { + case ACDB_INIT_CMD_INIT: + status = acdb_init_layers(); + break; + case ACDB_INIT_CMD_ADD_DATABASE: + if (IsNull(req) || req_size < sizeof(acdb_init_database_paths_t)) + return AR_EBADPARAM; + + status = acdb_init_add_database((acdb_init_database_paths_t*)req, + (acdb_handle_t*)rsp); + break; + case ACDB_INIT_CMD_REMOVE_DATABASE: + if (IsNull(req) || req_size < sizeof(acdb_handle_t)) + return AR_EBADPARAM; + + status = acdb_init_remove_database((acdb_handle_t*)req); + break; + case ACDB_INIT_CMD_RESET: + status = acdb_init_reset(); + break; + default: + status = AR_EUNSUPPORTED; + ACDB_ERR("Error[%d]: Unknown command id %d", cmd_id); + break; + } + return status; +} diff --git a/acdb/src/acdb_init_utility.c b/acdb/src/acdb_init_utility.c new file mode 100644 index 0000000..94928a6 --- /dev/null +++ b/acdb/src/acdb_init_utility.c @@ -0,0 +1,829 @@ +/** +*============================================================================= +* \file acdb_init_utility.c +* +* \brief +* Contains utility fucntions for ACDB SW initialiation. This inclues +* initializaing the ACDB Data and ACDB Delta Data files. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- + * Include Files + *--------------------------------------------------------------------------- */ + +#include "ar_osal_error.h" +#include "ar_osal_file_io.h" +#include "acdb_common.h" +#include "acdb_init_utility.h" +#include "acdb_types.h" +#include "acdb_parser.h" +#include + +int32_t AcbdInitLoadInMemFile(const char_t* fname, ar_fhandle fhandle, acdb_buffer_t* in_mem_file) +{ + in_mem_file->size = (uint32_t)ar_fsize(fhandle); + + if (in_mem_file->size == 0) + { + ACDB_ERR("Error[%d]: The file %s is empty", AR_EBADPARAM, fname); + return AR_EBADPARAM; + } + + int32_t status = ar_fmap(fhandle, &in_mem_file->buffer); + if (AR_EUNSUPPORTED == status) + { + in_mem_file->buffer = (void*)ACDB_MALLOC(uint8_t, in_mem_file->size); + + if (IsNull(in_mem_file->buffer)) + { + ACDB_ERR("Error[%d]: Not enough memory to allocate for file %s", AR_ENOMEMORY, fname); + return AR_ENOMEMORY; + } + status = AR_EOK; + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to map memory for file %s", status, fname); + } + + return status; +} + +int32_t AcbdInitUnloadInMemFile(acdb_buffer_t* in_mem_file) +{ + if (IsNull(in_mem_file)) + { + ACDB_ERR("Error[%d]: in_mem_file pointer is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + in_mem_file->size = 0; + + int32_t status = ar_funmap(in_mem_file->buffer); + if (AR_EUNSUPPORTED == status) + { + ACDB_FREE(in_mem_file->buffer); + } + else if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to unmap memory for in_mem_file", status); + } + + return status; +} + +void AcdbLogSwVersion(uint32_t major, uint32_t minor, uint32_t revision, uint32_t cpl) +{ + ACDB_PKT_LOG_DATA("ACDB_SW_MAJOR", &(major), sizeof(major)); + ACDB_PKT_LOG_DATA("ACDB_SW_MINOR", &(minor), sizeof(minor)); + ACDB_PKT_LOG_DATA("ACDB_SW_REVISION", &(revision), sizeof(revision)); + + if (cpl != INF) + { + ACDB_PKT_LOG_DATA("ACDB_SW_CPL", &(cpl), sizeof(cpl)); + ACDB_INFO("ACDB SW Version %u.%u.%u.%u", major, minor, revision, cpl); + } + else + { + ACDB_INFO("ACDB SW Version %u.%u.%u", major, minor, revision); + } +} + +void AcdbLogDeltaSwVersion(uint32_t major, uint32_t minor, uint32_t revision, uint32_t cpl) +{ + ACDB_PKT_LOG_DATA("ACDB_DELTA_SW_MAJOR", &(major), sizeof(major)); + ACDB_PKT_LOG_DATA("ACDB_DELTA_SW_MINOR", &(minor), sizeof(minor)); + ACDB_PKT_LOG_DATA("ACDB_DELTA_SW_REVISION", &(revision), sizeof(revision)); + + if (cpl != INF) + { + ACDB_PKT_LOG_DATA("ACDB_DELTA_SW_CPL", &(cpl), sizeof(cpl)); + ACDB_INFO("ACDB Delta SW Version %u.%u.%u.%u", major, minor, revision, cpl); + } + else + { + ACDB_INFO("ACDB Delta SW Version %u.%u.%u", major, minor, revision); + } +} + +void AcdbLogDeltaFileVersion(uint32_t major, uint32_t minor, uint32_t revision, uint32_t cpl) +{ + ACDB_PKT_LOG_DATA("ACDB_DELTA_FILE_MAJOR", &(major), sizeof(major)); + ACDB_PKT_LOG_DATA("ACDB_DELTA_FILE_MINOR", &(minor), sizeof(minor)); + ACDB_PKT_LOG_DATA("ACDB_DELTA_FILE_REVISION", &(revision), sizeof(revision)); + + if (cpl != INF) + { + ACDB_PKT_LOG_DATA("ACDB_DELTA_FILE_CPL", &(cpl), sizeof(cpl)); + ACDB_INFO("ACDB Delta File Version %u.%u.%u.%u", major, minor, revision, cpl); + } + else + { + ACDB_INFO("ACDB Delta File Version %u.%u.%u", major, minor, revision); + } +} + +void AcdbLogFileInfo(acdb_header_v1_t *header) +{ + time_t date_time = (time_t)header->date_modified; + struct tm *gm_date_time = NULL; + char_t* date_time_str = NULL; + const uint32_t description_length = 100; + char_t oem_info[100] = ""; + + gm_date_time = gmtime(&date_time); + + if (gm_date_time) + date_time_str = asctime(gm_date_time); + + if (256 == header->oem_info->legnth) + { + //trim and leave .. + ar_strcpy(&oem_info[0], description_length, + &header->oem_info->description[0], description_length); + + oem_info[description_length - 1] = '\0'; + oem_info[description_length - 2] = '.'; + oem_info[description_length - 3] = '.'; + } + else + { + ar_strcpy(&oem_info[0], header->oem_info->legnth, + &header->oem_info->description[0], header->oem_info->legnth); + } + + ACDB_INFO("\nOEM Info: %s", oem_info); + + if (!date_time_str) + { + ACDB_INFO( + "\nACDB File Version : v%u.%u.%u.%u", + header->file_version.major, + header->file_version.minor, + header->file_version.revision, + header->file_version.cpl_info); + } + else + { + ACDB_INFO( + "\nACDB File Version : v%u.%u.%u.%u" + "\nLast Modified : %s", + header->file_version.major, + header->file_version.minor, + header->file_version.revision, + header->file_version.cpl_info, + date_time_str); + } +} + +int32_t AcdbInitUtilGetFileData(const char_t* fname, ar_fhandle* fhandle, + acdb_buffer_t *in_mem_file) +{ + int32_t status = AR_EOK; + size_t bytes_read = 0; + + if (IsNull(fname) || IsNull(in_mem_file)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = ar_fopen(fhandle, fname, AR_FOPEN_READ_ONLY); + if (AR_FAILED(status) || fhandle == NULL) + { + ACDB_ERR("Error[%d]: Unable to open file: %s", status, fname); + return status; + } + + status = ar_fseek(*fhandle, 0, AR_FSEEK_BEGIN); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to fseek file: %s", status, fname); + return AR_EFAILED; + } + + status = AcbdInitLoadInMemFile(fname, *fhandle, in_mem_file); + if (AR_FAILED(status)) + { + ACDB_ERR("ERROR[%d]: Failed to load in_mem_file %s", status, fname); + return status; + } + + status = ar_fread(*fhandle, in_mem_file->buffer, in_mem_file->size, &bytes_read); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to read file: %s", status, fname); + goto end; + } + + if (bytes_read != in_mem_file->size) + { + status = AR_EBADPARAM; + ACDB_ERR("Error[%d]: File size does not match " + "the number of bytes read: %s", status, fname); + } + +end: + if (AR_FAILED(status)) + { + AcbdInitUnloadInMemFile(in_mem_file); + } + + return status; +} + +char *GetDeltaFileName_OLD(const char* fname, size_t fname_len, + acdb_path_t *delta_dir, uint32_t *delta_fpath_length) +{ + char* delta_fname = NULL; + char* delta_fname_ext = "delta"; + size_t ext_size = 6; + size_t slash_size = 0; + size_t delta_fname_size = 0; + size_t remaining_size = 0; + uint32_t delta_dir_length = 0; + + if (fname == NULL || fname_len == 0) + { + return NULL; + } + + fname_len = ar_strlen(fname, + ACDB_MAX_PATH_LENGTH); + + if (delta_dir == NULL) + { + //Delta file path is null, so use acdb file path and concatenate "delta" + delta_fname_size = fname_len + ar_strlen(delta_fname_ext, ext_size) + 1; + delta_fname = ACDB_MALLOC(char, delta_fname_size); + + if (IsNull(delta_fname)) return NULL; + + if (delta_fname != NULL) + { + ACDB_STR_CPY_SAFE(delta_fname, delta_fname_size, fname, fname_len); + ACDB_STR_CAT_SAFE(delta_fname, delta_fname_size, delta_fname_ext, + ar_strlen(delta_fname_ext, ext_size)); + } + } + else + { + //Delta file path is provided, so form the full path + //Ex. ..\acdb_data + \ + acdb_data.acdb + delta + uint32_t acdb_file_name_len = 0; + uint32_t offset = 0; + int32_t char_index = (int32_t)fname_len; + char *slash = NULL; + + /* Detect windows\linux style path prefixes + Absolute Paths + Ex. C:\acdb_data\ar_acdb.acdb + Ex. /acdb_data/ar_acdb.acdb + Relative paths + Ex. ..\acdb_data\ar_acdb.acdb + Ex. ../acdb_data/ar_acdb.acdb + */ + //if (!((fname[0] == '.' && fname[1] == '.') || + // (fname[1] == ':' && fname[2] == '\\') || + // fname[0] == '/')) + //{ + // char_index = 0; + //} + + while (--char_index > 0) + { + if (fname[char_index] == '\\' || + fname[char_index] == '/') + { + if (fname[char_index] == '/') + { + slash = "/"; + slash_size = 2; + } + + if (fname[char_index] == '\\') + { + slash = "\\"; + slash_size = 3; + } + + char_index++; + break; + } + } + + acdb_file_name_len = (uint32_t)fname_len - char_index; + delta_dir_length = (uint32_t)ar_strlen(delta_dir->path, + delta_dir->path_length); + + if (IsNull(slash)) + { + delta_fname_size = + delta_dir_length + + (size_t)acdb_file_name_len + + ar_strlen(delta_fname_ext, ext_size) + 1UL; + } + else + { + delta_fname_size = + delta_dir_length + + ar_strlen(slash, slash_size) + + acdb_file_name_len + + (ar_strlen(delta_fname_ext, ext_size) + 1); + } + + delta_fname = ACDB_MALLOC(char, delta_fname_size);//account for \0 + + if (IsNull(delta_fname)) return NULL; + + //delta file path: ..\acdb_data + ACDB_STR_CPY_SAFE(delta_fname + offset, delta_fname_size, + delta_dir->path, delta_dir_length); + offset += delta_dir_length; + remaining_size = delta_fname_size - delta_dir_length; + + //slash + if (!IsNull(slash)) + { + ACDB_STR_CPY_SAFE(delta_fname + offset, remaining_size, + slash, ar_strlen(slash, slash_size)); + offset += (uint32_t)ar_strlen(slash, slash_size); + remaining_size = delta_fname_size + - delta_dir_length - ar_strlen(slash, slash_size); + } + + //acdb_data.acdbdelta + ACDB_STR_CPY_SAFE(delta_fname + offset, remaining_size, + fname + char_index, acdb_file_name_len); + offset += acdb_file_name_len; + if (IsNull(slash)) + { + remaining_size = delta_fname_size + - delta_dir_length - acdb_file_name_len; + } + else + { + remaining_size = delta_fname_size + - delta_dir_length + - ar_strlen(slash, slash_size) - acdb_file_name_len; + } + + ACDB_STR_CAT_SAFE(delta_fname, delta_fname_size, + delta_fname_ext, ar_strlen(delta_fname_ext, ext_size)); + + uint32_t delta_file_name_len = + (uint32_t)ar_strlen(delta_fname, delta_fname_size); + if ((uint32_t)delta_fname_size != delta_file_name_len + 1UL) + { + ACDB_FREE(delta_fname); + delta_fname = NULL; + return delta_fname; + } + } + + *delta_fpath_length = (uint32_t)delta_fname_size; + + return delta_fname; +} + +acdb_path_t AcdbInitUtilGetDeltaFilePath( + const char* fname, size_t fname_len, acdb_path_t* delta_dir) +{ + char* delta_fname = NULL; + char* delta_fname_ext = "delta"; + size_t ext_size = 6; + size_t slash_size = 0; + size_t delta_fname_size = 0; + size_t remaining_size = 0; + uint32_t delta_dir_length = 0; + acdb_path_t delta_file_path = { 0 }; + + if (fname == NULL || fname_len == 0) + { + return delta_file_path; + } + + fname_len = ar_strlen(fname, + ACDB_MAX_PATH_LENGTH); + + if (delta_dir == NULL) + { + //Delta file path is null, so use acdb file path and concatenate "delta" + delta_fname_size = fname_len + ar_strlen(delta_fname_ext, ext_size) + 1; + delta_fname = ACDB_MALLOC(char, delta_fname_size); + + if (IsNull(delta_fname)) return delta_file_path; + + if (delta_fname != NULL) + { + ACDB_STR_CPY_SAFE(delta_fname, delta_fname_size, fname, fname_len); + ACDB_STR_CAT_SAFE(delta_fname, delta_fname_size, delta_fname_ext, + ar_strlen(delta_fname_ext, ext_size)); + } + } + else + { + //Delta file path is provided, so form the full path + //Ex. ..\acdb_data + \ + acdb_data.acdb + delta + uint32_t acdb_file_name_len = 0; + uint32_t offset = 0; + int32_t char_index = (int32_t)fname_len; + char* slash = NULL; + + /* Detect windows\linux style path prefixes + Absolute Paths + Ex. C:\acdb_data\ar_acdb.acdb + Ex. /acdb_data/ar_acdb.acdb + Relative paths + Ex. ..\acdb_data\ar_acdb.acdb + Ex. ../acdb_data/ar_acdb.acdb + */ + //if (!((fname[0] == '.' && fname[1] == '.') || + // (fname[1] == ':' && fname[2] == '\\') || + // fname[0] == '/')) + //{ + // char_index = 0; + //} + + while (--char_index > 0) + { + if (fname[char_index] == '\\' || + fname[char_index] == '/') + { + if (fname[char_index] == '/') + { + slash = "/"; + slash_size = 2; + } + + if (fname[char_index] == '\\') + { + slash = "\\"; + slash_size = 3; + } + + char_index++; + break; + } + } + + acdb_file_name_len = (uint32_t)fname_len - char_index; + delta_dir_length = (uint32_t)ar_strlen(delta_dir->path, + delta_dir->path_length); + + if (IsNull(slash)) + { + delta_fname_size = + delta_dir_length + + (size_t)acdb_file_name_len + + ar_strlen(delta_fname_ext, ext_size) + 1UL; + } + else + { + delta_fname_size = + delta_dir_length + + ar_strlen(slash, slash_size) + + acdb_file_name_len + + (ar_strlen(delta_fname_ext, ext_size) + 1); + } + + delta_fname = ACDB_MALLOC(char, delta_fname_size);//account for \0 + + if (IsNull(delta_fname)) return delta_file_path; + + //delta file path: ..\acdb_data + ACDB_STR_CPY_SAFE(delta_fname + offset, delta_fname_size, + delta_dir->path, delta_dir_length); + offset += delta_dir_length; + remaining_size = delta_fname_size - delta_dir_length; + + //slash + if (!IsNull(slash)) + { + ACDB_STR_CPY_SAFE(delta_fname + offset, remaining_size, + slash, ar_strlen(slash, slash_size)); + offset += (uint32_t)ar_strlen(slash, slash_size); + remaining_size = delta_fname_size + - delta_dir_length - ar_strlen(slash, slash_size); + } + + //acdb_data.acdbdelta + ACDB_STR_CPY_SAFE(delta_fname + offset, remaining_size, + fname + char_index, acdb_file_name_len); + offset += acdb_file_name_len; + if (IsNull(slash)) + { + remaining_size = delta_fname_size + - delta_dir_length - acdb_file_name_len; + } + else + { + remaining_size = delta_fname_size + - delta_dir_length + - ar_strlen(slash, slash_size) - acdb_file_name_len; + } + + ACDB_STR_CAT_SAFE(delta_fname, delta_fname_size, + delta_fname_ext, ar_strlen(delta_fname_ext, ext_size)); + + uint32_t delta_file_name_len = + (uint32_t)ar_strlen(delta_fname, delta_fname_size); + if ((uint32_t)delta_fname_size != delta_file_name_len + 1UL) + { + ACDB_FREE(delta_fname); + delta_fname = NULL; + return delta_file_path; + } + } + + delta_file_path.path_length = (uint32_t)delta_fname_size; + delta_file_path.path = delta_fname; + + return delta_file_path; +} + +int32_t AcdbInitUtilDeleteDeltaFileData(const char_t* acdb_file_path, + uint32_t acdb_file_path_length, acdb_path_t* delta_dir) +{ + int32_t status = ACDB_UTILITY_INIT_SUCCESS; + int32_t delta_result = AR_EOK; + acdb_path_t delta_file_path = { 0 }; + + delta_file_path = AcdbInitUtilGetDeltaFilePath( + acdb_file_path, acdb_file_path_length, delta_dir); + if (IsNull(delta_file_path.path)) + { + ACDB_ERR("Unable to get delta file path string"); + return ACDB_UTILITY_INIT_FAILURE; + } + else + { + delta_result = ar_fdelete(delta_file_path.path); + if (delta_result != 0) + { + ACDB_ERR("Error[%d]: Unable to delete delta acdb file", delta_result); + status = ACDB_UTILITY_INIT_FAILURE; + } + + ACDB_FREE(delta_file_path.path); + } + + return status; +} + +int32_t AcdbInitUtilGetDeltaInfo( + const char_t* acdb_file_path, uint32_t acdb_file_path_length, + acdb_path_t* delta_dir, AcdbInitUtilDeltaInfo *info) +{ + int32_t status = AR_EOK; + ar_fhandle* fhandle = NULL; + acdb_path_t delta_file_path = { 0 }; + + if (IsNull(info)) + { + ACDB_ERR("Error[%d]: The info input parameters is null", + AR_EBADPARAM); + + return AR_EBADPARAM; + } + + if (info->properties.file_access_io_flag == ACDB_FUNC_IO_UNUSED) + { + ACDB_ERR("Error[%d]: The file access IO flag is not set", + AR_EBADPARAM); + + return AR_EBADPARAM; + } + + if (IsNull(acdb_file_path) || acdb_file_path_length == 0) + { + ACDB_ERR("Error[%d]: The input file name is null or empty", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + delta_file_path = AcdbInitUtilGetDeltaFilePath( + acdb_file_path, (size_t)acdb_file_path_length, + delta_dir); + if (delta_file_path.path == NULL) + { + ACDB_ERR("Error[%d]: The delta file path is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + + info->properties.file_size = 0; + info->delta_path = delta_file_path; + + /* Try opening the delta file with RW, then RO to determine the + * access type */ + fhandle = ACDB_MALLOC(ar_fhandle, 1); + if (IsNull(fhandle)) + { + ACDB_ERR("Error[%d]: Unable to allocate memory for the file handle", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (info->properties.file_access_io_flag == ACDB_FUNC_IO_OUT) + { + info->properties.file_access = AR_FOPEN_READ_ONLY_WRITE; + status = ar_fopen(fhandle, delta_file_path.path, + info->properties.file_access); + if (status == AR_ENOTEXIST) + { + ACDB_DBG( + "Delta Acdb file does not exist. Creating new file..."); + info->properties.file_access = AR_FOPEN_WRITE_ONLY; + status = ar_fopen(fhandle, delta_file_path.path, + info->properties.file_access); + if (status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: The %s file path does not exist", + status, delta_file_path.path); + } + } + + if (AR_FAILED(status)) + { + info->properties.file_access = AR_FOPEN_READ_ONLY; + status = ar_fopen(fhandle, delta_file_path.path, + info->properties.file_access); + if (status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: The %s file does not exist", + status, delta_file_path.path); + goto end; + } + } + } + else if (info->properties.file_access_io_flag == ACDB_FUNC_IO_IN) + { + status = ar_fopen(fhandle, delta_file_path.path, info->properties.file_access); + if (status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: The %s file path does not exist", + status, delta_file_path.path); + goto end; + } + } + + if (!IsNull(fhandle) && AR_SUCCEEDED(status)) + { + info->properties.file_size = (uint32_t)ar_fsize(*fhandle); + status = ar_fclose(*fhandle); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Unable to close %s", status, delta_file_path.path); + goto end; + } + } + +end: + ACDB_FREE(fhandle); + + return status; +} + +int32_t AcdbInitUtilGetDeltaInfo2(acdb_path_t* delta_file_path, + acdb_init_util_file_properties_t* info) +{ + int32_t status = AR_EOK; + ar_fhandle* fhandle = NULL; + + if (IsNull(info)) + { + ACDB_ERR("Error[%d]: The info input parameters is null", + AR_EBADPARAM); + + return AR_EBADPARAM; + } + + if (info->file_access_io_flag == ACDB_FUNC_IO_UNUSED) + { + ACDB_ERR("Error[%d]: The file access IO flag is not set", + AR_EBADPARAM); + + return AR_EBADPARAM; + } + + /* Try opening the delta file with RW, then RO to determine the + * access type */ + fhandle = ACDB_MALLOC(ar_fhandle, 1); + if (IsNull(fhandle)) + { + ACDB_ERR("Error[%d]: Unable to allocate memory for the file handle", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (info->file_access_io_flag == ACDB_FUNC_IO_OUT) + { + info->file_access = AR_FOPEN_READ_ONLY_WRITE; + status = ar_fopen(fhandle, delta_file_path->path, + info->file_access); + if (status == AR_ENOTEXIST) + { + ACDB_DBG( + "Delta Acdb file does not exist. Creating new file..."); + info->file_access = AR_FOPEN_WRITE_ONLY; + status = ar_fopen(fhandle, delta_file_path->path, + info->file_access); + if (status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: The %s file path does not exist", + status, delta_file_path->path); + } + } + + if (AR_FAILED(status)) + { + info->file_access = AR_FOPEN_READ_ONLY; + status = ar_fopen(fhandle, delta_file_path->path, + info->file_access); + if (status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: The %s file does not exist", + status, delta_file_path->path); + goto end; + } + } + } + else if (info->file_access_io_flag == ACDB_FUNC_IO_IN) + { + status = ar_fopen(fhandle, delta_file_path->path, info->file_access); + if (status == AR_ENOTEXIST) + { + ACDB_ERR("Error[%d]: The %s file path does not exist", + status, delta_file_path->path); + goto end; + } + } + + if (!IsNull(fhandle) && AR_SUCCEEDED(status)) + { + info->file_size = (uint32_t)ar_fsize(*fhandle); + status = ar_fclose(*fhandle); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: " + "Unable to close %s", status, delta_file_path->path); + goto end; + } + } + +end: + ACDB_FREE(fhandle); + + return status; +} + +int32_t AcdbInitUtilOpenDeltaFile( + AcdbInitUtilDeltaInfo *info, ar_fhandle* delta_fhandle) +{ + int32_t status = AR_EOK; + + if (IsNull(info)) + { + ACDB_ERR("Error[%d]: One or more input parameters is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (IsNull(info->delta_path.path) || info->delta_path.path_length == 0) + { + ACDB_ERR("Error[%d]: The input file name is null or empty", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + status = ar_fopen(delta_fhandle, info->delta_path.path, + info->properties.file_access); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to open delta acdb file", status); + goto end; + } + + status = ar_fseek(*delta_fhandle, 0, AR_FSEEK_BEGIN); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Unable to seek file. Closing file..", status); + } + +end: + if (AR_FAILED(status)) + { + ar_fclose(*delta_fhandle); + *delta_fhandle = NULL; + } + + return status; +} diff --git a/acdb/src/acdb_parser.c b/acdb/src/acdb_parser.c new file mode 100644 index 0000000..e006d7e --- /dev/null +++ b/acdb/src/acdb_parser.c @@ -0,0 +1,202 @@ +/** +*============================================================================= +* \file acdb_parser.c +* +* \brief +* Handle parsing the ACDB Data files. +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- +* Include Files +*--------------------------------------------------------------------------- */ + +#include "ar_osal_file_io.h" +#include "ar_osal_error.h" +#include "ar_osal_mem_op.h" +#include "acdb_parser.h" +#include "acdb_common.h" +#include "acdb_utility.h" + +/* --------------------------------------------------------------------------- +* Preprocessor Definitions and Constants +*--------------------------------------------------------------------------- */ + +#define ACDB_FILE_TYPE 0x0 +#define ACDB_FILE_ID 0x42444341 // ACDB + +#define ACDB_FILE_VERSION_MAJOR 0x00000001 +#define ACDB_FILE_VERSION_MINOR 0x00000000 + +/* --------------------------------------------------------------------------- +* Type Declarations +*--------------------------------------------------------------------------- */ + +typedef struct acdb_file_properties_t +{ + /**< Identifies the file */ + uint32_t file_id; + /**< Indicates the type of file */ + uint32_t file_type; + /**< The size of the data section of the file after the + header and file properties */ + uint32_t file_data_size; +} acdb_file_properties_t; + +typedef struct acdb_chunk_header_t +{ + /**< The chunk identifier. See acdb_parser.h for list of identifiers */ + uint32_t id; + /**< The size of the chunk in bytes */ + uint32_t size; +}acdb_chunk_header_t; + +/* --------------------------------------------------------------------------- +* Static Function Declarations and Definitions +*--------------------------------------------------------------------------- */ + +int32_t acdb_parser_get_chunk( + void* file_buffer, uint32_t buffer_length, + uint32_t chunk_id, uint32_t *chunk_offset, uint32_t *chunk_size) +{ + int32_t status = AR_ENOTEXIST; + uint8_t *start_ptr = NULL; + uint8_t *end_ptr = NULL; + acdb_chunk_header_t *header = NULL; + + if (file_buffer == NULL || buffer_length == 0 || + buffer_length < sizeof(acdb_file_properties_t)) + { + return AR_EBADPARAM; + } + + /* Skip the file properties part of the acdb file to point + to the first chunk */ + start_ptr = (uint8_t*)file_buffer + sizeof(acdb_file_properties_t); + end_ptr = (uint8_t*)file_buffer + buffer_length; + + while (start_ptr < end_ptr) + { + if (start_ptr + sizeof(acdb_chunk_header_t) > end_ptr) + { + status = AR_EFAILED; + break; + } + + header = (acdb_chunk_header_t*)start_ptr; + + uint8_t* next_chunk = start_ptr + sizeof(acdb_chunk_header_t) + header->size; + if (next_chunk > end_ptr) + { + status = AR_EFAILED; + break; + } + + if (header->id == chunk_id) + { + *chunk_offset = (uint32_t)(start_ptr + - (uint8_t*)file_buffer + sizeof(acdb_chunk_header_t)); + *chunk_size = header->size; + status = AR_EOK; + break; + } + + start_ptr = next_chunk; + } + + return status; +} + +int32_t acdb_parser_validate_file(acdb_buffer_t *in_mem_file) +{ + int32_t status = AR_EOK; + acdb_file_properties_t *properties; + + if (IsNull(in_mem_file)) + { + ACDB_ERR("Error[%d]: The input parameter is null", + AR_EFAILED); + return AR_EFAILED; + } + + properties = (acdb_file_properties_t*)in_mem_file->buffer; + + if (in_mem_file->size < sizeof(acdb_file_properties_t)) + { + ACDB_ERR("Error[%d]: The file is missing property information", + AR_EFAILED); + return AR_EFAILED; + } + + if (properties->file_id != ACDB_FILE_ID && + properties->file_type != ACDB_FILE_TYPE) + { + ACDB_ERR("Error[%d]: The file is not an *.acdb file", AR_EFAILED); + return AR_EFAILED; + } + + if (in_mem_file->size != properties->file_data_size + + sizeof(acdb_file_properties_t)) + { + ACDB_ERR("Error[%d]: The file size is incorrect.", + AR_EFAILED, in_mem_file->size); + return AR_EFAILED; + } + + return status; +} + +int32_t acdb_parser_get_acdb_header_v1( + acdb_buffer_t* in_mem_file, acdb_header_v1_t *header) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint8_t* header_ptr = NULL; + ChunkInfo ci_head = { 0 }; + + if (IsNull(in_mem_file) || IsNull(header)) + { + ACDB_ERR("Error[%d]: One or more input parameters are null", + AR_EFAILED); + return AR_EFAILED; + } + + ci_head.chunk_id = ACDB_CHUNKID_HEAD; + status = acdb_parser_get_chunk(in_mem_file->buffer, in_mem_file->size, + ci_head.chunk_id, &ci_head.chunk_offset, &ci_head.chunk_size); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Chunk(%s) not found", + AR_EFAILED, &ci_head.chunk_id); + return status; + } + + //Header Version + header_ptr = (uint8_t*)in_mem_file->buffer + ci_head.chunk_offset; + header->header_version = *(uint32_t*)header_ptr; + offset += sizeof(uint32_t); + + //File version + ACDB_MEM_CPY_SAFE(&header->file_version, sizeof(acdb_file_version_t), + header_ptr + offset, sizeof(acdb_file_version_t)); + offset += sizeof(acdb_file_version_t); + + //Codec Info + header->codec_info = (acdb_codec_info_t*)(header_ptr + offset); + offset += sizeof(acdb_codec_info_t) + + header->codec_info->num_codecs * sizeof(acdb_codec_t); + + //Last Modified TimeStamp + header->date_modified = *(uint32_t*)(header_ptr + offset); + offset += sizeof(uint32_t); + + //OEM Info + header->oem_info = (acdb_oem_info_t*)(header_ptr + offset); + + return status; +} diff --git a/acdb/src/acdb_utility.c b/acdb/src/acdb_utility.c new file mode 100644 index 0000000..357456f --- /dev/null +++ b/acdb/src/acdb_utility.c @@ -0,0 +1,727 @@ +/** +*============================================================================= +* \file acdb_utility.c +* +* \brief +* Provides utility functions that are used accross ACDB Software +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +* +*============================================================================= +*/ + +/* --------------------------------------------------------------------------- +* Include Files +*--------------------------------------------------------------------------- */ + +#include "acdb_utility.h" +#include "acdb_common.h" +//#include + +/* --------------------------------------------------------------------------- +* Globals +*--------------------------------------------------------------------------- */ + +static ar_heap_info glb_ar_heap_info = +{ + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + +/* --------------------------------------------------------------------------- +* Functions +*--------------------------------------------------------------------------- */ + +//bool_t IsNullVar(uint32_t count, ...) +//{ +// va_list args; +// va_start(args, count); +// void* ptr = NULL; +// for (uint32_t i = 0; i < count; i++) +// { +// ptr = va_arg(args, void*); +// if (ptr == NULL) return TRUE; +// } +// va_end(args); +// return FALSE; +//} + +int32_t AcdbARHeapInit(void) +{ + int32_t status = AR_EOK; + glb_ar_heap_info.align_bytes = AR_HEAP_ALIGN_DEFAULT; + glb_ar_heap_info.heap_id = AR_HEAP_ID_DEFAULT; + glb_ar_heap_info.pool_type = AR_HEAP_POOL_DEFAULT; + glb_ar_heap_info.tag = AR_HEAP_TAG_DEFAULT; + + status = ar_heap_init(); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to initialize ar heap", status); + } + return status; +} + +int32_t AcdbARHeapDeinit(void) +{ + int32_t status = AR_EOK; + + status = ar_heap_deinit(); + if (AR_FAILED(status)) + { + ACDB_ERR("Error[%d]: Failed to de-initialize ar heap", status); + } + return status; +} + +void* AcdbMalloc(size_t size) +{ + return ar_heap_malloc(size, &glb_ar_heap_info); +} + +void AcdbFree(void* data) +{ + if (IsNull(data)) + return; + + ar_heap_free(data, &glb_ar_heap_info); +} + +//int32_t AcdbOffsetMemCpy(uint8_t* dst, uint8_t *src, uint32_t *offset, uint32_t size) +//{ +// if (IsNull(dst) || IsNull(src) || IsNull(offset)) +// { +// return AR_EBADPARAM; +// } +// +// ACDB_MEM_CPY(dst + *offset, src, size); +// offset += size; +// +// return AR_EOK; +//} + + int32_t AcdbDataCompareSearchKeys( + uint32_t* left, uint32_t *right, int num_params) + { + int32_t i = 0; + uint32_t* left_value = NULL; + uint32_t* right_value = NULL; + + // Assuming that the indices are all uint32_t. + for (i = 0; i < num_params; i++) + { + left_value = left + i; + right_value = right + i; + + if (*left_value > *right_value) + { + return 1; + } + else if (*left_value < *right_value) + { + return -1; + } + } + return 0; + } + + //int32_t AcdbDataCompareIndices(uint32_t* lookup, uint32_t *key, + // int num_params) + //{ + // int32_t i = 0; + // uint32_t* lookupVal = NULL; + // uint32_t* keyVal = NULL; + + // // Assuming that the indices are all uint32_t. + // for (i = 0; i < num_params; i++) + // { + // lookupVal = lookup + i; + // keyVal = key + i; + + // if (*lookupVal > *keyVal) + // { + // return 1; + // } + // else if (*lookupVal < *keyVal) + // { + // return -1; + // } + // } + // return 0; + //} +// +//int32_t AcdbDataBinarySearch(void *p_array, int32_t max, int32_t indexCount, +// void *p_cmd, int32_t n_param_count, uint32_t *index) +//{ +// int32_t result = SEARCH_ERROR; +// int32_t min = 0; +// int32_t mid = 0; +// int32_t compareResult = 0; +// +// uint32_t *lookUpArray = (uint32_t *)p_array; +// +// while (max >= min) +// { +// mid = (min + max) / 2; +// +// compareResult = AcdbDataCompareIndices(&lookUpArray[indexCount * mid], +// (uint32_t *)p_cmd, n_param_count); +// +// if (compareResult > 0) // search lower array +// { +// max = mid - 1; +// } +// else if (compareResult < 0) // search upper array +// { +// min = mid + 1; +// } +// else +// { +// // If its a partial search then the found index could no be the very first item +// // Find the first occurence of this element by going backward +// while (0 == AcdbDataCompareIndices(&lookUpArray[indexCount * (mid - 1)], +// (uint32_t *)p_cmd, n_param_count)) +// { +// mid = mid - 1; +// } +// *index = (uint32_t)mid; +// result = SEARCH_SUCCESS; +// break; +// } +// } +// +// return result; +//} +// + +//Binary Search already assumes that the lookup array and p_cmd is made up of uint32 types + +int32_t AcdbDataBinarySearch2(void *p_array, size_t sz_arr, void *p_cmd, + int32_t n_search_cmd_params, int32_t n_total_cmd_params, uint32_t *index) +{ + int32_t result = SEARCH_ERROR; + int32_t min = 0; + int32_t max = (int32_t)(sz_arr / (n_total_cmd_params * sizeof(uint32_t))) - 1; + int32_t mid = 0; + int32_t compareResult = 0; + uint32_t *lookUpArray = (uint32_t *)p_array; + uint32_t *search_key = (uint32_t *)p_cmd; + + while (max >= min) + { + mid = (min + max) / 2; + + compareResult = AcdbDataCompareSearchKeys( + search_key, &lookUpArray[n_total_cmd_params * mid], + n_search_cmd_params ); + + if (compareResult < 0) // search lower array + { + max = mid - 1; + } + else if (compareResult > 0) // search upper array + { + min = mid + 1; + } + else + { + /* If its a partial search then the found index could no be the + * very first item. Find the first occurence of this element + * by going backward + */ + if (mid > 0) + { + while (0 == AcdbDataCompareSearchKeys( + search_key, &lookUpArray[n_total_cmd_params * (mid - 1)], + n_search_cmd_params)) + { + if (mid <= min) break; + + mid = mid - 1; + } + } + + *index = (uint32_t)mid * n_total_cmd_params; + result = SEARCH_SUCCESS; + break; + } + } + + return result; +} + +void AcdbSort(void* p_array, uint32_t sz_arr) +{ + //insertion sort + + uint32_t* lst = (uint32_t*)p_array; + uint32_t tmp = 0; + int32_t j = 0; + uint32_t elem_count = sz_arr / sizeof(uint32_t); + + for (uint32_t i = 0; i + 1UL < elem_count; i++) + { + j = i; + while (j > -1) + { + if (lst[j] > lst[j + 1]) + { + tmp = lst[j]; + lst[j] = lst[j + 1]; + lst[j + 1] = tmp; + } + j--; + } + } +} + +int32_t AcdbSort2(size_t sz_arr, void* p_array, size_t sz_elem, uint32_t key_elem_pos) +{ + if (IsNull(p_array) || sz_arr == 0 || sz_elem == 0 || sz_arr < sz_elem) + return AR_EBADPARAM; + + if (1 == sz_arr / sz_elem) return AR_EOK; + + uint32_t* lst = (uint32_t*)p_array; + uint32_t elem_count = (uint32_t)sz_arr / (uint32_t)sz_elem; + int32_t elem_member_count = (uint32_t)sz_elem / sizeof(uint32_t); + int32_t lst_len = elem_count * elem_member_count; + uint32_t *tmp_elem = ACDB_MALLOC(uint32_t, elem_member_count); + int32_t j = 0; + + if (IsNull(tmp_elem)) return AR_ENOMEMORY; + + for (int32_t i = 0; i < lst_len - elem_member_count; i += elem_member_count) + { + j = i; + while (j > -1) + { + uint32_t a = lst[j + key_elem_pos]; + uint32_t b = lst[j + key_elem_pos + elem_member_count]; + if (a > b) + { + ACDB_MEM_CPY_SAFE((void*)tmp_elem, sz_elem, &lst[j], sz_elem); + ACDB_MEM_CPY_SAFE(&lst[j], sz_elem, &lst[j + elem_member_count], sz_elem); + ACDB_MEM_CPY_SAFE(&lst[j + elem_member_count], sz_elem, tmp_elem, sz_elem); + } + j -= elem_member_count; + } + } + + ACDB_FREE(tmp_elem); + return AR_EOK; +} + +uint32_t AcdbAlign(uint32_t byte_alignment, uint32_t byte_size) +{ + uint32_t aligned_byte_size = 0; + + if ((byte_size % byte_alignment) != 0) + { + aligned_byte_size = byte_size + (byte_alignment - ((byte_size % byte_alignment))); + } + else + { + aligned_byte_size = byte_size; + } + + return aligned_byte_size; +} + +uint32_t AcdbPadding(uint32_t byte_alignment, uint32_t byte_size) +{ + if ((byte_size % byte_alignment) != 0) + return (byte_alignment - ((byte_size % byte_alignment))); + + return 0; +} + +LinkedListNode *AcdbListCreateNode(void *p_struct) +{ + LinkedListNode *lnode = ACDB_MALLOC(LinkedListNode, 1); + + if (lnode == NULL) return NULL; + + lnode->p_next = NULL; + + lnode->p_struct = p_struct; + + return lnode; +} + +int32_t AcdbListAppend(LinkedList *list, LinkedListNode *node) +{ + //If the list is empty set the head + if (IsNull(list->p_head) && IsNull(list->p_tail)) + { + list->length = 0; + + list->p_head = node; + + list->p_tail = node; + + list->length++; + } + else + { + //get what tail is currently pointing to and point it to the inserted node + list->p_tail->p_next = node; + + //set the inserted node to tail + list->p_tail = node; + + list->length++; + } + + return AR_EOK; +} + +void AcdbListClear(LinkedList *list) +{ + if (IsNull(list)) return; + + LinkedListNode *cur_node = list->p_head; + + while (!IsNull(cur_node)) + { + AcdbListFreeAndSetNext(&cur_node); + } + + list->length = 0; + + list->p_head = NULL; + + list->p_tail = NULL; +} + +void AcdbListClear2(LinkedList *list, ACDB_LIST_CLEAR_CALLBACK free_obj_callback) +{ + if (IsNull(list)) return; + + LinkedListNode *cur_node = list->p_head; + + while (!IsNull(cur_node)) + { + if(!IsNull(free_obj_callback) && !IsNull(cur_node->p_struct)) + free_obj_callback(cur_node->p_struct); + + AcdbListFreeAndSetNext(&cur_node); + } + + list->length = 0; + + list->p_head = NULL; + + list->p_tail = NULL; +} + +void AcdbListFreeAndSetNext(LinkedListNode** node) +{ + if (*node == NULL) return; + + LinkedListNode *p_temp = NULL; + + p_temp = (*node)->p_next; + + ACDB_FREE(*node); + + *node = p_temp; + + p_temp = NULL; +} + +//void AcdbListSetNext(LinkedListNode* node) +//{ +// if (node == NULL) return; +// +// node = node->p_next; +//} + +bool_t AcdbListSetNext(LinkedListNode** node) +{ + if (*node == NULL) return TRUE; + + *node = (*node)->p_next; + return (*node) == NULL; +} + +int32_t AcdbListMerge(LinkedList *merge_to, LinkedList *merge_from) +{ + if (IsNull(merge_to->p_head) && IsNull(merge_to->p_tail)) + { + merge_to->p_head = merge_from->p_head; + merge_to->p_tail = merge_from->p_tail; + merge_to->length = merge_from->length; + } + else + { + merge_to->p_tail->p_next = merge_from->p_head; + merge_to->p_tail = merge_from->p_tail; + merge_to->length += merge_from->length; + } + + merge_from->length = 0; + merge_from->p_head = NULL; + merge_from->p_tail = NULL; + + return 0; +} + +void AcdbListMoveToEnd(LinkedList *list, LinkedListNode** node, LinkedListNode** prev_node) +{ + if (IsNull(list) || list->length == 0 || list->length == 1) return; + + LinkedListNode *tmp = NULL; + + if (list->length == 2) + { + //Swap Head and Tail + tmp = list->p_head; + list->p_head = list->p_tail; + list->p_tail = tmp; + list->p_tail->p_next = NULL; + list->p_head->p_next = list->p_tail; + tmp = NULL; + return; + } + + if (list->p_head == *node && IsNull(*prev_node)) + { + list->p_head = list->p_head->p_next; + (*node)->p_next = NULL; + AcdbListAppend(list, *node); + return; + } + else if (list->p_tail == *node) + { + return; + } + + (*prev_node)->p_next = (*node)->p_next; + (*node)->p_next = NULL; + AcdbListAppend(list, *node); +} + +int32_t AcdbListRemove(LinkedList *list, LinkedListNode *prev, LinkedListNode *node) +{ + if (IsNull(list) || IsNull(node)) return AR_EFAILED; + + if (IsNull(list->p_head) || IsNull(list->p_tail)) return AR_EFAILED; + + if (list->length == 1) + { + list->length = 0; + list->p_head = NULL; + list->p_tail = NULL; + return AR_EOK; + } + else if (list->p_tail == node) + { + list->length--; + if (!IsNull(prev)) + { + prev->p_next = NULL; + } + node->p_next = NULL; + return AR_EOK; + } + else if (list->p_head == node && IsNull(prev)) + { + list->length--; + list->p_head = list->p_head->p_next; + node->p_next = NULL; + return AR_EOK; + } + + list->length--; + if (!IsNull(prev)) + { + prev->p_next = node->p_next; + } + node->p_next = NULL; + + return AR_EOK; +} + +void LogKeyIDs(const AcdbUintList *keys, KeyVectorType type) +{ + if (keys == NULL) return; + + switch (type) + { + case GRAPH_KEY_VECTOR: + ACDB_DBG("Graph Key IDs(%d) Keys:", keys->count); + break; + case CAL_KEY_VECTOR: + ACDB_DBG("Calibration Key IDs(%d) Keys:", keys->count); + break; + case TAG_KEY_VECTOR: + ACDB_DBG("Tag Key IDs(%d) Keys:", keys->count); + break; + default: + return; + } + + for (uint32_t i = 0; i < keys->count; i++) + ACDB_DBG("[Key:0x%08x]", keys->list[i]); +} + +void LogKeyVector(const AcdbGraphKeyVector *key_vector, KeyVectorType type) +{ + if (key_vector == NULL || key_vector->graph_key_vector == NULL) return; + + switch (type) + { + case GRAPH_KEY_VECTOR: + ACDB_DBG("Graph Key Vector with %d key(s):", key_vector->num_keys); + break; + case CAL_KEY_VECTOR: + ACDB_DBG("Calibration Key Vector with %d key(s):", key_vector->num_keys); + break; + case TAG_KEY_VECTOR: + ACDB_DBG("Tag Key Vector with %d key(s):", key_vector->num_keys); + break; + default: + return; + } + + for (uint32_t i = 0; i < key_vector->num_keys; i++) + { + ACDB_DBG("[Key:0x%08x Val:0x%08x]", + key_vector->graph_key_vector[i].key, + key_vector->graph_key_vector[i].value); + } +} + +uint32_t AcdbCeil(uint32_t x, uint32_t y) +{ + return ((uint32_t)x % (uint32_t)y) == 0 ? x / y : x / y + 1; +} + +int32_t AcdbGenericListAddRange(void* list, void* items, uint32_t item_size, uint32_t count) +{ + AcdbGenericList* gen_list = (void*)list; + + //Add one or more items to the list + if (IsNull(list) || IsNull(items)) + return AR_EBADPARAM; + if (IsNull(gen_list->list)) + return AR_EFAILED; + if (item_size == 0 || count == 0) + { + ACDB_DBG("Warning[%d]: Unable to add items to the list " + "since item size or count is zero.", AR_EOK); + return AR_EOK; + } + + /* Not enough space to add new items to this list */ + if (count > gen_list->max_count || + gen_list->count + count > gen_list->max_count) + { + ACDB_DBG("Warning[%d]: No enough space to add new items to list."); + ACDB_DBG("List | max length %d.", gen_list->max_count); + ACDB_DBG("List | current length %d.", gen_list->count); + ACDB_DBG("List | number of items to add %d.", count); + return AR_ENEEDMORE; + } + + uint8_t* list_data = NULL; + if (gen_list->count == 0) + { + list_data = (uint8_t*)gen_list->list; + } + else + { + list_data = (uint8_t*)gen_list->list + gen_list->element_size * gen_list->count; + } + + ACDB_MEM_CPY_SAFE(list_data, item_size * count, items, item_size * count); + gen_list->count += count; + + return AR_EOK; +} + +int32_t AcdbGenericListFind(void* list, void* item, uint32_t item_size, uint32_t num_search_keys, AcdbGenericListItem* found_item) +{ + int32_t status = AR_EOK; + AcdbGenericList* gen_list = (void*)list; + if (IsNull(list) || IsNull(item) || IsNull(found_item)) + return AR_EBADPARAM; + if (IsNull(gen_list->list)) + return AR_EFAILED; + if (item_size == 0 || item_size != gen_list->element_size) + return AR_EFAILED; + + uint32_t list_size = gen_list->element_size * gen_list->count; + uint32_t item_index = 0; + uint32_t num_struct_elements = item_size / sizeof(uint32_t); + + if (list_size == 0) + { + /* The list is empty */ + return AR_ENOTEXIST; + } + if (SEARCH_ERROR == AcdbDataBinarySearch2( + gen_list->list, list_size, + item, num_search_keys, + num_struct_elements, &item_index)) + { + return AR_ENOTEXIST; + } + + found_item->index = item_index / num_struct_elements; + found_item->item = (uint8_t*)gen_list->list + found_item->index * gen_list->element_size; + + return status; +} + +int32_t AcdbGenericListSort(void* list, uint32_t key_elem_struct_position) +{ + int32_t status = AR_EOK; + AcdbGenericList* gen_list = (void*)list; + if (IsNull(list)) + return AR_EBADPARAM; + if (IsNull(gen_list->list)) + return AR_EFAILED; + + size_t list_size = (size_t)(gen_list->element_size * gen_list->count); + status = AcdbSort2(list_size, gen_list->list, gen_list->element_size, key_elem_struct_position); + + return status; +} + +int32_t AcdbGenericListInit(AcdbGenericList* list, uint32_t element_size, uint32_t max_list_size, void** list_data) +{ + if (IsNull(list)) + { + ACDB_ERR("Error[%d]: list input parameter is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + if (IsNull(list_data)) + { + ACDB_ERR("Error[%d]: list_data input parameter is null", AR_EBADPARAM); + return AR_EBADPARAM; + } + if (element_size == 0 || max_list_size == 0) + { + ACDB_DBG("Error[%d]: List max list size and/or element size cannot be zero", AR_EBADPARAM); + return AR_EBADPARAM; + } + + /* Set list properties */ + list->count = 0; + list->element_size = element_size; + list->max_count = max_list_size / element_size; + list->list = list_data; + + /* Set function pointers */ + list->add_range = AcdbGenericListAddRange; + list->find = AcdbGenericListFind; + list->sort = AcdbGenericListSort; + + return AR_EOK; +} diff --git a/ar_osal/Android.bp b/ar_osal/Android.bp new file mode 100644 index 0000000..5765630 --- /dev/null +++ b/ar_osal/Android.bp @@ -0,0 +1,5 @@ +cc_library_headers { + name: "libarosal_headers", + export_include_dirs: ["api"], + vendor: true, +} diff --git a/ar_osal/Android.mk b/ar_osal/Android.mk new file mode 100644 index 0000000..eb34af2 --- /dev/null +++ b/ar_osal/Android.mk @@ -0,0 +1,100 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +#---------------------------------------------------------------------------- +# Common definitons +#---------------------------------------------------------------------------- + +osal-def += -D_ANDROID_ -DAR_OSAL_USE_CUTILS -DPROPERTY_TRIGGER + +#---------------------------------------------------------------------------- +# Make the Shared library (liblx-osal) +#---------------------------------------------------------------------------- + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/api + +LOCAL_CFLAGS := $(osal-def) + +LOCAL_HEADER_LIBRARIES += audio_kernel_headers +LOCAL_HEADER_LIBRARIES += libarosal_headers +LOCAL_HEADER_LIBRARIES += qti_audio_kernel_uapi +LOCAL_HEADER_LIBRARIES += libdiag_headers +LOCAL_EXPORT_HEADER_LIBRARY_HEADERS := libarosal_headers + +include $(LIBION_HEADER_PATH_WRAPPER) +LOCAL_C_INCLUDES += $(LIBION_HEADER_PATHS) +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include/audio +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/vendor/qcom/opensource/audio-kernel/include +LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/diag/include + +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + +LOCAL_SRC_FILES := src/linux/ar_osal_mutex.c \ + src/linux/ar_osal_thread.c \ + src/linux/ar_osal_signal.c \ + src/linux/ar_osal_log.c \ + src/linux/ar_osal_file_io.c \ + src/linux/ar_osal_sleep.c\ + src/linux/ar_osal_mem_op.c\ + src/linux/ar_osal_heap.c\ + src/linux/ar_osal_timer.c\ + src/linux/ar_osal_string.c + +LOCAL_SRC_FILES += src/linux/qcom/ar_osal_log_pkt_op.c \ + src/linux/qcom/ar_osal_servreg.c + +LOCAL_SRC_FILES += src/linux/qcom/dyn_pd/ar_osal_dyn_pd.c + +ifeq ($(TARGET_KERNEL_VERSION),$(filter $(TARGET_KERNEL_VERSION), 4.14 4.19 5.4)) +LOCAL_SRC_FILES += src/linux/qcom/ar_osal_shmem_ion.c +else +LOCAL_SRC_FILES += src/linux/qcom/ar_osal_shmem_db.c \ + src/linux/qcom/ar_osal_shmem.c \ + src/linux/qcom/ar_osal_shmem_ap.c +endif + +LOCAL_SHARED_LIBRARIES := liblog \ + libdiag + +LOCAL_MODULE := liblx-osal +LOCAL_MODULE_OWNER := qti +LOCAL_MODULE_TAGS := optional +LOCAL_VENDOR_MODULE := true + +ifneq ($(strip $(AUDIO_FEATURE_OLD_ION_IMPL)), true) + include $(LIBION_HEADER_PATH_WRAPPER) + LOCAL_C_INCLUDES += $(LIBION_HEADER_PATHS) + LOCAL_SHARED_LIBRARIES += libion +endif + +ifeq ($(TARGET_AUDIO_DYNAMIC_PD_ENABLED), true) + LOCAL_HEADER_LIBRARIES += libfastrpc_vendor_headers + LOCAL_SHARED_LIBRARIES += libcdsprpc + LOCAL_SRC_FILES += src/linux/qcom/dyn_pd/cdsp_dyn_pd_stub.c + LOCAL_CFLAGS += -DAR_OSAL_USE_DYNAMIC_PD +endif + +ifeq ($(TARGET_PD_SERVICE_ENABLED), true) + LOCAL_SHARED_LIBRARIES += libpdmapper + LOCAL_SHARED_LIBRARIES += libpdnotifier + LOCAL_HEADER_LIBRARIES += libpdmapper_headers + LOCAL_HEADER_LIBRARIES += libpdnotifier_headers + LOCAL_HEADER_LIBRARIES += libqmi_legacy_headers + LOCAL_HEADER_LIBRARIES += libqmi_common_headers + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS) + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/libpdnotifier/inc + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qmi-framework/inc + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qmi/inc + LOCAL_CFLAGS += -DAR_OSAL_USE_PD_NOTIFIER +endif + +ifeq ($(AUDIO_FEATURE_ARE_ON_MDSP), true) + LOCAL_CFLAGS += -DMDSP_PROC +endif + +LOCAL_SHARED_LIBRARIES += libcutils +LOCAL_HEADER_LIBRARIES += vendor_common_inc + +include $(BUILD_SHARED_LIBRARY) diff --git a/ar_osal/Makefile.am b/ar_osal/Makefile.am new file mode 100644 index 0000000..02de8e8 --- /dev/null +++ b/ar_osal/Makefile.am @@ -0,0 +1,115 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = ar_osal.pc +EXTRA_DIST = $(pkgconfig_DATA) + +AM_CFLAGS = -Wall -Wno-pointer-to-int-cast -Wno-error=unused-function \ + -Wno-error=unused-label +AM_CFLAGS += -D__unused=__attribute__\(\(__unused__\)\) -DLINUX_ENABLED + +AM_CFLAGS += -I$(srcdir)/api + +osal_sources = ./api/ar_osal_error.h \ + ./api/ar_osal_file_io.h \ + ./api/ar_osal_heap.h \ + ./api/ar_osal_log.h \ + ./api/ar_osal_mem_op.h \ + ./api/ar_osal_mutex.h \ + ./api/ar_osal_servreg.h \ + ./api/ar_osal_shmem.h \ + ./api/ar_osal_signal.h \ + ./api/ar_osal_sleep.h \ + ./api/ar_osal_string.h \ + ./api/ar_osal_sys_id.h \ + ./api/ar_osal_thread.h \ + ./api/ar_osal_timer.h \ + ./api/ar_osal_types.h + +osal_c_sources = ./src/linux/ar_osal_file_io.c \ + ./src/linux/ar_osal_heap.c \ + ./src/linux/ar_osal_log.c \ + ./src/linux/ar_osal_mem_op.c \ + ./src/linux/ar_osal_mutex.c \ + ./src/linux/ar_osal_signal.c \ + ./src/linux/ar_osal_sleep.c \ + ./src/linux/ar_osal_string.c \ + ./src/linux/ar_osal_thread.c \ + ./src/linux/ar_osal_timer.c \ + ./src/linux/qcom/ar_osal_servreg.c \ + ./src/linux/qcom/dyn_pd/ar_osal_dyn_pd.c + + +if ARGS_VENDOR_QCOM +if AUDIO_DMA_SUPPORT +osal_c_sources += ./src/linux/qcom/ar_osal_shmem_db.c \ + ./src/linux/qcom/ar_osal_shmem.c \ + ./src/linux/qcom/ar_osal_shmem_ap.c +else # Use ion based shmem implementation. +osal_c_sources += ./src/linux/qcom/ar_osal_shmem_ion.c +endif +else #!ARGS_VENDOR_QCOM +if AUDIO_DMA_SUPPORT +osal_c_sources += ./src/linux/ar_osal_shmem_phy.c +else +# Use virtual memory based shmem implementation +osal_c_sources += ./src/linux/ar_osal_shmem_virtual.c +endif +endif + +if USE_DUMMY_DIAG +AM_CFLAGS += -I$(top_srcdir)/acdb/ats/transports/diag/linux/inc/ +osal_c_sources += ./src/linux/ar_osal_stub_log_pkt_op.c +else +osal_c_sources += ./src/linux/qcom/ar_osal_log_pkt_op.c +endif + +if LIBDIAG_HEADERS +AM_CFLAGS += -DUSE_LIBDIAG_HEADERS +endif + +if ARGS_USE_SYSLOG +AM_CFLAGS += -DAR_OSAL_USE_SYSLOG +endif + +if KERNEL_HEADER +AM_CFLAGS += -DMSM_AUDIO_CUSTOM_STACK +endif + +libar_osal_la_LIBADD = -lrt -lpthread + +if CUTILS_SUPPORTED +libar_osal_la_LIBADD += -lcutils -llog +AM_CFLAGS += -DAR_OSAL_USE_CUTILS +endif + +if ION_DRIVER_NOT_SUPPORTED +AM_CFLAGS += -DION_DRIVER_UNSUPPORTED +endif + +if USE_GLIB +libar_osal_la_LIBADD += -lglib-2.0 +AM_CFLAGS += $(GLIB_CFLAGS) -D_GNU_SOURCE -include glib.h +endif + +if USE_DUMMY_DIAG +#dummy diag, do not link real diag libs +else +libar_osal_la_LIBADD += -ldiag +endif + +if USE_G_STR_FUNC +AM_CFLAGS += -Dstrlcpy=g_strlcpy -Dstrlcat=g_strlcat +endif + +lib_includedir = $(includedir) +lib_include_HEADERS = $(osal_sources) +lib_LTLIBRARIES = libar-osal.la +libar_osal_la_CC = @CC@ +libar_osal_la_SOURCES = $(osal_c_sources) +libar_osal_la_CFLAGS = $(AM_CFLAGS) @DIAG_CFLAGS@ + +if LIBION_SUPPORTED +libar_osal_la_LIBADD += -lion +libar_osal_la_CFLAGS += @LIBION_CFLAGS@ +endif + +libar_osal_la_LDFLAGS = -shared -version-number @LT_VERSION_NUMBER@ diff --git a/ar_osal/api/ar_osal_dyn_pd.h b/ar_osal/api/ar_osal_dyn_pd.h new file mode 100644 index 0000000..6395d60 --- /dev/null +++ b/ar_osal/api/ar_osal_dyn_pd.h @@ -0,0 +1,38 @@ +#ifndef AR_OSAL_DYN_PD_H +#define AR_OSAL_DYN_PD_H + +/** + * \file ar_osal_dyn_pd.h + * + * \brief + * Defines APIs to create dynamic PD + * for the given processor domain. + * \copyright + *  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + *  SPDX-License-Identifier: BSD-3-Clause + */ +/** + * \brief initialize dynamic pd. + * + * \param[in] proc_id: satellite proc_id. + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_osal_dyn_pd_init(uint32_t proc_id); + +/** + * \brief de-initialize dynamic pd. + * + * \param[in] proc_id: satellite proc_id. + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_osal_dyn_pd_deinit(uint32_t proc_id); + +#endif diff --git a/ar_osal/api/ar_osal_error.h b/ar_osal/api/ar_osal_error.h new file mode 100644 index 0000000..99c0abd --- /dev/null +++ b/ar_osal/api/ar_osal_error.h @@ -0,0 +1,74 @@ +#ifndef AR_OSAL_ERROR_H +#define AR_OSAL_ERROR_H + +/** + * \file ar_osal_error.h + * \brief + * This file contains error codes used by AudioReach. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* ----------------------------------------------------------------------- +** ERROR CODES +** ----------------------------------------------------------------------- */ +/** Success. The operation completed with no errors. */ +#define AR_EOK (0) +/** General failure. */ +#define AR_EFAILED (1) +/** Bad operation parameter. */ +#define AR_EBADPARAM (2) +/** Unsupported routine or operation. */ +#define AR_EUNSUPPORTED (3) +/** Unsupported version. */ +#define AR_EVERSION (4) +/** Unexpected problem encountered. */ +#define AR_EUNEXPECTED (5) +/** Unhandled problem occurred. */ +#define AR_EPANIC (6) +/** Unable to allocate resource. */ +#define AR_ENORESOURCE (7) +/** Invalid handle. */ +#define AR_EHANDLE (8) +/** Operation is already processed. */ +#define AR_EALREADY (9) +/** Operation is not ready to be processed. */ +#define AR_ENOTREADY (10) +/** Operation is pending completion. */ +#define AR_EPENDING (11) +/** Operation cannot be accepted or processed. */ +#define AR_EBUSY (12) +/** Operation was aborted due to an error. */ +#define AR_EABORTED (13) +/** Operation requests an intervention to complete. */ +#define AR_ECONTINUE (14) +/** Operation requests an immediate intervention to complete. */ +#define AR_EIMMEDIATE (15) +/** Operation was not implemented. */ +#define AR_ENOTIMPL (16) +/** Operation needs more data or resources. */ +#define AR_ENEEDMORE (17) +/** Operation does not have memory. */ +#define AR_ENOMEMORY (18) +/** Item does not exist. */ +#define AR_ENOTEXIST (19) +/** Operation is finished. */ +#define AR_ETERMINATED (20) +/** Operation timeout. */ +#define AR_ETIMEOUT (21) +/** Data read/write failed. */ +#define AR_EIODATA (22) +/** Sub system reset occured. */ +#define AR_ESUBSYSRESET (23) +/** Duplicate subgraph or connection opened. */ +#define AR_EDUPLICATE (24) +/** @} */ /* end_addtogroup ar_error_codes */ + +/** Checks if a result is a success */ +#define AR_SUCCEEDED(x) (AR_EOK == (x) ) + +/** Checks if a result is failure. */ +#define AR_FAILED(x) (AR_EOK != (x) ) + +#endif /* #ifndef AR_OSAL_ERROR_H */ diff --git a/ar_osal/api/ar_osal_file_io.h b/ar_osal/api/ar_osal_file_io.h new file mode 100644 index 0000000..f6daf03 --- /dev/null +++ b/ar_osal/api/ar_osal_file_io.h @@ -0,0 +1,208 @@ +#ifndef AR_OSAL_FILE_IO_H +#define AR_OSAL_FILE_IO_H + +/** + * \file ar_osal_file_io.h + * \brief + * Defines public APIs for file IO operations. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** +* Structures and Typedefs +*/ +typedef void *ar_fhandle; + +/** Opens for reading, file position is at the beginning. + * If the file does not exist, the ar_fopen call fails. + */ +#define AR_FOPEN_READ_ONLY (0x00000001) +/** Opens an empty file for writing. If the given file exists, its contents are destroyed, + * file position is at the beginning. + */ +#define AR_FOPEN_WRITE_ONLY (0x00000002) +/** Opens an empty file for both reading and writing. If the file exists, + * its contents are destroyed, file position is at the beginning. + */ +#define AR_FOPEN_READ_WRITE (AR_FOPEN_READ_ONLY|AR_FOPEN_WRITE_ONLY) +/** Open for appending (writing at end of file), this parameter alone cannot be used with ar_fopen. + */ +#define AR_FOPEN_APPEND (0x00000004) +/** Opens for writing at the end of the file(appending). Creates the file if it does not exist. + */ +#define AR_FOPEN_WRITE_ONLY_APPEND (AR_FOPEN_WRITE_ONLY|AR_FOPEN_APPEND) +/** Opens for reading and appending. Creates the file if it does not exist. The file + * position for reading is at the beginning of the file, but write data is always appended + * to the end of the file. + */ +#define AR_FOPEN_READ_WRITE_APPEND (AR_FOPEN_READ_ONLY|AR_FOPEN_WRITE_ONLY|AR_FOPEN_APPEND) +/** Opens for both reading and writing. The file must exist, file position is at the beginning of file. + */ +#define AR_FOPEN_READ_ONLY_WRITE (0x00000008) + +typedef enum ar_fseek_reference { + /** + *The starting point is zero or the beginning of the file. + */ + AR_FSEEK_BEGIN = 0, + /** + *The starting point is the current end-of-file position. + */ + AR_FSEEK_END = 1, + /** + *The start point is the current value of the file pointer. + */ + AR_FSEEK_CURRENT = 2 +} ar_fseek_reference_t ; + +/** + * \brief ar_fopen + * open a file or create if does not exist. + * + * \param[out] handle: Handle to the file. + * \param[in] path: Absolute file path. + * \param[in] access: Type of access + * AR_FILE_OPEN_READ_ONLY + * AR_FILE_OPEN_WRITE_ONLY + * AR_FILE_OPEN_READ_WRITE + * AR_FOPEN_WRITE_ONLY_APPEND + * AR_FOPEN_READ_WRITE_APPEND + * AR_FOPEN_READ_ONLY_WRITE + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_fopen(ar_fhandle *handle, + const char_t *path, + uint32_t access); + +/** + * \brief ar_fsize + * Return file size. + * + * \param[in] handle: Handle to the file. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +size_t ar_fsize(ar_fhandle handle); + +/** + * \brief ar_fmap + * Map a file into Data Memory for Read Only access + * + * Whether this allocates heap memory for the buffer or not + * is platform dependent. On some platforms with low memory + * this may map non-volatile storage into a readable memory window instead. + * To free any possible resources allocated by this call, the caller + * MUST call ar_funmap + * + * \param[in] handle: Handle to the file + * \param[out] fbuffer: A pointer to the read-only Data memory buffer + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_fmap(ar_fhandle handle, + const void **fbuffer); + +/** + * \brief ar_funmap + * Un-map a file from Data Memory + * + * This call releases a buffer obtained by a previous call to ar_fmap + * and frees any resources that may be in use by it. + * The file still needs to be closed by a call to ar_fclose + * + * \param[in] fbuffer: The pointer to the file buffer obtained by ar_fmap + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_funmap(const void *fbuffer); + +/** + * \brief ar_fseek + * Move the file pointer for read/write to the required offset. + * + * \param[in] handle: Handle to the file. + * \param[in] offset: The number of bytes to move the file pointer. + * \param[in] ref: Refer to ar_fseek_reference_t for options. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_fseek(ar_fhandle handle, + size_t offset, + ar_fseek_reference_t ref); + +/** + * \brief ar_fread + * Read from file. + * + * \param[in] handle: Handle to the file. + * \param[in_out] buf_ptr: Buffer pointer to read data into. + * \param[in] read_size: Data size to read from file. + * \param[in_out] bytes_read: Actual data size read from file. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_fread(ar_fhandle handle, + void *buf_ptr, + size_t read_size, + size_t *bytes_read); + +/** + * \brief ar_fwrite + * write to file. + * + * \param[in] handle: Handle to the file. + * \param[in] buf_ptr: Buffer pointer to write data from. + * \param[in] write_size: Data size to write into file. + * \param[in_out] bytes_written: Actual data size written into file. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_fwrite(ar_fhandle handle, + void *buf_ptr, + size_t write_size, + size_t *bytes_written); + +/** + * \brief ar_fclose + * \param[in] handle: Handle to the file. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_fclose(ar_fhandle handle); + +/** + * \brief ar_fdelete + * \param[in] path: Absolute file path. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_fdelete(const char_t *path); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif //AR_OSAL_FILE_IO_H diff --git a/ar_osal/api/ar_osal_heap.h b/ar_osal/api/ar_osal_heap.h new file mode 100644 index 0000000..4fe5169 --- /dev/null +++ b/ar_osal/api/ar_osal_heap.h @@ -0,0 +1,136 @@ +#ifndef AR_OSAL_HEAP_H +#define AR_OSAL_HEAP_H + +/** + * \file ar_osal_heap.h + * \brief + * Defines public APIs for heap memory allocation. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** enum for heap memory byte alignments*/ +typedef enum _ar_heap_align_bytes +{ + AR_HEAP_ALIGN_DEFAULT = 0, /** default alignment */ + AR_HEAP_ALIGN_4_BYTES = 1, /** 4-byte boundary */ + AR_HEAP_ALIGN_8_BYTES = 2, /** 8-byte boundary */ + AR_HEAP_ALIGN_16_BYTES = 3, /** 16-byte boundary */ +} ar_heap_align_bytes; + +/** enum for heap memory ids */ +typedef enum _ar_heap_id +{ + AR_HEAP_ID_DEFAULT = 0, /** default heap id */ + AR_HEAP_ID_1 = 1, /** custom heap id 1 */ + AR_HEAP_ID_2 = 2, /** custom heap id 2 */ + AR_HEAP_ID_3 = 3, /** custom heap id 3 */ + AR_HEAP_ID_4 = 4, /** custom heap id 4 */ + AR_HEAP_ID_5 = 5, /** custom heap id 5 */ + AR_HEAP_ID_6 = 6, /** custom heap id 6 */ + AR_HEAP_ID_7 = 7, /** custom heap id 7 */ + AR_HEAP_ID_8 = 8, /** custom heap id 8 */ + AR_HEAP_ID_9 = 9, /** custom heap id 9 */ + AR_HEAP_ID_10 = 10, /** custom heap id 10 */ + AR_HEAP_ID_11 = 11, /** custom heap id 11 */ +} ar_heap_id; + +/** enum for heap memory types */ +typedef enum _ar_heap_pool_type +{ + /** default pool type, as supported by each platform. */ + AR_HEAP_POOL_DEFAULT = 0, + /** allocated memory is nonpaged and executable that is, instruction execution is enabled in this memory. */ + AR_HEAP_POOL_NON_PAGED_EXECUTE = 1, + /** allocated memory is nonpaged and instruction execution is disabled. */ + AR_HEAP_POOL_NON_PAGED_NX = 2, + /** allocated memory is pageable.*/ + AR_HEAP_POOL_PAGED = 4, +} ar_heap_pool_type; + +/** default heap memory tag ASCII characters: 'LASO'->'OSAL' */ +#define AR_HEAP_TAG_DEFAULT (0x4c41534f) + +/** +* Heap memory info structure +*/ +typedef struct ar_heap_info_t +{ + ar_heap_align_bytes align_bytes; /** heap memory byte alignment required.*/ + ar_heap_pool_type pool_type; /** pool type to allocate heap memory. */ + ar_heap_id heap_id; /** head id to allocate heap memory. */ + uint32_t tag; /** used for tracing heap memory allocations.default:AR_HEAP_TAG_DEFAULT */ + /** Specify the pool tag as a non - zero character literal of one to to four */ + /** characters delimited by single quotation marks(for example, 'Tag1'). */ + /** The string is usually specified in reverse order(for example, '1gaT'). */ + /** Each ASCII character in the tag must be a value in the range 0x20 (space)to 0x7E (tilde).*/ +} ar_heap_info, * par_heap_info; + +/** + * \brief ar_heap_init + * initialize heap memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_heap_init(void); + +/** + * \brief ar_heap_deinit. + * De-initialize heap memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_heap_deinit(void); + +/** + * \brief Allocates heap memory. + * + * \param[in] bytes: number of bytes to allocate heap memory. + * \param[in] heap_info: pointer of type: ar_heap_info. + * + * \return + * Nonzero -- Success: pointer to the allocated heap memory + * NULL -- Failure + * + */ +void* ar_heap_malloc(size_t bytes, par_heap_info heap_info); + +/** + * \brief Allocates heap memory and initialize with 0. + * + * \param[in] bytes: number of bytes to allocate heap memory. + * \param[in] heap_info: pointer of type: ar_heap_info. + * + * \return + * Nonzero -- Success: pointer to the allocated heap memory + * NULL -- Failure + * + */ +void* ar_heap_calloc(size_t bytes, par_heap_info heap_info); + +/** + * \brief Frees heap memory. + * + * \param[in] heap_ptr: pointer to heap memory obtained from ar_heap_alloc(). + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +void ar_heap_free(void* heap_ptr, par_heap_info heap_info); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* #ifndef AR_OSAL_HEAP_H */ + diff --git a/ar_osal/api/ar_osal_log.h b/ar_osal/api/ar_osal_log.h new file mode 100644 index 0000000..939e6cd --- /dev/null +++ b/ar_osal/api/ar_osal_log.h @@ -0,0 +1,88 @@ +#ifndef AR_OSAL_LOG_H +#define AR_OSAL_LOG_H + +/** + * \file ar_osal_log.h + * \brief + * Defines public APIs for message logging. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +#define AR_CRITICAL (0x1) /**< critical message, log unrecoverable condition .*/ +#define AR_ERROR (0x2) /**< error message, represents code bugs that should be debugged and fixed.*/ +#define AR_DEBUG (0x4) /**< debug message, required for debug. Not enabled by default*/ +#define AR_INFO (0x8) /**< Use for vital info that needs to exist in default logs */ +#define AR_VERBOSE (0x10)/**< verbose message, useful primarily to help developers debug low-level code */ + +extern uint32_t ar_log_lvl; /*gobal variable to control the log levels*/ + +/* Initialize logging */ +void ar_log_init(void); + +/* Deinitialize logging*/ +void ar_log_deinit(void); + +/* log function implemented by each platform*/ +/* NOTE: New line ("\n") escape sequence is not expected to be provided with the end of each log message, + each platform implementation is expected to support this if not implicitly supported, by default every + new log message will be on a new line*/ +void ar_log(uint32_t level, const char_t* log_tag, const char_t* file, + const char_t* fn, int32_t ln, const char_t* format, ...); + +/* Set log level dynamically */ +/* This is designed so that a debugging user can turn on specific logs at + * runtime. Call needs to be implemented in some higher layer or debugging tool + * Pass as input the bitwise OR of the log levels desired. + * Example: AR_CRITICAL|AR_ERROR|AR_INFO + */ +void ar_set_log_level(uint32_t level); + +#define AR_LOG_VERBOSE(log_tag, ...) \ + if (ar_log_lvl & AR_VERBOSE) { \ + ar_log(AR_VERBOSE, log_tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \ + } + +#define AR_LOG_INFO(log_tag,...) \ + if (ar_log_lvl & AR_INFO) { \ + ar_log(AR_INFO, log_tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \ + } + +#define AR_LOG_DEBUG(log_tag, ...) \ + if (ar_log_lvl & AR_DEBUG) { \ + ar_log(AR_DEBUG, log_tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \ + } +#define AR_LOG_ERR(log_tag, ...) \ + if (ar_log_lvl & AR_ERROR) { \ + ar_log(AR_ERROR, log_tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \ + } + +#define AR_LOG_CRITICAL(log_tag, ...) \ + if (ar_log_lvl & AR_CRITICAL) { \ + ar_log(AR_CRITICAL, log_tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \ + } + +#define AR_FATAL_PRIO (AR_CRITICAL) /**< Fatal priority debug message. */ +#define AR_ERROR_PRIO (AR_ERROR ) /**< Error priority debug message. */ +#define AR_HIGH_PRIO (AR_INFO ) /**< High priority debug message. */ +#define AR_MED_PRIO (AR_DEBUG ) /**< Medium priority debug message. */ +#define AR_LOW_PRIO (AR_VERBOSE ) /**< Low priority debug message. */ + +#define AR_LOG_FATAL(log_tag, ...) AR_LOG_CRITICAL(log_tag, __VA_ARGS__) +#define AR_LOG_HIGH(log_tag, ...) AR_LOG_INFO(log_tag, __VA_ARGS__) +#define AR_LOG_ERROR(log_tag, ...) AR_LOG_ERR(log_tag, __VA_ARGS__) +#define AR_LOG_MED(log_tag, ...) AR_LOG_DEBUG(log_tag, __VA_ARGS__) +#define AR_LOG_LOW(log_tag, ...) AR_LOG_VERBOSE(log_tag, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif //AR_OSAL_LOG_H diff --git a/ar_osal/api/ar_osal_log_pkt_op.h b/ar_osal/api/ar_osal_log_pkt_op.h new file mode 100644 index 0000000..669ea05 --- /dev/null +++ b/ar_osal/api/ar_osal_log_pkt_op.h @@ -0,0 +1,144 @@ +#ifndef AR_OSAL_LOG_PKT_OP_H +#define AR_OSAL_LOG_PKT_OP_H + +/** +* \file ar_osal_log_pkt_op.h +* \brief +* Defines platform agnostic APIs for sending log packets to +* the PC. +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "ar_osal_types.h" +#include "ar_osal_heap.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + /**< An enumeration of supported transports */ + typedef enum ar_log_data_transport_t + { + AR_LOG_DATA_TRANSPORT_UNKNOWN = 0x0, + AR_LOG_DATA_TRANSPORT_DIAG = 0x1, + AR_LOG_DATA_TRANSPORT_TCPIP = 0x2, + }ar_log_data_transport_t; + + typedef struct ar_log_pkt_op_init_info_t + { + ar_log_data_transport_t + data_transport; /**< The data transport to use when sending + log packets */ + ar_heap_info heap_info; /**< Heap information used to identify memory + allocated by the data transport */ + }ar_log_pkt_op_init_info_t, *par_log_pkt_op_init_info_t; + + /** + * \brief ar_log_pkt_op_init + * + * Initialzes the data transport mechanism + * + * \param[in] info: pointer to info structure containing heap and data + * transport information that is used to initialize the pai + * + * + * \return + * Success -- 0 + * Failure -- non-zero + */ + int32_t ar_log_pkt_op_init(ar_log_pkt_op_init_info_t *info); + + /** + * \brief ar_log_pkt_op_deinit + * + * Deinitializes the utility and release any/all + * resources aquired + * + * \depends + * ar_log_pkt_op_init(...) must be called before this function + * + * \return + * Success -- returns a pointer to the allocated memory + * Failure -- returns null if the allocation fails + */ + int32_t ar_log_pkt_op_deinit(void); + + /** + * \brief ar_log_pkt_get_max_size + * + * Retrieve the max size of a log packet that can be sent through + * the data transport + * + * \depends + * ar_log_pkt_op_init(...) must be called before this function + * + * \return + * return the max log packet size + */ + uint32_t ar_log_pkt_get_max_size(void); + + /** + * \brief ar_log_pkt_alloc + * + * Allocates a log packet and returns a pointer to the memory + * + * \param[in] logcode: the log code used for the packet. See + * ar_util_data_log_codes.h in the AR Util + * \param[in] length: the size of the packet to allocate + * + * \depends + * commit or free operations must be called ASAP after this call since + * the allocation is performed in the transport layer shared resource pool + * + * \return + * Success -- returns a pointer to the allocated memory + * Failure -- returns null if the allocation fails + */ + void *ar_log_pkt_alloc(uint16_t logcode, uint32_t length); + + /** + * \brief ar_log_pkt_commit + * + * Commits the log packet and then frees the memory pointed to by ptr + * + * \param[in] ptr: pointer to memory allocated through ar_log_pkt_alloc + * + * \return + * Success -- 0 + * Failure -- non-zero + */ + int32_t ar_log_pkt_commit(void *ptr); + + /** + * \brief ar_log_pkt_free + * + * Releases resources aquired through ar_log_pkt_alloc + * + * \param[in] ptr: pointer to memory allocated through ar_log_pkt_alloc + * + * \return + * n/a + */ + void ar_log_pkt_free(void *ptr); + + /** + * \brief ar_log_code_status + * + * Checks whether a log code is enable + * + * \param[in] logcode: the log code to check. See ar_util_data_log_codes.h + * in the AR Util + * + * \return + * TRUE -- ENABLED + * FALSE -- DISABLED + */ + bool_t ar_log_code_status(uint16_t logcode); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* AR_OSAL_LOG_PKT_OP_H */ \ No newline at end of file diff --git a/ar_osal/api/ar_osal_mem_op.h b/ar_osal/api/ar_osal_mem_op.h new file mode 100644 index 0000000..f6c4e80 --- /dev/null +++ b/ar_osal/api/ar_osal_mem_op.h @@ -0,0 +1,78 @@ +#ifndef AR_OSAL_MEM_OP_H +#define AR_OSAL_MEM_OP_H + + /** + * \file ar_osal_mem_op.h + * \brief + * Defines public APIs for memory operations. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** + * \brief ar_mem_cpy + * copies bytes between buffers. + * \param[in_out] dest: destinatiopn buffer to copy data. + * \param[in] dest_size: destination buffer size. + * \param[in] src: source buffer pointer to copy data from. + * \param[in] size: bytes to copy from source buffer. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_mem_cpy(void* dest, size_t dest_size, const void* src, size_t size); + +/** + * \brief ar_mem_move + * copies bytes from source area to destination area. + * \param[in_out] dest: destinatiopn buffer to copy data. + * \param[in] dest_size: destination buffer size. + * \param[in] src: source buffer pointer to copy data from. + * \param[in] size: bytes to copy from source buffer. + * \return + * 0 -- Success + * Nonzero -- Failure + * note: If some regions of the source area and the destination overlap, ar_mem_move + * ensures that the original source bytes in the overlapping region are copied before + * being overwritten. + */ +int32_t ar_mem_move(void* dest, size_t dest_size, const void* src, size_t size); + +/** + * \brief ar_mem_set + * set buffer to specified value. + * \param[in_out] dest: destinatiopn buffer to set the specified value. + * \param[in] c: specified value to set, of integer type. + * \param[in] size: buffer bytes to set the value, must be multiple of specified value "c" data size. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_mem_set(void* dest, int32_t c, size_t size); + +/** + * \brief ar_mem_cmp + * compare two buffers. + * \param[in] buff1: first buffer. + * \param[in] buff2: second buffer. + * \param[in] size: bytes to compare. + * \return + * < 0 buff1 < buff2 + * 0 buff1 == buff2 + * > 0 buff1 > buff2 + */ +int32_t ar_mem_cmp(const void* buff1, const void* buff2, size_t size); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* #ifndef AR_OSAL_MEM_OP_H */ + diff --git a/ar_osal/api/ar_osal_mutex.h b/ar_osal/api/ar_osal_mutex.h new file mode 100644 index 0000000..b3d2530 --- /dev/null +++ b/ar_osal/api/ar_osal_mutex.h @@ -0,0 +1,204 @@ +#ifndef AR_OSAL_MUTEX_H +#define AR_OSAL_MUTEX_H + +/** + * \file ar_osal_mutex.h + * \brief + * This file contains mutex APIs. Recursive mutexes are always used +* for thread-safe programming. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** @weakgroup weakf_ar_osal_mutex_intro +This section describes the following priority inheritance mutex functions. +Recursive mutex are always used for thread-safe programming. + - ar_osal_mutex_init() + - ar_osal_mutex_deinit() + - ar_osal_mutex_get_size() + - ar_osal_mutex_create() + - ar_osal_mutex_destroy() + - ar_osal_mutex_lock() + - ar_osal_mutex_try_lock() + - ar_osal_mutex_unlock() +*/ + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/* ======================================================================= +INCLUDE FILES FOR MODULE +========================================================================== */ +#include "ar_osal_types.h" + +/** @addtogroup mutex +@{ */ + +/* ----------------------------------------------------------------------- +** Global definitions/forward declarations +** ----------------------------------------------------------------------- */ + +/** ar osal mutex type object. +*/ +typedef void *ar_osal_mutex_t; + +/**************************************************************************** +** Mutex +*****************************************************************************/ + +/** + Initializes a mutex. Memory for mutex object is created by client and + this API is used to initialize the mutex. + Recursive mutexes are always used. + + @datatypes + ar_osal_mutex_t + + @param[in] mutex: Pointer to the mutex object handle. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. @newpage +*/ +int32_t ar_osal_mutex_init(ar_osal_mutex_t mutex); + +/** + De-initializes a mutex. Mutex memory was provided by client and this + API is used to de-initialize the mutex before freeing the object. + + @datatypes + ar_osal_mutex_t + + @param[in] mutex: Pointer to the mutex object handle. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. @newpage +*/ +int32_t ar_osal_mutex_deinit(ar_osal_mutex_t mutex); + +/** + Get size of mutex object. This API is used to get the mutex object + size for client to allocate memory for the mutex object. + + @datatypes + ar_osal_mutex_t + + @return + Size of mutex object + + @dependencies + None. @newpage +*/ +size_t ar_osal_mutex_get_size(void); + + +/** + Creates and initialize a mutex. Recursive mutex are always used. + Mutex memory allocation and initialization done by this API + osal_mutex_create() or osal_mutex_init() would be used, but not both. + + @datatypes + ar_osal_mutex_t + + @param[Out] mutex: Pointer to the mutex object handle. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. @newpage +*/ +int32_t ar_osal_mutex_create(ar_osal_mutex_t *mutex); + +/** + Delete/free a mutex object. This function must be called for + each corresponding osal_mutex_create function to clean up all + resources. + + @datatypes + ar_osal_mutex_t + + @param[in] mutex: Pointer to the mutex. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the object must have been created. + @newpage +*/ +int32_t ar_osal_mutex_destroy(ar_osal_mutex_t mutex); + +/** + Locks a mutex. Recursive mutex are always used. + + @datatypes + ar_osal_mutex_t + + @param[in] mutex: Pointer to the mutex. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the object must be created. + @newpage + +*/ +int32_t ar_osal_mutex_lock(ar_osal_mutex_t mutex); + +/** + Attempts to lock a mutex. If the mutex is already locked and unavailable, + a failure is returned. + + @datatypes + ar_osal_mutex_t + + @param[in] mutex: Pointer to the mutex. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the object must be created. + @newpage +*/ +int32_t ar_osal_mutex_try_lock(ar_osal_mutex_t mutex); + +/** + Unlocks a mutex. Recursive mutex are always used. + + @datatypes + ar_osal_mutex_t + + @param[in] mutex: Pointer to the mutex. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the object must be created. + @newpage + */ +int32_t ar_osal_mutex_unlock(ar_osal_mutex_t mutex); + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif // #ifndef AR_OSAL_MUTEX_H diff --git a/ar_osal/api/ar_osal_servreg.h b/ar_osal/api/ar_osal_servreg.h new file mode 100644 index 0000000..ac15435 --- /dev/null +++ b/ar_osal/api/ar_osal_servreg.h @@ -0,0 +1,218 @@ +#ifndef AR_OSAL_SERVREG_H +#define AR_OSAL_SERVREG_H + +/** + * \file ar_osal_servreg.h + * \brief + * Defines public APIs for service location, + * notification and state registration. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** Max length of the domain name i.e "soc/domain/subdomain" or + * service name i.e "provider/service" is 64 bytes + * e.g. msm/adsp/audio_pd or avs/audio or audio/avs_mdf_sdsp or + * audio/avs_mdf_mdsp + */ +#define AR_OSAL_SERVREG_NAME_LENGTH_MAX (64) + +/** ar osal servreg type object. +*/ +typedef void *ar_osal_servreg_t; + +/** Struct representing the name of the service or domain and the instance id + */ +typedef struct { + /**< Name of the service or domain. */ + char_t name[AR_OSAL_SERVREG_NAME_LENGTH_MAX + 1]; + + /**< Instance ID. */ + uint32_t instance_id; +}ar_osal_servreg_entry_type; + +/** Service state up/down indicator. + */ +typedef enum ar_osal_service_state { + /* service is in down state */ + AR_OSAL_SERVICE_STATE_DOWN = 0, + /* service is in up state */ + AR_OSAL_SERVICE_STATE_UP = 1, +} ar_osal_service_state_type; + +/** Servreg client type: listener or service provider. + */ +typedef enum ar_osal_client { + /* invalid client */ + AR_OSAL_CLIENT_INVALID = 0, + /* listener client */ + AR_OSAL_CLIENT_LISTENER = 1, + /* service provide client */ + AR_OSAL_CLIENT_SERVICE_PROVIDER = 2, +} ar_osal_client_type; + +/** Servreg callback notify events. +*/ +typedef enum ar_osal_servreg_cb_event +{ + /* service state notify event */ + AR_OSAL_SERVICE_STATE_NOTIFY = 1, +} ar_osal_servreg_cb_event_type; + +/** servreg service state notify callback payload. + */ +typedef struct ar_osal_servreg_state_notify_payload { + /* Service notification for */ + ar_osal_servreg_entry_type service; + /* Service domain notification for */ + ar_osal_servreg_entry_type domain; + /* service state on a domain */ + ar_osal_service_state_type service_state; +} ar_osal_servreg_state_notify_payload_type; + +/** +* \brief ar_osal_servreg_init +* Initialize servreg interface. +* Note:This API has to be called before any other API in this interface. +* Should be called at least once and is expected to be serialized if called +* multiple times. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t ar_osal_servreg_init(void); + +/** +* \brief ar_osal_servreg_deinit +* Uninitialize servreg interface. +* Should be called in pair with ar_osal_servreg_init() and +* should be a serialized call. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t ar_osal_servreg_deinit(void); + +/** +* \brief ar_osal_servreg_get_domainlist +* Client to call this API to get a list of domains(msm/domain/subdomain) on which +* a given service(provider/service) is supported. +* +* \param[in] service: service(provider/service) for which domain(s) list is required. +* \param[in out] domain_list: service supported in domain(s), client to provide +*. payload buffer pointer. +* \param[in out] num_domains: Client to provide the num_domains to get the domain list. +*. If num_domains is zero and domain_list is NULL, API will return +*. the number of domains for the given service if available. +* +* \return +* 0 -- Success +* Nonzero -- Failure +* AR_ENOMEMORY- Failed due to insufficient memory, client to call the API again +* with required size as returned in num_domains. +*. +*/ +int32_t ar_osal_servreg_get_domainlist(ar_osal_servreg_entry_type *service, + ar_osal_servreg_entry_type *domain_list, + uint32_t *num_domains); + +/** +* \brief ar_osal_servreg_callback +* Callback function to notify clients for any changes in +* service state(up/down). +* \param[in] servreg_handle: Servreg handle returned with ar_osal_servreg_register() for the given service. +* \param[in] event_id: callback event id supported by ar_osal_servreg_cb_event_type . +* \param[in] cb_context: payload/context provided by client in ar_osal_servreg_register() . +*.\param[in] payload: payload provided by the callback. +*. service state UP/DOWN payload ar_osal_servreg_state_notify_payload_type. +*.\param[in] payload_size: payload size in bytes. +* \return +* none +*/ +typedef void(*ar_osal_servreg_callback)(ar_osal_servreg_t servreg_handle, + ar_osal_servreg_cb_event_type event_id, void *cb_context, void *payload, + uint32_t payload_size); + +/** +* \brief ar_osal_servreg_register +* Service client(s) to register for the domain service state change notifications. +* +* \param[in] client_type: indicates registering client is a listener or service provider. +* \param[in opt] cb_func: callback function pointer to get notifications on. +*. This is parameter is optional to Service provider registration. +* \param[in opt] cb_context: callback function payload/context provided by client. +*. This is parameter is optional to Service provider registration. +* \param[in] domain: domain of the service(msm/domain/subdomain) for which the +*. state change notifications to be provided. +* \param[in] service: service(provider/service) for which the +*. state change notifications to be provided. +* \return +* servreg_handle on success. +* null on failure. +*/ +ar_osal_servreg_t ar_osal_servreg_register(ar_osal_client_type client_type, + ar_osal_servreg_callback cb_func, + void *cb_context, + ar_osal_servreg_entry_type *domain, + ar_osal_servreg_entry_type *service); + +/** +* \brief ar_osal_servreg_deregister +* Service client(s) to deregister for the service state change notifications. +* +* \param[in] servreg_handle: interface handle returned by ar_osal_servreg_register(). +* +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t ar_osal_servreg_deregister(ar_osal_servreg_t servreg_handle); + +/** +* \brief ar_osal_servreg_set_state +* Service provider to call this API to register its service states(UP/DOWN). +* This API to be used only by the service provider(msm/domain/subdomain/provider/service) +* and not by service client(s). +* +* \param[in] servreg_handle: interface handle returned by ar_osal_servreg_register(). +* \param[in] state: new service state for service registered using ar_osal_servreg_register(). +*. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t ar_osal_servreg_set_state(ar_osal_servreg_t servreg_handle, + ar_osal_service_state_type state); + +/** +* \brief ar_osal_servreg_restart_service +* HLOS calls this API to trigger a restart (PDR or SSR) on a given +* processor +* +* \param[in] servreg_handle: interface handle returned by +* ar_osal_servreg_register() which identifies the desired processor +* +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t ar_osal_servreg_restart_service(ar_osal_servreg_t servreg_handle); + +/** +* \brief induce panic to crash the system +* +*/ +void ar_osal_panic(); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif //AR_OSAL_SERVREG_H diff --git a/ar_osal/api/ar_osal_shmem.h b/ar_osal/api/ar_osal_shmem.h new file mode 100644 index 0000000..b3198d2 --- /dev/null +++ b/ar_osal/api/ar_osal_shmem.h @@ -0,0 +1,300 @@ +#ifndef AR_OSAL_SHMEM_H +#define AR_OSAL_SHMEM_H + +/** + * \file ar_osal_shmem.h + * \brief + * Defines public APIs for shared memory allocation for DSP. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" +#include "ar_osal_sys_id.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + + /** enum for shmem memory type*/ +typedef enum ar_shmem_memory_type +{ + /** 0 Shared physical memory allocation.*/ + AR_SHMEM_PHYSICAL_MEMORY = 0, + /** 1 Shared virtual memory allocation */ + AR_SHMEM_VIRTUAL_MEMORY = 1 +}ar_shmem_memory_type_t; + +/** enum for shmem cache type*/ +typedef enum ar_shmem_cache_type +{ + /** 0 cached.*/ + AR_SHMEM_CACHED = 0, + /** 1 uncached.*/ + AR_SHMEM_UNCACHED = 1 +}ar_shmem_cache_type_t; + +/** enum for shmem offset/address buffer index type*/ +typedef enum ar_shmem_buffer_index_type +{ + /** 0 use physical or virtual addresses.*/ + AR_SHMEM_BUFFER_ADDRESS = 0, + /** 1 use offsets, the offset is from the base address.*/ + AR_SHMEM_BUFFER_OFFSET = 1 +}ar_shmem_buffer_index_type_t; + +typedef enum ar_shmem_pd_type +{ + STATIC_PD = 1, + DYNAMIC_PD = 2 +} ar_shmem_pd_type_t; + +/**< Bits to indicate if hardware accelerator is enabled/disabled */ +#define AR_SHMEM_HW_ACCELERATOR_ENABLED 0x1 +#define AR_SHMEM_HW_ACCELERATOR_DISABLED 0x0 + +/**< Bit mask for hardware accelerator flag */ +#define AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG 0x1 +/**< Shift amount for hardware accelerator setup flag */ +#define AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG 0x0 + +typedef struct ar_shmem_proc_info_t { + uint8_t proc_id; + ar_shmem_pd_type_t proc_type; + bool_t is_active; +} ar_shmem_proc_info; + + /** + * Shared memory info structure + */ +typedef struct ar_shmem_info_t +{ + ar_shmem_cache_type_t cache_type; /**< in, cache type, cached or uncached memory */ + size_t buf_size; /**< in, shared buffer size, should be a minimum of 4K and multiple of 4K only*/ + ar_shmem_memory_type_t mem_type; /**< out, shmem memory type, virtual or physical for ar_shmem_alloc()*/ + /**< in, shmem memory type, virtual or physical for ar_shmem_map()*/ + ar_shmem_buffer_index_type_t index_type; /**< out, DSP to operate on buffer offsets or on address pointers.*/ + uint32_t ipa_lsw; /**< out, smmu mapped ipa lsw, output for ar_shmem_alloc()/ar_shmem_map() */ + uint32_t ipa_msw; /**< out, smmu mapped ipa msw, output for ar_shmem_alloc()/ar_shmem_map() */ + uint32_t pa_lsw; /**< out, physical address lsw, alignment requirements apply, like 4k, + start address multiple of 64, output of ar_shmem_alloc()*/ + /**< in, physical address lsw, alignment requirements apply, like 4k, + start address multiple of 64, input for ar_shmem_map()*/ + uint32_t pa_msw; /**< out, physical address msw, alignment requirements apply, like 4k, + start address multiple of 64, output of ar_shmem_alloc()*/ + /**< in, physical address lsw, alignment requirements apply, like 4k + start address multiple of 64, input for ar_shmem_map()*/ + void *vaddr; /**< out, virtual address 64bit/32bit, alignment requirements apply, like 4k, + start address multiple of 64, input for ar_shmem_alloc()*/ + uint64_t metadata; /**< out opt, pointer address to metadata structure defined by each platform + for ar_shmem_alloc()*/ + uint8_t num_sys_id; /**< in, number of subsystem IDs provided with ar_shmem_alloc()/ar_shmem_map() call.*/ + ar_shmem_proc_info *sys_id; /**< in, pointer to array of size num_sys_id for sub-system Ids provided + in ar_osal_sys_id.h, used to allocate shared memory between the given + list of sys_id provided with ar_shmem_alloc()/ar_shmem_map() call.*/ + uint32_t platform_info; /**< in opt, optional field for passing platform specific data to OSAL, this can be + used for example to communicate some heap properties provided only for ar_shmem_alloc()*/ + uint32_t flags; /**< in, Bit field for flags. + @values{for bit 0} + - 1 -- hardware accelerator enabled, use AR_SHMEM_HW_ACCELERATOR_ENABLED + - 0 -- hardware accelerator disabled, use AR_SHMEM_HW_ACCELERATOR_DISABLED + - To set this bit, use #AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG and + AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG + All other bits are reserved; must be set to 0. */ +} ar_shmem_info; + +/** +* Shared memory physical address and size details for hyp assign. +*/ +typedef struct ar_shmem_hyp_assign_phys_addr_t +{ + uint64_t phys_addr; /**< 64-bit physical address. */ + size_t size; /**< size in bytes for the buffer pointed by phys_addr*/ +} ar_shmem_hyp_assign_phys_addr; + +/** +* Destination sub system permission bit mask types supported. +* Combination of permissions can be used as per requirements. +*/ +typedef enum ar_shmem_hyp_assign_dest_sys_perm_t +{ + DEST_SYS_PERM_INVALID = 0x0, /**< Invalid permission bit mask. */ + DEST_SYS_PERM_EXEC = 0x1, /**< Execute permission bit mask. */ + DEST_SYS_PERM_WRITE_ONLY = 0x2, /**< Write only permission bit mask. */ + DEST_SYS_PERM_EXEC_WRITE = (DEST_SYS_PERM_EXEC | DEST_SYS_PERM_WRITE_ONLY), /**< Execute and Write permission.*/ + DEST_SYS_PERM_READ_ONLY = 0x4, /**< Read only permission bit mask. */ + DEST_SYS_PERM_EXEC_READ = (DEST_SYS_PERM_EXEC | DEST_SYS_PERM_READ_ONLY), /**< Execute and Read permission. */ + DEST_SYS_PERM_WRITE_READ = (DEST_SYS_PERM_WRITE_ONLY | DEST_SYS_PERM_READ_ONLY), /**< Write and Read permission. */ + DEST_SYS_PERM_EXEC_WRITE_READ = (DEST_SYS_PERM_EXEC | DEST_SYS_PERM_WRITE_ONLY | DEST_SYS_PERM_READ_ONLY), /**< Execute, Write and Read permission. */ +} ar_shmem_hyp_assign_dest_sys_perm; + +/** +* Destination sub system id details and permission required for hyp assign. +*/ +typedef struct ar_shmem_hyp_assign_dest_sys_info_t +{ + uint64_t dest_sys_id; /**< destination sub system id, refer to ar_osal_sys_id.h */ + ar_shmem_hyp_assign_dest_sys_perm dest_perm; /**< destination permissions */ +} ar_shmem_hyp_assign_dest_sys_info; + +/** +* Hyp assign physical memory info structure. +*/ +typedef struct ar_shmem_hyp_assign_phys_info_t +{ + ar_shmem_hyp_assign_phys_addr *phys_addr_list; /**< list of hyp_assign_phys_addr structures.*/ + uint32_t phys_addr_list_size; /**< number of phys_addr_list entries.*/ + uint64_t *src_sys_list; /**< source sub system Id list, refer to ar_osal_sys_id.h for sys ids.*/ + uint32_t src_sys_list_size; /**< number of src_sys_list entries.*/ + ar_shmem_hyp_assign_dest_sys_info *dest_sys_list; /**< destination sys list hyp_assign_dest_sys_info.*/ + uint32_t dest_sys_list_size; /**< number of destination sys list/dest_sys_list entires.*/ + uint64_t metadata; /**< in opt, pointer address to metadata structure defined by platform + during ar_shmem_alloc() call.*/ +} ar_shmem_hyp_assign_phys_info; + + +/** + * \brief Initialize the shared memory interface (V1 API). + * + * This function initializes the shared memory interface using the + * default configuration. It performs the legacy initialization flow. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_init(); + +/** + * \brief Initialize the shared memory interface using a list of processor domains (V2 API). + * + * This V2 API selects the appropriate shared memory implementation + * based on the provided list of processor domain IDs. + * + * Passing num_master_procs = 0 results in behavior equivalent to the + * V1 API (ar_shmem_init), allowing a smooth transition from V1 to V2. + * + * \param[in] num_master_procs Number of processor domain IDs. + * \param[in] master_procs Pointer to an array of processor domain IDs. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_init_v2(uint32_t num_master_procs, uint32_t *master_procs); + +/** + * \brief Allocates shared memory. + * Only non cached memory allocation supported. + * Size if multiple of 4KB and the returned is aligned to 4KB boundary. + * Buffer start address should be atleast 64bit multiple aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_alloc(ar_shmem_info *info); + +/** + * Frees shared memory. + * + * \param[in] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_free(ar_shmem_info *info); + +/** + * \brief Helps map memory with SMMU an already allocated shared memory + * for a give sub system. + * Size should be multiple of 4KB boundary. + * Buffer start address should be 64bit aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.mem_type + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * required output parameters in ar_shmem_info + * ar_shmem_info_t.ipa_lsw + * ar_shmem_info_t.ipa_msw + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_map(ar_shmem_info *info); + +/** + * \brief Helps unmap the shared memory allocated externally with SMMU. + * + * \param[in] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.mem_type + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ + int32_t ar_shmem_unmap(ar_shmem_info *info); + + /** + * \brief Helps to hyp assign physical memory between source and destination sub systems. + * + * \param[in] info: pointer to ar_shmem_hyp_assign_phys_info. + + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info); + +/** +* \brief ar_shmem_get_uid. +* Get associated unique identifier(UID) for the shared memory +* pointed by alloc_handle, platform which doesn`t support UID +* should return alloc_handle as UID with expectation of +* alloc_handle being unique. +* +* \param[in] alloc_handle: handle for the shared memory. +* \param[out] uid: unique identifier to the shmem. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t ar_shmem_get_uid(uint64_t alloc_handle, uint64_t *uid); + +/** + * \brief ar_shmem_deinit. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_deinit(void); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* #ifndef AR_OSAL_SHMEM_H */ + diff --git a/ar_osal/api/ar_osal_signal.h b/ar_osal/api/ar_osal_signal.h new file mode 100644 index 0000000..03d09c0 --- /dev/null +++ b/ar_osal/api/ar_osal_signal.h @@ -0,0 +1,244 @@ +#ifndef AR_OSAL_SIGNAL_H +#define AR_OSAL_SIGNAL_H + +/** + * \file ar_osal_signal.h + * \brief + * Defines public APIs for signal. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** @weakgroup weakf_osal_signal_intro +This section describes the following signal functions: +- ar_osal_signal_init() +- ar_osal_signal_deinit() +- ar_osal_signal_get_size() +- ar_osal_signal_create() +- ar_osal_signal_destroy() +- ar_osal_signal_set() +- ar_osal_signal_clear() +- ar_osal_signal_wait() +- ar_osal_signal_timedwait() +*/ + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ +/* ======================================================================= +INCLUDE FILES FOR MODULE +========================================================================== */ +#include "ar_osal_types.h" + +/** @addtogroup ar osal signal +@{ */ + +/* ----------------------------------------------------------------------- +** Global definitions/forward declarations +** ----------------------------------------------------------------------- */ + +/**************************************************************************** +** Signals +*****************************************************************************/ + +/** Signal to be triggered by events, or used to trigger events. + +*/ +typedef void *ar_osal_signal_t; + +/** + initialize a signal object. The client must allocate the memory for the signal and + pass the pointer to this function. + The signal object is initially cleared. + + @datatypes + ar_osal_signal_t + + @param[in] signal: Pointer to the signal object. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. @newpage +*/ +int32_t ar_osal_signal_init(ar_osal_signal_t signal); + +/** + De-initialize a signal object. + + @datatypes + ar_osal_signal_t + + @param[in] signal: Pointer to the signal. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. @newpage +*/ +int32_t ar_osal_signal_deinit(ar_osal_signal_t signal); + + +/** + Get signal object size for client to allocate its memory. + + @datatypes + ar_osal_signal_t + + @return + Size of signal object + + @dependencies + None. @newpage +*/ +size_t ar_osal_signal_get_size(void); +/** + Create a signal and initialize. Signal object memory is allocated by this API and + returned to the client. + The signal object is initially cleared. + ar_osal_signal_create() or ar_osal_signal_init() would be used, but not both. + + @datatypes + ar_osal_signal_t + + @param[out] signal: Pointer to the signal. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. @newpage +*/ +int32_t ar_osal_signal_create(ar_osal_signal_t *signal); + +/** + Destroy a signal. Frees the memory allocated by ar_osal_signal_create + API. Signal objects must not be destroyed while its still in use. + + @datatypes + ar_osal_signal_t + + @param[in] signal: Pointer to the signal. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the signal group must be created and + initialized. @newpage +*/ +int32_t ar_osal_signal_destroy(ar_osal_signal_t signal); + +/** + Sets signal in the specified signal object. + + @datatypes + ar_osal_signal_t + + @param[in] signal: Pointer to the signal. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the signal group must be created and + initialized. +*/ +int32_t ar_osal_signal_set(ar_osal_signal_t signal); + +/** + Clear signal in the specified signal object. + Signal must be explicitly cleared by a thread when it is awakened, + the wait operations do not automatically clear it. + + Clearing a signal that is already cleared has no effect. + + @datatypes + ar_osal_signal_t + + @param[in] signal: Pointer to the signal. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the signal group must be created and + initialized. +*/ +int32_t ar_osal_signal_clear(ar_osal_signal_t signal); + + +/** + Wait on a signal, wait infinitely for the signal to be set. + + If a thread is waiting on a signal object for signal to be set, + and the signal object is set, then the thread is awakened. + + The signal can be cleared once the signal is set. + + The signal must be manually cleared using the ar_osal_signal_clear + function. Any number of waiting threads, or threads that subsequently + begin wait operations for the specified signal object, will be released + while the signal object's state is signaled. + + If a signal is set before a thread is waiting, then it will be returned + immediately and the signal must be cleared to avoid unintended behavior + + @datatypes + ar_osal_signal_t + + @param[in] signal: Pointer to the signal. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the signal group must be created and + initialized. +*/ +int32_t ar_osal_signal_wait(ar_osal_signal_t signal); + +/** + Wait on signal till timeout happens. + + The signal can be cleared once the signal is set or timeout occurs. + + The signal must be manually cleared using the ar_osal_signal_clear + function. Any number of waiting threads, or threads that subsequently + begin wait operations for the specified signal object, will be released + while the signal object's state is signaled. + + If a signal is set before a thread is waiting, then it will be returned + immediately and the signal must be cleared to avoid unintended behavior + + @datatypes + ar_osal_signal_t + + @param[in] signal: Pointer to the signal. + @param[in] timeout_in_nsec: Time to wait in nano seconds + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + Before calling this function, the signal group must be created and + initialized. +*/ +int32_t ar_osal_signal_timedwait(ar_osal_signal_t signal, int64_t timeout_in_nsec); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif // #ifndef AR_OSAL_SIGNAL_H + diff --git a/ar_osal/api/ar_osal_signal2.h b/ar_osal/api/ar_osal_signal2.h new file mode 100644 index 0000000..a673560 --- /dev/null +++ b/ar_osal/api/ar_osal_signal2.h @@ -0,0 +1,291 @@ +#ifndef AR_OSAL_SIGNAL2_H +#define AR_OSAL_SIGNAL2_H + +/** + * \file ar_osal_signal2.h + * \brief + * Defines public APIs for signal2 used by DSP. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** @weakgroup weakf_osal_signal2_intro +This section describes the following signal2 functions: +- ar_osal_signal2_init() +- ar_osal_signal2_deinit() +- ar_osal_signal2_get_size() +- ar_osal_signal2_create() +- ar_osal_signal2_destroy() +- ar_osal_signal2_set() +- ar_osal_signal2_get() +- ar_osal_signal2_clear() +- ar_osal_signal2_wait_any() +- ar_osal_signal2_wait_all() +*/ + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ +/*===================================================================== + Typedefs + ======================================================================*/ +#include "ar_osal_types.h" + +/** @addtogroup signals_types +@{ */ +/** ar_osal_signal2 type + */ +typedef void *ar_osal_signal2_t; +/** @} */ /* end_addtogroup signals_types */ + +/*===================================================================== + Functions +======================================================================*/ + +/*======================================================================*/ +/**@ingroup func_osal_signal2_init + Initializes a signal2 object. + Signal returns the initialized object. + The signal object is initially cleared. + signal object memory is allocated by the client. + + @datatypes + #ar_osal_signal2_t + + @param[in] signal2: Pointer to the initialized object. + + @return + 0 -- Success + Nonzero -- Failure + + + @dependencies + + */ +/* ======================================================================*/ +int32_t ar_osal_signal2_init(ar_osal_signal2_t signal2); + +/*======================================================================*/ +/**@ingroup func_osal_signal2_deinit + De-initializes signal2 object. + + @datatypes + ar_osal_signal2_t + + @param[in] signal2: Pointer to the initialized object. + + @return + 0 -- Success + Nonzero -- Failure + + + @dependencies + */ + +/* ======================================================================*/ +int32_t ar_osal_signal2_deinit(ar_osal_signal2_t signal2); + +/*======================================================================*/ +/**@ingroup func_osal_signal2_get_size + Get signal object size for object memory allocation by client. + + @datatypes + ar_osal_signal2_t + + @return + Size of signal object + + + @dependencies + */ + +/* ======================================================================*/ +size_t ar_osal_signal2_get_size(void); + +/*======================================================================*/ +/**@ingroup func_osal_signal2_create + Signal object memory is allocated and initialized by this API. + osal_signal2_create() or osal_signal2_init() would be used, but not both. + + @datatypes + ar_osal_signal2_t + + @param[Out] signal2: Pointer to the initialized object. + + @return + 0 -- Success + Nonzero -- Failure + + + @dependencies + + */ +/* ======================================================================*/ +int32_t ar_osal_signal2_create(ar_osal_signal2_t *signal2); + + +/*======================================================================*/ +/**@ingroup func_osal_signal2_destroy + Destroys the specified signal object. + + @note1cont Signal objects must not be destroyed while they are still in use. If this + happens the behavior is undefined. + @note1cont In general, application code should "destroy" a signal2 object prior to + deallocating it; calling osal_signal2_destroy() before deallocating it ensures + that all osal_signal2_set() calls have completed. + + @datatypes + #ar_osal_signal2_t + + @param[in] signal2: Pointer to the signal object to destroy. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. + */ +/* ======================================================================*/ +int32_t ar_osal_signal2_destroy(ar_osal_signal2_t signal2); + +/*======================================================================*/ +/**@ingroup func_osal_signal2_wait_any + Suspends the current thread until any of the specified signals are set. + + Signals are represented as bits 0-31 in the 32-bit mask value. A mask bit value of 1 indicates + that a signal is to be waited on, and 0 that it is not to be waited on. + + If a thread is waiting on a signal object for any of the specified set of signals to be set, + and one or more of those signals is set in the signal object, then the thread is awakened. + + At most one thread can wait on a signal object at any given time. + + Signals must be explicitly cleared by a thread when it is awakened + the wait operations do not automatically clear them. + + @datatypes + #ar_osal_signal2_t + + @param[in] signal2: Pointer to the signal object to wait on. + @param[in] signal2_mask: Mask value identifying the individual signals + in the signal object to be waited on. + + @return + A 32 bit word with current signals. + + @dependencies + None. +*/ +/* ======================================================================*/ +uint32_t ar_osal_signal2_wait_any(ar_osal_signal2_t signal2, uint32_t signal2_mask); + +/*======================================================================*/ +/**@ingroup func_osal_signal2_wait_all + Suspends the current thread until all of the specified signals are set. + + Signals are represented as bits 0-31 in the 32-bit mask value. A mask bit value of 1 indicates + that a signal is to be waited on, and 0 that it is not to be waited on. + + If a thread is waiting on a signal object for all of the specified set of signals to be set, + and all of those signals are set in the signal object, then the thread is awakened. + + At most one thread can wait on a signal object at any given time. + + Signals must be explicitly cleared by a thread when it is awakened + the wait operations do not automatically clear them. + + @datatypes + #ar_osal_signal2_t + + @param[in] signal2: Pointer to the signal object to wait on. + @param[in] signal2_mask: Mask value which identifies the individual signals + in the signal object to be waited on. + + @return + A 32 bit word with current signals. + + @dependencies + None. +*/ +/* ======================================================================*/ +uint32_t ar_osal_signal2_wait_all(ar_osal_signal2_t signal2, uint32_t signal2_mask); + +/*======================================================================*/ +/**@ingroup func_osal_signal2_set + Sets signals in the specified signal object. + + Signals are represented as bits 0-31 in the 32-bit mask value. A mask bit value of 1 indicates + that a signal is to be set, and 0 that it is not to be set. + + @datatypes + ar_osal_signal2_t + + @param[in] signal2: Pointer to the signal object to be modified. + @param[in] signal2_mask: Mask value identifying the individual + signals to be set in the signal object. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. +*/ +/* ======================================================================*/ +int32_t ar_osal_signal2_set(ar_osal_signal2_t signal2, uint32_t signal2_mask); + +/*======================================================================*/ +/**@ingroup func_osal_signal2_get + Gets a signal from a signal object. + + Returns the current signal values of the specified signal object. + + @datatypes + ar_osal_signal2_t + + @param[in] signal2: Pointer to the signal object to access. + + @return + A 32 bit word with current signals + + @dependencies + None. +*/ +/* ======================================================================*/ +uint32_t ar_osal_signal2_get(ar_osal_signal2_t signal2); + +/*======================================================================*/ +/**@ingroup func_osal_signal2_clear + Clear signals in the specified signal object. + + Signals are represented as bits 0-31 in the 32-bit signal2_mask value. + A signal2_mask bit value of 1 indicates that a signal is to be cleared, + and 0 that it is not to be cleared. + + Signals must be explicitly cleared by a thread when it is awakened + the wait operations do not automatically clear them. + + @datatypes + ar_osal_signal2_t + + @param[in] signal: Pointer to the signal object to modify. + @param[in] signal2_mask: signal2_mask value identifying the + individual signals to be cleared in the signal object. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. + */ +/* ======================================================================*/ +int32_t ar_osal_signal2_clear(ar_osal_signal2_t signal2, uint32_t signal2_mask); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* AR_OSAL_SIGNAL2_H */ diff --git a/ar_osal/api/ar_osal_sleep.h b/ar_osal/api/ar_osal_sleep.h new file mode 100644 index 0000000..5f9b6ce --- /dev/null +++ b/ar_osal/api/ar_osal_sleep.h @@ -0,0 +1,48 @@ +#ifndef AR_OSAL_SLEEP_H +#define AR_OSAL_SLEEP_H + +/** + * \file ar_osal_sleep.h + * \brief + * This file contains APIs to suspend thread execution + * for the required duration. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + /* ======================================================================= + INCLUDE FILES FOR MODULE + ========================================================================== */ +#include "ar_osal_types.h" + + /**************************************************************************** + ** Sleep + *****************************************************************************/ + /** + Micro second sleep function. Sleep internal may not be accurate + as requested, it would vary based on resolution of system clock ticks. + Note that a ready thread is not guaranteed to run immediately. + Consequently, the thread may not run until some time after the sleep interval + elapses. + + @param[in] micro_seconds: sleep duration in micro seconds. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. @newpage + */ + int32_t ar_osal_micro_sleep(uint64_t micro_seconds); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* #ifndef AR_OSAL_SLEEP_H */ + diff --git a/ar_osal/api/ar_osal_string.h b/ar_osal/api/ar_osal_string.h new file mode 100644 index 0000000..a8a15a6 --- /dev/null +++ b/ar_osal/api/ar_osal_string.h @@ -0,0 +1,131 @@ +#ifndef AR_OSAL_STRING_H +#define AR_OSAL_STRING_H + +/** + * \file ar_osal_string.h + * \brief + * Defines public APIs for string operations. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** + * \brief ar_strlen + * Get the length of the string. + * \param[in] str: NULL terminated string buffer pointer. + * \param[in] size: String buffer size in bytes. + * \return + * Number of characters in the string, not including the terminating null + * character. If there is no null terminator in the buffer, provided + * string buffer size is returned to indicate the error. + */ +size_t ar_strlen(const char_t* str, size_t size); + +/** + * \brief ar_strcpy + * Copies character from source to destination string. + * \param[in_out] str_dest: Destination string buffer. + * \param[in] str_dest_size: Size in characters. + * \param[in] str_src: Source string to copy from. + * \param[in] cpy_size: Size in characters to copy from source string. + * \return + * 0 -- Success + * Nonzero -- Failure + * note: Always null terminator is appended to the destination and string + * truncation will occur if destination size is smaller or equal to characters copy size. + */ +int32_t ar_strcpy(char_t* str_dest, size_t str_dest_size, const char_t* str_src, size_t cpy_size); + +/** + * \brief ar_strcmp + * Compare characters in two given strings. + * \param[in] str1: Null terminated string 1 + * \param[in] str2: Null terminated string 2 + * \param[in] num: number of characters to compare. + * \return + * < 0 str1 < str2 + * 0 str1 == str2 + * > 0 str1 > str2 + */ +int32_t ar_strcmp(const char_t* str1, const char_t* str2, size_t num); + +/** +* \brief ar_strcat +* Append character from source to destination string. +* \param[in_out] str_dest: Destination string buffer. +* \param[in] str_dest_size: Size in characters. +* \param[in] str_src: Source string to copy from. +* \param[in] apnd_size: Size in characters to append from source string. +* \return +* 0 -- Success +* Nonzero -- Failure +* note: Always null terminator is appended to the destination after concatenation and string +* truncation will occur if destination size is smaller or equal to source. +*/ +int32_t ar_strcat(char_t* str_dest, size_t str_dest_size, const char_t* str_src, size_t apnd_size); + +/** + * \brief ar_strstr + * Search string in string. + * \param[in] str: Null terminated string + * \param[in] str_search: Null terminated string to search for. + * \return + * Pointer to the first occurrence of str_search in str. + * NULL- if not found. + */ +char_t* ar_strstr(const char_t* str, const char_t* str_search); + +/*--------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------*/ +/** +* \brief ar_sprintf +* Write formated data to a string. +* \param[in_out] str_dest: Destination string buffer. +* \param[in] str_dest_size: Size in bytes. +* \param[in] format: Format control string. +* \param[in] "..." : variable arguments. +* \return +* Number of characters written to the buffer(null terminator not counted). +* Destination is appended with null terminator always, if data is greater than the +* destination buffer size, truncation will occur with appended null terminator. +*/ + +/** +* \brief ar_sscanf +* Read formated data from a string. +* \param[in] str_src: Stored string buffer. +* \param[in] format: Format control string. +* \param[in] "..." : variable arguments. +* \return +* Number of fields successfully converted and assigned, the return value does not include +* fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. +*/ + +#if defined(_WIN64) || defined(_WIN32) /* WIN32/WIN64 and Windows kernel.*/ + +#define ar_sprintf(str_dest, str_dest_size, format, ...) _snprintf_s(str_dest, str_dest_size, _TRUNCATE, format, __VA_ARGS__) +#define ar_sscanf(str_src, format, ...) sscanf_s(str_src, format, __VA_ARGS__) + +#else /* all others */ + +#define ar_sprintf(str_dest, str_dest_size, format, ...) snprintf(str_dest, str_dest_size, format, __VA_ARGS__) +#define ar_sscanf(str_src, format, ...) sscanf(str_src, format, __VA_ARGS__) + +#endif + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* #ifndef AR_OSAL_STRING_H */ + diff --git a/ar_osal/api/ar_osal_sys_id.h b/ar_osal/api/ar_osal_sys_id.h new file mode 100644 index 0000000..4b60ee1 --- /dev/null +++ b/ar_osal/api/ar_osal_sys_id.h @@ -0,0 +1,76 @@ +#ifndef AR_OSAL_SYS_ID_H +#define AR_OSAL_SYS_ID_H + +/** + * \file ar_osal_sys_id.h + * \brief + * Defines Supported Sub-System IDs. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +/** +* Invalid sub system +*/ +#define AR_SUB_SYS_ID_INVALID 0 +/** +* Used for MODEM DSP sub system + */ +#define AR_MODEM_DSP 1 +/** +* Used for ADSP sub system +*/ +#define AR_AUDIO_DSP 2 +/** +* Used for AP sub system +*/ +#define AR_APSS 3 +/** +* Used for SENSOR DSP sub system +*/ +#define AR_SENSOR_DSP 4 +/** +* Used for COMPUTE DSP sub system +*/ +#define AR_COMPUTE_DSP 5 +/** +* Used for Companion chip DSP (CC_DSP) sub system +*/ +#define AR_CC_DSP 6 +/** +* Used for APSS2 sub system +*/ +#define AR_APSS2 0xC + +/** +* First sub system ID +*/ +#define AR_SUB_SYS_ID_FIRST AR_MODEM_DSP +/** +* Last sub system ID +*/ +#define AR_SUB_SYS_ID_LAST AR_APSS2 + +/** +* Bit masks representing the subsystem IDs. Update when subystem gets +* added or removed. +*/ +#define AR_SUB_SYS_IDS_MASK 0x83F + +#ifdef MDSP_PROC +#define AR_DEFAULT_DSP AR_MODEM_DSP +#else +#define AR_DEFAULT_DSP AR_AUDIO_DSP +#endif + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif //AR_OSAL_SYS_ID_H diff --git a/ar_osal/api/ar_osal_thread.h b/ar_osal/api/ar_osal_thread.h new file mode 100644 index 0000000..971e6e6 --- /dev/null +++ b/ar_osal/api/ar_osal_thread.h @@ -0,0 +1,211 @@ +#ifndef AR_OSAL_THREAD_H +#define AR_OSAL_THREAD_H + +/** + * \file ar_osal_thread.h + * \brief + * Defines public APIs for thread. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** @weakgroup weakf_osal_thread_intro +Threads must be joined to avoid memory leaks. The following thread functions +are used to create and destroy threads, and to change thread priorities. +- ar_osal_thread_create() +- ar_osal_thread_attr_init() +- ar_osal_thread_join_destroy() +- ar_osal_thread_get_priority() +- ar_osal_thread_set_priority() +- ar_osal_thread_self_get_priority() +- ar_osal_thread_self_set_priority() +*/ + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ +/* ======================================================================= +INCLUDE FILES FOR MODULE +========================================================================== */ +#include "ar_osal_types.h" + +/** @addtogroup osal_thread +@{ */ +#include "ar_osal_types.h" +/* ----------------------------------------------------------------------- +** Global definitions/forward declarations +** ----------------------------------------------------------------------- */ + +/** Handle to a thread. */ +typedef void * ar_osal_thread_t; + +/** Thread attributes. */ +typedef struct ar_osal_thread_attr_t +{ + char_t *thread_name; /**< Pointer to the thread name */ + uint32_t stack_size; /**< Size of the thread stack */ + int32_t priority; /**< Thread priority */ +}ar_osal_thread_attr_t; + +/**************************************************************************** +** Threads +*****************************************************************************/ +/** + osal thread start function definition. + + @param[in] thread_param: The client supplied data pointer when creating + a thread. + + */ +typedef void (*ar_osal_thread_start_routine) (void *thread_param); + + +/** + Thread attribute initialization API, client allocates the memory for ar_osal_thread + + @datatypes + osal_thread_attribute_t + + @param[in] thread_attr: Initialize thread object. + + @return + 0 -- Success + Nonzero -- Failure + + @dependencies + None. @newpage +*/ +int32_t ar_osal_thread_attr_init(ar_osal_thread_attr_t *thread_attr); + +/** + Creates and launches a thread. + + @datatypes + ar_osal_thread_t + + @param[out] thread: Pointer to the thread. + @param[in] thread_attr: Pointer to the thread attributes. + @param[in] thread_start: Pointer to the entry function of the thread. + @param[in] thread_param: Pointer to the arguments passed to the entry + function. + An argument can be to any pointer type. + @detdesc + The thread stack can be passed in as the osal_thread_stack argument, or + osal_thread_stack=NULL indicates that osal allocates the stack internally. + If the caller provides the stack, the caller is responsible for freeing + the stack memory after joining the thread. + @par + Pre-allocated stacks must be freed after the dying thread is joined. The + caller must specify the heap in which the thread stack is to be allocated. + + @return + 0 -- Success + Nonzero -- Failure. + + @dependencies + None. @newpage +*/ +int32_t ar_osal_thread_create( ar_osal_thread_t *thread, + ar_osal_thread_attr_t *attr_ptr, + ar_osal_thread_start_routine thread_start, + void *thread_param); + +/** + Get current thread id. + + + @param[Out] thread id: Current thread id. + + @return + Thread id. + + @dependencies + Before calling this function, the object must be created and initialized. +*/ +int64_t ar_osal_thread_get_id(void); + +/** + Waits for a specified thread to exit, and collects the exit status + and clear the thread object + + @datatypes + ar_osal_thread_t + + @param[in] thread: Thread to wait on. + + @return + 0 -- Success. + Nonzero -- Failure. + + @dependencies + Before calling this function, the object must be created and initialized. +*/ +int32_t ar_osal_thread_join_destroy(ar_osal_thread_t thread); + +/** + Queries the thread priority using a thread handle. + + @param[in] thread: Thread handle. + @param[out] get_priority: current thread priority + + 0 -- Success. + Nonzero -- Failure. + + @dependencies + Before calling this function, the object must be created and initialized. + @newpage +*/ +int32_t ar_osal_thread_get_priority(ar_osal_thread_t thread, int32_t *get_priority); + +/** + Changes the thread priority using a thread handle. + + @param[in] thread: Thread handle. + @param[in] set_priority: New thread priority to set + + @return + 0 -- Success. + Nonzero -- Failure. + + @dependencies + Before calling this function, the object must be created and initialized. +*/ +int32_t ar_osal_thread_set_priority(ar_osal_thread_t thread, int32_t set_priority); + +/** + Queries the thread priority within the thread work function. + + @param[out] get_priority: get thread priority + + @return + 0 -- Success. + Nonzero -- Failure. + + @dependencies + Before calling this function, the object must be created and initialized. + @newpage +*/ +int32_t ar_osal_thread_self_get_priority(int32_t *get_priority); + +/** + Changes the thread priority within the thread work function. + + @param[in] set_priority: New priority to set + + @return + 0 -- Success. + Nonzero -- Failure. + + @dependencies + Before calling this function, the object must be created and initialized. +*/ +int32_t ar_osal_thread_self_set_priority(int32_t set_priority); + +/** @} */ /* end_addtogroup ar_osal_thread */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif // #ifndef AR_OSAL_THREAD_H + diff --git a/ar_osal/api/ar_osal_timer.h b/ar_osal/api/ar_osal_timer.h new file mode 100644 index 0000000..02c3ce2 --- /dev/null +++ b/ar_osal/api/ar_osal_timer.h @@ -0,0 +1,40 @@ +#ifndef AR_OSAL_TIMER_H +#define AR_OSAL_TIMER_H + +/** + * \file ar_osal_timer.h + * \brief + * Defines public APIs for timer operations. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** + * \brief ar_timer_get_time_in_us + * Gets the wall clock time in microseconds + * \return + * Wall clock time in microseconds. + */ +uint64_t ar_timer_get_time_in_us(void); + + +/** + * \brief ar_timer_get_time_in_ms + * Gets the wall clock time in milliseconds + * \return + * Wall clock time in milliseconds. + */ +uint64_t ar_timer_get_time_in_ms(void); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* #ifndef AR_OSAL_TIMER_H */ diff --git a/ar_osal/api/ar_osal_types.h b/ar_osal/api/ar_osal_types.h new file mode 100644 index 0000000..c4fa1c0 --- /dev/null +++ b/ar_osal/api/ar_osal_types.h @@ -0,0 +1,252 @@ +#ifndef AR_OSAL_TYPES_H +#define AR_OSAL_TYPES_H + +/** + * \file ar_osal_types.h + * \brief + * This file contains basic types and pre processor macros. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#if defined(__H2XML__) + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef signed long long int64_t; +typedef unsigned long long uint64_t; + +#else /** else of defined(__H2XML__) */ + +/* ----------------------------------------------------------------------- +** COMMON to all ---> START +** ----------------------------------------------------------------------- */ + /* ----------------------------------------------------------------------- + ** Standard Types + ** ----------------------------------------------------------------------- */ + + #include + #include + #include + +#ifdef __INTEGRITY + #include "mmdefs.h" +#endif + /* ------------------------------------------------------------------------ + ** Character and boolean + ** ------------------------------------------------------------------------ */ +#ifndef __INTEGRITY /* defined only on greenhills compiler */ + typedef char char_t; /**< Character type */ + typedef unsigned char bool_t; /**< Boolean value type. */ +#endif + + #ifndef FALSE + #define FALSE 0 + #endif + + #ifndef TRUE + #define TRUE 1 + #endif +/* ----------------------------------------------------------------------- +** COMMON to all ---> END +** ----------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------- +** COMMON to all except windows kernel ---> START +** ----------------------------------------------------------------------- */ +#if !defined(_KERNEL_MODE) + + /** PAGING functiona and data*/ + + /** By default, the linker assigns names such as ".text" and ".data" to the code and data sections + *of a driver image file. When the driver is loaded, the I/O manager makes these sections nonpaged. + *A nonpaged section is always memory-resident. + *A driver developer has the option to make designated parts of a driver pageable so that Windows + *can move these parts to the paging file when they are not in use. To make a code or data section + *pageable, the driver developer assigns a name that begins with "PAGE" to the section. The I/O manager + *checks the names of the sections when it loads a driver. If a section name begins with "PAGE", + *the I/O manager makes the section pageable. + *Code that runs at IRQL >= DISPATCH_LEVEL must be memory-resident. That is, this code must be either + *in a nonpageable segment, or in a pageable segment that is locked in memory. If code that is running + *at IRQL >= DISPATCH_LEVEL causes a page fault, a bug check occurs. Drivers can use the PAGED_CODE macro + *to verify that pageable functions are called only at appropriate IRQLs. + */ + + /** Paged functions*/ + + /** Should be used at the start of functions group to be paged */ + #define PAGED_FUNCTIONS_START + + /** Should be used at the end of functions group to be paged */ + #define PAGED_FUNCTIONS_END + + /** Should be used at the start of the paged function definition */ + #define PAGED_FUNCTION() + + /** Paged Data*/ + + /** Should be used at the start of the vairables group to be paged */ + #define PAGED_DATA_START + + /** Should be used at the end of the variables group to be paged */ + #define PAGED_DATA_END + +/* ----------------------------------------------------------------------- +** COMMON to all except windows kernel ---> END +** ----------------------------------------------------------------------- */ +#endif + +/* ----------------------------------------------------------------------- +** Windows kernel and user mode ---> START +** ----------------------------------------------------------------------- */ +#if defined(_WIN64) || defined(_WIN32) + + #include + +/* ----------------------------------------------------------------------- +** Windows kernel mode only ---> START +** ----------------------------------------------------------------------- */ + #if defined(_KERNEL_MODE) + + #include + #include + #include + #include + #include + + #define snprintf(X,Y,...) _snprintf_s(X, Y, _TRUNCATE, __VA_ARGS__) + + + + #ifndef false + #define false 0 + #endif + + #ifndef true + #define true 1 + #endif + + + /** Paged functions*/ + + /** Should be used at the start of functions group to be paged */ + #define PAGED_FUNCTIONS_START __pragma (code_seg("PAGEAR")) + + /** Should be used at the end of functions group to be paged */ + #define PAGED_FUNCTIONS_END __pragma (code_seg()) + + /** Should be used at the start of the paged function definition */ + #define PAGED_FUNCTION() PAGED_CODE(); + + /** Paged Data*/ + + /** Should be used at the start of the vairables group to be paged */ + #define PAGED_DATA_START __pragma (data_seg("PAGEAR")) + + /** Should be used at the end of the variables group to be paged */ + #define PAGED_DATA_END __pragma (data_seg()) + +/* ----------------------------------------------------------------------- +** Windows kernel mode only ---> END +** ----------------------------------------------------------------------- */ + #else + +/* ----------------------------------------------------------------------- +** Windows user mode only ---> START +** ----------------------------------------------------------------------- */ + #include + #include +/* ----------------------------------------------------------------------- +** Windows user mode only ---> END +** ----------------------------------------------------------------------- */ + #endif + + + #define __UNREFERENCED_PARAM(x) (x) /*UNREFERENCED_PARAMETER is not used here, getting conflict including windows.h with INFINITE redefined in DSP(media_fmt_api.h)*/ + #define __UNUSED + +/* ----------------------------------------------------------------------- +** Windows kernel and user mode ---> END +** ----------------------------------------------------------------------- */ +#else + +/* ----------------------------------------------------------------------- +** Rest of the Platforms ---> START +** ----------------------------------------------------------------------- */ + + #include + #define __UNREFERENCED_PARAM(x) + + #if defined (__GNUC__) + #define __UNUSED __attribute__((unused)) + #else + #define __UNUSED + #endif + + /** Function parameter annotations + */ + /** This parameter must have a valid value and will not be changed by the function + */ + #define _In_ + + /** This parameter may not have valid value and will not be changed by the function. + */ + #define _In_opt_ + + /** This parameter does not have a valid value, but must be a valid value after the + * function call returns. + */ + #define _Out_ + + /** This parameter does not have a valid value before and after the function call returns. + */ + #define _Out_opt_ + + /** This parameter must have a valid value before and should have a different value after + * the function call returns. + */ + #define _Inout_ + + /** This parameter may not have a valid value before and after the function call returns. + */ + #define _Inout_opt_ + + /** This Parameter cannot be null and should have a valid pointer to location after the + * function call returns. + */ + #define _Outptr_ + + /** This Parameter can be null and should have a valid pointer to location after the + * function call returns. + */ + #define _Outptr_opt_ + + /** Interrupt request level(IRQL) */ + /** Driver code or system APIs can only run on certain IRQLs. Developer must ensure IRQL requirements are met. + *Code with in spin lock usage must not be paged. + *Code with in spin lock must be minimum possible. + *Interrupts/callbacks function running at DISPATCH IRQL (high priorities) should not be paged. + *Identify functions which could run at PASSIVE IRQL( low priority). + */ + #define _IRQL_requires_max_(irql) + + #define _IRQL_requires_min_(irql) + + /** Normal priority level */ + #define PASSIVE_LEVEL + + /** Runs at high priority level, these functions should not be paged.*/ + #define DISPATCH_LEVEL + +/* ----------------------------------------------------------------------- +** Rest of the Platforms ---> END +** ----------------------------------------------------------------------- */ +#endif + +#endif /* __H2XML__ */ +#endif /* #ifndef AR_OSAL_TYPES_H */ diff --git a/ar_osal/ar_osal.pc.in b/ar_osal/ar_osal.pc.in new file mode 100644 index 0000000..52be5fd --- /dev/null +++ b/ar_osal/ar_osal.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ar_osal +Description: ar osal library +Version: @LT_VERSION@ +Libs: -L${libdir} -lar-osal +Cflags: -I${includedir} diff --git a/ar_osal/src/linux/ar_osal_file_io.c b/ar_osal/src/linux/ar_osal_file_io.c new file mode 100644 index 0000000..5f6d08c --- /dev/null +++ b/ar_osal/src/linux/ar_osal_file_io.c @@ -0,0 +1,326 @@ +/** + * \file ar_osal_file_io.c + * + * \brief + * This file has implementation of file input/output related + * helper functions. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define AR_OSAL_FILE_IO_LOG_TAG "COFI" +#include +#include +#include +#include +#include +#include +#include "ar_osal_file_io.h" +#include "ar_osal_log.h" +#include "ar_osal_error.h" + +#ifdef AR_OSAL_USE_CUTILS +#include + +const char* gsl_log_paths[] = {"/data/vendor/audio/gsl_log.bin", + "/data/vendor/etc/audio/gsl_log.bin"}; +#endif + +#define AR_FILE_WRITE_MAX_SIZE ( (256)*(1024)*(1024) ) //256 MB + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_fopen(_Out_ ar_fhandle *handle, + _In_ const char_t *path, + _In_ uint32_t access) +{ + int32_t rc = 0; + char *file_mode = NULL; + FILE *file_ptr; + FILE *fileptr = NULL; + + if (NULL == path || NULL == handle) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s: File path or handle is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + +#ifdef AR_OSAL_USE_CUTILS + // ignore gpr packet log open if logging disabled + if(!property_get_bool("vendor.audio.gpr.enable.packet.logs", 0)) + for(int i = 0; i < sizeof(gsl_log_paths) / sizeof(gsl_log_paths[0]); ++i) + if(!strcmp(path, gsl_log_paths[i])){ + *handle = NULL; + return AR_EBADPARAM; + } +#endif + + switch (access) { + case AR_FOPEN_READ_ONLY: + file_mode = "r"; + break; + case AR_FOPEN_WRITE_ONLY: + file_mode = "wb"; + break; + case AR_FOPEN_READ_ONLY_WRITE: + file_mode = "r+"; + fileptr = fopen(path, "r"); + if(fileptr){ + fclose(fileptr); + } + else { + rc = AR_ENOTEXIST; + goto done; + } + break; + case AR_FOPEN_APPEND: + file_mode = "a"; + break; + case AR_FOPEN_WRITE_ONLY_APPEND: + file_mode = "a"; + break; + case AR_FOPEN_READ_WRITE_APPEND: + file_mode = "a+"; + break; + case AR_FOPEN_READ_WRITE: + file_mode = "w+"; + fileptr = fopen(path, "r"); + if(fileptr){ + fclose(fileptr); + } + else { + rc = AR_EFAILED; + goto done; + } + break; + default: + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s not a valid file open access specifier %d \n",__func__, access); + rc = AR_EBADPARAM; + goto done; + } + file_ptr = fopen(path, file_mode); + + if (NULL == file_ptr) { + rc = AR_EBADPARAM; + /* + *TODO: Add a util api to print the errno with custom + * string to avoid 80 char overflow + */ + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s fail for %s err:%d %s\n",__func__, path, rc, strerror(errno)); + } + + if(access == AR_FOPEN_WRITE_ONLY || access == AR_FOPEN_WRITE_ONLY_APPEND) + { + if(AR_FILE_WRITE_MAX_SIZE <= ar_fsize(file_ptr)) + { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG, + "%s max size detected - truncating to zero size \n", __func__ ); + if(0 != ftruncate(fileno(file_ptr), 0)) + { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s fail to truncate %s err: %s\n", + __func__, path, strerror(errno)); + } + } + } + *handle = file_ptr; + +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +size_t ar_fsize(_In_ ar_fhandle handle) +{ + int32_t rc = 0; + FILE *file_ptr = (FILE *)handle; + struct stat file_info; + size_t file_size = 0; + int fd = 0; + + if (NULL == handle) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s Invalid file handle\n",__func__); + rc = AR_EBADPARAM; + goto done; + } + + fd = fileno(file_ptr); + + if (fd < 0) { + rc = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%sinvalid file handle %d %s\n", __func__, rc, strerror(errno)); + goto done; + } + + rc = fstat(fd, &file_info); + if (0 != rc) { + rc = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%sfstat for file failed with error %d %s\n", __func__, rc, strerror(errno)); + goto done; + } + + file_size = file_info.st_size; + return file_size; +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_fmap(ar_fhandle handle, + const void **fbuffer) +{ + return AR_EUNSUPPORTED; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_funmap(const void *fbuffer) +{ + return AR_EUNSUPPORTED; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_fseek(_In_ ar_fhandle handle, + _In_ size_t offset, + _In_ ar_fseek_reference_t ref) +{ + int32_t rc = 0; + ar_fseek_reference_t fseek_ref; + FILE *file_ptr = (FILE *)handle; + + if (NULL == handle) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s Invalid file handle\n",__func__); + rc = AR_EBADPARAM; + return rc; + } + + switch (ref) { + case AR_FSEEK_BEGIN: + fseek_ref = SEEK_SET; + break; + case AR_FSEEK_END: + fseek_ref = SEEK_END; + break; + case AR_FSEEK_CURRENT: + fseek_ref = SEEK_CUR; + default : + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"Invalid reference id %d\n", fseek_ref); + return AR_EFAILED; + break; + } + + rc = fseek(file_ptr, offset, fseek_ref); + if (0 != rc) { + rc = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s failed %d: %s\n",__func__, rc, strerror(errno)); + } + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_fread( _In_ ar_fhandle handle, + _Inout_ void *buf_ptr, + _In_ size_t read_size, + _Inout_ size_t *bytes_read) +{ + int32_t rc = 0; + FILE *file_ptr = (FILE *)handle; + + if (NULL == handle) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s Invalid file handle\n",__func__); + rc = AR_EBADPARAM; + goto done; + } + + if (NULL == buf_ptr || NULL == bytes_read) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s input buf is NULL or bytes_read ptr is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + + /* + *Having size of object as 1 helps ensure that the fread + *gives correct number of bytes if a failure occurs reading + *for read_size number of bytes. + */ + *bytes_read = fread(buf_ptr, 1, read_size, file_ptr); + if (ferror(file_ptr)) { + rc = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s failed with error %d %s\n", __func__, rc, strerror(errno)); + } +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_fwrite(_In_ ar_fhandle handle, + _Inout_ void *buf_ptr, + _In_ size_t write_size, + _Inout_ size_t *bytes_written) +{ + int32_t rc = 0; + FILE *file_ptr = (FILE *)handle; + + if (NULL == handle) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s Invalid file handle\n",__func__); + rc = AR_EBADPARAM; + goto done; + } + + if (NULL == buf_ptr || NULL == bytes_written) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s input buf is NULL or bytes_written ptr is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + *bytes_written = fwrite(buf_ptr, 1, write_size, file_ptr); + if (ferror(file_ptr)) { + rc = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s failed with error %d %s\n", __func__, rc, strerror(errno)); + } + if(EOF == fflush(file_ptr)) + { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s error in fwrite\n",__func__); + rc = AR_EFAILED; + } +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_fclose(_In_ ar_fhandle handle) +{ + int32_t rc = 0; + FILE *file_ptr = (FILE *)handle; + + if (NULL == handle) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s Invalid file handle\n",__func__); + rc = AR_EBADPARAM; + goto done; + } + + rc = fclose(file_ptr); + if (0 != rc) { + rc = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s failed %d %s\n", __func__, rc, strerror(errno)); + } +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_fdelete(_In_ const char_t *path) +{ + int32_t rc = 0; + + if (NULL == path) { + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s Invalid path\n",__func__); + rc = AR_EBADPARAM; + goto done; + } + rc = remove(path); + if (0 != rc) { + rc = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_FILE_IO_LOG_TAG,"%s failed %d %s\n", __func__, rc, strerror(errno)); + } +done: + return rc; +} diff --git a/ar_osal/src/linux/ar_osal_heap.c b/ar_osal/src/linux/ar_osal_heap.c new file mode 100644 index 0000000..bc931b5 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_heap.c @@ -0,0 +1,124 @@ +/** + * \file ar_osal_heap.c + * + * \brief + * Defines public APIs for heap memory allocation. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ar_osal_heap.h" +#include "ar_osal_error.h" +#include + +/** + * \brief ar_heap_init + * initialize heap memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_heap_init(void) { + return AR_EOK; +} + +/** + * \brief ar_heap_deinit. + * De-initialize heap memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_heap_deinit(void) { + return AR_EOK; +} + +/** + * \brief Allocates heap memory. + * + * \param[in] bytes: number of bytes to allocate heap memory. + * \param[in] heap_info: pointer of type: ar_heap_info. + * + * \return + * Nonzero -- Success: pointer to the allocated heap memory + * NULL -- Failure + * + */ +void* ar_heap_malloc(_In_ size_t bytes, _In_ par_heap_info heap_info) +{ + void* pBuff = NULL; + size_t alignment = AR_HEAP_ALIGN_DEFAULT; + if (NULL == heap_info) { + goto end; + } + switch (heap_info->align_bytes) { + case AR_HEAP_ALIGN_4_BYTES: /** 4-byte boundary */ + alignment = 4; + break; + case AR_HEAP_ALIGN_8_BYTES: /** 8-byte boundary */ + alignment = 8; + break; + case AR_HEAP_ALIGN_16_BYTES: /** 16-byte boundary */ + alignment = 16; + break; + case AR_HEAP_ALIGN_DEFAULT: /** Default */ + break; + } + if (AR_HEAP_ALIGN_DEFAULT == heap_info->align_bytes) { + pBuff = malloc(bytes); + } else { + if (alignment < sizeof(void *)) { + alignment = sizeof(void *); + } + if (posix_memalign(&pBuff, alignment, bytes) != 0) { + pBuff = NULL; + } + } + +end: + return pBuff; +} + + +/** + * \brief Allocates heap memory and initialize with 0. + * + * \param[in] bytes: number of bytes to allocate heap memory. + * \param[in] heap_info: pointer of type: ar_heap_info. + * + * \return + * Nonzero -- Success: pointer to the allocated heap memory + * NULL -- Failure + * + */ +void* ar_heap_calloc(_In_ size_t bytes, _In_ par_heap_info heap_info) +{ + void* pBuf = NULL; + pBuf = ar_heap_malloc(bytes, heap_info); + if (NULL != pBuf) { + memset(pBuf, 0, bytes); + } + return pBuf; +} + +/** + * \brief Frees heap memory. + * + * \param[in] heap_ptr: pointer to heap memory obtained from ar_heap_alloc(). + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +void ar_heap_free(_In_ void* heap_ptr, _In_ par_heap_info heap_info) +{ + if (NULL != heap_ptr && NULL != heap_info) { + free(heap_ptr); + } + return; +} + diff --git a/ar_osal/src/linux/ar_osal_log.c b/ar_osal/src/linux/ar_osal_log.c new file mode 100644 index 0000000..766f054 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_log.c @@ -0,0 +1,101 @@ +/** + * \file ar_osal_log.c + * + * \brief + * This file has implementation of logging related helper functions. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#ifdef AR_OSAL_USE_CUTILS +#include +#endif + +#ifdef AR_OSAL_USE_SYSLOG +#include + +#ifndef ANDROID_LOG_DEBUG +#define ANDROID_LOG_DEBUG 3 +#endif + +#ifndef ANDROID_LOG_INFO +#define ANDROID_LOG_INFO 4 +#endif + +#ifndef ANDROID_LOG_ERROR +#define ANDROID_LOG_ERROR 6 +#endif + +#ifndef ANDROID_LOG_VERBOSE +#define ANDROID_LOG_VERBOSE 2 +#endif + +#ifndef ANDROID_LOG_FATAL +#define ANDROID_LOG_FATAL 7 +#endif + +static inline void __android_log_write(int prio, const char *tag, const char *msg) +{ + syslog(prio, "%s - %s", tag, msg); +} +#else +#include +#endif + +#include "ar_osal_log.h" +#define LOG_BUF_SIZE 1024 + +uint32_t ar_log_lvl = (AR_CRITICAL|AR_ERROR|AR_INFO); + +_IRQL_requires_max_(DISPATCH_LEVEL) +void ar_log_init(void) +{ +#ifdef AR_OSAL_USE_CUTILS + //set this property to change the args debug logging enabled. + if(property_get_bool("vendor.audio.args.enable.debug.logs", 0)) { + ar_log_lvl = (AR_CRITICAL|AR_ERROR|AR_INFO|AR_DEBUG); + } + //set this property to change the args verbose logging enabled. + if(property_get_bool("vendor.audio.args.enable.verbose.logs", 0)) { + ar_log_lvl = (AR_CRITICAL|AR_ERROR|AR_INFO|AR_DEBUG|AR_VERBOSE); + } +#endif +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +void ar_log(uint32_t level, const char_t* log_tag, const char_t* file, + const char_t* fn, int32_t ln, const char_t* format, ...) +{ + va_list ap; + char buf_temp[LOG_BUF_SIZE]; + char buf[LOG_BUF_SIZE]; + + va_start(ap, format); + snprintf(buf_temp, LOG_BUF_SIZE, "%s:%s:%d %s", file, fn, ln, format); + vsnprintf(buf, LOG_BUF_SIZE, buf_temp, ap); + va_end(ap); + + if (level == AR_DEBUG) { + __android_log_write(ANDROID_LOG_DEBUG, log_tag, buf); + } else if (level == AR_INFO){ + __android_log_write(ANDROID_LOG_INFO, log_tag, buf); + } else if (level == AR_ERROR) { + __android_log_write(ANDROID_LOG_ERROR, log_tag, buf); + } + else if (level == AR_VERBOSE) { + __android_log_write(ANDROID_LOG_VERBOSE, log_tag, buf); + } + else if (level == AR_CRITICAL) { + __android_log_write(ANDROID_LOG_FATAL, log_tag, buf); + } +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +void ar_log_deinit(void) +{ + +} diff --git a/ar_osal/src/linux/ar_osal_mem_op.c b/ar_osal/src/linux/ar_osal_mem_op.c new file mode 100644 index 0000000..5a97f41 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_mem_op.c @@ -0,0 +1,108 @@ +/** + * \file ar_osal_mem_op.c + * + * \brief + * Defines public APIs for memory operations. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_mem_op.h" +#include "ar_osal_error.h" + +/** + * \brief ar_mem_cpy + * copies bytes between buffers. + * \param[in_out] dest: destinatiopn buffer to copy data. + * \param[in] dest_size: destination buffer size. + * \param[in] src: source buffer pointer to copy data from. + * \param[in] size: bytes to copy from source buffer. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_mem_cpy(_Inout_ void* dest, _In_ size_t dest_size, _In_ const void* src, _In_ size_t size) +{ + int32_t cStatus = AR_EOK; + if (NULL == dest || NULL == src || 0 == dest_size || 0 == size || + dest_size < size) { + cStatus = AR_EBADPARAM; + goto end; + } + memcpy(dest, src, size); +end: + return cStatus; +} + +/** + * \brief ar_mem_move + * copies bytes from source area to destination area. + * \param[in_out] dest: destinatiopn buffer to copy data. + * \param[in] dest_size: destination buffer size. + * \param[in] src: source buffer pointer to copy data from. + * \param[in] size: bytes to copy from source buffer. + * \return + * 0 -- Success + * Nonzero -- Failure + * note: If some regions of the source area and the destination overlap, ar_mem_move + * ensures that the original source bytes in the overlapping region are copied before + * being overwritten. + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_mem_move(_Inout_ void* dest, _In_ size_t dest_size, _In_ const void* src, _In_ size_t size) +{ + int32_t cStatus = AR_EOK; + if (NULL == dest || NULL == src || 0 == dest_size || 0 == size || + dest_size < size) { + cStatus = AR_EBADPARAM; + goto end; + } + memmove(dest, src, size); +end: + return cStatus; +} + +/** + * \brief ar_mem_set + * set buffer to specified value. + * \param[in_out] dest: destinatiopn buffer to set the specified value. + * \param[in] c: specified value to set, of integer type. + * \param[in] size: buffer bytes to set the value, must be multiple of specified value "c" data size. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_mem_set(_Inout_ void* dest, _In_ int32_t c, _In_ size_t size) +{ + int32_t cStatus = AR_EOK; + if (NULL == dest || 0 == size ) { + cStatus = AR_EBADPARAM; + goto end; + } + memset(dest, c, size); +end: + return cStatus; +} + +/** + * \brief ar_mem_cmp + * compare two buffers. + * \param[in] buff1: first buffer. + * \param[in] buff2: second buffer. + * \param[in] size: bytes to compare. + * \return + * < 0 buff1 < buff2 + * 0 buff1 == buff2 + * > 0 buff1 > buff2 + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_mem_cmp(_In_ const void* buff1, _In_ const void* buff2, _In_ size_t size) +{ + /* no check for null input pointer or size as the system itself doesn`t provide it*/ + return memcmp(buff1, buff2, size); +} + diff --git a/ar_osal/src/linux/ar_osal_mutex.c b/ar_osal/src/linux/ar_osal_mutex.c new file mode 100644 index 0000000..fdcd151 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_mutex.c @@ -0,0 +1,158 @@ +/** + * \file ar_osal_mutex.c + * + * \brief + * This file implements mutex apis. Recursive mutexes are always used + * for thread-safe programming. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define AR_OSAL_MUTEX_LOG_TAG "COMU" +#include +#include +#include +#include +#include "ar_osal_mutex.h" +#include "ar_osal_log.h" +#include "ar_osal_error.h" + +/* Internal lock definition */ +typedef struct osal_int_mutex { + pthread_mutex_t mutex; +} osal_int_mutex_t; + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_mutex_init(_Inout_ ar_osal_mutex_t mutex __unused) +{ + return AR_ENOTIMPL; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_mutex_deinit(_In_ ar_osal_mutex_t mutex __unused) +{ + return AR_ENOTIMPL; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +size_t ar_osal_mutex_get_size(void) +{ + return sizeof(osal_int_mutex_t); +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_mutex_create(_Inout_ ar_osal_mutex_t *ar_osal_mutex) +{ + int32_t rc; + osal_int_mutex_t* the_mutex; + + if (NULL == ar_osal_mutex) { + return AR_EBADPARAM; + } + + the_mutex = ((osal_int_mutex_t *) malloc(sizeof(osal_int_mutex_t))); + if (NULL == the_mutex) { + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: failed to allocate memory for mutex\n", __func__); + rc = AR_ENOMEMORY; + goto exit; + } + + rc = pthread_mutex_init(&the_mutex->mutex, NULL); + if (rc) { + rc = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: failed to initialize mutex\n", __func__); + goto fail; + } + + *ar_osal_mutex = the_mutex; + return 0; + +fail: + free(the_mutex); + +exit: + return rc; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_mutex_destroy(_In_ ar_osal_mutex_t ar_osal_mutex) +{ + int32_t rc = 0; + osal_int_mutex_t *the_mutex = ar_osal_mutex; + + if (NULL == the_mutex) { + return AR_EBADPARAM; + } + + rc = pthread_mutex_destroy(&the_mutex->mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: Failed to destroy mutex\n", __func__); + rc = AR_EFAILED; + goto exit; + } + free(the_mutex); + +exit: + return rc; +} + +_IRQL_requires_min_(PASSIVE_LEVEL) +int32_t ar_osal_mutex_lock(_In_ ar_osal_mutex_t ar_osal_mutex) +{ + int32_t rc; + osal_int_mutex_t *the_mutex = ar_osal_mutex; + + if (NULL == the_mutex) { + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: ar_osal_mutex is NULL\n", __func__); + return AR_EBADPARAM; + } + + rc = pthread_mutex_lock(&the_mutex->mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: Failed to lock ar_osal_mutex\n", __func__); + rc = AR_EFAILED; + } + return rc; +} + +_IRQL_requires_min_(PASSIVE_LEVEL) +int32_t ar_osal_mutex_try_lock(_In_ ar_osal_mutex_t ar_osal_mutex) +{ + int32_t rc; + osal_int_mutex_t *the_mutex = ar_osal_mutex; + + if (NULL == the_mutex) { + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: ar_osal_mutex is NULL\n", __func__); + return AR_EBADPARAM; + } + + rc = pthread_mutex_trylock(&the_mutex->mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: Failed to lock ar_osal_mutex\n", __func__); + rc = AR_EFAILED; + } + return rc; +} + +_IRQL_requires_min_(PASSIVE_LEVEL) +int32_t ar_osal_mutex_unlock(_In_ ar_osal_mutex_t ar_osal_mutex) +{ + int32_t rc; + osal_int_mutex_t *the_mutex = ar_osal_mutex; + + if (NULL == the_mutex) { + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: ar_osal_mutex is NULL\n", __func__); + return AR_EBADPARAM; + } + + rc = pthread_mutex_unlock(&the_mutex->mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_MUTEX_LOG_TAG,"%s: Failed to release ar_osal_mutex\n", __func__); + rc = AR_EFAILED; + } + return rc; +} diff --git a/ar_osal/src/linux/ar_osal_shmem_phy.c b/ar_osal/src/linux/ar_osal_shmem_phy.c new file mode 100644 index 0000000..36e90e9 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_shmem_phy.c @@ -0,0 +1,692 @@ +/** + * + * \file ar_osal_shmem_phy.c + * + * \brief + * This file has implementation for DMA buffer based shared memory allocation for DSP. + + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#define AR_OSAL_SHMEM_LOG_TAG "COSH" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_audio.h" +#include "ar_osal_shmem.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#include "ar_osal_sleep.h" +#define SHMEM_4K_ALIGNMENT 0x1000 + +#define AR_MEM_DRIVER_PATH "/dev/msm_audio_mem" +#define AR_MEM_DRIVER_PATH_CMA "/dev/msm_audio_mem_cma" + +#define DMABUF_SYS_HEAP_PATH "/dev/dma_heap/linux,cma" +#define DMABUF_SYS_HEAP_PATH_UNCACHED "/dev/dma_heap/linux,cma-uncached" + +#define AR_FD_OPEN_RETRY_US (500*1000) +#define AR_FD_OPEN_NUM_RETRIES 4 + +typedef struct ar_shmem_handle_data { + int32_t heap_fd; + bool dma_sync_flag; +} ar_shmem_handle_data_t; + +typedef struct ar_shmem_pdata { + int dmabuf_fd; + int dmabuf_fd_cma; + int armem_fd; + int armem_fd_cma; + bool dmabuf_cma_mem_enabled; +} ar_shmem_pdata_t; + +static ar_shmem_pdata_t *pdata = NULL; + +static pthread_mutex_t ar_shmem_lock = PTHREAD_MUTEX_INITIALIZER; + +/** + * \brief ar_shmem_validate_sys_id + * internal function to validate supported SYS IDs. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +static int32_t ar_shmem_validate_sys_id(uint8_t num_sys_id, ar_shmem_proc_info *sys_id) +{ + int32_t status = AR_EOK; + + if (0 == num_sys_id || NULL == sys_id) + return AR_EBADPARAM; + + for (uint8_t i = 0; i < num_sys_id; ++i) { + if (AR_AUDIO_DSP != sys_id[i].proc_id && + AR_MODEM_DSP != sys_id[i].proc_id && + AR_SENSOR_DSP != sys_id[i].proc_id && + AR_COMPUTE_DSP != sys_id[i].proc_id && + AR_APSS != sys_id[i].proc_id && + AR_APSS2 != sys_id[i].proc_id) { + status = AR_EBADPARAM; + break; + } + } + return status; +} + +static int32_t ar_shmem_map_dynamic_pd(ar_shmem_info *info, bool_t map) +{ + return AR_EOK; +} + +static int32_t ar_shmem_map_static_pd(ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle = NULL; + + if (NULL == info) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: invalid shmem param", __func__); + status = AR_EBADPARAM; + goto end; + } + if (0 == info->pa_lsw && 0 == info->pa_msw) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: pa_lsw:0x%x|pa_msw:0x%x passed", + info->pa_lsw, info->pa_msw); + status = AR_EBADPARAM; + goto end; + } + shmem_handle = (ar_shmem_handle_data_t *) + malloc(sizeof(ar_shmem_handle_data_t)); + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s:malloc for shmem handle failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + + info->ipa_lsw = 0; + info->ipa_msw = 0; + info->metadata = 0; + info->index_type = AR_SHMEM_BUFFER_OFFSET; + info->mem_type = AR_SHMEM_PHYSICAL_MEMORY; + + /* + *This api is called by clients when the clients already have allocated shared memory + *and now we just need to map it with DSP. On LX platforms what we recieve from clients + *is the ion fd, which is passed in the form of pa_lsw and pa_msw. Hence we extract the same + *and pass it on to the audio ion driver. + */ + shmem_handle->heap_fd = (((int64_t)info->pa_msw << 32) | info->pa_lsw); + + info->vaddr = mmap(0, info->buf_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shmem_handle->heap_fd, 0); + if (info->vaddr == MAP_FAILED) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: mmap failed \n", __func__); + status = AR_ENOMEMORY; + goto err2; + } + + if ((uint64_t)info->vaddr % SHMEM_4K_ALIGNMENT) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: 4k alignment check failed vaddr(0x%pK)", info->vaddr); + info->vaddr = NULL; + status = AR_EUNEXPECTED; + goto err2; + } + info->metadata = (uint64_t)shmem_handle; + info->ipa_lsw = info->pa_lsw; + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG," SHMEM: memory_type(0x%x)|index_type(0x%x)" + "buf_size(0x%x)|vaddr(0x%pK)| ipa_lsw(0x%x)| status(0x%x) ",info->mem_type, + info->index_type, info->buf_size, info->vaddr, info->ipa_lsw, status); + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) && pdata->dmabuf_cma_mem_enabled) { + if (pdata->armem_fd_cma) { + status = ioctl(pdata->armem_fd_cma, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else + status = ioctl(pdata->armem_fd, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:Physical address map failed status %d\n", __func__, status); + goto err2; + } + goto end; + +err2: + free(shmem_handle); +end: + return status; +} + +static int32_t ar_shmem_unmap_static_pd(ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle; + + if (NULL == info) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: invalid shmem param", __func__); + status = AR_EBADPARAM; + goto end; + } + shmem_handle = (ar_shmem_handle_data_t *)(intptr_t)info->metadata; + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: shmem_handle is NULL\n", + __func__); + status = AR_EBADPARAM; + goto end; + } + + munmap(info->vaddr, info->buf_size); + if (shmem_handle->heap_fd) { + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG) && pdata->dmabuf_cma_mem_enabled)) { + if (pdata->armem_fd_cma) { + status = ioctl(pdata->armem_fd_cma, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->heap_fd); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else + status = ioctl(pdata->armem_fd, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->heap_fd); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:unmap failed. status %d\n", __func__, status); + } + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG,"%s:shmem heap fd %d\n", __func__, shmem_handle->heap_fd); + close(shmem_handle->heap_fd); + } else { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s Invalid dmabuf_fd \n", __func__); + } + if (shmem_handle) + free(shmem_handle); + info->metadata = 0; + info->vaddr = NULL; +end: + return status; +} + +/* + *\brief ar_shmem_init + * initialize shared memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_init(void) +{ + int32_t status = AR_EOK; + + pthread_mutex_lock(&ar_shmem_lock); + if (NULL != pdata) { + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG,"%s: init already done\n", __func__); + goto end; + } + + pdata = (ar_shmem_pdata_t *) calloc(1, sizeof(ar_shmem_pdata_t)); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: calloc failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG, "%s: Using dmaheap path: linux,system-uncached %s\n", __func__, DMABUF_SYS_HEAP_PATH_UNCACHED); + pdata->dmabuf_fd = open(DMABUF_SYS_HEAP_PATH_UNCACHED, O_RDONLY | O_CLOEXEC); + + /*Check if dma_buf heap initialize the dmabuf_handle to invalid handle */ + if (pdata->dmabuf_fd < 0) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:dmabuf dev open failed errno:%d\n", __func__, pdata->dmabuf_fd); + status = AR_ENOTEXIST; + goto end; + } + + for (int j = 0; j < AR_FD_OPEN_NUM_RETRIES; ++j) { + pdata->armem_fd = open(AR_MEM_DRIVER_PATH, O_RDWR); + if (pdata->armem_fd < 0) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "armem fd open(%s) failed with errno:%d, retries %d\n", + AR_MEM_DRIVER_PATH, errno, j); + ar_osal_micro_sleep(AR_FD_OPEN_RETRY_US); + } + else { + break; + } + } + if (pdata->armem_fd < 0) { + status = AR_ENOTEXIST; + close(pdata->dmabuf_fd); + goto end; + } + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG,"%s armem fd open success %s\n", __func__, AR_MEM_DRIVER_PATH); + + end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/* + * \brief Allocates shared memory. + * Only non cached memory allocation supported. + * Size if multiple of 4KB and the returned is aligned to 4KB boundary. + * Buffer start address should be atleast 64bit multiple aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_alloc(_Inout_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle = NULL; + struct dma_heap_allocation_data heap_data; + struct dma_buf_sync sync; + memset(&heap_data, 0, sizeof(heap_data)); + memset(&sync, 0, sizeof(sync)); + + pthread_mutex_lock(&ar_shmem_lock); + + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state", __func__); + status = AR_EUNSUPPORTED; + goto end; + } + + if (NULL == info || 0 == info->buf_size) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"Error: info(NULL)|buf_size(0) passed"); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + shmem_handle = (ar_shmem_handle_data_t *)calloc(1, sizeof(ar_shmem_handle_data_t)); + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:malloc for shmem handle failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + + info->ipa_lsw = 0; + info->ipa_msw = 0; + info->metadata = 0; + info->pa_lsw = 0; + info->pa_msw = 0; + info->index_type = AR_SHMEM_BUFFER_OFFSET; + info->mem_type = AR_SHMEM_PHYSICAL_MEMORY; + + heap_data.len = info->buf_size; + heap_data.fd_flags = O_RDWR; + + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) && pdata->dmabuf_cma_mem_enabled) { + status = ioctl(pdata->dmabuf_fd_cma, DMA_HEAP_IOCTL_ALLOC, &heap_data); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap alloc failed, errno: %d\n", + __func__, status); + status = AR_ENOMEMORY; + goto end; + } + } + else { + status = ioctl(pdata->dmabuf_fd, DMA_HEAP_IOCTL_ALLOC, &heap_data); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap alloc failed, errno: %d\n", + __func__, status); + status = AR_ENOMEMORY; + goto end; + } + } + + info->vaddr = mmap(0, info->buf_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + heap_data.fd, 0); + if (info->vaddr == MAP_FAILED) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: mmap failed \n", __func__); + status = AR_ENOMEMORY; + goto err1; + } + + if ((uint64_t)info->vaddr % SHMEM_4K_ALIGNMENT) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: 4k alignment check failed vaddr(0x%pK)", info->vaddr); + info->vaddr = NULL; + status = AR_EUNEXPECTED; + goto err2; + } + + sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW; + status = ioctl(heap_data.fd, DMA_BUF_IOCTL_SYNC, &sync); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap set access failed, errno: %d\n", + __func__, status); + status = AR_EUNEXPECTED; + goto err2; + } + + shmem_handle->heap_fd = heap_data.fd; + shmem_handle->dma_sync_flag = true; + info->metadata = (uint64_t)shmem_handle; + info->ipa_lsw = shmem_handle->heap_fd; + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG," SHMEM: cached|memory_type(0x%x)|index_type(0x%x) buf_size(0x%x)|vaddr(0x%pK)| ipa_lsw(0x%x)| status(0x%x) ", + info->mem_type, info->index_type, info->buf_size, info->vaddr, info->ipa_lsw, status); + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) && pdata->dmabuf_cma_mem_enabled) { + if (pdata->armem_fd_cma) { + status = ioctl(pdata->armem_fd_cma, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else + status = ioctl(pdata->armem_fd, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:Physical address map failed status %d\n", + __func__, status); + goto err2; + } + status = ar_shmem_map_dynamic_pd(info, true); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s:dynamic pd map failed status %d\n", + __func__, status); + goto err2; + } + goto end; + + err2: + munmap(info->vaddr, info->buf_size); + shmem_handle->dma_sync_flag = false; + + err1: + close(shmem_handle->heap_fd); + free(shmem_handle); + + end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/* + * Frees shared memory. + * + * \param[in] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_free(_In_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle = NULL; + struct dma_buf_sync sync; + + pthread_mutex_lock(&ar_shmem_lock); + + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state\n", __func__); + status = AR_EBADPARAM; + goto end; + } + + if (NULL == info || NULL == info->vaddr){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid info %pK\n", __func__, info); + status = AR_EBADPARAM; + goto end; + } + + if (0 == info->metadata || 0 == info->buf_size){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid params handle %pK buf_size %zu\n", + __func__, info->metadata, info->buf_size); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + status = ar_shmem_map_dynamic_pd(info, false); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s:dynamic pd unmap failed. status %d\n", __func__, status); + } + + shmem_handle = (ar_shmem_handle_data_t *)(intptr_t)info->metadata; + + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: shmem_handle is NULL\n", + __func__); + status = AR_EBADPARAM; + goto end; + } + if (shmem_handle && shmem_handle->dma_sync_flag) { + sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW; + status = ioctl(shmem_handle->heap_fd, DMA_BUF_IOCTL_SYNC, &sync); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap set access failed, errno: %d\n", + __func__, status); + } + shmem_handle->dma_sync_flag = false; + } + munmap(info->vaddr, info->buf_size); + if (shmem_handle->heap_fd) { + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) && pdata->dmabuf_cma_mem_enabled) { + if (pdata->armem_fd_cma) { + status = ioctl(pdata->armem_fd_cma, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->heap_fd); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else { + status = ioctl(pdata->armem_fd, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->heap_fd); + } + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:unmap failed. status %d\n", __func__, status); + } + close(shmem_handle->heap_fd); + } else { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s Invalid dmabuf_fd \n", __func__); + } + if (shmem_handle) + free(shmem_handle); + info->metadata = 0; + info->vaddr = NULL; + end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/** + * \brief Helps map memory with SMMU an already allocated shared memory + * for a give sub system. + * Size should be multiple of 4KB boundary. + * Buffer start address should be 64bit aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * required output parameters in ar_shmem_info + * ar_shmem_info_t.ipa_lsw + * ar_shmem_info_t.ipa_msw + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_map(_Inout_ ar_shmem_info *info) +{ + int32_t status = AR_EOK, i = 0; + bool_t static_pd = false; + + pthread_mutex_lock(&ar_shmem_lock); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state", __func__); + status = AR_EUNSUPPORTED; + goto end; + } + + if (NULL == info || 0 == info->buf_size) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"Error: info(NULL)|buf_size(0) passed"); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + for (i = 0; i < info->num_sys_id; ++i) { + if (info->sys_id[i].proc_type == STATIC_PD) { + static_pd = true; + break; + } + } + if (static_pd) { + status = ar_shmem_map_static_pd(info); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "static pd map failed with error %d", status); + goto end; + } + } + status = ar_shmem_map_dynamic_pd(info, true); + if (status) { + ar_shmem_unmap_static_pd(info); + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "dynamic pd map failed with error %d", status); + } +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/** + *\brief Helps unmap the shared memory allocated externally with SMMU + * + *\param[in] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_unmap(_In_ ar_shmem_info *info) +{ + int32_t status = AR_EOK, i = 0; + bool_t static_pd = false; + + pthread_mutex_lock(&ar_shmem_lock); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state\n", __func__); + status = AR_EBADPARAM; + goto end; + } + + if (NULL == info || NULL == info->vaddr){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid info %pK\n", __func__, info); + status = AR_EBADPARAM; + goto end; + } + + if (0 == info->metadata || 0 == info->buf_size){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid params handle %pK buf_size %zu\n", + __func__, info->metadata, info->buf_size); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + status = ar_shmem_map_dynamic_pd(info, false); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s: dynamic pd unmap failed", __func__); + } + for (i = 0; i < info->num_sys_id; ++i) { + if (info->sys_id[i].proc_type == STATIC_PD) { + static_pd = true; + break; + } + } + if (static_pd) { + status = ar_shmem_unmap_static_pd(info); + if (status) + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s: static pd unmap failed", __func__); + } +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +int32_t ar_shmem_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info) +{ + return AR_EOK; +} + +/* + * \brief ar_shmem_deinit. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_deinit(void) +{ + + pthread_mutex_lock(&ar_shmem_lock); + + if (pdata == NULL) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s not in init state\n", __func__); + pthread_mutex_unlock(&ar_shmem_lock); + return AR_EOK; + } + + if (pdata->dmabuf_fd){ + close(pdata->dmabuf_fd); + } + + if (pdata->armem_fd){ + close(pdata->armem_fd); + } + + if (pdata->dmabuf_fd_cma){ + close(pdata->dmabuf_fd_cma); + } + + if (pdata->armem_fd_cma){ + close(pdata->armem_fd_cma); + } + + free(pdata); + pdata = NULL; + pthread_mutex_unlock(&ar_shmem_lock); + + return AR_EOK; +} diff --git a/ar_osal/src/linux/ar_osal_shmem_virtual.c b/ar_osal/src/linux/ar_osal_shmem_virtual.c new file mode 100644 index 0000000..a5befd0 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_shmem_virtual.c @@ -0,0 +1,371 @@ +/** + * + * \file ar_osal_shmem_virtual.c + * + * \brief + * This file has implementation for Virtual Address based shared memory allocation for DSP. + + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include +#include "ar_osal_shmem.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" + +#define AR_OSAL_SHMEM_LOG_TAG "AOSH" +/*Memory pointer to be 4K aligned for ADSP, MDSP,SDSP and CDSP */ +#define SHMEM_4K_ALIGNMENT (4096) + + +/** + * \brief ar_shmem_validate_sys_id + * internal function to validate supported SYS IDs. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_validate_sys_id(_In_ uint8_t num_sys_id, _In_ ar_shmem_proc_info *sys_id) +{ + PAGED_FUNCTION(); + int32_t status = AR_EOK; + if (0 == num_sys_id || NULL == sys_id) + { + status = AR_EBADPARAM; + goto end; + } + + for (uint8_t i = 0; i < num_sys_id; i++) + { + if (AR_AUDIO_DSP != sys_id[i].proc_id && + AR_MODEM_DSP != sys_id[i].proc_id && + AR_SENSOR_DSP != sys_id[i].proc_id && + AR_COMPUTE_DSP != sys_id[i].proc_id && + AR_APSS != sys_id[i].proc_id && + AR_APSS2 != sys_id[i].proc_id) + { + status = AR_EBADPARAM; + break; + } + } + +end: + return status; +} + +/* + *\brief ar_shmem_init + * initialize shared memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_init(void) +{ + PAGED_FUNCTION(); + return AR_EOK; +} + +/** + * \brief Initialize the shared memory interface using a list of processor domains (V2 API). + * + * This V2 API selects the appropriate shared memory implementation + * based on the provided list of processor domain IDs. + * + * Passing num_master_procs = 0 results in behavior equivalent to the + * V1 API (ar_shmem_init), allowing a smooth transition from V1 to V2. + * + * \param[in] num_master_procs Number of processor domain IDs. + * \param[in] master_procs Pointer to an array of processor domain IDs. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_init_v2(uint32_t num_master_procs, uint32_t *master_procs) +{ + PAGED_FUNCTION(); + return AR_EOK; +} + +/* + * \brief Allocates shared memory. + * Only non cached memory allocation supported. + * Size if multiple of 4KB and the returned is aligned to 4KB boundary. + * Buffer start address should be atleast 64bit multiple aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_alloc(_Inout_ ar_shmem_info *info) +{ + PAGED_FUNCTION(); + int32_t status = AR_EOK; + void *p = 0; + + if (NULL == info || 0 == info->buf_size) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"Error: info(NULL)|buf_size(0) passed"); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + info->ipa_lsw = 0; + info->ipa_msw = 0; + info->metadata = 0; + info->pa_lsw = 0; + info->pa_msw = 0; + info->index_type = AR_SHMEM_BUFFER_ADDRESS; + info->mem_type = AR_SHMEM_VIRTUAL_MEMORY; + + + if (0 != posix_memalign(&p, SHMEM_4K_ALIGNMENT, info->buf_size)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: posix_memalign failed"); + status = AR_ENOMEMORY; + goto end; + } + info->vaddr = p; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "vaddr(0x%p)", info->vaddr); + if (NULL == info->vaddr) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: no memory available"); + status = AR_ENOMEMORY; + goto end; + } + /*validate address for 64 byte alignment */ + if ((uint64_t)info->vaddr % SHMEM_4K_ALIGNMENT) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: 4k alignment check failed vaddr(0x%p)", info->vaddr); + free(info->vaddr); + info->vaddr = NULL; + status = AR_EUNEXPECTED; + goto end; + } + + info->pa_lsw = info->ipa_lsw = (uint32_t)(uintptr_t)info->vaddr; + info->pa_msw = info->ipa_msw = (uint32_t)((uint64_t)((uintptr_t)(info->vaddr)) >> 32); + + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG, " SHMEM: cache_type(0x%x)|memory_type(0x%x)|index_type(0x%x)|buf_size(0x%x)|vaddr(0x%p)|status(0x%x) ", + info->cache_type, info->mem_type, info->index_type, info->buf_size, info->vaddr, status); +end: + return status; +} + +/* + * Frees shared memory. + * + * \param[in] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_free(_In_ ar_shmem_info *info) +{ + PAGED_FUNCTION(); + int32_t status = AR_EOK; + if (NULL == info || NULL == info->vaddr) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: handle(NULL) passed"); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id, info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG, "SHMEM: freed(0x%p)", info->vaddr); + free(info->vaddr); + info->vaddr = NULL; + +end: + return status; +} + +/** + * \brief Helps map memory with SMMU an already allocated shared memory + * for a give sub system. + * Size should be multiple of 4KB boundary. + * Buffer start address should be 64bit aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.mem_type + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * required output parameters in ar_shmem_info + * ar_shmem_info_t.ipa_lsw + * ar_shmem_info_t.ipa_msw + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_map(ar_shmem_info *info) +{ + PAGED_FUNCTION(); + int32_t status = AR_EOK; + + if (NULL == info || 0 == info->buf_size + || (0 == info->pa_lsw && 0 == info->pa_msw) ) + { + if(info) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: buf_size(0)|pa_lsw:0x%x|pa_msw:0x%x passed", + info->pa_lsw, info->pa_msw); + } + else { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: info(NULL)"); + } + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id, info->sys_id)) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + info->ipa_lsw = info->pa_lsw; /*return pa to ipa*/ + info->ipa_msw = info->pa_msw; + + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG, + "SHMEM: cache_type(0x%x)|memory_type(0x%x)|buf_size(0x%x)|ipa_lsw(0x%x)|ipa_msw(0x%x)|status(0x%x) ", + info->cache_type, info->mem_type, info->buf_size, + info->ipa_lsw, info->ipa_msw, status); +end: + return status; +} + +/** + *\brief Helps unmap the shared memory allocated externally with SMMU + * + *\param[in] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.mem_type + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_unmap(ar_shmem_info *info) +{ + PAGED_FUNCTION(); + int32_t status = AR_EOK; + + if (NULL == info || 0 == info->buf_size + || (0 == info->pa_lsw && 0 == info->pa_msw) ) + { + if(info) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: info(NULL)|buf_size(0)|pa_lsw:0x%x|pa_msw:0x%x passed", + info->pa_lsw, info->pa_msw); + } + else { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: info(NULL)"); + } + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id, info->sys_id)) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + /*no handling required*/ +end: + return status; +} + +/** + * Helps to hyp assign physical memory between source and destination sub systems. + * + * \param[in] info: info: pointer to ar_shmem_hyp_assign_phys_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info) +{ + PAGED_FUNCTION(); + __UNREFERENCED_PARAM(info); + /*no op*/ + return AR_EOK; +} + +/* + * \brief ar_shmem_deinit. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_deinit(void) +{ + PAGED_FUNCTION(); + return AR_EOK; +} + + +/** + * \brief ar_shmem_get_uid. + * Get associated unique identifier(UID) for the shared memory + * pointed by alloc_handle, platform which doesn`t support UID + * should return alloc_handle as UID with expectation of + * alloc_handle being unique. + * + * \param[in] alloc_handle: handle for the shared memory. + * \param[out] uid: unique identifier to the shmem. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_get_uid(uint64_t alloc_handle, uint64_t* uid) +{ + PAGED_FUNCTION(); + int32_t status = AR_EFAILED; + + if (NULL != uid) + { + *uid = alloc_handle; + status = AR_EOK; + } + + return status; +} diff --git a/ar_osal/src/linux/ar_osal_signal.c b/ar_osal/src/linux/ar_osal_signal.c new file mode 100644 index 0000000..44d9995 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_signal.c @@ -0,0 +1,316 @@ +/** + * \file ar_osal_signal.c + * + * \brief + * This file defines signal variable implementaion. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define AR_OSAL_SIGNAL_LOG_TAG "COSI" +#include +#include +#include +#include +#include +#include "ar_osal_signal.h" +#include "ar_osal_log.h" +#include "ar_osal_error.h" + +/* Internal condition definition */ +typedef struct osal_int_signal { + pthread_mutex_t osal_mutex; + pthread_cond_t osal_cond; + bool signalled; +} osal_int_signal_t; + +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_osal_signal_init(_In_ ar_osal_signal_t signal __unused) +{ + return AR_ENOTIMPL; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_osal_signal_deinit(_In_ ar_osal_signal_t signal __unused) +{ + return AR_ENOTIMPL; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +size_t ar_osal_signal_get_size() +{ + return sizeof(osal_int_signal_t); +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_osal_signal_create(_Inout_ ar_osal_signal_t *ret_signal) +{ + int32_t rc; + osal_int_signal_t *the_signal; + pthread_condattr_t attr; + if (NULL == ret_signal) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: signal is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + the_signal = (osal_int_signal_t *)malloc(sizeof(osal_int_signal_t)); + if (NULL == the_signal) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: failed to allocate signal memory\n", __func__); + rc = AR_ENOMEMORY; + goto done; + } + + rc = pthread_mutex_init(&the_signal->osal_mutex, NULL); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to init mutex, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_mutex; + } + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + rc = pthread_cond_init(&the_signal->osal_cond, &attr); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to init cond, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_cond; + } + the_signal->signalled = false; + *ret_signal = the_signal; + goto done; +err_cond: + pthread_mutex_destroy(&the_signal->osal_mutex); +err_mutex: + free(the_signal); +done: + return rc; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_signal_wait(_In_ ar_osal_signal_t signal) +{ + int32_t rc; + osal_int_signal_t *the_signal; + if (NULL == signal) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: signal is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + the_signal = (osal_int_signal_t *)signal; + rc = pthread_mutex_lock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to acquire lock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + if (true == the_signal->signalled) + { + rc = pthread_mutex_unlock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to unlock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + } + goto done; + } + + rc = pthread_cond_wait(&the_signal->osal_cond, &the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to wait on signal, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_cond; + } + + rc = pthread_mutex_unlock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to unlock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } +err_cond: + pthread_mutex_unlock(&the_signal->osal_mutex); +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_signal_timedwait(_In_ ar_osal_signal_t signal, _In_ int64_t timeout_in_nsec) +{ + int32_t rc; + osal_int_signal_t *the_signal; + struct timespec osal_ts; + + if (NULL == signal) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: signal is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + + clock_gettime(CLOCK_MONOTONIC, &osal_ts); + osal_ts.tv_sec += (timeout_in_nsec / 1000000000); + osal_ts.tv_nsec += (timeout_in_nsec % 1000000000); + + if (osal_ts.tv_nsec >= 1000000000) { + osal_ts.tv_sec += 1; + osal_ts.tv_nsec -= 1000000000; + } + + the_signal = (osal_int_signal_t *)signal; + rc = pthread_mutex_lock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to acquire lock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + + if (true == the_signal->signalled) { + rc = pthread_mutex_unlock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to unlock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + } + goto done; + } + + rc = pthread_cond_timedwait(&the_signal->osal_cond, &the_signal->osal_mutex, &osal_ts); + if (rc) { + + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to wait on signal, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_cond; + } + + rc = pthread_mutex_unlock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to unlock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + } +err_cond: + pthread_mutex_unlock(&the_signal->osal_mutex); +done: + return rc; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_osal_signal_set(_In_ ar_osal_signal_t signal) +{ + int32_t rc; + osal_int_signal_t *the_signal; + + if (NULL == signal) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: signal is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + + the_signal = (osal_int_signal_t *)signal; + rc = pthread_mutex_lock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to acquire lock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + the_signal->signalled = true; + + rc = pthread_cond_broadcast(&the_signal->osal_cond); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to signal on signal, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_cond; + } + + rc = pthread_mutex_unlock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to unlock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + } +err_cond: + pthread_mutex_unlock(&the_signal->osal_mutex); +done: + return rc; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_osal_signal_destroy(_In_ ar_osal_signal_t signal) +{ + int32_t rc; + osal_int_signal_t *the_signal; + + if (NULL == signal) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: signal is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + + the_signal = (osal_int_signal_t *)signal; + + the_signal-> signalled = false; + rc = pthread_mutex_lock(&the_signal->osal_mutex); + + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to acquire lock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + return rc; + } + rc = pthread_cond_destroy(&the_signal->osal_cond); + + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to destroy signal, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_cond; + } + rc = pthread_mutex_unlock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to unlock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_destroy; + } + rc = pthread_mutex_destroy(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to destroy mutex, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + } + goto done; + +err_cond: + pthread_mutex_unlock(&the_signal->osal_mutex); +err_destroy: + pthread_mutex_destroy(&the_signal->osal_mutex); +done: + free(signal); + return rc; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_osal_signal_clear(_In_ ar_osal_signal_t signal) +{ + int32_t rc; + osal_int_signal_t *the_signal; + + if (NULL == signal) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: signal is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + + the_signal = (osal_int_signal_t *)signal; + rc = pthread_mutex_lock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to acquire lock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + + the_signal->signalled = false; + + rc = pthread_mutex_unlock(&the_signal->osal_mutex); + if (rc) { + AR_LOG_ERR(AR_OSAL_SIGNAL_LOG_TAG,"%s: Failed to unlock, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + } + +done: + return rc; +} diff --git a/ar_osal/src/linux/ar_osal_signal2.c b/ar_osal/src/linux/ar_osal_signal2.c new file mode 100644 index 0000000..e275fd6 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_signal2.c @@ -0,0 +1,84 @@ +/** + * \file ar_osal_signal2.c + * + * \brief + * This file has implementation of signal2 APIs. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include "ar_osal_signal2.h" + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_signal2_init(_Inout_ ar_osal_signal2_t osal_signal2) +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_signal2_deinit(_In_ ar_osal_signal2_t osal_signal2) +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +size_t ar_osal_signal2_get_size() +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_signal2_create(_Out_ ar_osal_signal2_t *osal_signal2) +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_signal2_destroy(_In_ ar_osal_signal2_t osal_signal2) +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +uint32_t ar_osal_signal2_wait_any(_In_ ar_osal_signal2_t osal_signal2, _In_ uint32_t osal_signal2_mask) +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +uint32_t ar_osal_signal2_wait_all( _In_ ar_osal_signal2_t osal_signal2, _In_ uint32_t osal_signal2_mask); +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_signal2_set(_In_ ar_osal_signal2_t osal_signal2, _In_ uint32_t osal_signal2_mask) +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +uint32_t ar_osal_signal2_get(_In_ ar_osal_signal2_t osal_signal2) +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_signal2_clear(_In_ ar_osal_signal2_t osal_signal2, _In_ uint32_t osal_signal2_mask) +{ + ALOGE("%s: not implemented\n", __func__); + return -ENOSYS; +} diff --git a/ar_osal/src/linux/ar_osal_sleep.c b/ar_osal/src/linux/ar_osal_sleep.c new file mode 100644 index 0000000..f6eac73 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_sleep.c @@ -0,0 +1,43 @@ +/** + * \file ar_osal_sleep.c + * + * \brief + * This file has implementation of suspend thread execution for the required + * duration. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define AR_OSAL_SLEEP_LOG_TAG "COSL" +#include +#include "ar_osal_signal.h" +#include "ar_osal_log.h" +#include "ar_osal_error.h" + +_IRQL_requires_min_(PASSIVE_LEVEL) +int32_t ar_osal_micro_sleep(_In_ uint64_t micro_seconds) +{ + int32_t status = 0; + while (micro_seconds != 0) { + if (micro_seconds > 999999) { + status = usleep(999999); + if (0 != status) { + AR_LOG_ERR(AR_OSAL_SLEEP_LOG_TAG,"%s: usleep error %d", __func__, status); + goto exit; + } + micro_seconds -= 999999; + } + else { + status = usleep(micro_seconds); + if (0 != status) { + AR_LOG_ERR(AR_OSAL_SLEEP_LOG_TAG,"%s: usleep error %d", __func__, status); + goto exit; + } + break; + } + } +exit: + return status; +} diff --git a/ar_osal/src/linux/ar_osal_string.c b/ar_osal/src/linux/ar_osal_string.c new file mode 100644 index 0000000..5e6dc37 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_string.c @@ -0,0 +1,119 @@ +/** + * \file ar_osal_string.c + * + * \brief + * Defines public APIs for string operations. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ar_osal_types.h" +#include "ar_osal_error.h" +#include + +/** + * \brief ar_strlen + * Get the length of the string. + * \param[in] str: NULL terminated string buffer pointer. + * \param[in] size: String buffer size in bytes. + * \return + * Number of characters in the string, not including the terminating null + * character. If there is no null terminator in the buffer, provided + * string buffer size is returned to indicate the error. + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +size_t ar_strlen(_In_ const char_t* str, _In_ size_t size) +{ + return strnlen(str, size); +} + +/** + * \brief ar_strcpy + * Copies character from source to destination string. + * \param[in_out] str_dest: Destination string buffer. + * \param[in] str_dest_size: Size in characters. + * \param[in] str_src: Source string to copy from. + * \param[in] cpy_size: Size in characters to copy from source string. + * \return + * 0 -- Success + * Nonzero -- Failure + * note: Always null terminator is appended to the destination and string + * truncation will occur if destination size is smaller or equal to characters copy size. + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_strcpy(_Inout_ char_t* str_dest, _In_ size_t str_dest_size, _In_ const char_t* str_src, _In_ size_t cpy_size) +{ + size_t final_cpy_size = 0; + if (!str_dest || !str_src) + return AR_EFAILED; + + if (str_dest_size == 0 || cpy_size == 0) + return AR_EFAILED; + + if (cpy_size < str_dest_size) + final_cpy_size = cpy_size + 1; + else if (cpy_size >= str_dest_size ) + final_cpy_size = str_dest_size; + + strlcpy(str_dest, str_src, final_cpy_size); + + return AR_EOK; +} + +/** + * \brief ar_strcmp + * Compare characters in two given strings. + * \param[in] str1: Null terminated string 1 + * \param[in] str2: Null terminated string 2 + * \param[in] num: number of characters to compare. + * \return + * < 0 str1 < str2 + * 0 str1 == str2 + * > 0 str1 > str2 + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_strcmp(_In_ const char_t* str1, _In_ const char_t* str2, _In_ size_t num) +{ + return strncmp(str1, str2, num); +} + +/** +* \brief ar_strcat +* Append character from source to destination string. +* \param[in_out] str_dest: Destination string buffer. +* \param[in] str_dest_size: Size in characters. +* \param[in] str_src: Source string to copy from. +* \param[in] apnd_size: Size in characters to append from source string. +* \return +* 0 -- Success +* Nonzero -- Failure +* note: Always null terminator is appended to the destination after concatenation and string +* truncation will occur if destination size is smaller or equal to source. +*/ +_IRQL_requires_max_(DISPATCH_LEVEL) +int32_t ar_strcat(_Inout_ char_t* str_dest, _In_ size_t str_dest_size, _In_ const char_t* str_src, _In_ size_t apnd_size) +{ + if (str_dest_size < + ar_strlen(str_dest, str_dest_size) + + apnd_size + 1) + return AR_EFAILED; + + strlcat(str_dest, str_src, str_dest_size); + return AR_EOK; +} + +/** + * \brief ar_strstr + * Search string in string. + * \param[in] str: Null terminated string + * \param[in] str_search: Null terminated string to search for. + * \return + * Pointer to the first occurrence of str_search in str. + * NULL- if not found. + */ +_IRQL_requires_max_(DISPATCH_LEVEL) +char_t* ar_strstr(_In_ const char_t* str, _In_ const char_t* str_search) +{ + return strstr(str, str_search); +} diff --git a/ar_osal/src/linux/ar_osal_stub_log_pkt_op.c b/ar_osal/src/linux/ar_osal_stub_log_pkt_op.c new file mode 100644 index 0000000..e3af518 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_stub_log_pkt_op.c @@ -0,0 +1,45 @@ +/** +* \file ar_osal_stub_log_pkt_op.c +* \brief +* Defines stub APIs for ar_log_pkt. +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "ar_osal_log_pkt_op.h" +#include "ar_osal_error.h" + +int32_t ar_log_pkt_op_init(ar_log_pkt_op_init_info_t *info) +{ + return AR_EOK; +} + +int32_t ar_log_pkt_op_deinit() +{ + return AR_EOK; +} + +uint32_t ar_log_pkt_get_max_size() +{ + return 0; +} + +void *ar_log_pkt_alloc(uint16_t logcode, uint32_t length) +{ + return NULL; +} + +int32_t ar_log_pkt_commit(void *ptr) +{ + return AR_EOK; +} + +void ar_log_pkt_free(void *ptr) +{ +} + +bool_t ar_log_code_status(uint16_t logcode) +{ + return true; +} diff --git a/ar_osal/src/linux/ar_osal_thread.c b/ar_osal/src/linux/ar_osal_thread.c new file mode 100644 index 0000000..aff02f7 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_thread.c @@ -0,0 +1,316 @@ +/** + * \file ar_osal_thread.c + * + * \brief + * This file has implementation of thread related helper functions. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define _GNU_SOURCE +#define AR_OSAL_THREAD_LOG_TAG "COTL" +#include +#include +#include +#include +#include "ar_osal_thread.h" +#include "ar_osal_log.h" +#include "ar_osal_error.h" + +typedef struct osal_int_thread { + pthread_t pthread_handle; + ar_osal_thread_start_routine fn; + void* param; +} osal_int_thread_t; + +static void* osal_thread_wrapper(void *param) +{ + osal_int_thread_t *the_thread = (osal_int_thread_t *)param; + if (NULL != the_thread) + the_thread->fn(the_thread->param); + return NULL; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_thread_attr_init(_In_ ar_osal_thread_attr_t *thread_attr) +{ + int32_t rc = 0; + pthread_attr_t attr; + struct sched_param param; + size_t size; + if (NULL == thread_attr) + { + rc = AR_EBADPARAM; + goto done; + } + + rc = pthread_attr_init(&attr); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to init attributes, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + + rc = pthread_attr_getschedparam(&attr, ¶m); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to init attributes, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + + rc = pthread_attr_getstacksize(&attr, &size); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to init attributes, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + thread_attr->thread_name = NULL; + thread_attr->priority = param.sched_priority; + thread_attr->stack_size = size; + +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_thread_create(_Out_ ar_osal_thread_t *ret_thread, + _In_ ar_osal_thread_attr_t *attr_ptr, + _In_ ar_osal_thread_start_routine osal_thread_start, + _In_opt_ void *osal_thread_param) +{ + int32_t rc; + osal_int_thread_t *the_thread; + pthread_attr_t attr; + void *ret_val; + struct sched_param sch_param; + + if (NULL == ret_thread || NULL == attr_ptr) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: ret_thread or attr_ptr is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + + the_thread = (osal_int_thread_t *) malloc(sizeof(osal_int_thread_t)); + if (NULL == the_thread) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to allocate memory\n", __func__); + rc = AR_ENOMEMORY; + goto done; + } + + rc = pthread_attr_init(&attr); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to init attributes, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_attr; + } + rc = pthread_attr_setstacksize(&attr, attr_ptr->stack_size); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to set stack size, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_attr; + } + + memset(&sch_param, 0, sizeof(sch_param)); + sch_param.sched_priority = attr_ptr->priority; + rc = pthread_attr_setschedparam (&attr, &sch_param); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to set thread priority , rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_set; + } + + rc = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to set detach state, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_set; + } + the_thread->fn = osal_thread_start; + the_thread->param = osal_thread_param; + rc = pthread_create(&the_thread->pthread_handle, &attr, + osal_thread_wrapper, the_thread); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to create thread, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_set; + } + + if (attr_ptr->thread_name){ + rc = pthread_setname_np(the_thread->pthread_handle, attr_ptr->thread_name); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to create thread, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_destroy; + } + } + + rc = pthread_attr_destroy(&attr); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to destroy attributes, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto err_destroy; + } + + *ret_thread = (ar_osal_thread_t *)the_thread; + goto done; + +err_destroy: + pthread_join(the_thread->pthread_handle, &ret_val); + +err_set: + pthread_attr_destroy(&attr); + +err_attr: + free(the_thread); + +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_thread_join_destroy(_In_ ar_osal_thread_t thread) +{ + int32_t rc = 0; + osal_int_thread_t *the_thread; + void *ret_val; + + if (NULL == thread) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Thread is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + the_thread = (osal_int_thread_t *)thread; + rc = pthread_join(the_thread->pthread_handle, &ret_val); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to join the thread, rc = %d\n", __func__, rc); + rc = AR_EFAILED; + } + + free(the_thread); + +done: + return rc; +} + +static int32_t set_thread_prioirity(pthread_t *pthread_handle, int32_t new_thread_priority) +{ + int32_t rc = 0; + int policy = 0; + struct sched_param sch_param; + + memset(&sch_param, 0, sizeof(sch_param)); + rc = pthread_getschedparam(*pthread_handle, &policy, &sch_param); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to get thread scheduling params , rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + sch_param.sched_priority = new_thread_priority; + rc = pthread_setschedparam(*pthread_handle, policy, &sch_param); + if (rc) + { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to set new thread prioritypriority rc:%d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + +done: + return rc; +} + +_IRQL_requires_min_(PASSIVE_LEVEL) +int32_t ar_osal_thread_set_priority(_In_ ar_osal_thread_t thread, _In_ int32_t new_thread_priority) +{ + int32_t rc = 0; + osal_int_thread_t *the_thread; + + if (NULL == thread) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Thread is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + + the_thread = (osal_int_thread_t *)thread; + rc = set_thread_prioirity(&the_thread->pthread_handle, new_thread_priority); + +done: + return rc; +} + +_IRQL_requires_min_(PASSIVE_LEVEL) +int32_t ar_osal_thread_self_set_priority(_In_ int32_t new_thread_priority) +{ + int32_t rc = 0; + pthread_t pthread_handle = pthread_self(); + + rc = set_thread_prioirity(&pthread_handle, new_thread_priority); + + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_thread_self_get_priority(_Inout_ int32_t *ret_thread_priority) +{ + int32_t rc = 0; + pthread_t pthread_handle = pthread_self(); + struct sched_param sch_param; + int policy; + + memset(&sch_param, 0, sizeof(sch_param)); + rc = pthread_getschedparam(pthread_handle, &policy, &sch_param); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to get thread priority , rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + + *ret_thread_priority = sch_param.sched_priority; + +done: + return rc; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_thread_get_priority(_In_ ar_osal_thread_t thread, _Inout_ int32_t *ret_thread_priority) +{ + int32_t rc = 0; + osal_int_thread_t *the_thread; + struct sched_param sch_param; + int policy; + + if (NULL == thread) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Thread is NULL\n", __func__); + rc = AR_EBADPARAM; + goto done; + } + + the_thread = (osal_int_thread_t *)thread; + + memset(&sch_param, 0, sizeof(sch_param)); + rc = pthread_getschedparam (the_thread->pthread_handle, &policy, &sch_param); + if (rc) { + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Failed to get thread priority , rc = %d\n", __func__, rc); + rc = AR_EFAILED; + goto done; + } + + *ret_thread_priority = sch_param.sched_priority; + +done: + return rc; +} + +_IRQL_requires_min_(PASSIVE_LEVEL) +int64_t ar_osal_thread_get_id() +{ + return (int64_t)pthread_self(); +} + +int32_t ar_osal_thread_self_terminate() +{ + AR_LOG_ERR(AR_OSAL_THREAD_LOG_TAG,"%s: Not Implemented\n", __func__); + return AR_ENOTIMPL; +} diff --git a/ar_osal/src/linux/ar_osal_timer.c b/ar_osal/src/linux/ar_osal_timer.c new file mode 100644 index 0000000..67523f3 --- /dev/null +++ b/ar_osal/src/linux/ar_osal_timer.c @@ -0,0 +1,49 @@ +/** + * \file ar_osal_timer.c + * + * \brief + * This file has implementation of timer operations. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include "ar_osal_error.h" +#include "ar_osal_heap.h" + +/** + * \brief ar_timer_get_time_in_us + *        Gets the wall clock time in microseconds + * \return + *        Wall clock time in microseconds. + */ +uint64_t ar_timer_get_time_in_us(void) +{ + uint64_t us = 0; + struct timespec ts; + + if (!clock_gettime(CLOCK_BOOTTIME, &ts)) + us = ((ts.tv_sec * 1000000LL) + (ts.tv_nsec / 1000LL)); + + return us; +} + +/** + * \brief ar_timer_get_time_in_ms + *        Gets the wall clock time in milliseconds + * \return + *        Wall clock time in milliseconds. + */ +uint64_t ar_timer_get_time_in_ms(void) +{ + uint64_t ms = 0; + struct timespec ts; + + if(!clock_gettime(CLOCK_BOOTTIME, &ts)) + ms = ((ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL)); + + return ms; +} diff --git a/ar_osal/src/linux/qcom/ar_osal_log_pkt_op.c b/ar_osal/src/linux/qcom/ar_osal_log_pkt_op.c new file mode 100644 index 0000000..f36b3aa --- /dev/null +++ b/ar_osal/src/linux/qcom/ar_osal_log_pkt_op.c @@ -0,0 +1,173 @@ +/** +* \file ar_osal_log_pkt_op.c +* \brief +* Defines platform agnostic APIs for sending log packets to +* the PC. +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "ar_osal_log_pkt_op.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#ifndef USE_LIBDIAG_HEADERS +#include "comdef.h" +#else +#include "diag_comdef.h" +#endif +#include "diag_lsm.h" +#include "log.h" + +/**< +Length of the DIAG log packet header in bytes. The QXDM Pro log +code, and system timestamp. Each log packet must begin with a +member of type log_hdr_type which is 12 bytes. */ +#define AR_OSAL_LOG_DIAG_HEADER_LENGTH 12 + +#define ar_osal_log_alloc(code, length) log_alloc(code, length) +#define ar_osal_log_commit(ptr) log_commit(ptr) +#define ar_osal_log_free(ptr) log_free(ptr) +#define ar_osal_log_status(code) log_status(code) + +/** +* \brief ar_log_pkt_op_init +* +* Initialzes the data transport mechanism +* +* \param[in] info: pointer to info structure containing heap and data +* transport information that is used to initialize the pai +* +* +* \return +* Success -- 0 +* Failure -- non-zero +*/ +int32_t ar_log_pkt_op_init(ar_log_pkt_op_init_info_t *info) +{ + __UNREFERENCED_PARAM(info); + + if(Diag_LSM_Init(NULL)) + { + return AR_EOK; + } + + return AR_EFAILED; +} + +/** +* \brief ar_log_pkt_op_deinit +* +* Deinitializes the utility and release any/all +* resources aquired +* +* \depends +* ar_log_pkt_op_init(...) must be called before this function +* +* \return +* Success -- returns a pointer to the allocated memory +* Failure -- returns null if the allocation fails +*/ +int32_t ar_log_pkt_op_deinit() +{ + if(Diag_LSM_DeInit()) + { + return AR_EOK; + } + + return AR_EFAILED; +} + +/** +* \brief ar_log_pkt_get_max_size +* +* Retrieve the max size of a log packet that can be sent through +* the data transport +* +* \depends +* ar_log_pkt_op_init(...) must be called before this function +* +* \return +* return the max log packet size +*/ +uint32_t ar_log_pkt_get_max_size() +{ + return 3360;//4k +} + +/** +* \brief ar_log_pkt_alloc +* +* Allocates a log packet and returns a pointer to the memory +* +* \param[in] logcode: the log code used for the packet +* \param[in] length: the size of the packet to allocate +* +* \depends +* commit or free operations must be called ASAP after this call since +* the allocation is performed in the transport layer shared resource pool +* +* \return +* Success -- returns a pointer to the allocated memory +* Failure -- returns null if the allocation fails +*/ +void *ar_log_pkt_alloc(uint16_t logcode, uint32_t length) +{ + uint8_t *ptr = (uint8_t*)ar_osal_log_alloc( + logcode, + AR_OSAL_LOG_DIAG_HEADER_LENGTH + length); + + return ptr + AR_OSAL_LOG_DIAG_HEADER_LENGTH; +} + +/** +* \brief ar_log_pkt_commit +* +* Commits the log packet and then frees the memory pointed to by ptr +* +* \param[in] ptr: pointer to memory allocated through ar_log_pkt_alloc +* +* \return +* n/a +*/ +int32_t ar_log_pkt_commit(void *ptr) +{ + ar_osal_log_commit( + (uint8_t*)ptr - AR_OSAL_LOG_DIAG_HEADER_LENGTH); + + return AR_EOK; +} + +/** +* \brief ar_log_pkt_free +* +* Releases resources aquired through ar_log_pkt_alloc +* +* \param[in] ptr: pointer to memory allocated through ar_log_pkt_alloc +* +* \return +* n/a +*/ +void ar_log_pkt_free(void *ptr) +{ + if (!ptr) return; + + ar_osal_log_free( + (uint8_t*)ptr - AR_OSAL_LOG_DIAG_HEADER_LENGTH); +} + +/** +* \brief ar_log_code_status +* +* Checks whether a log code is enable +* +* \param[in] logcode: the log code to check. +* +* \return +* TRUE -- ENABLED +* FALSE -- DISABLED +*/ +bool_t ar_log_code_status(uint16_t logcode) +{ + return ar_osal_log_status(logcode); +} \ No newline at end of file diff --git a/ar_osal/src/linux/qcom/ar_osal_servreg.c b/ar_osal/src/linux/qcom/ar_osal_servreg.c new file mode 100644 index 0000000..b2b1fc3 --- /dev/null +++ b/ar_osal/src/linux/qcom/ar_osal_servreg.c @@ -0,0 +1,591 @@ +/** + * \file ar_osal_serverg.c + * + * \brief + * This file has implementation of service location, notification, and + * state registration. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define AR_OSAL_SERVREG_TAG "COSR" +#include +#include "ar_osal_types.h" +#include "ar_osal_servreg.h" +#include "ar_osal_mutex.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#include "ar_osal_mem_op.h" +#include +#include +#include +#include +#include +#ifdef AR_OSAL_USE_CUTILS +#include +#endif + + #ifdef __cplusplus + extern "C" { + #endif /* __cplusplus */ + +#ifdef AR_OSAL_USE_PD_NOTIFIER +#include +#include +#include +SR_DL_Handle* pd_mapper_handle; +#else +#include "ar_osal_sys_id.h" +char_t domain_name[AR_SUB_SYS_ID_LAST + 1][24] = { "msm/adsp/audio_pd", "msm/mdsp/audio_pd", "msm/adsp/audio_pd","msm/apss/audio_pd","msm/sdsp/audio_pd","msm/cdsp/audio_pd" }; +#endif /* AR_OSAL_USE_PD_NOTIFIER */ + +#define ADSP_LOADER_PATH "/sys/kernel/boot_adsp/ssr" +#define PROC_PANIC_PATH "/proc/sysrq-trigger" + +#define AR_OSAL_SERVREG_CLIENT_NAME "apps/ar_osal" + +int32_t g_init_done = 0; +struct ar_osal_service_node +{ + + ar_osal_servreg_t srv_handle; + ar_osal_servreg_entry_type service; + ar_osal_servreg_entry_type domain; + void *cb_context; + ar_osal_servreg_callback cb_func; + ar_osal_service_state_type srv_state; +#ifdef AR_OSAL_USE_PD_NOTIFIER + PD_Notifier_Handle *pd_handle; +#endif /* AR_OSAL_USE_PD_NOTIFIER */ +}; + +typedef struct ar_osal_service_node ar_osal_service_node; +ar_osal_servreg_t serv_reg_handle; + +#ifdef AR_OSAL_USE_PD_NOTIFIER +static ar_osal_service_state_type pd_event_to_ar_osal_pd_state(enum pd_event event) +{ + ar_osal_service_state_type ret = AR_OSAL_SERVICE_STATE_DOWN; + switch (event) { + case EVENT_PD_DOWN: + ret = AR_OSAL_SERVICE_STATE_DOWN; + break; + case EVENT_PD_UP: + ret = AR_OSAL_SERVICE_STATE_UP; + break; + default: + ret = AR_OSAL_SERVICE_STATE_DOWN; + break; + } + return ret; +} + +static ar_osal_service_state_type pd_state_to_ar_osal_pd_state(pd_state state) +{ + ar_osal_service_state_type ret = AR_OSAL_SERVICE_STATE_DOWN; + + switch (state) { + case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: + ret = AR_OSAL_SERVICE_STATE_DOWN; + break; + case SERVREG_NOTIF_SERVICE_STATE_UP_V01: + ret = AR_OSAL_SERVICE_STATE_UP; + break; + default: + ret = AR_OSAL_SERVICE_STATE_DOWN; + } + return ret; +} + +static void ar_osal_pd_notifier_cb(void *data, enum pd_event event) +{ + ar_osal_service_node *entry = (ar_osal_service_node *)data; + ar_osal_service_state_type state = pd_event_to_ar_osal_pd_state(event); + ar_osal_servreg_state_notify_payload_type notify_state; + + AR_LOG_INFO(AR_OSAL_SERVREG_TAG, "ar_osal_pd_notifier_cb state(%d) service(%s)", + state, entry->service.name ); + AR_LOG_INFO(AR_OSAL_SERVREG_TAG, "ar_osal_pd_notifier_cb state(%d) domain(%s)", + state, entry->domain.name ); + + notify_state.service_state = state; + memcpy((void*)¬ify_state.service, (const void*)&entry->service, sizeof(ar_osal_servreg_entry_type)); + memcpy((void*)¬ify_state.domain, (const void*)&entry->domain, sizeof(ar_osal_servreg_entry_type)); + + + if (entry) + { + if (entry->cb_func) + { + entry->cb_func((ar_osal_servreg_t)entry, + AR_OSAL_SERVICE_STATE_NOTIFY, + entry->cb_context, + (void*)¬ify_state, + sizeof(notify_state)); + } + entry->srv_state = state; + } +} +#endif /* AR_OSAL_USE_PD_NOTIFIER */ + + +/** +* \brief ar_osal_servreg_init +* Initialize servreg interface. +*........Note:This API has to be called before any other API in this interface. +*........Should be called at least once and is expected to be serialized if called +* multiple times. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_servreg_init(void) +{ + int32_t status = AR_EOK; + // ar_osal_servreg_type_t* handle = NULL; + if (g_init_done) + { + g_init_done++; + return status; + } + g_init_done = 1; +#ifdef AR_OSAL_USE_PD_NOTIFIER + pd_mapper_handle = servreg_alloc_DLHandle(); + if (!pd_mapper_handle) + { + status = AR_ENOMEMORY; + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "servreg allocation error status(%d)", status); + goto end; + } +#endif /* AR_OSAL_USE_PD_NOTIFIER */ + // strlcpy(handle->client_name, AR_OSAL_SERVREG_TAG, sizeof(handle->client_name)); + AR_LOG_INFO(AR_OSAL_SERVREG_TAG, "ar_osal_servreg_init success status(%d)", status); +end: + return status; +} + +/** +* \brief ar_osal_servreg_deinit +* Uninitialize servreg interface. +*........Should be called in pair with ar_osal_servreg_init() and +*........should be a serialized call. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_servreg_deinit(void) +{ + //uint32_t status = AR_EOK; + // ar_osal_servreg_type_t* handle = (ar_osal_servreg_type_t*)pd_handle; + g_init_done--; + if (0 != g_init_done) + { + goto end; + } +#ifdef AR_OSAL_USE_PD_NOTIFIER + if (pd_mapper_handle) + { + servreg_free_DLHandle(pd_mapper_handle); + pd_mapper_handle = NULL; + } +#endif /* AR_OSAL_USE_PD_NOTIFIER */ +end: + return AR_EOK; +} + +/** +* \brief ar_osal_servreg_get_domainlist +* Client to call this API to get a list of domains(msm/domain/subdomain) on which +* a given service(provider/service) is supported. +* +* \param[in] service: service(provider/service) for which domain(s) list is required. +* \param[in out] domain_list: service supported in domain(s), client to provide +*. payload buffer pointer. +* \param[in out] num_domains: Client to provide the num_domains to get the domain list. +*. Input NULL domain_list to get the number of domains +* for the given service if available in num_domains. +* +* \return +* 0 -- Success +* Nonzero -- Failure +* AR_ENOMEMORY- Failed due to insufficient memory, client to call the API again +* with required size as returned in num_domains. +*. +*/ + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_servreg_get_domainlist(_In_ ar_osal_servreg_entry_type *service, + _Inout_opt_ ar_osal_servreg_entry_type *domain_list, + _Inout_ uint32_t *num_domains) +{ + int32_t status = AR_EOK; + if (NULL == service || NULL == num_domains) + { + status = AR_EBADPARAM; + goto end; + } +#ifdef AR_OSAL_USE_PD_NOTIFIER + if (NULL == domain_list) + { + enum SR_Result_Enum rc = SR_RESULT_SUCCESS; + rc = servreg_get_domainlist((char *)service->name, pd_mapper_handle); + if (rc != SR_RESULT_SUCCESS) + { + status = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "servreg_get_domainlist error status(%d)" + "servreg status(%d)", status, rc); + goto end; + } + + //return single domain + *num_domains = servreg_get_numentries(pd_mapper_handle); + status = AR_ENOMEMORY; + } + else if ((domain_list != NULL) && (num_domains > 0)) + { + //copy domain details + enum SR_Result_Enum rc = SR_RESULT_SUCCESS; + uint32_t i = 0; + //memcpy_s(domain_list->name, sizeof(domain_list->name), domain_name, sizeof(domain_name)); + for (i = 0; i < *num_domains; i++) + { + char* name; + int instance = 0; + int service_data_valid = 0; + int service_data = 0; + rc = servreg_get_entry(pd_mapper_handle, + &name, + &instance, + &service_data_valid, + &service_data, + i); + if (rc != SR_RESULT_SUCCESS) + { + status = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, + "servreg_get_domainlist entry(%d) error status(%d)" + "servreg status(%d)", + i, status, rc); + goto end; + } + + strlcpy((domain_list + i)->name, name, sizeof(domain_list->name)); + (domain_list + i)->instance_id = instance; + + AR_LOG_INFO(AR_OSAL_SERVREG_TAG, "servreg_get_domainlist entry(%d)" + " instance(%d) domain name(%s)", + i, instance, (domain_list + i)->name); + } + } + else + { + // service not found. + status = AR_EBADPARAM; + } +#else + if (NULL == domain_list) + { + //return supported domains + *num_domains = AR_SUB_SYS_ID_LAST; + status = AR_ENOMEMORY; + goto end; + } + + //copy domain details + strlcpy(domain_list[0].name, domain_name[AR_MODEM_DSP], sizeof(domain_list[0].name)); + strlcpy(domain_list[1].name, domain_name[AR_AUDIO_DSP], sizeof(domain_list[1].name)); + strlcpy(domain_list[2].name, domain_name[AR_APSS], sizeof(domain_list[2].name)); + strlcpy(domain_list[3].name, domain_name[AR_SENSOR_DSP], sizeof(domain_list[3].name)); + strlcpy(domain_list[4].name, domain_name[AR_COMPUTE_DSP], sizeof(domain_list[4].name)); + domain_list[0].instance_id = 74; + domain_list[1].instance_id = 74; + domain_list[2].instance_id = 74; + domain_list[3].instance_id = 74; + domain_list[4].instance_id = 74; + *num_domains = AR_SUB_SYS_ID_LAST; +#endif + +end: + AR_LOG_INFO(AR_OSAL_SERVREG_TAG, + "ar_osal_servreg_get_domainlist service(%s) status(0x%x)", + service->name, status); + return status; +} + +/** +* \brief ar_osal_servreg_register +* Service client(s) to register for the domain service state change notifications. +* +* \param[in opt] cb_func: callback function pointer to get notifications on. +*. This is parameter is optional to Service provider registration. +* \param[in opt] cb_context: callback function payload/context provided by client. +*. This is parameter is optional to Service provider registration. +* \param[in] domain: domain of the service(msm/domain/subdomain) for which the +*. state change notifications to be provided. +* \param[in] service: service(provider/service) for which the +*. state change notifications to be provided. +* \return +* servreg_handle on success. +* null on failure. +*/ +_IRQL_requires_max_(PASSIVE_LEVEL) +ar_osal_servreg_t ar_osal_servreg_register(_In_ ar_osal_client_type client_type __unused, + _In_opt_ ar_osal_servreg_callback cb_func, + _In_opt_ void *cb_context, + _In_ ar_osal_servreg_entry_type *domain, + _In_ ar_osal_servreg_entry_type *service) +{ +#ifndef AR_OSAL_USE_PD_NOTIFIER + return NULL; +#else + char pd_service_name[AR_OSAL_SERVREG_NAME_LENGTH_MAX + 1]; + ar_osal_service_node* srv_reg_handle = NULL; + enum pd_rcode pd_rc = PD_NOTIFIER_FAIL; + pd_state state = SERVREG_NOTIF_SERVICE_STATE_DOWN_V01; + + if (NULL == domain || NULL == service || NULL == cb_func) + { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "Invalid input params"); + goto end; + } + srv_reg_handle = (ar_osal_service_node*)malloc(sizeof(ar_osal_service_node)); + if (!srv_reg_handle) + { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "handle allocation failed"); + goto end; + } + + memset((void*)srv_reg_handle, 0, sizeof(ar_osal_service_node)); + memcpy(&srv_reg_handle->service, service, sizeof(ar_osal_servreg_entry_type)); + memcpy(&srv_reg_handle->domain, domain, sizeof(ar_osal_servreg_entry_type)); + + srv_reg_handle->cb_func = cb_func; + srv_reg_handle->cb_context = cb_context; + snprintf(pd_service_name, sizeof(pd_service_name), "%s/%s", domain->name, service->name); + + srv_reg_handle->pd_handle = pd_notifier_alloc(pd_service_name, + AR_OSAL_SERVREG_CLIENT_NAME, + domain->instance_id, + ar_osal_pd_notifier_cb, + (void*)srv_reg_handle); + + if (!srv_reg_handle->pd_handle) + { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "pd_notifier_alloc failed"); + free(srv_reg_handle); + srv_reg_handle = NULL; + goto end; + } + + pd_rc = pd_notifier_register(srv_reg_handle->pd_handle, &state); + + if (pd_rc != PD_NOTIFIER_SUCCESS) { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "pd_notifier_register failed for %s, status(%d)", + pd_service_name, pd_rc); + pd_notifier_free(srv_reg_handle->pd_handle); + free(srv_reg_handle); + srv_reg_handle = NULL; + goto end; + } + else { + AR_LOG_INFO(AR_OSAL_SERVREG_TAG, + "Successfully registered %s. Curr state is %s state (0x%08x)", + pd_service_name, + (state == EVENT_PD_UNKNOWN) ? "unknown" : + ((state == EVENT_PD_UP) ? "up" : + ((state == EVENT_PD_DOWN) ? "down" : "out of range")), + state); + srv_reg_handle->srv_state = pd_state_to_ar_osal_pd_state(state); + } + +end: + return (ar_osal_servreg_t)srv_reg_handle; +#endif +} + +/** +* \brief ar_osal_servreg_deregister +* Service client(s) to deregister for the service state change notifications. +* +* \param[in] servreg_handle: interface handle returned by ar_osal_servreg_allocate_handle(). +* +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_servreg_deregister(_In_ ar_osal_servreg_t servreg_handle) +{ +#ifndef AR_OSAL_USE_PD_NOTIFIER + return 1; +#else + int32_t status = AR_EOK; + enum pd_rcode pd_rc = PD_NOTIFIER_FAIL; + ar_osal_service_node* srv_reg_handle = (ar_osal_service_node*)servreg_handle; + if (NULL == servreg_handle) + { + status = AR_EBADPARAM; + goto end; + } + + pd_rc = pd_notifier_deregister(srv_reg_handle->pd_handle); + if (pd_rc != PD_NOTIFIER_SUCCESS) { + status = AR_EFAILED; + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "pd_notifier_deregister error: status(%d)" + "pd_notifier status(%d)", + status, pd_rc); + pd_notifier_free(srv_reg_handle->pd_handle); + free(srv_reg_handle); + srv_reg_handle = NULL; + goto end; + } + pd_notifier_free(srv_reg_handle->pd_handle); + free(srv_reg_handle); + srv_reg_handle = NULL; +end: + return status; +#endif +} + +/** +* \brief ar_osal_servreg_set_state +* Service provider to call this API to register its service states(UP/DOWN). +* This API to be used only by the service provider(msm/domain/subdomain/provider/service) +* and not by service client(s). +* +* \param[in] servreg_handle: interface handle returned by ar_osal_servreg_allocate_handle(). +* \param[in] state: new service state for service registered using ar_osal_servreg_register(). +*. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_servreg_set_state(_In_ ar_osal_servreg_t servreg_handle __unused, + _In_ ar_osal_service_state_type state __unused) +{ + return AR_ENOTIMPL; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +_IRQL_requires_max_(PASSIVE_LEVEL) +static int32_t ar_osal_servreg_ssr() { +#ifdef PROPERTY_TRIGGER + if (property_set("vendor.audio.ssr.trigger", "1")) { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "%s: set property failed", __func__); + return -1; + } + return 0; +#else + int fd_dsplder; + int32_t rc = 0; + + fd_dsplder = open(ADSP_LOADER_PATH, O_WRONLY); + + if(fd_dsplder < 0) { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "%s: open (%s) fail - %s (%d)", + __func__, ADSP_LOADER_PATH, strerror(errno), errno); + rc = errno; + } else if (write(fd_dsplder, "1", 1) < 0) { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "%s: write (%s) fail - %s (%d)", + __func__, ADSP_LOADER_PATH, strerror(errno), errno); + rc = errno; + } + + return rc; +#endif +} + +/** +* \brief induce panic to crash the system +* +*/ +void ar_osal_panic() +{ +#ifdef PROPERTY_TRIGGER + if (property_set("vendor.audio.crash.trigger", "1")) + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "%s: set property failed", __func__); +#else + char panic_set ='c'; + int fd_sysrq = 0; + + fd_sysrq = open(PROC_PANIC_PATH, O_WRONLY); + + if(fd_sysrq < 0) { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, "%s: open (%s) fail - %s (%d)", __func__, + PROC_PANIC_PATH, strerror(errno), errno); + //ignore if panic path can't be opened + } else if (write(fd_sysrq, &panic_set, 1) < 0) { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG,"%s: write (%s) fail - %s (%d)", __func__, + PROC_PANIC_PATH, strerror(errno), errno); + } +#endif +} + +/** +* \brief ar_osal_servreg_restart_service +* HLOS calls this API to trigger a restart (PDR or SSR) on a given +* processor +* +* \param[in] servreg_handle: interface handle returned by +* ar_osal_servreg_register() which identifies the desired processor +* +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t ar_osal_servreg_restart_service(ar_osal_servreg_t servreg_handle) +{ +#ifndef AR_OSAL_USE_PD_NOTIFIER + return 1; +#else + int32_t rc = AR_EOK; + int32_t ssr_rc; + enum pd_rcode pd_rc; + ar_osal_service_node* serv_reg_handle = (ar_osal_service_node*)servreg_handle; +#ifdef AR_OSAL_USE_CUTILS + char value[256] = {0}; + + property_get("persist.vendor.audio.induce_crash", value, ""); + if (!strncmp("true", value, sizeof("true"))) + ar_osal_panic(); + + property_get("persist.vendor.audio.spf_restart", value, ""); + if (strncmp("true", value, sizeof("true"))) { + AR_LOG_INFO(AR_OSAL_SERVREG_TAG, "SPF restart feature disabled\n"); + return rc; + } +#endif + + AR_LOG_INFO(AR_OSAL_SERVREG_TAG, "Restarting service %d", servreg_handle); + + if (serv_reg_handle == NULL) + { + rc = AR_EBADPARAM; + goto end; + } + + pd_rc = pd_notifier_restart_pd(serv_reg_handle->pd_handle); + if (pd_rc != PD_NOTIFIER_SUCCESS) { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, + "Failed to restart audio service rc(%d) perform SSR\n", pd_rc); + ssr_rc = ar_osal_servreg_ssr(); + if (ssr_rc) { + AR_LOG_ERR(AR_OSAL_SERVREG_TAG, + "Failed to restart audio DSP rc(%d)\n", ssr_rc); + rc = AR_EUNEXPECTED; + } + } + +end: + return rc; +#endif +} diff --git a/ar_osal/src/linux/qcom/ar_osal_shmem.c b/ar_osal/src/linux/qcom/ar_osal_shmem.c new file mode 100644 index 0000000..9bcc27b --- /dev/null +++ b/ar_osal/src/linux/qcom/ar_osal_shmem.c @@ -0,0 +1,77 @@ +/** + * + * \file ar_osal_shmem.c + * + * \brief + * This file has implementation for selection of functions with ARM/DSP-specific processing. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include "ar_osal_shmem.h" // Public API +#include "ar_osal_error.h" // Error codes +#include "ar_osal_log.h" +#include "ar_osal_shmem_dsp.h" +#include "ar_osal_shmem_ap.h" +#define AR_OSAL_SHMEM_LOG_TAG "COSH" + +static bool are_on_apps = false; + +int32_t ar_shmem_init() +{ + return AR_EOK; +} + +int32_t ar_shmem_init_v2(uint32_t num_master_procs, uint32_t *master_procs) +{ + /* Assumption: There is no case with multiple master processors with one of them being APSS. */ + for (int i = 0; i < num_master_procs; i++) { + if(master_procs[i]== AR_APSS){ + are_on_apps = true; + break; + } + } + + return are_on_apps ? ar_shmem_ap_init() : ar_shmem_dsp_init(); +} + +int32_t ar_shmem_alloc(ar_shmem_info *info) +{ + return are_on_apps ? ar_shmem_ap_alloc(info) : ar_shmem_dsp_alloc(info); +} + +int32_t ar_shmem_free(ar_shmem_info *info) +{ + return are_on_apps ? ar_shmem_ap_free(info) : ar_shmem_dsp_free(info); +} + +int32_t ar_shmem_map(ar_shmem_info *info) +{ + return are_on_apps ? ar_shmem_ap_map(info) : ar_shmem_dsp_map(info); +} + +int32_t ar_shmem_unmap(ar_shmem_info *info) +{ + return are_on_apps ? ar_shmem_ap_unmap(info) : ar_shmem_dsp_unmap(info); +} + +int32_t ar_shmem_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info) +{ + return are_on_apps ? ar_shmem_ap_hyp_assign_phys(info) + : ar_shmem_dsp_hyp_assign_phys(info); +} + +int32_t ar_shmem_get_uid(uint64_t alloc_handle, uint64_t *uid) +{ + if (are_on_apps) { + return ar_shmem_ap_get_uid(alloc_handle, uid); + } + return AR_EUNSUPPORTED; +} + +int32_t ar_shmem_deinit(void) +{ + int32_t rc = are_on_apps ? ar_shmem_ap_deinit() : ar_shmem_dsp_deinit(); + return rc; +} diff --git a/ar_osal/src/linux/qcom/ar_osal_shmem_ap.c b/ar_osal/src/linux/qcom/ar_osal_shmem_ap.c new file mode 100644 index 0000000..c318bd3 --- /dev/null +++ b/ar_osal/src/linux/qcom/ar_osal_shmem_ap.c @@ -0,0 +1,294 @@ +/** + * + * \file ar_osal_shmem_ap.c + * + * \brief + * This file has implementation for shared memory implementation for ARM master processor. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include "ar_osal_shmem.h" +#include "ar_osal_shmem_ap.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +/*Memory pointer to be 4K aligned for ADSP, MDSP,SDSP and CDSP */ +#define SHMEM_4K_ALIGNMENT (4096) +/** + * \brief ar_shmem_validate_sys_id + * internal function to validate supported SYS IDs. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +static int32_t ar_shmem_validate_sys_id(uint8_t num_sys_id, ar_shmem_proc_info *sys_id) +{ + int32_t status = AR_EOK; + + if (0 == num_sys_id || NULL == sys_id) + return AR_EBADPARAM; + + for (uint8_t i = 0; i < num_sys_id; ++i) { + if (AR_APSS != sys_id[i].proc_id) { + status = AR_EBADPARAM; + break; + } + } + + return status; +} +/* + *\brief ar_shmem_init + * initialize shared memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_ap_init(void) +{ + return AR_EOK; +} +/* + * \brief Allocates shared memory. + * Only non cached memory allocation supported. + * Size if multiple of 4KB and the returned is aligned to 4KB boundary. + * Buffer start address should be atleast 64bit multiple aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_ap_alloc(_Inout_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + void *p = 0; + if (NULL == info || 0 == info->buf_size) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: info(NULL)\nbuf_size(0) passed"); + status = AR_EBADPARAM; + goto end; + } + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id, info->sys_id)) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + info->ipa_lsw = 0; + info->ipa_msw = 0; + info->metadata = 0; + info->pa_lsw = 0; + info->pa_msw = 0; + info->index_type = AR_SHMEM_BUFFER_ADDRESS; + info->mem_type = AR_SHMEM_VIRTUAL_MEMORY; + if (0 != posix_memalign(&p, SHMEM_4K_ALIGNMENT, info->buf_size)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: posix_memalign failed"); + status = AR_ENOMEMORY; + goto end; + } + info->vaddr = p; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "vaddr(0x%p)", info->vaddr); + if (NULL == info->vaddr) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: no memory available"); + status = AR_ENOMEMORY; + goto end; + } + /*validate address for 64 byte alignment */ + if ((uint64_t)info->vaddr % SHMEM_4K_ALIGNMENT) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: 4k alignment check failed vaddr(0x%p)", info->vaddr); + free(info->vaddr); + info->vaddr = NULL; + status = AR_EUNEXPECTED; + goto end; + } + info->pa_lsw = info->ipa_lsw = (uint32_t)(uintptr_t)info->vaddr; + info->pa_msw = info->ipa_msw = (uint32_t)((uint64_t)((uintptr_t)(info->vaddr)) >> 32); + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG, + " SHMEM: " + "cache_type(0x%x)\nmemory_type(0x%x)\nindex_type(0x%x)\nbuf_size(0x%x)\nvaddr(0x%p)\nstatus(0x%x) ", + info->cache_type, + info->mem_type, + info->index_type, + info->buf_size, + info->vaddr, + status); +end: + return status; +} +/* + * Frees shared memory. + * + * \param[in] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_ap_free(_In_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + if (NULL == info || NULL == info->vaddr) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: handle(NULL) passed"); + status = AR_EBADPARAM; + goto end; + } + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id, info->sys_id)) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG, "SHMEM: freed(0x%p)", info->vaddr); + free(info->vaddr); + info->vaddr = NULL; +end: + return status; +} +/** + * \brief Helps map memory with SMMU an already allocated shared memory + * for a give sub system. + * Size should be multiple of 4KB boundary. + * Buffer start address should be 64bit aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_ap_map(ar_shmem_info *info) +{ + int32_t status = AR_EOK; + if (NULL == info || 0 == info->buf_size || (0 == info->pa_lsw && 0 == info->pa_msw)) + { + if (info) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, + "Error: buf_size(0)\npa_lsw:0x%x\npa_msw:0x%x passed", + info->pa_lsw, + info->pa_msw); + } + else + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: info(NULL)"); + } + status = AR_EBADPARAM; + goto end; + } + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id, info->sys_id)) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + info->ipa_lsw = info->pa_lsw; /*return pa to ipa*/ + info->ipa_msw = info->pa_msw; + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG, + "SHMEM: " + "cache_type(0x%x)\nmemory_type(0x%x)\nbuf_size(0x%x)\nipa_lsw(0x%x)\nipa_msw(0x%x)\nstatus(0x%x) ", + info->cache_type, + info->mem_type, + info->buf_size, + info->ipa_lsw, + info->ipa_msw, + status); +end: + return status; +} +/** + *\brief Helps unmap the shared memory allocated externally with SMMU + * + *\param[in] info: pointer to ar_shmem_info. + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_ap_unmap(ar_shmem_info *info) +{ + int32_t status = AR_EOK; + if (NULL == info || 0 == info->buf_size || (0 == info->pa_lsw && 0 == info->pa_msw)) + { + if (info) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, + "Error: info(NULL)\nbuf_size(0)\npa_lsw:0x%x\npa_msw:0x%x passed", + info->pa_lsw, + info->pa_msw); + } + else + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: info(NULL)"); + } + status = AR_EBADPARAM; + goto end; + } + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id, info->sys_id)) + { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + /*no handling required*/ +end: + return status; +} +/** + * Helps to hyp assign physical memory between source and destination sub systems. + * + * \param[in] info: info: pointer to ar_shmem_hyp_assign_phys_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_ap_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info) +{ + __UNREFERENCED_PARAM(info); + /*no op*/ + return AR_EOK; +} +/* + * \brief ar_shmem_deinit. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_ap_deinit(void) +{ + return AR_EOK; +} +/** + * \brief ar_shmem_get_uid. + * Get associated unique identifier(UID) for the shared memory + * pointed by alloc_handle, platform which doesn`t support UID + * should return alloc_handle as UID with expectation of + * alloc_handle being unique. + * + * \param[in] alloc_handle: handle for the shared memory. + * \param[out] uid: unique identifier to the shmem. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_ap_get_uid(uint64_t alloc_handle, uint64_t *uid) +{ + int32_t status = AR_EFAILED; + if (NULL != uid) + { + *uid = alloc_handle; + status = AR_EOK; + } + return status; +} diff --git a/ar_osal/src/linux/qcom/ar_osal_shmem_ap.h b/ar_osal/src/linux/qcom/ar_osal_shmem_ap.h new file mode 100644 index 0000000..da93757 --- /dev/null +++ b/ar_osal/src/linux/qcom/ar_osal_shmem_ap.h @@ -0,0 +1,27 @@ +/** + * + * \file ar_osal_shmem.h + * + * \brief + * Defines public APIs for shared memory allocation for ARM master processor. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include "ar_osal_shmem.h" // Public API +#include "ar_osal_error.h" // Error codes +#include "ar_osal_log.h" +#define AR_OSAL_SHMEM_LOG_TAG "COSH" + +// --- Backend-specific prototypes (defined in your existing sources) --- +// ap backend (ar_osal_shmem_ap.c) +int32_t ar_shmem_ap_init(void); +int32_t ar_shmem_ap_alloc(ar_shmem_info *info); +int32_t ar_shmem_ap_free(ar_shmem_info *info); +int32_t ar_shmem_ap_map(ar_shmem_info *info); +int32_t ar_shmem_ap_unmap(ar_shmem_info *info); +int32_t ar_shmem_ap_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info); +int32_t ar_shmem_ap_get_uid(uint64_t alloc_handle, uint64_t *uid); +int32_t ar_shmem_ap_deinit(void); diff --git a/ar_osal/src/linux/qcom/ar_osal_shmem_db.c b/ar_osal/src/linux/qcom/ar_osal_shmem_db.c new file mode 100644 index 0000000..ac6a99e --- /dev/null +++ b/ar_osal/src/linux/qcom/ar_osal_shmem_db.c @@ -0,0 +1,866 @@ +/** + * + * \file ar_osal_shmem.c + * + * \brief + * This file has implementation for DMA buffer based shared memory allocation for DSP. + + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#define AR_OSAL_SHMEM_LOG_TAG "COSH" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef MSM_AUDIO_CUSTOM_STACK +#include +#else +#include +#endif +#ifdef AR_OSAL_USE_CUTILS +#include +#endif +#include "ar_osal_shmem.h" +#include "ar_osal_shmem_dsp.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#ifdef AR_OSAL_USE_DYNAMIC_PD +#include "remote.h" +#endif +#include "ar_osal_sleep.h" +#define SHMEM_4K_ALIGNMENT 0x1000 +#ifndef ION_DRIVER_UNSUPPORTED +#define AR_MEM_DRIVER_PATH "/dev/msm_audio_ion" +#define AR_MEM_DRIVER_PATH_CMA "/dev/msm_audio_ion_cma" +#else +#define AR_MEM_DRIVER_PATH "/dev/msm_audio_mem" +#define AR_MEM_DRIVER_PATH_CMA "/dev/msm_audio_mem_cma" +#endif +#ifdef MDSP_PROC +#define DMABUF_SYS_HEAP_PATH "/dev/dma_heap/qcom,audio" +#else +#define DMABUF_SYS_HEAP_PATH "/dev/dma_heap/system" +#endif +#define DMABUF_SYS_HEAP_PATH_UNCACHED "/dev/dma_heap/qcom,system-uncached" +#define DMABUF_SYS_HEAP_PATH_CMA "/dev/dma_heap/qcom,audio-ml" +#define AR_FD_OPEN_RETRY_US (500*1000) +#define AR_FD_OPEN_NUM_RETRIES 4 + +#define AR_FD_OPEN_RETRY_US (500*1000) +#define AR_FD_OPEN_NUM_RETRIES 4 + +#ifdef AR_OSAL_USE_DYNAMIC_PD +static int32_t ar_dsp_domain_id[AR_SUB_SYS_ID_LAST + 1] = { + -1, MDSP_DOMAIN_ID, ADSP_DOMAIN_ID, -1, SDSP_DOMAIN_ID, CDSP_DOMAIN_ID, -1 +}; +#endif + +typedef struct ar_shmem_handle_data { + int32_t heap_fd; + bool dma_sync_flag; +} ar_shmem_handle_data_t; + +typedef struct ar_shmem_pdata { + int dmabuf_fd; + int dmabuf_fd_cma; + int armem_fd; + int armem_fd_cma; + bool dmabuf_cma_mem_enabled; +} ar_shmem_pdata_t; + +static ar_shmem_pdata_t *pdata = NULL; + +static pthread_mutex_t ar_shmem_lock = PTHREAD_MUTEX_INITIALIZER; + +/** + * \brief ar_shmem_validate_sys_id + * internal function to validate supported SYS IDs. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +static int32_t ar_shmem_validate_sys_id(uint8_t num_sys_id, ar_shmem_proc_info *sys_id) +{ + int32_t status = AR_EOK; + + if (0 == num_sys_id || NULL == sys_id) + return AR_EBADPARAM; + + for (uint8_t i = 0; i < num_sys_id; ++i) { + if (AR_AUDIO_DSP != sys_id[i].proc_id && + AR_MODEM_DSP != sys_id[i].proc_id && + AR_SENSOR_DSP != sys_id[i].proc_id && + AR_COMPUTE_DSP != sys_id[i].proc_id && + AR_APSS != sys_id[i].proc_id && + AR_APSS2 != sys_id[i].proc_id) { + status = AR_EBADPARAM; + break; + } + } + return status; +} + +#ifdef AR_OSAL_USE_DYNAMIC_PD +static int32_t ar_shmem_map_dynamic_pd(ar_shmem_info *info, bool_t map) +{ + int32_t i = 0, status = AR_EOK; + + if (NULL == info) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: invalid shmem param", __func__); + status = AR_EBADPARAM; + return status; + } + for (i = 0; i < info->num_sys_id; ++i) { + if (info->sys_id[i].proc_type == DYNAMIC_PD) { + + if (map) { + status = fastrpc_mmap(ar_dsp_domain_id[info->sys_id[i].proc_id], + info->ipa_lsw, info->vaddr, 0, + info->buf_size, FASTRPC_MAP_FD); + } else { + if (info->sys_id[i].is_active) + status = fastrpc_munmap(ar_dsp_domain_id[info->sys_id[i].proc_id], + info->ipa_lsw, info->vaddr, + info->buf_size); + else + AR_LOG_DEBUG(AR_OSAL_SHMEM_LOG_TAG,"%s: skip unmap as pd %d is down", + __func__, info->sys_id[i].proc_id); + } + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s:fastrpc_%s failed status %d", + __func__, map ? "mmap" : "munmap", status); + break; + } + } + } + + if (status && map) { + while (i-- > 0) { + if (info->sys_id[i].proc_type == DYNAMIC_PD) + fastrpc_munmap(ar_dsp_domain_id[info->sys_id[i].proc_id], + info->ipa_lsw, info->vaddr, info->buf_size); + } + } + + return status; +} +#else +static int32_t ar_shmem_map_dynamic_pd(ar_shmem_info *info, bool_t map) +{ + return AR_EOK; +} +#endif + +static int32_t ar_shmem_map_static_pd(ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle = NULL; + + if (NULL == info) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: invalid shmem param", __func__); + status = AR_EBADPARAM; + goto end; + } + if (0 == info->pa_lsw && 0 == info->pa_msw) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: pa_lsw:0x%x|pa_msw:0x%x passed", + info->pa_lsw, info->pa_msw); + status = AR_EBADPARAM; + goto end; + } + shmem_handle = (ar_shmem_handle_data_t *) + malloc(sizeof(ar_shmem_handle_data_t)); + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s:malloc for shmem handle failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + + info->ipa_lsw = 0; + info->ipa_msw = 0; + info->metadata = 0; + info->index_type = AR_SHMEM_BUFFER_OFFSET; + info->mem_type = AR_SHMEM_PHYSICAL_MEMORY; + + /* + *This api is called by clients when the clients already have allocated shared memory + *and now we just need to map it with DSP. On LX platforms what we recieve from clients + *is the ion fd, which is passed in the form of pa_lsw and pa_msw. Hence we extract the same + *and pass it on to the audio ion driver. + */ + shmem_handle->heap_fd = (((int64_t)info->pa_msw << 32) | info->pa_lsw); + + info->vaddr = mmap(0, info->buf_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shmem_handle->heap_fd, 0); + if (info->vaddr == MAP_FAILED) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: mmap failed \n", __func__); + status = AR_ENOMEMORY; + goto err2; + } + + if ((uint64_t)info->vaddr % SHMEM_4K_ALIGNMENT) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: 4k alignment check failed vaddr(0x%pK)", info->vaddr); + info->vaddr = NULL; + status = AR_EUNEXPECTED; + goto err2; + } + info->metadata = (uint64_t)shmem_handle; + info->ipa_lsw = info->pa_lsw; + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG," SHMEM: memory_type(0x%x)|index_type(0x%x)" + "buf_size(0x%x)|vaddr(0x%pK)| ipa_lsw(0x%x)| status(0x%x) ",info->mem_type, + info->index_type, info->buf_size, info->vaddr, info->ipa_lsw, status); + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) && pdata->dmabuf_cma_mem_enabled) { + if (pdata->armem_fd_cma) { + status = ioctl(pdata->armem_fd_cma, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else + status = ioctl(pdata->armem_fd, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:Physical address map failed status %d\n", __func__, status); + goto err2; + } + goto end; + +err2: + free(shmem_handle); +end: + return status; +} + +static int32_t ar_shmem_unmap_static_pd(ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle; + + if (NULL == info) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: invalid shmem param", __func__); + status = AR_EBADPARAM; + goto end; + } + shmem_handle = (ar_shmem_handle_data_t *)(intptr_t)info->metadata; + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: shmem_handle is NULL\n", + __func__); + status = AR_EBADPARAM; + goto end; + } + + munmap(info->vaddr, info->buf_size); + if (shmem_handle->heap_fd) { + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG) && pdata->dmabuf_cma_mem_enabled)) { + if (pdata->armem_fd_cma) { + status = ioctl(pdata->armem_fd_cma, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->heap_fd); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else + status = ioctl(pdata->armem_fd, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->heap_fd); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:unmap failed. status %d\n", __func__, status); + } + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG,"%s:shmem heap fd %d\n", __func__, shmem_handle->heap_fd); + close(shmem_handle->heap_fd); + } else { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s Invalid dmabuf_fd \n", __func__); + } + if (shmem_handle) + free(shmem_handle); + info->metadata = 0; + info->vaddr = NULL; +end: + return status; +} + +/* + *\brief ar_shmem_init + * initialize shared memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_dsp_init(void) +{ + int32_t status = AR_EOK; + bool use_uncached_heap = false; + + pthread_mutex_lock(&ar_shmem_lock); + if (NULL != pdata) { + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG,"%s: init already done\n", __func__); + goto end; + } + + pdata = (ar_shmem_pdata_t *) calloc(1, sizeof(ar_shmem_pdata_t)); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: calloc failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + +#ifdef AR_OSAL_USE_CUTILS + use_uncached_heap = property_get_bool("vendor.audio.gsl.shmem.dmaheap.uncached", false); +#endif + if (use_uncached_heap) { + AR_LOG_INFO ("%s: Using dmaheap path: qcom,system-uncached\n", __func__); + pdata->dmabuf_fd = open(DMABUF_SYS_HEAP_PATH_UNCACHED, O_RDONLY | O_CLOEXEC); + } else { + AR_LOG_INFO ("%s: Using dmaheap path: system\n", __func__); + pdata->dmabuf_fd = open(DMABUF_SYS_HEAP_PATH, O_RDONLY | O_CLOEXEC); + } + /*Check if dma_buf heap initialize the dmabuf_handle to invalid handle */ + if (pdata->dmabuf_fd < 0) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:dmabuf dev open failed errno:%d\n", __func__, pdata->dmabuf_fd); + status = AR_ENOTEXIST; + goto end; + } + + for (int j = 0; j < AR_FD_OPEN_NUM_RETRIES; ++j) { + pdata->armem_fd = open(AR_MEM_DRIVER_PATH, O_RDWR); + if (pdata->armem_fd < 0) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "armem fd open(%s) failed with errno:%d, retries %d\n", + AR_MEM_DRIVER_PATH, errno, j); + ar_osal_micro_sleep(AR_FD_OPEN_RETRY_US); + } + else { + break; + } + } + if (pdata->armem_fd < 0) { + status = AR_ENOTEXIST; + close(pdata->dmabuf_fd); + goto end; + } + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG,"%s armem fd open success %s\n", __func__, AR_MEM_DRIVER_PATH); + +#ifdef AR_OSAL_USE_CUTILS + pdata->dmabuf_cma_mem_enabled = + property_get_bool("vendor.audio.feature.dmabuf.cma.memory.enable", false); +#endif + if(pdata->dmabuf_cma_mem_enabled) { + /*Check if dma_buf heap initialize the dmabuf_handle to invalid handle */ + pdata->dmabuf_fd_cma = open(DMABUF_SYS_HEAP_PATH_CMA, O_RDONLY | O_CLOEXEC); + if (pdata->dmabuf_fd_cma <= 0) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:dmabuf fd cma dev open failed errno:%d\n", + __func__, pdata->dmabuf_fd_cma); + status = AR_ENOTEXIST; + close(pdata->armem_fd); + close(pdata->dmabuf_fd); + goto end; + } + + pdata->armem_fd_cma = open(AR_MEM_DRIVER_PATH_CMA, O_RDWR); + if (pdata->armem_fd_cma <= 0) { + status = AR_ENOTEXIST; + AR_LOG_ERR("%s armem fd cma open failed %s status %d\n", + __func__, AR_MEM_DRIVER_PATH_CMA, status); + close(pdata->armem_fd); + close(pdata->dmabuf_fd); + close(pdata->dmabuf_fd_cma); + goto end; + } + + } + + end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/* + * \brief Allocates shared memory. + * Only non cached memory allocation supported. + * Size if multiple of 4KB and the returned is aligned to 4KB boundary. + * Buffer start address should be atleast 64bit multiple aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_dsp_alloc(_Inout_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle = NULL; + struct dma_heap_allocation_data heap_data; + struct dma_buf_sync sync; + memset(&heap_data, 0, sizeof heap_data); + memset(&sync, 0, sizeof sync); + + pthread_mutex_lock(&ar_shmem_lock); + + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state", __func__); + status = AR_EUNSUPPORTED; + goto end; + } + + if (NULL == info || 0 == info->buf_size) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"Error: info(NULL)|buf_size(0) passed"); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + shmem_handle = (ar_shmem_handle_data_t *)calloc(1, sizeof(ar_shmem_handle_data_t)); + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:malloc for shmem handle failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + + info->ipa_lsw = 0; + info->ipa_msw = 0; + info->metadata = 0; + info->pa_lsw = 0; + info->pa_msw = 0; + info->index_type = AR_SHMEM_BUFFER_OFFSET; + info->mem_type = AR_SHMEM_PHYSICAL_MEMORY; + + heap_data.len = info->buf_size; + heap_data.fd_flags = O_RDWR; + + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) && pdata->dmabuf_cma_mem_enabled) { + status = ioctl(pdata->dmabuf_fd_cma, DMA_HEAP_IOCTL_ALLOC, &heap_data); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap alloc failed, errno: %d\n", + __func__, status); + status = AR_ENOMEMORY; + goto end; + } + } + else { + status = ioctl(pdata->dmabuf_fd, DMA_HEAP_IOCTL_ALLOC, &heap_data); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap alloc failed, errno: %d\n", + __func__, status); + status = AR_ENOMEMORY; + goto end; + } + } + + info->vaddr = mmap(0, info->buf_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + heap_data.fd, 0); + if (info->vaddr == MAP_FAILED) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: mmap failed \n", __func__); + status = AR_ENOMEMORY; + goto err1; + } + + if ((uint64_t)info->vaddr % SHMEM_4K_ALIGNMENT) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: 4k alignment check failed vaddr(0x%pK)", info->vaddr); + info->vaddr = NULL; + status = AR_EUNEXPECTED; + goto err2; + } + + sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW; + status = ioctl(heap_data.fd, DMA_BUF_IOCTL_SYNC, &sync); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap set access failed, errno: %d\n", + __func__, status); + status = AR_EUNEXPECTED; + goto err2; + } + + shmem_handle->heap_fd = heap_data.fd; + shmem_handle->dma_sync_flag = true; + info->metadata = (uint64_t)shmem_handle; + info->ipa_lsw = shmem_handle->heap_fd; + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG," SHMEM: cached|memory_type(0x%x)|index_type(0x%x) buf_size(0x%x)|vaddr(0x%pK)| ipa_lsw(0x%x)| status(0x%x) ", + info->mem_type, info->index_type, info->buf_size, info->vaddr, info->ipa_lsw, status); + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) && pdata->dmabuf_cma_mem_enabled) { + if (pdata->armem_fd_cma) { + status = ioctl(pdata->armem_fd_cma, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else + status = ioctl(pdata->armem_fd, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:Physical address map failed status %d\n", + __func__, status); + goto err2; + } + status = ar_shmem_map_dynamic_pd(info, true); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s:dynamic pd map failed status %d\n", + __func__, status); + goto err2; + } + goto end; + + err2: + munmap(info->vaddr, info->buf_size); + shmem_handle->dma_sync_flag = false; + + err1: + close(shmem_handle->heap_fd); + free(shmem_handle); + + end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/* + * Frees shared memory. + * + * \param[in] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_dsp_free(_In_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle = NULL; + struct dma_buf_sync sync; + + pthread_mutex_lock(&ar_shmem_lock); + + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in i state\n", __func__); + status = AR_EBADPARAM; + goto end; + } + + if (NULL == info || NULL == info->vaddr){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid info %pK\n", __func__, info); + status = AR_EBADPARAM; + goto end; + } + + if (0 == info->metadata || 0 == info->buf_size){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid params handle %pK buf_size %zu\n", + __func__, info->metadata, info->buf_size); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + status = ar_shmem_map_dynamic_pd(info, false); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s:dynamic pd unmap failed. status %d\n", __func__, status); + } + + shmem_handle = (ar_shmem_handle_data_t *)(intptr_t)info->metadata; + + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: shmem_handle is NULL\n", + __func__); + status = AR_EBADPARAM; + goto end; + } + if (shmem_handle && shmem_handle->dma_sync_flag) { + sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW; + status = ioctl(shmem_handle->heap_fd, DMA_BUF_IOCTL_SYNC, &sync); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap set access failed, errno: %d\n", + __func__, status); + } + shmem_handle->dma_sync_flag = false; + } + munmap(info->vaddr, info->buf_size); + if (shmem_handle->heap_fd) { + if (((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) && pdata->dmabuf_cma_mem_enabled) { + if (pdata->armem_fd_cma) { + status = ioctl(pdata->armem_fd_cma, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->heap_fd); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else { + status = ioctl(pdata->armem_fd, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->heap_fd); + } + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:unmap failed. status %d\n", __func__, status); + } + close(shmem_handle->heap_fd); + } else { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s Invalid dmabuf_fd \n", __func__); + } + if (shmem_handle) + free(shmem_handle); + info->metadata = 0; + info->vaddr = NULL; + end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/** + * \brief Helps map memory with SMMU an already allocated shared memory + * for a give sub system. + * Size should be multiple of 4KB boundary. + * Buffer start address should be 64bit aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * required output parameters in ar_shmem_info + * ar_shmem_info_t.ipa_lsw + * ar_shmem_info_t.ipa_msw + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_dsp_map(_Inout_ ar_shmem_info *info) +{ + int32_t status = AR_EOK, i = 0; + bool_t static_pd = false; + + pthread_mutex_lock(&ar_shmem_lock); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state", __func__); + status = AR_EUNSUPPORTED; + goto end; + } + + if (NULL == info || 0 == info->buf_size) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"Error: info(NULL)|buf_size(0) passed"); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + for (i = 0; i < info->num_sys_id; ++i) { + if (info->sys_id[i].proc_type == STATIC_PD) { + static_pd = true; + break; + } + } + if (static_pd) { + status = ar_shmem_map_static_pd(info); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "static pd map failed with error %d", status); + goto end; + } + } + status = ar_shmem_map_dynamic_pd(info, true); + if (status) { + ar_shmem_unmap_static_pd(info); + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "dynamic pd map failed with error %d", status); + } +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/** + *\brief Helps unmap the shared memory allocated externally with SMMU + * + *\param[in] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +int32_t ar_shmem_dsp_unmap(_In_ ar_shmem_info *info) +{ + int32_t status = AR_EOK, i = 0; + bool_t static_pd = false; + + pthread_mutex_lock(&ar_shmem_lock); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state\n", __func__); + status = AR_EBADPARAM; + goto end; + } + + if (NULL == info || NULL == info->vaddr){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid info %pK\n", __func__, info); + status = AR_EBADPARAM; + goto end; + } + + if (0 == info->metadata || 0 == info->buf_size){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid params handle %pK buf_size %zu\n", + __func__, info->metadata, info->buf_size); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + status = ar_shmem_map_dynamic_pd(info, false); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s: dynamic pd unmap failed", __func__); + } + for (i = 0; i < info->num_sys_id; ++i) { + if (info->sys_id[i].proc_type == STATIC_PD) { + static_pd = true; + break; + } + } + if (static_pd) { + status = ar_shmem_unmap_static_pd(info); + if (status) + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "%s: static pd unmap failed", __func__); + } +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/** + * Helps to hyp assign physical memory between source and destination sub systems. + * + * \param[in] info: info: pointer to ar_shmem_hyp_assign_phys_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_dsp_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info) +{ + int32_t status = AR_EOK; + uint32_t shm_addr_lsw = 0; + ar_shmem_handle_data_t *shmem_handle = NULL; + struct dma_buf_sync sync; + + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state\n", __func__); + status = AR_EBADPARAM; + goto end; + } + + if(!(pdata->dmabuf_cma_mem_enabled)) { + return AR_EOK; + } + for (int i = 0; i < info->phys_addr_list_size; i++) { + shm_addr_lsw = (info->phys_addr_list->phys_addr) & 0xFFFFFFFF; + for (int j = 0; j < info->src_sys_list_size; j++) { + if (info->src_sys_list[j] == AR_APSS) { + if (info->metadata) { + shmem_handle = (ar_shmem_handle_data_t *)(intptr_t)info->metadata; + if (shmem_handle && shmem_handle->dma_sync_flag) { + sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW; + status = ioctl(shmem_handle->heap_fd, DMA_BUF_IOCTL_SYNC, &sync); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: DMA heap set access failed, errno: %d\n", + __func__, status); + status = AR_EBADPARAM; + goto end; + } + shmem_handle->dma_sync_flag = false; + } + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG,"%s:IOCTL_MAP_HYP_ASSIGN\n", __func__); + status = ioctl(pdata->armem_fd_cma, IOCTL_MAP_HYP_ASSIGN, shm_addr_lsw); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:hyp_assign failed. status %d\n", + __func__, status); + } + } else { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid params handle \n", __func__); + status = AR_EBADPARAM; + goto end; + } + } else { + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG,"%s:IOCTL_UNMAP_HYP_ASSIGN\n", __func__); + status = ioctl(pdata->armem_fd_cma, IOCTL_UNMAP_HYP_ASSIGN, shm_addr_lsw); + + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:unmap_hyp_assign failed. status %d\n", + __func__, status); + } + } + } + info->phys_addr_list++; + } +end: + return status; +} + +/* + * \brief ar_shmem_deinit. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_shmem_dsp_deinit(void) +{ + + pthread_mutex_lock(&ar_shmem_lock); + + if (pdata == NULL) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s not in init state\n", __func__); + pthread_mutex_unlock(&ar_shmem_lock); + return AR_EOK; + } + + if (pdata->dmabuf_fd){ + close(pdata->dmabuf_fd); + } + + if (pdata->armem_fd){ + close(pdata->armem_fd); + } + + if (pdata->dmabuf_fd_cma){ + close(pdata->dmabuf_fd_cma); + } + + if (pdata->armem_fd_cma){ + close(pdata->armem_fd_cma); + } + + free(pdata); + pdata = NULL; + pthread_mutex_unlock(&ar_shmem_lock); + + return AR_EOK; +} diff --git a/ar_osal/src/linux/qcom/ar_osal_shmem_dsp.h b/ar_osal/src/linux/qcom/ar_osal_shmem_dsp.h new file mode 100644 index 0000000..b9a40f2 --- /dev/null +++ b/ar_osal/src/linux/qcom/ar_osal_shmem_dsp.h @@ -0,0 +1,25 @@ +/** + * + * \file ar_osal_shmem.c + * + * \brief + * Defines public APIs for shared memory allocation for DSP. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include "ar_osal_shmem.h" // Public API +#include "ar_osal_error.h" // Error codes +#include "ar_osal_log.h" +#define AR_OSAL_SHMEM_LOG_TAG "COSH" + +// DSP backend (ar_osal_shmem_dsp.c) +int32_t ar_shmem_dsp_init(void); +int32_t ar_shmem_dsp_alloc(ar_shmem_info *info); +int32_t ar_shmem_dsp_free(ar_shmem_info *info); +int32_t ar_shmem_dsp_map(ar_shmem_info *info); +int32_t ar_shmem_dsp_unmap(ar_shmem_info *info); +int32_t ar_shmem_dsp_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info); +int32_t ar_shmem_dsp_deinit(void); diff --git a/ar_osal/src/linux/qcom/ar_osal_shmem_ion.c b/ar_osal/src/linux/qcom/ar_osal_shmem_ion.c new file mode 100644 index 0000000..081ad3e --- /dev/null +++ b/ar_osal/src/linux/qcom/ar_osal_shmem_ion.c @@ -0,0 +1,692 @@ +/** + * + * \file ar_osal_shmem.c + * + * \brief + * This file has implementation for ION based shared memory allocation for DSP. + + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define AR_OSAL_SHMEM_LOG_TAG "COSH" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ar_osal_log.h" +#include + +#if TARGET_ION_ABI_VERSION >= 2 +#include +#endif + +#include "ar_osal_shmem.h" +#include "ar_osal_error.h" + +/* Memory pointer to be 4K aligned for ADSP, MDSP,SDSP and CDSP */ +#define SHMEM_4K_ALIGNMENT 0x1000 +#define ION_DRIVER_PATH "/dev/msm_audio_ion" +#define ION_DRIVER_PATH_CMA "/dev/msm_audio_ion_cma" + +/* Systems without SMMU use AUDIO_HEAP for ion allocations */ +#ifdef USE_AUDIO_HEAP_ID +#define HEAP_MASK ION_HEAP(ION_AUDIO_HEAP_ID) +#else +#define HEAP_MASK ION_HEAP(ION_SYSTEM_HEAP_ID) +#endif +#ifdef TARGET_USES_ION_CMA_MEMORY +#define HEAP_MASK_CMA ION_HEAP(ION_AUDIO_ML_HEAP_ID) +#endif + +typedef struct ar_shmem_handle_data { + /*ion fd created on ion memory allocation*/ + int64_t ion_mem_fd; +#ifndef TARGET_ION_ABI_VERSION + /* ion userspace handle used in legagcy ion implementation*/ + int32_t ion_user_handle; +#endif +} ar_shmem_handle_data_t; + +typedef struct ar_shmem_pdata { + int32_t ion_handle; + int ion_fd; + int ion_fd_cma; +} ar_shmem_pdata_t; + +static ar_shmem_pdata_t *pdata = NULL; + +static pthread_mutex_t ar_shmem_lock = PTHREAD_MUTEX_INITIALIZER; + +/** +* \brief ar_shmem_validate_sys_id +* internal function to validate supported SYS IDs. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +int32_t ar_shmem_validate_sys_id(uint8_t num_sys_id, ar_shmem_proc_info *sys_id) +{ + int32_t status = AR_EOK; + if (0 == num_sys_id || NULL == sys_id) + { + status = AR_EBADPARAM; + goto end; + } + + for (uint8_t i = 0; i < num_sys_id; i++) + { + if (AR_AUDIO_DSP != sys_id[i].proc_id && + AR_MODEM_DSP != sys_id[i].proc_id && + AR_SENSOR_DSP != sys_id[i].proc_id && + AR_COMPUTE_DSP != sys_id[i].proc_id && + AR_APSS != sys_id[i].proc_id && + AR_APSS2 != sys_id[i].proc_id) + { + status = AR_EBADPARAM; + break; + } + } + +end: + return status; +} + +/* + *\brief ar_shmem_init + * initialize shared memory interface. + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_init(void) +{ + int32_t status = AR_EOK; + pthread_mutex_lock(&ar_shmem_lock); + if (NULL != pdata) { + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG,"%s: init already done\n", __func__); + goto end; + } + + pdata = (ar_shmem_pdata_t *) malloc(sizeof(ar_shmem_pdata_t)); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: malloc failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + /*initialize the ion_handle to invalid handle */ + pdata->ion_handle = -1; +#if TARGET_ION_ABI_VERSION >= 2 + pdata->ion_handle = ion_open(); +#else + pdata->ion_handle = open("/dev/ion", O_RDONLY | O_DSYNC); +#endif + if (pdata->ion_handle < 0) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ion dev open failed errno:%d\n", __func__, pdata->ion_handle); + status = AR_ENOTEXIST; + free(pdata); + goto end; + } + pdata->ion_fd = open(ION_DRIVER_PATH, O_RDWR); + if (pdata->ion_fd < 0) { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s ion fd open failed %s status %d\n", __func__, ION_DRIVER_PATH, status); + goto end; + } + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG,"%s ion fd open success %s\n", __func__, ION_DRIVER_PATH); +#ifdef TARGET_USES_ION_CMA_MEMORY + pdata->ion_fd_cma = open(ION_DRIVER_PATH_CMA, O_RDWR); + if (pdata->ion_fd_cma < 0) { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s ion fd open failed %s status %d\n", + __func__, ION_DRIVER_PATH_CMA, status); + goto end; + } + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG,"%s ion fd open success %s\n", __func__, ION_DRIVER_PATH_CMA); +#else + pdata->ion_fd_cma = 0; + AR_LOG_INFO(AR_OSAL_SHMEM_LOG_TAG,"%s ion CMA memory not used in this platform", __func__); +#endif +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/* + * \brief Allocates shared memory. + * Only non cached memory allocation supported. + * Size if multiple of 4KB and the returned is aligned to 4KB boundary. + * Buffer start address should be atleast 64bit multiple aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + * + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_alloc(_Inout_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_cache_type_t ctype; + ar_shmem_handle_data_t *shmem_handle = NULL; + uint32_t heap_mask; +#ifndef TARGET_ION_ABI_VERSION + struct ion_fd_data fd_data; + struct ion_allocation_data alloc_data; +#endif + + pthread_mutex_lock(&ar_shmem_lock); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state", __func__); + status = AR_EUNSUPPORTED; + goto end; + } + + if (NULL == info || 0 == info->buf_size) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"Error: info(NULL)|buf_size(0) passed"); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + shmem_handle = (ar_shmem_handle_data_t *) + malloc(sizeof(ar_shmem_handle_data_t)); + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:malloc for shmem handle failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + + info->ipa_lsw = 0; + info->ipa_msw = 0; + info->metadata = 0; + info->pa_lsw = 0; + info->pa_msw = 0; + info->index_type = AR_SHMEM_BUFFER_OFFSET; + info->mem_type = AR_SHMEM_PHYSICAL_MEMORY; + + if (info->cache_type == AR_SHMEM_CACHED) { + ctype = 1; + } else { + ctype = 0; + } + +#ifdef TARGET_USES_ION_CMA_MEMORY + heap_mask = ((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) ? HEAP_MASK_CMA : HEAP_MASK; +#else + heap_mask = HEAP_MASK; +#endif + +#if TARGET_ION_ABI_VERSION >= 2 + status = ion_alloc_fd(pdata->ion_handle, info->buf_size, + SHMEM_4K_ALIGNMENT, heap_mask, + ctype, &shmem_handle->ion_mem_fd); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: ION alloc failed errno: %d\n", + __func__, status); + shmem_handle->ion_mem_fd = -1; + status = AR_ENOMEMORY; + goto end; + } +#else + alloc_data.len = info->buf_size; + alloc_data.align = SHMEM_4K_ALIGNMENT; + alloc_data.heap_id_mask = heap_mask; + alloc_data.flags = ctype; + /* Initialize handle to 0 */ + alloc_data.handle = 0; + status = ioctl(pdata->ion_handle, ION_IOC_ALLOC, &alloc_data); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: ION alloc failed, errno: %d\n", + __func__, status); + status = AR_ENOMEMORY; + goto end; + } + fd_data.handle = alloc_data.handle; + shmem_handle->ion_user_handle = (uint32_t)alloc_data.handle; + status = ioctl(pdata->ion_handle, ION_IOC_SHARE, &fd_data); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: ION_IOC_SHARE, errno: %d\n", + __func__, status); + status = AR_ENOMEMORY; + goto err1; + } + shmem_handle->ion_mem_fd = fd_data.fd; +#endif + info->vaddr = mmap(0, info->buf_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shmem_handle->ion_mem_fd, 0); + if (info->vaddr == MAP_FAILED) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: mmap failed \n", __func__); + status = AR_ENOMEMORY; + goto err2; + } + + if ((uint64_t)info->vaddr % SHMEM_4K_ALIGNMENT) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: 4k alignment check failed vaddr(0x%pK)", info->vaddr); + info->vaddr = NULL; + status = AR_EUNEXPECTED; + goto err2; + } + info->metadata = (uint64_t)shmem_handle; + info->ipa_lsw = shmem_handle->ion_mem_fd; + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG," SHMEM: cache_type(0x%x)|memory_type(0x%x)|index_type(0x%x) buf_size(0x%x)|vaddr(0x%pK)| ipa_lsw(0x%x)| status(0x%x) ", + ctype, info->mem_type, info->index_type, info->buf_size, info->vaddr, info->ipa_lsw, status); + + if ((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) { + if (pdata->ion_fd_cma) { + status = ioctl(pdata->ion_fd_cma, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else { + status = ioctl(pdata->ion_fd, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + } + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:Physical address map failed status %d\n", __func__, status); + goto err2; + } + goto end; + +err2: + close(shmem_handle->ion_mem_fd); +#ifndef TARGET_ION_ABI_VERSION +err1: + status = ioctl(pdata->ion_handle, ION_IOC_FREE, + &shmem_handle->ion_user_handle); + if (status < 0) + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: ION Free failed %d\n", __func__, status); +#endif + free(shmem_handle); +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/* + * Frees shared memory. + * + * \param[in] info: pointer to ar_shmem_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_free(_In_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle; + pthread_mutex_lock(&ar_shmem_lock); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state\n", __func__); + status = AR_EBADPARAM; + goto end; + } + + if (NULL == info || NULL == info->vaddr){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid info %pK\n", __func__, info); + status = AR_EBADPARAM; + goto end; + } + + if (0 == info->metadata || 0 == info->buf_size){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid params handle %pK buf_size %zu\n", + __func__, info->metadata, info->buf_size); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + shmem_handle = (ar_shmem_handle_data_t *)(intptr_t)info->metadata; + munmap(info->vaddr, info->buf_size); + if ((info->flags) & (1 << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) { + if (pdata->ion_fd_cma) { + status = ioctl(pdata->ion_fd_cma, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->ion_mem_fd); + } else { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } else { + status = ioctl(pdata->ion_fd, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->ion_mem_fd); + } + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:unmap failed. status %d\n", __func__, status); + } + if (shmem_handle->ion_mem_fd) { + close(shmem_handle->ion_mem_fd); + } else { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s Invalid ion_mem_fd \n", __func__); + } +#ifndef TARGET_ION_ABI_VERSION + status = ioctl(pdata->ion_handle, ION_IOC_FREE, + &shmem_handle->ion_user_handle); + if (status < 0) + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: ION Free failed %d\n", __func__, status); +#endif + free(shmem_handle); + info->metadata = 0; + info->vaddr = NULL; +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/** + * \brief Helps map memory with SMMU an already allocated shared memory + * for a give sub system. + * Size should be multiple of 4KB boundary. + * Buffer start address should be 64bit aligned. + * + * \param[in_out] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * required output parameters in ar_shmem_info + * ar_shmem_info_t.ipa_lsw + * ar_shmem_info_t.ipa_msw + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_map(_Inout_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle = NULL; + + pthread_mutex_lock(&ar_shmem_lock); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state", __func__); + status = AR_EUNSUPPORTED; + goto end; + } + + if (NULL == info || 0 == info->buf_size) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"Error: info(NULL)|buf_size(0) passed"); + status = AR_EBADPARAM; + goto end; + } + + if (0 == info->pa_lsw && 0 == info->pa_msw) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"Error: pa_lsw:0x%x|pa_msw:0x%x passed", + info->pa_lsw, info->pa_msw); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + shmem_handle = (ar_shmem_handle_data_t *) + malloc(sizeof(ar_shmem_handle_data_t)); + if (NULL == shmem_handle) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:malloc for shmem handle failed\n", __func__); + status = AR_ENOMEMORY; + goto end; + } + + info->ipa_lsw = 0; + info->ipa_msw = 0; + info->metadata = 0; + info->index_type = AR_SHMEM_BUFFER_OFFSET; + info->mem_type = AR_SHMEM_PHYSICAL_MEMORY; + + /* + *This api is called by clients when the clients already have allocated shared memory + *and now we just need to map it with DSP. On LX platforms what we recieve from clients + *is the ion fd, which is passed in the form of pa_lsw and pa_msw. Hence we extract the same + *and pass it on to the audio ion driver. + */ + shmem_handle->ion_mem_fd = (((int64_t)info->pa_msw << 32) | info->pa_lsw); + + info->vaddr = mmap(0, info->buf_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shmem_handle->ion_mem_fd, 0); + if (info->vaddr == MAP_FAILED) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s: mmap failed \n", __func__); + status = AR_ENOMEMORY; + goto err2; + } + + if ((uint64_t)info->vaddr % SHMEM_4K_ALIGNMENT) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: 4k alignment check failed vaddr(0x%pK)", info->vaddr); + info->vaddr = NULL; + status = AR_EUNEXPECTED; + goto err2; + } + info->metadata = (uint64_t)shmem_handle; + info->ipa_lsw = info->pa_lsw; + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG," SHMEM: memory_type(0x%x)|index_type(0x%x)" + "buf_size(0x%x)|vaddr(0x%pK)| ipa_lsw(0x%x)| status(0x%x) ",info->mem_type, + info->index_type, info->buf_size, info->vaddr, info->ipa_lsw, status); + status = ioctl(pdata->ion_fd, IOCTL_MAP_PHYS_ADDR, info->ipa_lsw); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:Physical address map failed status %d\n", __func__, status); + goto err2; + } + goto end; + +err2: + free(shmem_handle); +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/** + *\brief Helps unmap the shared memory allocated externally with SMMU + * + *\param[in] info: pointer to ar_shmem_info. + * required input parameters in ar_shmem_info + * ar_shmem_info_t.cache_type + * ar_shmem_info_t.buf_size + * ar_shmem_info_t.pa_lsw + * ar_shmem_info_t.pa_msw + * ar_shmem_info_t.num_sys_id + * ar_shmem_info_t.sys_id + * + *\return + * 0 -- Success + * Nonzero -- Failure + * + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_unmap(_In_ ar_shmem_info *info) +{ + int32_t status = AR_EOK; + ar_shmem_handle_data_t *shmem_handle; + pthread_mutex_lock(&ar_shmem_lock); + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state\n", __func__); + status = AR_EBADPARAM; + goto end; + } + + if (NULL == info || NULL == info->vaddr){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid info %pK\n", __func__, info); + status = AR_EBADPARAM; + goto end; + } + + if (0 == info->metadata || 0 == info->buf_size){ + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:invalid params handle %pK buf_size %zu\n", + __func__, info->metadata, info->buf_size); + status = AR_EBADPARAM; + goto end; + } + + if (AR_EOK != ar_shmem_validate_sys_id(info->num_sys_id,info->sys_id)) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG, "Error: invalid sys_id(%d) passed", info->sys_id); + status = AR_EBADPARAM; + goto end; + } + + shmem_handle = (ar_shmem_handle_data_t *)(intptr_t)info->metadata; + munmap(info->vaddr, info->buf_size); + status = ioctl(pdata->ion_fd, IOCTL_UNMAP_PHYS_ADDR, shmem_handle->ion_mem_fd); + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:unmap failed. status %d\n", __func__, status); + } + AR_LOG_VERBOSE(AR_OSAL_SHMEM_LOG_TAG,"%s:shmem heap fd %d\n", __func__, shmem_handle->ion_mem_fd); + close(shmem_handle->ion_mem_fd); + free(shmem_handle); + info->metadata = 0; + info->vaddr = NULL; +end: + pthread_mutex_unlock(&ar_shmem_lock); + return status; +} + +/* + * Helps to hyp assign physical memory between source and destination sub systems. + * + * \param[in] info: info: pointer to ar_shmem_hyp_assign_phys_info. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_hyp_assign_phys(ar_shmem_hyp_assign_phys_info *info) +{ + int32_t status = AR_EOK; + uint32_t shm_addr_lsw = 0; + if (NULL == pdata) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:not in init state\n", __func__); + status = AR_EBADPARAM; + goto end; + } + for (int i = 0; i < info->phys_addr_list_size; i++) { + shm_addr_lsw = (info->phys_addr_list->phys_addr) & 0xFFFFFFFF; + for (int j = 0; j < info->src_sys_list_size; j++) { +#ifdef TARGET_USES_ION_CMA_MEMORY + if (pdata->ion_fd_cma) { + if (info->src_sys_list[j] == AR_APSS) { + status = ioctl(pdata->ion_fd_cma, IOCTL_MAP_HYP_ASSIGN, shm_addr_lsw); + } else { + status = ioctl(pdata->ion_fd_cma, IOCTL_UNMAP_HYP_ASSIGN, shm_addr_lsw); + } + if (status) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:hyp_assign failed. status %d\n", + __func__, status); + } + } + else +#endif + { + status = AR_ENOTEXIST; + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:ION CMA memory does not exist %d\n", + __func__, status); + } + } + info->phys_addr_list++; + } +end: + return status; +} + +/** +* \brief ar_shmem_get_uid. +* Get associated unique identifier(UID) for the shared memory +* pointed by alloc_handle, platform which doesn`t support UID +* should return alloc_handle as UID with expectation of +* alloc_handle being unique. +* +* \param[in] alloc_handle: handle for the shared memory. +* \param[out] uid: unique identifier to the shmem. +* \return +* 0 -- Success +* Nonzero -- Failure +*/ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_get_uid(uint64_t alloc_handle, uint64_t *uid) +{ + int32_t status = AR_EOK; + struct stat file_stat; + + if (NULL == uid) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:%d Invalid parameter passed \n", + __func__, __LINE__); + status = AR_EBADPARAM; + goto end; + } + /*Note that on LX platform alloc_handle should always be a file descriptor*/ + status = fstat(alloc_handle, &file_stat); + if (status == -1) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s:%d fstat api failed %d\n", + __func__, __LINE__, errno); + status = AR_EFAILED; + goto end; + } + *uid = file_stat.st_ino; + +end: + return status; +} + + +/* + * \brief ar_shmem_deinit. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_shmem_deinit(void) +{ + pthread_mutex_lock(&ar_shmem_lock); + if (pdata == NULL) { + AR_LOG_ERR(AR_OSAL_SHMEM_LOG_TAG,"%s not in init state\n", __func__); + return AR_EOK; + } + if (pdata->ion_handle){ +#if TARGET_ION_ABI_VERSION >= 2 + ion_close(pdata->ion_handle); +#else + close(pdata->ion_handle); +#endif + } + if (pdata->ion_fd) + close(pdata->ion_fd); + if (pdata->ion_fd_cma) + close(pdata->ion_fd_cma); + free(pdata); + pdata = NULL; + pthread_mutex_unlock(&ar_shmem_lock); + return AR_EOK; +} diff --git a/ar_osal/src/linux/qcom/dyn_pd/ar_osal_dyn_pd.c b/ar_osal/src/linux/qcom/dyn_pd/ar_osal_dyn_pd.c new file mode 100644 index 0000000..6f1b980 --- /dev/null +++ b/ar_osal/src/linux/qcom/dyn_pd/ar_osal_dyn_pd.c @@ -0,0 +1,230 @@ +/** + * \file ar_osal_dyn_pd.c + * + * \brief + * This file has implementation of pd init for proc domains. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define AR_DYN_PD "ar_dyn_pd" +#include "ar_osal_error.h" +#include "ar_osal_types.h" + +#ifdef AR_OSAL_USE_DYNAMIC_PD + +#include +#include "AEEStdErr.h" +#include "cdsp_dyn_pd.h" +#include "remote.h" +#include "ar_osal_dyn_pd.h" +#include "ar_osal_sys_id.h" +#include "ar_osal_log.h" + +#define STATUS_CONTEXT 0x12345678 + +/** Maximum length of URI for remote_handle_open() calls */ +#define MAX_DOMAIN_URI_SIZE 12 + +#pragma weak remote_session_control +#pragma weak remote_handle_control + +struct fastrpc_domain { + char_t *pd_URI_domain; + remote_handle64 pd_handle; +} domain_data[AR_SUB_SYS_ID_LAST + 1]; + +/** Domain type for multi-domain RPC calls */ +typedef struct domain_t { + /** Domain ID */ + int32_t id; + /** URI for remote_handle_open */ + char_t uri[MAX_DOMAIN_URI_SIZE]; +} domain; + +static int32_t dsp_domain_id[AR_SUB_SYS_ID_LAST + 1] = { + -1, MDSP_DOMAIN_ID, ADSP_DOMAIN_ID, -1, SDSP_DOMAIN_ID, CDSP_DOMAIN_ID, -1 +}; + +static pthread_mutex_t ar_pd_lock = PTHREAD_MUTEX_INITIALIZER; + +domain supported_domains[] = { + {ADSP_DOMAIN_ID, ADSP_DOMAIN}, + {MDSP_DOMAIN_ID, MDSP_DOMAIN}, + {SDSP_DOMAIN_ID, SDSP_DOMAIN}, + {CDSP_DOMAIN_ID, CDSP_DOMAIN} +}; + +static int32_t ar_map_error_code(int32_t nErr) +{ + int32_t ar_err = AR_EOK; + switch (nErr) { + case AEE_SUCCESS: + ar_err = AR_EOK; + break; + case AEE_EFAILED: + ar_err = AR_EFAILED; + break; + case AEE_EBADPARM: + ar_err = AR_EBADPARAM; + break; + case AEE_EUNSUPPORTED: + ar_err = AR_EUNSUPPORTED; + break; + case AEE_EUNSUPPORTEDAPI: + ar_err = AR_EUNSUPPORTED; + break; + case AEE_EVERSIONNOTSUPPORT: + ar_err = AR_EVERSION; + break; + case AEE_ERESOURCENOTFOUND: + ar_err = AR_EVERSION; + break; + case AEE_EINVHANDLE: + ar_err = AR_EHANDLE; + break; + case AEE_EALREADYLOADED: + ar_err = AR_EHANDLE; + break; + case AEE_EACKPENDING: + ar_err = AR_EPENDING; + break; + case AEE_EBUSY: + ar_err = AR_EBUSY; + break; + case AEE_ENEEDMORE: + ar_err = AR_ENEEDMORE; + break; + case AEE_ENOMEMORY: + ar_err = AR_ENEEDMORE; + break; + case AEE_ENOSUCH: + ar_err = AR_ENOTEXIST; + break; + default: + ar_err = AR_EFAILED; + break; + } + return ar_err; +} + +static domain *get_domain(int domain_id) +{ + uint32_t i = 0; + uint32_t size = sizeof(supported_domains)/sizeof(domain); + + for (i = 0; i < size; ++i) { + if (supported_domains[i].id == domain_id) + return &supported_domains[i]; + } + return NULL; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_dyn_pd_init(_In_ uint32_t proc_id) +{ + int32_t nErr = AEE_SUCCESS; + uint32_t pd_URI_domain_len = strlen(audio_pd_cdsp_URI) + MAX_DOMAIN_URI_SIZE; + domain *my_domain = NULL; + int32_t domain_id = -1; + + pthread_mutex_lock(&ar_pd_lock); + domain_data[proc_id].pd_handle = -1; + domain_data[proc_id].pd_URI_domain = NULL; + domain_id = dsp_domain_id[proc_id]; + + my_domain = get_domain(domain_id); + if (my_domain == NULL) { + nErr = AEE_EBADPARM; + AR_LOG_ERR(AR_DYN_PD, "unable to get domain struct %d error 0x%x", domain_id, nErr); + goto exit; + } + + if (remote_session_control) { + struct remote_rpc_control_unsigned_module data; + data.domain = domain_id; + data.enable = 1; + if (AEE_SUCCESS != (nErr = remote_session_control(DSPRPC_CONTROL_UNSIGNED_MODULE, + (void*)&data, sizeof(data)))) { + AR_LOG_ERR(AR_DYN_PD, "remote_session_control failed error 0x%x", nErr); + goto exit; + } + } else { + nErr = AEE_EUNSUPPORTED; + AR_LOG_ERR(AR_DYN_PD, "remote_session_control interface is not supported on this device error 0x%x", nErr); + goto exit; + } + + if ((domain_data[proc_id].pd_URI_domain = (char *)malloc(pd_URI_domain_len)) == NULL) { + nErr = AEE_ENOMEMORY; + AR_LOG_ERR(AR_DYN_PD, "unable to allocate memory for pd_URI_domain of size: %d", + pd_URI_domain_len); + goto exit; + } + + nErr = snprintf(domain_data[proc_id].pd_URI_domain, pd_URI_domain_len, "%s%s", + audio_pd_cdsp_URI, my_domain->uri); + if (nErr < 0) { + AR_LOG_ERR(AR_DYN_PD, "populating pd URI domain failed. error 0x%x", nErr); + nErr = AEE_EFAILED; + goto exit; + } + + if (AEE_SUCCESS == (nErr = audio_pd_cdsp_open(domain_data[proc_id].pd_URI_domain, + &domain_data[proc_id].pd_handle))) { + if (AEE_SUCCESS == (nErr = audio_pd_cdsp_init(domain_data[proc_id].pd_handle))) { + AR_LOG_INFO(AR_DYN_PD, "audio_pd_cdsp init done"); + } + } + + if (nErr) { + AR_LOG_ERR(AR_DYN_PD, "Failed to initialize cdsp audio pd on domain %d error 0x%x", + domain_id, nErr); + goto exit; + } + pthread_mutex_unlock(&ar_pd_lock); + return ar_map_error_code(nErr); + +exit: + if (domain_data[proc_id].pd_URI_domain) { + free(domain_data[proc_id].pd_URI_domain); + } + pthread_mutex_unlock(&ar_pd_lock); + return ar_map_error_code(nErr); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +int32_t ar_osal_dyn_pd_deinit(_In_ uint32_t proc_id) +{ + int32_t nErr = AEE_SUCCESS; + + pthread_mutex_lock(&ar_pd_lock); + if (domain_data[proc_id].pd_handle != -1) { + if (AEE_SUCCESS == (nErr = audio_pd_cdsp_deinit(domain_data[proc_id].pd_handle))) { + AR_LOG_INFO(AR_DYN_PD, "audio_pd_cdsp deinit done"); + } + if (AEE_SUCCESS != (nErr = audio_pd_cdsp_close(domain_data[proc_id].pd_handle))) { + AR_LOG_ERR(AR_DYN_PD, "Failed to close handle error 0x%x", nErr); + } + domain_data[proc_id].pd_handle = -1; + } + + if (domain_data[proc_id].pd_URI_domain) { + free(domain_data[proc_id].pd_URI_domain); + domain_data[proc_id].pd_URI_domain = NULL; + } + pthread_mutex_unlock(&ar_pd_lock); + return ar_map_error_code(nErr); +} +#else +int32_t ar_osal_dyn_pd_init(uint32_t proc_id) +{ + return AR_ENOTIMPL; +} +int32_t ar_osal_dyn_pd_deinit(uint32_t proc_id) +{ + return AR_ENOTIMPL; +} +#endif diff --git a/ar_osal/src/linux/qcom/dyn_pd/cdsp_dyn_pd.h b/ar_osal/src/linux/qcom/dyn_pd/cdsp_dyn_pd.h new file mode 100644 index 0000000..c37cc69 --- /dev/null +++ b/ar_osal/src/linux/qcom/dyn_pd/cdsp_dyn_pd.h @@ -0,0 +1,271 @@ +#ifndef _CDSP_DYN_PD_H +#define _CDSP_DYN_PD_H +/** + *  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + *  SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include + + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE +#ifndef _QAIC_ENV_H +#define _QAIC_ENV_H + +#include +#ifdef _WIN32 +#include "qtest_stdlib.h" +#else +#define MALLOC malloc +#define FREE free +#endif + +#ifdef __GNUC__ +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#else +#pragma GCC diagnostic ignored "-Wpragmas" +#endif +#pragma GCC diagnostic ignored "-Wuninitialized" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef _ATTRIBUTE_UNUSED + +#ifdef _WIN32 +#define _ATTRIBUTE_UNUSED +#else +#define _ATTRIBUTE_UNUSED __attribute__ ((unused)) +#endif + +#endif // _ATTRIBUTE_UNUSED + +#ifndef _ATTRIBUTE_VISIBILITY + +#ifdef _WIN32 +#define _ATTRIBUTE_VISIBILITY +#else +#define _ATTRIBUTE_VISIBILITY __attribute__ ((visibility("default"))) +#endif + +#endif // _ATTRIBUTE_VISIBILITY + +#ifndef __QAIC_REMOTE +#define __QAIC_REMOTE(ff) ff +#endif //__QAIC_REMOTE + +#ifndef __QAIC_HEADER +#define __QAIC_HEADER(ff) ff +#endif //__QAIC_HEADER + +#ifndef __QAIC_HEADER_EXPORT +#define __QAIC_HEADER_EXPORT +#endif // __QAIC_HEADER_EXPORT + +#ifndef __QAIC_HEADER_ATTRIBUTE +#define __QAIC_HEADER_ATTRIBUTE +#endif // __QAIC_HEADER_ATTRIBUTE + +#ifndef __QAIC_IMPL +#define __QAIC_IMPL(ff) ff +#endif //__QAIC_IMPL + +#ifndef __QAIC_IMPL_EXPORT +#define __QAIC_IMPL_EXPORT +#endif // __QAIC_IMPL_EXPORT + +#ifndef __QAIC_IMPL_ATTRIBUTE +#define __QAIC_IMPL_ATTRIBUTE +#endif // __QAIC_IMPL_ATTRIBUTE + +#ifndef __QAIC_STUB +#define __QAIC_STUB(ff) ff +#endif //__QAIC_STUB + +#ifndef __QAIC_STUB_EXPORT +#define __QAIC_STUB_EXPORT +#endif // __QAIC_STUB_EXPORT + +#ifndef __QAIC_STUB_ATTRIBUTE +#define __QAIC_STUB_ATTRIBUTE +#endif // __QAIC_STUB_ATTRIBUTE + +#ifndef __QAIC_SKEL +#define __QAIC_SKEL(ff) ff +#endif //__QAIC_SKEL__ + +#ifndef __QAIC_SKEL_EXPORT +#define __QAIC_SKEL_EXPORT +#endif // __QAIC_SKEL_EXPORT + +#ifndef __QAIC_SKEL_ATTRIBUTE +#define __QAIC_SKEL_ATTRIBUTE +#endif // __QAIC_SKEL_ATTRIBUTE + +#ifdef __QAIC_DEBUG__ + #ifndef __QAIC_DBG_PRINTF__ + #include + #define __QAIC_DBG_PRINTF__( ee ) do { printf ee ; } while(0) + #endif +#else + #define __QAIC_DBG_PRINTF__( ee ) (void)0 +#endif + + +#define _OFFSET(src, sof) ((void*)(((char*)(src)) + (sof))) + +#define _COPY(dst, dof, src, sof, sz) \ + do {\ + struct __copy { \ + char ar[sz]; \ + };\ + *(struct __copy*)_OFFSET(dst, dof) = *(struct __copy*)_OFFSET(src, sof);\ + } while (0) + +#define _COPYIF(dst, dof, src, sof, sz) \ + do {\ + if(_OFFSET(dst, dof) != _OFFSET(src, sof)) {\ + _COPY(dst, dof, src, sof, sz); \ + } \ + } while (0) + +_ATTRIBUTE_UNUSED +static __inline void _qaic_memmove(void* dst, void* src, int size) { + int i = 0; + for(i = 0; i < size; ++i) { + ((char*)dst)[i] = ((char*)src)[i]; + } +} + +#define _MEMMOVEIF(dst, src, sz) \ + do {\ + if(dst != src) {\ + _qaic_memmove(dst, src, sz);\ + } \ + } while (0) + + +#define _ASSIGN(dst, src, sof) \ + do {\ + dst = OFFSET(src, sof); \ + } while (0) + +#define _STD_STRLEN_IF(str) (str == 0 ? 0 : strlen(str)) + +#include "AEEStdErr.h" + +#ifdef _WIN32 +#define _QAIC_FARF(level, msg, ...) (void)0 +#else +#define _QAIC_FARF(level, msg, ...) \ + do {\ + if(0 == (HAP_debug_v2) ) {\ + (void)0; \ + } else { \ + FARF(level, msg , ##__VA_ARGS__); \ + } \ + }while(0) +#endif //_WIN32 for _QAIC_FARF + +#define _TRY(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + __QAIC_DBG_PRINTF__((__FILE__ ":%d:error:%d:%s\n", __LINE__, (int)(ee),#func));\ + goto ee##bail;\ + } \ + } while (0) + +#define _TRY_FARF(ee, func) \ + do { \ + if (AEE_SUCCESS != ((ee) = func)) {\ + goto ee##farf##bail;\ + } \ + } while (0) + +#define _CATCH(exception) exception##bail: if (exception != AEE_SUCCESS) + +#define _CATCH_FARF(exception) exception##farf##bail: if (exception != AEE_SUCCESS) + +#define _ASSERT(nErr, ff) _TRY(nErr, 0 == (ff) ? AEE_EBADPARM : AEE_SUCCESS) + +#ifdef __QAIC_DEBUG__ +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, __FILE_LINE__, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#else +#define _ALLOCATE(nErr, pal, size, alignment, pv) _TRY(nErr, _allocator_alloc(pal, 0, size, alignment, (void**)&pv));\ + _ASSERT(nErr,pv || !(size)) +#endif + + +#endif // _QAIC_ENV_H + +#ifdef __cplusplus +extern "C" { +#endif +/** +* functions remoted from the avs during init to the dsp +*/ +/** + * Opens the handle in the specified domain. If this is the first + * handle, this creates the session. Typically this means opening + * the device, aka open("/dev/adsprpc-smd"), then calling ioctl + * device APIs to create a PD on the DSP to execute our code in, + * then asking that PD to dlopen the .so and dlsym the skel function. + * + * @param uri, _URI"&_dom=aDSP" + * _URI is a QAIC generated uri, or + * "file:///?_skel_handle_invoke&_modver=1.0" + * If the _dom parameter is not present, _dom=DEFAULT is assumed + * but not forwarded. + * Reserved uri keys: + * [0]: first unamed argument is the skel invoke function + * _dom: execution domain name, _dom=mDSP/aDSP/DEFAULT + * _modver: module version, _modver=1.0 + * _*: any other key name starting with an _ is reserved + * Unknown uri keys/values are forwarded as is. + * @param h, resulting handle + * @retval, 0 on success + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(audio_pd_cdsp_open)(const char* uri, remote_handle64* h) __QAIC_HEADER_ATTRIBUTE; +/** + * Closes a handle. If this is the last handle to close, the session + * is closed as well, releasing all the allocated resources. + + * @param h, the handle to close + * @retval, 0 on success, should always succeed + */ +__QAIC_HEADER_EXPORT int __QAIC_HEADER(audio_pd_cdsp_close)(remote_handle64 h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(audio_pd_cdsp_init)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT int __QAIC_HEADER(audio_pd_cdsp_deinit)(remote_handle64 _h) __QAIC_HEADER_ATTRIBUTE; +#ifndef audio_pd_cdsp_URI +#define audio_pd_cdsp_URI "file:///libaudio_pd_cdsp_skel.so?audio_pd_cdsp_skel_handle_invoke&_modver=1.0" +#endif /*audio_pd_cdsp_URI*/ +#ifdef __cplusplus +} +#endif +#endif //_CDSP_DYN_PD_H diff --git a/ar_osal/src/linux/qcom/dyn_pd/cdsp_dyn_pd_stub.c b/ar_osal/src/linux/qcom/dyn_pd/cdsp_dyn_pd_stub.c new file mode 100644 index 0000000..eaefa5b --- /dev/null +++ b/ar_osal/src/linux/qcom/dyn_pd/cdsp_dyn_pd_stub.c @@ -0,0 +1,319 @@ +#ifndef _CDSP_DYN_PD_STUB_H +#define _CDSP_DYN_PD_STUB_H +/** + *  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + *  SPDX-License-Identifier: BSD-3-Clause + */ +#include "cdsp_dyn_pd.h" +#include +#ifndef _WIN32 +#include "HAP_farf.h" +#include +#endif //_WIN32 for HAP_farf +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include +#include + +typedef struct _heap _heap; +struct _heap { + _heap* pPrev; + const char* loc; + uint64_t buf; +}; + +typedef struct _allocator { + _heap* pheap; + uint8_t* stack; + uint8_t* stackEnd; + int nSize; +} _allocator; + +_ATTRIBUTE_UNUSED +static __inline int _heap_alloc(_heap** ppa, const char* loc, int size, void** ppbuf) { + _heap* pn = 0; + pn = MALLOC((size_t)size + sizeof(_heap) - sizeof(uint64_t)); + if(pn != 0) { + pn->pPrev = *ppa; + pn->loc = loc; + *ppa = pn; + *ppbuf = (void*)&(pn->buf); + return 0; + } else { + return -1; + } +} +#define _ALIGN_SIZE(x, y) (((x) + (y-1)) & ~(y-1)) + +_ATTRIBUTE_UNUSED +static __inline int _allocator_alloc(_allocator* me, + const char* loc, + int size, + unsigned int al, + void** ppbuf) { + if(size < 0) { + return -1; + } else if (size == 0) { + *ppbuf = 0; + return 0; + } + if((_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + (size_t)size) < (uintptr_t)me->stack + (size_t)me->nSize) { + *ppbuf = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al); + me->stackEnd = (uint8_t*)_ALIGN_SIZE((uintptr_t)me->stackEnd, al) + size; + return 0; + } else { + return _heap_alloc(&me->pheap, loc, size, ppbuf); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_deinit(_allocator* me) { + _heap* pa = me->pheap; + while(pa != 0) { + _heap* pn = pa; + const char* loc = pn->loc; + (void)loc; + pa = pn->pPrev; + FREE(pn); + } +} + +_ATTRIBUTE_UNUSED +static __inline void _allocator_init(_allocator* me, uint8_t* stack, int stackSize) { + me->stack = stack; + me->stackEnd = stack + stackSize; + me->nSize = stackSize; + me->pheap = 0; +} + + +#endif // _ALLOCATOR_H + +#ifndef SLIM_H +#define SLIM_H + +#include + +//a C data structure for the idl types that can be used to implement +//static and dynamic language bindings fairly efficiently. +// +//the goal is to have a minimal ROM and RAM footprint and without +//doing too many allocations. A good way to package these things seemed +//like the module boundary, so all the idls within one module can share +//all the type references. + + +#define PARAMETER_IN 0x0 +#define PARAMETER_OUT 0x1 +#define PARAMETER_INOUT 0x2 +#define PARAMETER_ROUT 0x3 +#define PARAMETER_INROUT 0x4 + +//the types that we get from idl +#define TYPE_OBJECT 0x0 +#define TYPE_INTERFACE 0x1 +#define TYPE_PRIMITIVE 0x2 +#define TYPE_ENUM 0x3 +#define TYPE_STRING 0x4 +#define TYPE_WSTRING 0x5 +#define TYPE_STRUCTURE 0x6 +#define TYPE_UNION 0x7 +#define TYPE_ARRAY 0x8 +#define TYPE_SEQUENCE 0x9 + +//these require the pack/unpack to recurse +//so it's a hint to those languages that can optimize in cases where +//recursion isn't necessary. +#define TYPE_COMPLEX_STRUCTURE (0x10 | TYPE_STRUCTURE) +#define TYPE_COMPLEX_UNION (0x10 | TYPE_UNION) +#define TYPE_COMPLEX_ARRAY (0x10 | TYPE_ARRAY) +#define TYPE_COMPLEX_SEQUENCE (0x10 | TYPE_SEQUENCE) + + +typedef struct Type Type; + +#define INHERIT_TYPE\ + int32_t nativeSize; /*in the simple case its the same as wire size and alignment*/\ + union {\ + struct {\ + const uintptr_t p1;\ + const uintptr_t p2;\ + } _cast;\ + struct {\ + uint32_t iid;\ + uint32_t bNotNil;\ + } object;\ + struct {\ + const Type *arrayType;\ + int32_t nItems;\ + } array;\ + struct {\ + const Type *seqType;\ + int32_t nMaxLen;\ + } seqSimple; \ + struct {\ + uint32_t bFloating;\ + uint32_t bSigned;\ + } prim; \ + const SequenceType* seqComplex;\ + const UnionType *unionType;\ + const StructType *structType;\ + int32_t stringMaxLen;\ + uint8_t bInterfaceNotNil;\ + } param;\ + uint8_t type;\ + uint8_t nativeAlignment\ + +typedef struct UnionType UnionType; +typedef struct StructType StructType; +typedef struct SequenceType SequenceType; +struct Type { + INHERIT_TYPE; +}; + +struct SequenceType { + const Type * seqType; + uint32_t nMaxLen; + uint32_t inSize; + uint32_t routSizePrimIn; + uint32_t routSizePrimROut; +}; + +//byte offset from the start of the case values for +//this unions case value array. it MUST be aligned +//at the alignment requrements for the descriptor +// +//if negative it means that the unions cases are +//simple enumerators, so the value read from the descriptor +//can be used directly to find the correct case +typedef union CaseValuePtr CaseValuePtr; +union CaseValuePtr { + const uint8_t* value8s; + const uint16_t* value16s; + const uint32_t* value32s; + const uint64_t* value64s; +}; + +//these are only used in complex cases +//so I pulled them out of the type definition as references to make +//the type smaller +struct UnionType { + const Type *descriptor; + uint32_t nCases; + const CaseValuePtr caseValues; + const Type * const *cases; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; + uint8_t inCaseAlignment; + uint8_t routCaseAlignmentPrimIn; + uint8_t routCaseAlignmentPrimROut; + uint8_t nativeCaseAlignment; + uint8_t bDefaultCase; +}; + +struct StructType { + uint32_t nMembers; + const Type * const *members; + int32_t inSize; + int32_t routSizePrimIn; + int32_t routSizePrimROut; + uint8_t inAlignment; + uint8_t routAlignmentPrimIn; + uint8_t routAlignmentPrimROut; +}; + +typedef struct Parameter Parameter; +struct Parameter { + INHERIT_TYPE; + uint8_t mode; + uint8_t bNotNil; +}; + +#define SLIM_IFPTR32(is32,is64) (sizeof(uintptr_t) == 4 ? (is32) : (is64)) +#define SLIM_SCALARS_IS_DYNAMIC(u) (((u) & 0x00ffffff) == 0x00ffffff) + +typedef struct Method Method; +struct Method { + uint32_t uScalars; //no method index + int32_t primInSize; + int32_t primROutSize; + int maxArgs; + int numParams; + const Parameter * const *params; + uint8_t primInAlignment; + uint8_t primROutAlignment; +}; + +typedef struct Interface Interface; + +struct Interface { + int nMethods; + const Method * const *methodArray; + int nIIds; + const uint32_t *iids; + const uint16_t* methodStringArray; + const uint16_t* methodStrings; + const char* strings; +}; + + +#endif //SLIM_H + + +#ifndef _AUDIO_PD_CDSP_SLIM_H +#define _AUDIO_PD_CDSP_SLIM_H +#include + +#ifndef __QAIC_SLIM +#define __QAIC_SLIM(ff) ff +#endif +#ifndef __QAIC_SLIM_EXPORT +#define __QAIC_SLIM_EXPORT +#endif + +static const Parameter parameters[3] = {{SLIM_IFPTR32(0x8,0x10),{{(const uintptr_t)0x0,0}}, 4,SLIM_IFPTR32(0x4,0x8),0,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),3,0},{SLIM_IFPTR32(0x4,0x8),{{(const uintptr_t)0xdeadc0de,(const uintptr_t)0}}, 0,SLIM_IFPTR32(0x4,0x8),0,0}}; +static const Parameter* const parameterArrays[3] = {(&(parameters[0])),(&(parameters[1])),(&(parameters[2]))}; +static const Method methods[3] = {{REMOTE_SCALARS_MAKEX(0,0,0x2,0x0,0x0,0x1),0x4,0x0,2,2,(&(parameterArrays[0])),0x4,0x1},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x1,0x0),0x0,0x0,1,1,(&(parameterArrays[2])),0x1,0x0},{REMOTE_SCALARS_MAKEX(0,0,0x0,0x0,0x0,0x0),0x0,0x0,0,0,0,0x0,0x0}}; +static const Method* const methodArrays[4] = {&(methods[0]),&(methods[1]),&(methods[2]),&(methods[2])}; +static const char strings[25] = "deinit\0close\0open\0uri\0h\0"; +static const uint16_t methodStrings[7] = {13,18,22,7,22,0,2}; +static const uint16_t methodStringsArrays[4] = {0,3,6,5}; +__QAIC_SLIM_EXPORT const Interface __QAIC_SLIM(audio_pd_cdsp_slim) = {4,&(methodArrays[0]),0,0,&(methodStringsArrays [0]),methodStrings,strings}; +#endif //_AUDIO_PD_CDSP_SLIM_H + + +#ifdef __cplusplus +extern "C" { +#endif +__QAIC_STUB_EXPORT int __QAIC_STUB(audio_pd_cdsp_open)(const char* uri, remote_handle64* h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_open)(uri, h); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(audio_pd_cdsp_close)(remote_handle64 h) __QAIC_STUB_ATTRIBUTE { + return __QAIC_REMOTE(remote_handle64_close)(h); +} +static __inline int _stub_method(remote_handle64 _handle, uint32_t _mid) { + remote_arg* _pra = 0; + int _nErr = 0; + _TRY_FARF(_nErr, __QAIC_REMOTE(remote_handle64_invoke)(_handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _pra)); + _CATCH_FARF(_nErr) { + _QAIC_FARF(RUNTIME_ERROR, "ERROR 0x%x: handle=0x%"PRIx64", scalar=0x%x, method ID=%d: %s failed\n", _nErr , _handle, REMOTE_SCALARS_MAKEX(0, _mid, 0, 0, 0, 0), _mid, __func__); + } + return _nErr; +} +__QAIC_STUB_EXPORT int __QAIC_STUB(audio_pd_cdsp_init)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 2; + return _stub_method(_handle, _mid); +} +__QAIC_STUB_EXPORT int __QAIC_STUB(audio_pd_cdsp_deinit)(remote_handle64 _handle) __QAIC_STUB_ATTRIBUTE { + uint32_t _mid = 3; + return _stub_method(_handle, _mid); +} +#ifdef __cplusplus +} +#endif +#endif //_CDSP_DYN_PD_STUB_H diff --git a/ar_util/Android.mk b/ar_util/Android.mk new file mode 100644 index 0000000..d6060ac --- /dev/null +++ b/ar_util/Android.mk @@ -0,0 +1,57 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := liblx-ar_util +LOCAL_MODULE_OWNER := qti +LOCAL_MODULE_TAGS := optional +LOCAL_VENDOR_MODULE := true + +LOCAL_SRC_FILES := \ + src/ar_util_list.c \ + src/ar_util_data_log.c \ + src/ar_util_err_detection.c + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + liblx-osal + +LOCAL_CFLAGS := -D_ANDROID_ +LOCAL_HEADER_LIBRARIES := libspf-headers +LOCAL_C_INCLUDES := $(LOCAL_PATH)/api \ + $(LOCAL_PATH)/inc + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/api + +include $(BUILD_SHARED_LIBRARY) + +# Build test library. +include $(CLEAR_VARS) + +LOCAL_MODULE := ar_util_in_test_example +LOCAL_VENDOR_MODULE := true + +LOCAL_SRC_FILES := \ + test/src/ar_osal_mutex_thread.c \ + test/src/ar_osal_signal_thread.c \ + test/src/ar_osal_test.c \ + test/src/ar_osal_test_service.c \ + test/src/ar_test_file_io.c \ + test/src/ar_test_heap.c \ + test/src/ar_test_list.c \ + test/src/ar_test_mem_op.c \ + test/src/ar_test_shmem.c \ + test/src/ar_test_sleep.c \ + test/src/ar_test_string.c\ + test/src/ar_test_data_log.c \ + test/src/ar_test_log_pkt_op.c + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + liblx-ar_util \ + liblx-osal + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/api \ + $(LOCAL_PATH)/test/inc \ + $(LOCAL_PATH)/inc + +include $(BUILD_EXECUTABLE) diff --git a/ar_util/Makefile.am b/ar_util/Makefile.am new file mode 100644 index 0000000..1feddd5 --- /dev/null +++ b/ar_util/Makefile.am @@ -0,0 +1,26 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = ar_util.pc +EXTRA_DIST = $(pkgconfig_DATA) + +AM_CFLAGS = -Werror -Wall -Wno-error=unused-variable + +AM_CFLAGS += -I$(srcdir)/inc +AM_CFLAGS += -I$(srcdir)/api +AM_CFLAGS += -I$(top_srcdir)/ar_osal/api -I$(top_srcdir)/spf/api/apm -I$(top_srcdir)/spf/api/ar_utils + +util_sources = ./api/ar_util_data_log_codes.h \ + ./api/ar_util_data_log.h \ + ./api/ar_util_list.h + +lib_includedir = $(includedir) +lib_include_HEADERS = $(util_sources) + +util_c_sources = src/ar_util_data_log.c \ + src/ar_util_err_detection.c \ + src/ar_util_list.c + +lib_LTLIBRARIES = libar-util.la +libar_util_la_CC = @CC@ +libar_util_la_SOURCES = $(util_c_sources) +libar_util_la_CFLAGS = $(AM_CFLAGS) +libar_util_la_LDFLAGS = -shared -version-number @LT_VERSION_NUMBER@ diff --git a/ar_util/api/ar_util_data_log.h b/ar_util/api/ar_util_data_log.h new file mode 100644 index 0000000..74be9f5 --- /dev/null +++ b/ar_util/api/ar_util_data_log.h @@ -0,0 +1,263 @@ +#ifndef AR_UTIL_DATA_LOG_H +#define AR_UTIL_DATA_LOG_H + +/** +* \file ar_util_data_log.h +* \brief +* Defines platform agnostic APIs for logging data through a data +* transport(diag, tcpip, etc...) +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** An enumeration of the log packet types supported by the utility. */ +typedef enum ar_log_pkt_type_t +{ + AR_DATA_LOG_PKT_TYPE_UNKNOWN = 0x00, /**< Unknown log packet*/ + AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM = 0x01, /**< Bitstream log packet format. */ + AR_DATA_LOG_PKT_TYPE_AUDIO_PCM = 0x02, /**< PCM Log packet. */ + AR_DATA_LOG_PKT_TYPE_GENERIC = 0x03, /**< A general purpose log packets that adds headers + for handling fragmentation and re-assembly */ + AR_DATA_LOG_PKT_TYPE_RAW = 0x04 /**< A raw data packet where data is sent as is */ +} ar_log_pkt_type_t; + +typedef enum ar_data_log_generic_fmt_t +{ + AR_LOG_PKT_GENERIC_FMT_CAL_BLOB = 0x5043414C, /**< 'P''C''A''L'. Calibration Blob data format */ + AR_LOG_PKT_GENERIC_FMT_RAW = 0x52415720 /**< 'R''A''W'''. Raw data format */ +}ar_data_log_generic_fmt_t; + +/** PCM data format information for the logging utility user. */ +typedef struct ar_data_log_pcm_info_t +{ + uint32_t sampling_rate; /**< PCM sampling rate. + @values 8000 Hz, 48000 Hz, etc. */ + uint16_t num_channels; /**< Number of channels in the PCM stream. */ + uint8_t bits_per_sample; /**< Bits per sample for the PCM data. */ + uint8_t interleaved; /**< Specifies whether the data is interleaved. */ + uint16_t *channel_mapping; /**< Array of channel mappings. */ +} ar_data_log_pcm_info_t; + +/** Format of the data being logged: PCM or bitstream. */ +typedef struct ar_data_log_audio_fmt_info_t +{ + ar_data_log_pcm_info_t + pcm_data_fmt; /**< Format of the PCM data. */ + uint32_t media_fmt_id; /**< Format of the bitstream data. */ +} ar_data_log_audio_fmt_info_t; + +/**< Log Packet allocation information */ +typedef struct ar_data_log_alloc_info_t +{ + uint32_t log_code; /**< The log code used for logging */ + uint32_t buffer_size; /**< The length of the buffer to log */ + ar_log_pkt_type_t pkt_type; /**< The type of packet to use for logging data */ +} ar_data_log_alloc_info_t; + +/**< Contains information needed to log a packet through +the ar_data_log_commit(...) API */ +typedef struct ar_data_log_commit_info_t +{ + uint32_t session_id; /**< The session id for the log packet */ + uint32_t log_tap_id; /**< The log tap point id */ + uint32_t buffer_size; /**< The length of the buffer to log */ + ar_log_pkt_type_t pkt_type; /**< The type of packet to use for logging data */ + void *pkt_info; /**< Pointer to the packet info structure that is + determined by pkt_type. See "Packet Info Structures". + For Raw packets, set this to NULL */ + void *log_pkt_data; /**< Pointer to the data section of the log packet */ +} ar_data_log_commit_info_t; + +/**< Contains information needed to log a buffer through +the ar_data_log_submit(...) API.*/ +typedef struct ar_data_log_submit_info_t +{ + uint16_t log_code; /**< The log code used for logging */ + uint32_t session_id; /**< The session id for the log packet */ + uint32_t log_tap_id; /**< The log tap point id */ + ar_log_pkt_type_t pkt_type; /**< The type of packet to use for logging data */ + void *pkt_info; /**< Pointer to the packet info structure that is + determined by pkt_type. See "Packet Info Structures". + For Raw packets, set this to NULL */ + uint32_t buffer_size; /**< The length of the buffer to log */ + int8_t *buffer; /**< Pointer to the buffer to be logged. */ +} ar_data_log_submit_info_t; + +/* +------------------------------------------------------------------------------- + Packet Info Structures +------------------------------------------------------------------------------- +*/ + +/**< Additional packet information for PCM/Bitstream packets used in +conjunction with the pkt_info field in ar_data_log_submit_info_t +and ar_data_log_commit_info_t */ +typedef struct ar_data_log_pcm_pkt_info_t +{ + uint64_t log_time_stamp; /**< Timestamp in microseconds. */ + ar_data_log_audio_fmt_info_t + data_info; /**< Pointer to the data packet information. */ + uint32_t *seq_number_ptr; /**< Reference to sequence number + variable shared by client. */ +}ar_data_log_pcm_pkt_info_t; + +/**< Additional packet information for General purpose packets used in +conjunction with the pkt_info field in ar_data_log_submit_info_t +and ar_data_log_commit_info_t */ +typedef struct ar_data_log_generic_pkt_info_t +{ + uint64_t log_time_stamp; /**< Timestamp in microseconds. */ + uint32_t token_id; /**< Used to distinguish the logging source of + a packet or set of packets */ + ar_data_log_generic_fmt_t format; /**< Specifies the command format to use in + the generic log packet */ +}ar_data_log_generic_pkt_info_t; + +/* +------------------------------------------------------------------------------- + Data Logging Formats for AR_DATA_LOG_PKT_TYPE_GENERIC +------------------------------------------------------------------------------- +*/ + +typedef struct ar_data_log_blob_fmt_t +{ + uint32_t data_size; /**< The length in bytes of the data that + follows this header */ + uint8_t data[0]; /**< The data */ +}ar_data_log_blob_fmt_t; + +/*============================================================================= +Function Declarations +=============================================================================*/ +/** +* \brief +* Initializes the data logging utility +* +* \return +* AR_EOK : on success +* AR_E : on failure +* +* \dependencies +* None +*/ +int32_t ar_data_log_init(void); + +/** +* \brief +* Deitializes the data logging utility +* +* \return +* AR_EOK : on success +* AR_E : on failure +* +* \dependencies +* None +*/ +int32_t ar_data_log_deinit(void); + +/** + * \brief + * Checks whether the log code is enabled + * + * \return + * TRUE : is enabled + * FALSE : is disabled + * + * \dependencies + * None + */ +bool_t ar_data_log_code_status(uint16_t log_code); + +/** +* \brief +* Returns the max log packet size +* +* \dependencies +* None +*/ +uint32_t ar_data_log_get_max_packet_size(void); + +/** +* \brief +* Allocates a data log packet +* +* \param[in] info: Contains the info needed to allocate a log packet +* +* \dependencies +* None. +* +* \return +* Pointer to the payload of the allocated log packet. +* Returns NULL if buffer allocation fails or log code is disabled. +* +* +---------------++----------------+ +* | Packet Header || Packet Payload | +* +---------------++----------------+ +* /\ +*/ +void *ar_data_log_alloc(ar_data_log_alloc_info_t *info); + +/** +* Commits a packet for logging. The log header is populated by this call. +* The client fills in the data portion of the packet. +* +* \param[in] info: A pointer to the commit info structure that contains +* info needed to commit a packet. +* +* \dependencies +* A log packet needs to be allocated with ar_data_log_alloc(...) +* before calling ar_data_log_commit +* +* \return +* 0 -- Success +* \par +* Nonzero -- Failure +* +*/ +int32_t ar_data_log_commit(ar_data_log_commit_info_t *info); + +/** +* \brief +* Segments a buffer into log packets and commits each packet for data logging. +* Log packet allocation and disposal are automatically taken care of. +* +* \param[in] info: A pointer to the submit info structure that contains +* the buffer to log as well as info for creating the +* log packet +* +* \return +* 0 -- Success +* Nonzero -- Failure +* +* \dependencies +* None +*/ +int32_t ar_data_log_submit(ar_data_log_submit_info_t *info); + +/** +* \brief +* Releases the memory allocated for a log packet +* +* \param[in] log_ptr : pointer to the payload of the data log packet +* \param[in] pkt_type : the type of packet that needs to be freed +* +* \return +* None. +* +* \dependencies +* Must call ar_data_log_alloc(..) before freeing +* Only pointers returned after calling ar_data_log_alloc(..) can be freed +*/ +void ar_data_log_free(void *log_pkt_payload_ptr, ar_log_pkt_type_t pkt_type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* AR_UTIL_DATA_LOG_H */ \ No newline at end of file diff --git a/ar_util/api/ar_util_data_log_codes.h b/ar_util/api/ar_util_data_log_codes.h new file mode 100644 index 0000000..111871b --- /dev/null +++ b/ar_util/api/ar_util_data_log_codes.h @@ -0,0 +1,41 @@ +#ifndef AR_UTIL_DATA_LOG_CODES_H +#define AR_UTIL_DATA_LOG_CODES_H + +/** +* \file ar_util_data_log.h +* \brief +* Defines log codes used by the AR Util Data Logging Utility +* +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ + +/** Log codes for audio/voice data path logging. */ + +#define AR_DATA_LOG_CODE_UNUSED 0x0 /**< Unused. */ +#define AR_DATA_LOG_CODE_AUD_DEC_IN 0x152E /**< audio decoder input. */ +#define AR_DATA_LOG_CODE_AUD_POPP_IN 0x152F /**< audio POPP input. */ +#define AR_DATA_LOG_CODE_AUD_COPP_IN 0x1531 /**< audio COPP input. */ +#define AR_DATA_LOG_CODE_AUD_POPREP_IN 0x1534 /**< audio POPREP input. */ +#define AR_DATA_LOG_CODE_AUD_COPREP_IN 0x1532 /**< audio COPREP input. */ +#define AR_DATA_LOG_CODE_AUD_MTMX_RX_IN 0x1530 /**< audio matrix Rx input. */ +#define AR_DATA_LOG_CODE_AUD_MTMX_TX_IN 0x1533 /**< audio matrix Tx input. */ +#define AR_DATA_LOG_CODE_AUD_ENC_IN 0x1535 /**< audio encoder input. */ +#define AR_DATA_LOG_CODE_AUD_ENC_OUT 0x1536 /**< audio encoder output. */ +#define AR_DATA_LOG_CODE_AFE_RX_TX_OUT 0x1586 /**< AFE Rx output and AFE Tx input. */ +#define AR_DATA_LOG_CODE_VPTX 0x158A /**< vptx near and far input and output. */ +#define AR_DATA_LOG_CODE_VPRX 0x158A /**< Logs PCM data at vprx output. */ +#define AR_DATA_LOG_CODE_VOC_ENC_IN 0x158B /**< voice encoder input */ +#define AR_DATA_LOG_CODE_VOC_PKT_OUT 0x14EE /**< voice encoder output . */ +#define AR_DATA_LOG_CODE_VOC_PKT_IN 0x14EE /**< voice decoder input. */ +#define AR_DATA_LOG_CODE_VOC_DEC_OUT 0x158B /**< voice decoder output. */ +#define AR_DATA_LOG_CODE_AFE_ALGO_CALIB 0x17D8 /**< Logs run-time parameters of algorithms in AFE. */ +#define AR_DATA_LOG_CODE_PP_RTM 0x184B /**< Logs RTM parameters of algorithms in PP. */ +#define AR_DATA_LOG_CODE_LSM_OUTPUT 0x1882 /**< LSM output. */ +#define AR_DATA_LOG_CODE_AUD_DEC_OUT 0x19AF /**< audio Decoder output. */ +#define AR_DATA_LOG_CODE_AUD_COPP_OUT 0x19B0 /**< audio COPP output. */ +#define AR_DATA_LOG_CODE_AUD_POPP_OUT 0x19B1 /**< audio POPP output. */ +#define AR_DATA_LOG_CODE_ATS 0x14A7 /**< Audio Tuning Service Log Code */ + +#endif /* AR_UTIL_DATA_LOGGER_H */ \ No newline at end of file diff --git a/ar_util/api/ar_util_err_detection.h b/ar_util/api/ar_util_err_detection.h new file mode 100644 index 0000000..4fba435 --- /dev/null +++ b/ar_util/api/ar_util_err_detection.h @@ -0,0 +1,113 @@ +#ifndef AR_UTIL_ERR_DET_H +#define AR_UTIL_ERR_DET_H +/** + * \file ar_util_err_detection.h + * + * \brief + * Header for SPF error detection framework + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* \brief +* Initializes one error detection context +* +* Multiple error detection contexts are useful in multi-master DSP scenarios, +* so that a fatal error on one master does not require the other to restart. +* The error detection context stores some persistent data which is used in +* error analysis +* +* \param[in] proc_handle: the master proc to initialize context for +* \param[in] client_data: data to return when this master proc needs restart +* +* \return +* AR_EOK : on success +* AR_E : on failure +* +* \dependencies +* None +*/ + +int32_t ar_err_det_init_ctxt(uint32_t proc_handle, void* client_data); + +/** +* \brief +* Destroys one error detection context +* +* Multiple error detection contexts are useful in multi-master SPF scenarios, +* so that a fatal error on one master does not require the other to restart +* +* \param[in] proc_handle: the master proc to destroy context for +* +* \return +* AR_EOK : on success +* AR_E : on failure +* +* \dependencies +* None +*/ + +int32_t ar_err_det_destroy_ctxt(uint32_t proc_handle); + +/** +* \brief +* Reset state variables for an error detection context +* +* After SSR or PDR we must reset state variables in a context, like time since +* last restart or number of timeouts logged. This API will not reset the client +* data stored on context init. +* +* \param[in] proc_handle: the master proc ID to reset the context for +* +* \return +* AR_EOK : on success +* AR_E : on failure +* +* \dependencies +* None +*/ + +int32_t ar_err_det_reset_ctxt(uint32_t proc_handle); + +/** +* \brief +* Determines whether SPF is in an unrecoverable state +* +* Multiple error detection contexts are useful in multi-master DSP scenarios, +* so that a fatal error on one master does not require the other to restart +* We identify them by the proc_id. +* +* \param[in] proc_handle: the master proc to use for error analysis +* \param[in] err_code: the error code returned by SPF +* \param[in] opcode: the opcode for which the error code was returned +* \param[out] do_restart: true when serious error requiring restart is detected. +* false otherwise +* \param[out] client_data: data to return when this master proc needs restart. +* +* \return +* AR_EOK : on successful error analysis, meaning do_restart is valid +* AR_E : otherwise, meaning do_restart should be ignored +* +* The implication of do_restart being true is that client should restart SPF by +* doing e.g. PDR on the master proc. +* +* \dependencies +* None +*/ +int32_t ar_err_det_detect_spf_error(uint32_t proc_handle, int32_t err_code, + uint32_t opcode, bool_t *do_restart, void **client_data); + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif // #ifndef AR_ERR_DET_H + diff --git a/ar_util/api/ar_util_list.h b/ar_util/api/ar_util_list.h new file mode 100644 index 0000000..c687673 --- /dev/null +++ b/ar_util/api/ar_util_list.h @@ -0,0 +1,172 @@ +#ifndef AR_UTIL_LIST_H +#define AR_UTIL_LIST_H + +/** + * \file ar_util_list.h + * \brief + * Defines public AudioReach UTIL APIs for double linked list. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +typedef struct ar_list_node_t ar_list_node_t; +typedef struct ar_list_t ar_list_t; + +typedef void (*ar_list_lock_enter_fn_t)(void); +typedef void (*ar_list_lock_leave_fn_t)(void); + +struct ar_list_node_t +{ + /**< Indicates the last known list for which this node belonged. */ + ar_list_t *list; + /**< The previous node. */ + ar_list_node_t *prev; + /**< The next node. */ + ar_list_node_t *next; +}; + +struct ar_list_t +{ + /**< A special dummy node to implement the NULL object pattern. */ + ar_list_node_t dummy; + /**< The number of nodes linked to this linked list. */ + uint32_t size; + /**< Optional, the user supplied lock implementation function. */ + ar_list_lock_enter_fn_t lock_fn; + /**< optional, the user supplied unlock implementation function. */ + ar_list_lock_leave_fn_t unlock_fn; + /**< Enable secure linked list flag. */ + bool_t en_secure; +}; + +/** ar_list_for_each_entry: iterate over list */ +#define ar_list_for_each_entry(iter, list) \ + for (iter = (list)->dummy.next; \ + iter != &((list)->dummy); iter = iter->next) + +/** + * \brief ar_list_init: initialize a list to itself. + * if lock_fn and unlock_fn are not provided + * client has to synchronize the list operations. + * \param[in] list: pointer to ar_list_t. + * \param[in_opt] lock_fn: lock function pointer. + * \param[in_opt] unlock_fn: unlock function pointer. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_init(ar_list_t *list, + ar_list_lock_enter_fn_t lock_fn, + ar_list_lock_leave_fn_t unlock_fn); + +/** + * \brief ar_list_init_node + * + * \param[in] node: pointer to ar_list_node_t. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_init_node(ar_list_node_t *node); + +/** + * \brief ar_list_add_tail + * + * \param[in] list: pointer to ar_list_t. + * \param[in] node: node to be added to the list. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_add_tail(ar_list_t *list, ar_list_node_t *node); + +/** + * \brief ar_list_remove_head + * + * \param[in] list: pointer to ar_list_t. + * \param[out]ret_node: pointer to the removed node. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_remove_head(ar_list_t *list, ar_list_node_t **ret_node); + +/** + * \brief ar_list_delete + * + * \param[in] list: pointer to ar_list_t. + * \param[in] node: pointer to node to be deleted. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_delete(ar_list_t *list, ar_list_node_t *node); + +/** + * \brief ar_list_clear + * + * \param[in] list: pointer to ar_list_t. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_clear(ar_list_t *list); + +/** +* \brief ar_list_is_empty: check if the list is empty. +* +* \param[in] list: pointer to ar_list_t. +* +* \return +* 1 if the list is empty +* 0 otherwise +*/ +static inline int32_t ar_list_is_empty(ar_list_t *list) +{ + return (list->dummy.next == &list->dummy); +} + +/** +* \brief ar_list_get_head: return the head node from list. +* +* \param[in] list: pointer to ar_list_t. +* +* \return +* address of head node +*/ +static inline ar_list_node_t* ar_list_get_head(ar_list_t *list) +{ + return list->dummy.next; +} + +/** +* \brief ar_list_get_tail: return the tail node from list. +* +* \param[in] list: pointer to ar_list_t. +* +* \return +* address of tail node +*/ +static inline ar_list_node_t* ar_list_get_tail(ar_list_t *list) +{ + return list->dummy.prev; +} + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* AR_UTIL_LIST_H */ diff --git a/ar_util/ar_util.pc.in b/ar_util/ar_util.pc.in new file mode 100644 index 0000000..93ed5ce --- /dev/null +++ b/ar_util/ar_util.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ar_util +Description: ar_util library +Version: @LT_VERSION@ +Libs: -L${libdir} -lar-util +Cflags: -I${includedir} diff --git a/ar_util/inc/ar_util_log_pkt_i.h b/ar_util/inc/ar_util_log_pkt_i.h new file mode 100644 index 0000000..de44f90 --- /dev/null +++ b/ar_util/inc/ar_util_log_pkt_i.h @@ -0,0 +1,211 @@ +#ifndef AR_UTIL_LOG_PKT_I_H +#define AR_UTIL_LOG_PKT_I_H + +/** +* \file ar_util_log_pkt_i.h +* \brief +* Defines internal structures used by the data logging utility +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "ar_osal_types.h" + +/* Log container tags */ +#define AR_AUDIOLOG_CNTR_LOG_HEADER 0x0001 /** Container tag for the log header. */ +#define AR_AUDIOLOG_CNTR_USER_SESSION 0x0002 /** Container tag for the user session. */ +#define AR_AUDIOLOG_CNTR_PCM_DATA_FORMAT 0x0004 /** Container tag for the PCM data format. */ +#define AR_AUDIOLOG_CNTR_BS_DATA_FORMAT 0x0005 /** Container tag for the bitstream data format. */ + +#define AR_LOGGING_MAX_NUM_CH 32 /** Maximum number of channels supported for multichannel PCM logging. */ + +#define AR_SEG_PKT (0xDEADBEEF) /** Magic number for indicating the fragmented packet. */ + +enum ar_util_interleaving_t +{ + AR_UTIL_INTERLEAVED, + /**< Data for all channels is present in one buffer. The samples are + interleaved per channel. */ + + AR_UTIL_DEINTERLEAVED_PACKED, + /**< Data for all channels is present in one buffer. All of the samples of + one channel are present, followed by all of the samples of + the next channel, etc. */ + + AR_UTIL_DEINTERLEAVED_UNPACKED, + /**< Data for each channel is present in a different buffer. In this case, + the capi_stream_data_t::buf_ptr field points to an array of buffer + structures with the number of elements equal to the number of channels. + The bufs_num field must be set to the number of channels. */ + + AR_UTIL_INVALID_INTERLEAVING = 0xFFFFFFFF + /**< Interleaving is not valid. */ +}; + +/*========================================================================== + Structure definitions + ========================================================================== */ +/* Overall log packet structure +* For PCM data, the containers are in following order: +* AUDIOLOG_HEADER +* AUDIOLOG_USER_SESSION +* AUDIOLOG_PCM_DATA_FORMAT +* +* For Bitsream data: +* AUDIOLOG_HEADER +* AUDIOLOG_USER_SESSION +* AUDIOLOG_BITSTREAM_DATA_FORMAT +* +* For RAW data +* n/a (there are no containers) +* +* For Generic Packet Data +* DATA_LOG_HEADER +* COMMAND_HEADER +* DATA +*/ + +/** User session container. */ +typedef struct ar_log_pkt_user_session_t +{ + uint16_t size; /**< Size information for this container. */ + uint16_t tag; /**< Tag information for this container. */ + uint32_t user_session_id; /**< User session ID. Currently not used; set this parameter to zero. */ + uint64_t time_stamp; /**< Timestamp (in microseconds) for the log packet. */ +} +ar_log_pkt_user_session_t; + +/** Audio log PCM data format container. */ +typedef struct ar_log_pkt_pcm_data_format_t +{ + uint16_t size; /**< Size information for this container. */ + uint16_t tag; /**< Tag information for this container. */ + uint32_t log_tap_id; /**< GUID for the tap point. */ + uint32_t sampling_rate; /**< PCM sampling rate (8000 Hz, 48000 Hz, etc.). */ + uint16_t num_channels; /**< Number of channels in the PCM stream. */ + uint8_t pcm_width; /**< Bits per sample for the PCM data. */ + uint8_t interleaved; /**< Specifies whether the data is interleaved. */ + uint8_t channel_mapping[AR_LOGGING_MAX_NUM_CH]; /**< Array of channel mappings. @newpagetable */ +} +ar_log_pkt_pcm_data_format_t; + +/** Audio log bitstream data format container. */ +typedef struct ar_log_pkt_bitstream_data_format_t +{ + uint16_t size; /**< Size information for this container. */ + uint16_t tag; /**< Tag information for this container. */ + uint32_t log_tap_id; /**< GUID for the tap point. */ + uint32_t media_fmt_id; /**< Media format ID for the audio/voice encoder/decoder. */ +} +ar_log_pkt_bitstream_data_format_t; + +/** Common header structure for PCM/bitstream data. */ +typedef struct ar_log_pkt_cmn_audio_header_t +{ + uint16_t size; /**< Size information for this container. */ + uint16_t tag; /**< Tag information for this container. */ + uint32_t log_session_id; /**< Log session ID. */ + uint32_t log_fragment_number; /**< Log fragment number. */ + uint32_t fragment_size; /**< Size in bytes of the payload, excluding the header. */ + uint32_t fragment_offset; /**< Fragment offset. Currently not used. */ + ar_log_pkt_user_session_t + user_session_info; /**< Audio log user session. */ +} +ar_log_pkt_cmn_audio_header_t; + +typedef struct ar_log_pkt_fragment_info_t +{ + uint16_t header_length; /**< The size of this header not including header_length */ + uint16_t fragment_count; /**< The total number of buffer fragments */ + uint32_t buffer_length; /**< The total Length of the client buffer being logged */ + uint32_t session_id; /**< Log session ID. */ + uint32_t tap_point_id; /**< Tap point ID. */ + uint32_t token_id; /**< A unique identifier for the client */ + uint32_t reserved; /**< Used for maintaining 8 byte alignment */ + uint16_t fragment_num; /**< The packet fragment number */ + uint16_t fragment_length; /**< The length of the buffer fragment which is at most + AR_UTIL_DATA_LOGGER_MAX_LOG_PKT_SIZE */ + uint32_t fragment_offset; /**< Offset of the fragment in the client buffer */ + uint64_t time_stamp; /**< The time stamp in microseconds of when the packet is + committed */ +}ar_log_pkt_fragment_info_t; + +/**< Data log header for General Purpose. */ +typedef struct ar_log_pkt_data_format_header_t +{ + uint16_t header_length; /**< The this structure not including header_length */ + uint16_t version; /**< The header version. */ + uint32_t format_id; /**< The Format ID used to identify the format of the + data after this header */ +} +ar_log_pkt_data_format_header_t; + +/**< Audio log packet header for PCM data. */ +typedef struct ar_log_pkt_pcm_header_t +{ + ar_log_pkt_cmn_audio_header_t cmn_struct; /**< Common header structure for + PCM/bitstream data. */ + ar_log_pkt_pcm_data_format_t pcm_data_fmt; /**< Audio log PCM data format. */ +} +ar_log_pkt_pcm_header_t; + +/** Audio log packet header for bitstream data. */ +typedef struct ar_log_pkt_bitstream_header_t +{ + ar_log_pkt_cmn_audio_header_t cmn_struct; /**< Common header structure for + PCM/bitstream data. */ + ar_log_pkt_bitstream_data_format_t bs_data_fmt; /**< Audio log bitstream data format. */ +} +ar_log_pkt_bitstream_header_t; + +/** Log packet header for command based packets. */ +typedef struct ar_log_pkt_generic_header_t +{ + ar_log_pkt_fragment_info_t info; /**< Information about the log packet that will be used + by packet recievers to re-assemble buffers sent + by clients*/ + ar_log_pkt_data_format_header_t cmd; /**< The command header describing the packet contents */ +} +ar_log_pkt_generic_header_t; + +/*========================================================================== + Log Packet Structures + ========================================================================== */ + +/**< Log Packet for PCM Data */ +typedef struct ar_data_log_pkt_pcm_t +{ + ar_log_pkt_pcm_header_t + header; /**< Audio log header for PCM data. */ + uint8_t payload[0]; /**< Contains the logged pcm data. */ +} +ar_data_log_pkt_pcm_t; + +/**< Log Packet for bitstream data. */ +typedef struct ar_data_log_pkt_bit_stream_t +{ + ar_log_pkt_bitstream_header_t + header; /**< Audio log header for bitstream data. */ + uint8_t payload[0]; /**< Contains the logged bitsream data. */ +} +ar_data_log_pkt_bit_stream_t; + +/**< Generic Log packet for general purpose use */ +typedef struct ar_data_log_pkt_generic_t +{ + ar_log_pkt_generic_header_t + header; /**< General purpose log header. */ + uint8_t payload[0]; /**< Contains the logged data. */ +} +ar_data_log_pkt_generic_t; + +/**< Raw Log packet +typedef struct ar_data_log_pkt_raw_t +{ + uint8_t payload[0]; // Contains the raw data. +} +ar_data_log_pkt_raw_t; +*/ + +#endif /* AR_UTIL_LOG_PKT_I_H */ diff --git a/ar_util/src/ar_util_data_log.c b/ar_util/src/ar_util_data_log.c new file mode 100644 index 0000000..aeb0381 --- /dev/null +++ b/ar_util/src/ar_util_data_log.c @@ -0,0 +1,896 @@ +/** +* \file ar_util_data_log.c +* +* \brief +* Defines platform agnostic APIs for logging data through a data +* transport(diag, tcpip, etc...) +* \copyright +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "ar_util_log_pkt_i.h" +#include "ar_util_data_log.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_log_pkt_op.h" +#include "ar_osal_types.h" + +#define AR_DATA_LOG_LOG_TAG "AR Data Logger" +#define AR_DATA_LOG_ERR(...) AR_LOG_ERR(AR_DATA_LOG_LOG_TAG, __VA_ARGS__) +#define AR_DATA_LOG_DBG(...) AR_LOG_DEBUG(AR_DATA_LOG_LOG_TAG, __VA_ARGS__) +#define AR_DATA_LOG_INFO(...) AR_LOG_INFO(AR_DATA_LOG_LOG_TAG, __VA_ARGS__) + +/* +------------------------------------------------------------------------------- +| Log packet info structure +------------------------------------------------------------------------------- +*/ +typedef struct fragment_info_t +{ + uint32_t total_count; + uint32_t number; + uint32_t length; + uint32_t offset; +}fragment_info_t; + +/* +------------------------------------------------------------------------------- +| Internal Helper Function Prototypes +------------------------------------------------------------------------------- +*/ +int32_t _get_max_log_pkt_data_size( + ar_log_pkt_type_t pkt_type, uint32_t *max_log_pkt_data_size); + +void *_log_alloc_pkt( + uint32_t buffer_size, uint32_t log_code, + bool_t handle_fragments, ar_log_pkt_type_t pkt_type); + +static int32_t _log_bitsream_pkt( + void *log_pkt, int8_t *buffer, uint32_t buffer_size, + fragment_info_t *fragment, + ar_data_log_submit_info_t *info); + +static int32_t _log_pcm_pkt( + void *log_pkt, int8_t *buffer, uint32_t buffer_size, + fragment_info_t *fragment, + ar_data_log_submit_info_t *info); + +static int32_t _log_generic_pkt( + void *log_pkt, int8_t *buffer, uint32_t buffer_size, + fragment_info_t *fragment, + ar_data_log_submit_info_t *info); + +static int32_t _log_raw_pkt( + void *log_pkt, int8_t *buffer, uint32_t buffer_size); + +/* +------------------------------------------------------------------------------- +| Public Functions +------------------------------------------------------------------------------- +*/ +int32_t ar_data_log_init() +{ + int32_t status = AR_EOK; + + status = ar_log_pkt_op_init(NULL); + if (AR_FAILED(status)) + { + AR_DATA_LOG_ERR("Status[%d]: " + "Failed to initialize the data logging utility.", status); + } + return status; +} + +int32_t ar_data_log_deinit() +{ + int32_t status = AR_EOK; + + status = ar_log_pkt_op_deinit(); + if (AR_FAILED(status)) + { + AR_DATA_LOG_ERR("Status[%d]: " + "Failed to de-initialize the data logging utility.", status); + } + return status; +} + +bool_t ar_data_log_code_status(uint16_t log_code) +{ + return ar_log_code_status(log_code); +} + +uint32_t ar_data_log_get_max_packet_size() +{ + return ar_log_pkt_get_max_size(); +} + +void *ar_data_log_alloc(ar_data_log_alloc_info_t *info) +{ + int32_t status = AR_EOK; + uint32_t max_log_pkt_size = 0; + + if (!info) + return NULL; + + status = _get_max_log_pkt_data_size(info->pkt_type, &max_log_pkt_size); + if (AR_FAILED(status)) + { + return NULL; + } + + if (info->buffer_size > max_log_pkt_size) + { + AR_DATA_LOG_ERR("Status[%d]: " + "buffer size of %d bytes is larger than max log packet size of %d bytes.", + AR_EBADPARAM, info->buffer_size, max_log_pkt_size); + return NULL; + } + + return _log_alloc_pkt( + info->buffer_size, info->log_code, FALSE, info->pkt_type); +} + +int32_t ar_data_log_commit(ar_data_log_commit_info_t *info) +{ + int32_t status = AR_EOK; + void *log_pkt = NULL; + + if (!info || !info->log_pkt_data) + { + AR_DATA_LOG_ERR("Status[%d]: Bad input parameter(s)", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + switch (info->pkt_type) + { + case AR_DATA_LOG_PKT_TYPE_AUDIO_PCM: + { + uint16_t i = 0; + ar_data_log_pkt_pcm_t *log_pkt_pcm = + (ar_data_log_pkt_pcm_t *)( + (uint8_t *)info->log_pkt_data - sizeof(ar_data_log_pkt_pcm_t)); + + ar_data_log_pcm_pkt_info_t *pcm_log_pkt_info = + (ar_data_log_pcm_pkt_info_t*)info->pkt_info; + + ar_data_log_pcm_info_t *pcm_data_info_ptr = (ar_data_log_pcm_info_t *)( + &pcm_log_pkt_info->data_info.pcm_data_fmt); + + ar_log_pkt_pcm_data_format_t *pcm_data_fmt = (ar_log_pkt_pcm_data_format_t *)( + &(log_pkt_pcm->header.pcm_data_fmt)); + + log_pkt_pcm->header.cmn_struct.tag = AR_AUDIOLOG_CNTR_LOG_HEADER; + log_pkt_pcm->header.cmn_struct.size = sizeof(ar_log_pkt_pcm_header_t); + log_pkt_pcm->header.cmn_struct.log_session_id = info->session_id; + log_pkt_pcm->header.cmn_struct.log_fragment_number = 0; + log_pkt_pcm->header.cmn_struct.fragment_size = info->buffer_size; + log_pkt_pcm->header.cmn_struct.fragment_offset = 0; + + log_pkt_pcm->header.cmn_struct.user_session_info.tag = AR_AUDIOLOG_CNTR_USER_SESSION; + log_pkt_pcm->header.cmn_struct.user_session_info.size = sizeof(ar_log_pkt_user_session_t); + log_pkt_pcm->header.cmn_struct.user_session_info.user_session_id = 0; + uint64_t timestamp = 0;// posal_timer_get_time(); ar osal needs to support timer op + log_pkt_pcm->header.cmn_struct.user_session_info.time_stamp = timestamp; + + log_pkt_pcm->header.pcm_data_fmt.tag = AR_AUDIOLOG_CNTR_PCM_DATA_FORMAT; + log_pkt_pcm->header.pcm_data_fmt.size = sizeof(ar_log_pkt_pcm_data_format_t); + log_pkt_pcm->header.pcm_data_fmt.log_tap_id = info->log_tap_id; + log_pkt_pcm->header.pcm_data_fmt.sampling_rate = pcm_log_pkt_info->data_info.pcm_data_fmt.sampling_rate; + log_pkt_pcm->header.pcm_data_fmt.num_channels = pcm_log_pkt_info->data_info.pcm_data_fmt.num_channels; + // log_pkt_pcm->header.pcm_data_fmt.pcm_width = pcm_log_pkt_info->data_info.pcm_data_fmt.pcm_width; + log_pkt_pcm->header.pcm_data_fmt.interleaved = pcm_log_pkt_info->data_info.pcm_data_fmt.interleaved; + + if (NULL != pcm_data_info_ptr->channel_mapping) + { + for (i = 0; i < pcm_data_info_ptr->num_channels; i++) + { + pcm_data_fmt->channel_mapping[i] = (uint8_t)( + pcm_data_info_ptr->channel_mapping[i]); + } + } + else /* Provide the default mapping */ + { + for (i = 0; i < pcm_data_info_ptr->num_channels; i++) + { + pcm_data_fmt->channel_mapping[i] = (uint8_t)i + 1; + } + } + + /* Set the remaining channels elements as un-used */ + for (i = pcm_data_info_ptr->num_channels; i < AR_LOGGING_MAX_NUM_CH; i++) + { + pcm_data_fmt->channel_mapping[i] = 0; + } + + log_pkt = (void*)log_pkt_pcm; + break; + + } + case AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM: + { + ar_data_log_pkt_bit_stream_t *log_pkt_bitstream = + (ar_data_log_pkt_bit_stream_t *)( + (uint8_t *)info->log_pkt_data - sizeof(ar_data_log_pkt_bit_stream_t)); + + log_pkt_bitstream->header.cmn_struct.tag = AR_AUDIOLOG_CNTR_LOG_HEADER; + log_pkt_bitstream->header.cmn_struct.size = sizeof(ar_log_pkt_bitstream_header_t); + log_pkt_bitstream->header.cmn_struct.log_session_id = info->session_id; + log_pkt_bitstream->header.cmn_struct.log_fragment_number = 0; + log_pkt_bitstream->header.cmn_struct.fragment_size = info->buffer_size; + log_pkt_bitstream->header.cmn_struct.fragment_offset = 0; + + log_pkt_bitstream->header.cmn_struct.user_session_info.tag = AR_AUDIOLOG_CNTR_USER_SESSION; + log_pkt_bitstream->header.cmn_struct.user_session_info.size = sizeof(ar_log_pkt_user_session_t); + log_pkt_bitstream->header.cmn_struct.user_session_info.user_session_id = 0; + uint64_t timestamp = 0;//posal_timer_get_time(); ar osal needs to support timer op + log_pkt_bitstream->header.cmn_struct.user_session_info.time_stamp = timestamp; + + log_pkt_bitstream->header.bs_data_fmt.tag = AR_AUDIOLOG_CNTR_BS_DATA_FORMAT; + log_pkt_bitstream->header.bs_data_fmt.size = sizeof(ar_log_pkt_bitstream_data_format_t); + log_pkt_bitstream->header.bs_data_fmt.log_tap_id = info->log_tap_id; + log_pkt_bitstream->header.bs_data_fmt.media_fmt_id = 0; + + log_pkt = (void*)log_pkt_bitstream; + break; + } + case AR_DATA_LOG_PKT_TYPE_GENERIC: + { + ar_data_log_generic_pkt_info_t *pkt_info = + (ar_data_log_generic_pkt_info_t*)info->pkt_info; + + ar_data_log_pkt_generic_t *log_pkt_generic = + (ar_data_log_pkt_generic_t *)( + (uint8_t *)info->log_pkt_data - sizeof(ar_data_log_pkt_generic_t)); + + log_pkt_generic->header.info.header_length = sizeof(ar_log_pkt_fragment_info_t) - sizeof(uint32_t); + log_pkt_generic->header.info.fragment_count = 1; + log_pkt_generic->header.info.fragment_num = 1; + log_pkt_generic->header.info.fragment_length = (uint16_t)info->buffer_size; + log_pkt_generic->header.info.fragment_offset = 0; + log_pkt_generic->header.info.buffer_length = info->buffer_size; + log_pkt_generic->header.info.time_stamp = pkt_info->log_time_stamp; + + log_pkt_generic->header.cmd.header_length = 1; + log_pkt_generic->header.cmd.version = 1; + log_pkt_generic->header.cmd.format_id = pkt_info->format; + + log_pkt = (void*)log_pkt_generic; + break; + } + case AR_DATA_LOG_PKT_TYPE_RAW: + log_pkt = info->log_pkt_data; + break; + default: + AR_DATA_LOG_ERR("Status[%d]: The log packet Packet Type#%d given does" + " not support the commit operation.", + AR_EUNSUPPORTED, info->pkt_type); + return AR_EUNSUPPORTED; + } + + status = ar_log_pkt_commit(log_pkt); + if (AR_FAILED(status)) + { + AR_DATA_LOG_ERR("Status[%d]: Unable to commit log packet for Packet Type#%d.", + AR_EUNSUPPORTED, info->pkt_type); + } + + return status; +} + +int32_t ar_data_log_submit(ar_data_log_submit_info_t *info) +{ + int32_t status = AR_EOK; + int8_t *buffer_ptr = NULL; + uint32_t remaining_buffer_size = 0; + void *log_pkt = NULL; + uint32_t log_pkt_size = 0; + uint32_t max_log_pkt_size = 0; + uint8_t interleaved = 0; + uint32_t num_channels = 0; + bool_t is_first_seg = TRUE; + fragment_info_t fragment = { 0 }; + + if (!info) + { + AR_DATA_LOG_ERR("Status[%d]: Bad input parameter", AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (!ar_data_log_code_status(info->log_code)) + { + AR_DATA_LOG_DBG("Log code 0x%x is not enabled."); + return AR_EOK; + } + + status = _get_max_log_pkt_data_size(info->pkt_type, &max_log_pkt_size); + if (AR_FAILED(status)) + { + return status; + } + + buffer_ptr = info->buffer; + remaining_buffer_size = info->buffer_size; + + fragment.total_count = (remaining_buffer_size % max_log_pkt_size) == 0 ? + (remaining_buffer_size / max_log_pkt_size) : + (remaining_buffer_size / max_log_pkt_size) + 1; + + while (remaining_buffer_size > 0) + { + if (remaining_buffer_size < max_log_pkt_size) + { + log_pkt_size = remaining_buffer_size; + } + else + { + log_pkt_size = max_log_pkt_size; + } + + log_pkt = _log_alloc_pkt( + log_pkt_size, info->log_code, TRUE, info->pkt_type); + if (!log_pkt) + { + AR_DATA_LOG_ERR("Status[%d]: _log_alloc_pkt failed", AR_ENOMEMORY); + return AR_ENOMEMORY; + } + fragment.length = log_pkt_size; + + switch (info->pkt_type) + { + case AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM: + status = _log_bitsream_pkt( + log_pkt, buffer_ptr, log_pkt_size, + &fragment, info); + break; + case AR_DATA_LOG_PKT_TYPE_AUDIO_PCM: + + interleaved = ((ar_data_log_pcm_pkt_info_t*) + info->pkt_info)->data_info.pcm_data_fmt.interleaved; + num_channels = ((ar_data_log_pcm_pkt_info_t*) + info->pkt_info)->data_info.pcm_data_fmt.num_channels; + + if ((max_log_pkt_size == log_pkt_size) && + (info->buffer_size > max_log_pkt_size) && + (TRUE == is_first_seg) && + (!interleaved)) + { + is_first_seg = FALSE; + } + + if (FALSE == is_first_seg) + { + fragment.number = AR_SEG_PKT; + } + + status = _log_pcm_pkt( + log_pkt, buffer_ptr, info->buffer_size, + &fragment, info); + + break; + case AR_DATA_LOG_PKT_TYPE_GENERIC: + status = _log_generic_pkt( + log_pkt, buffer_ptr, info->buffer_size, + &fragment, info); + break; + case AR_DATA_LOG_PKT_TYPE_RAW: + status = _log_raw_pkt( + log_pkt, buffer_ptr, log_pkt_size); + break; + default: + break; + } + + if (AR_FAILED(status)) + { + ar_log_pkt_free(log_pkt); + return status; + } + + fragment.number++; + fragment.offset += log_pkt_size; + remaining_buffer_size -= log_pkt_size; + + if (info->pkt_type == AR_DATA_LOG_PKT_TYPE_AUDIO_PCM && !interleaved) + { + buffer_ptr += log_pkt_size / num_channels; + continue; + } + + buffer_ptr += log_pkt_size; + } + + buffer_ptr = NULL; + log_pkt = NULL; + + return status; +} + +void ar_data_log_free(void *log_pkt_payload_ptr, ar_log_pkt_type_t pkt_type) +{ + uint32_t log_header_size = 0; + uint8_t *log_pkt_ptr = NULL; + + if (NULL == log_pkt_payload_ptr || + pkt_type == AR_DATA_LOG_PKT_TYPE_UNKNOWN) + { + AR_DATA_LOG_ERR("Status[%d]: Bad input parameter(s)", + AR_EBADPARAM); + return; + } + + switch (pkt_type) + { + case AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM: + log_header_size = (sizeof(ar_data_log_pkt_bit_stream_t)); + break; + case AR_DATA_LOG_PKT_TYPE_AUDIO_PCM: + log_header_size = (sizeof(ar_data_log_pkt_pcm_t)); + break; + case AR_DATA_LOG_PKT_TYPE_GENERIC: + log_header_size = (sizeof(ar_data_log_pkt_generic_t)); + break; + case AR_DATA_LOG_PKT_TYPE_RAW: + break; + default: + break; + } + + log_pkt_ptr = (uint8_t*)log_pkt_payload_ptr - log_header_size; + + ar_log_pkt_free(log_pkt_ptr); +} + +/* +------------------------------------------------------------------------------- +| Internal Helper Functions +------------------------------------------------------------------------------- +*/ + +int32_t _get_max_log_pkt_data_size( + ar_log_pkt_type_t pkt_type, uint32_t *max_log_pkt_data_size) +{ + int32_t status = AR_EOK; + uint32_t max_log_pkt_size = ar_log_pkt_get_max_size(); + uint32_t log_header_size = 0; + + if (0 == max_log_pkt_size) + { + AR_DATA_LOG_ERR("Status[%d]: The transport layer returned a " + "max packet size of zero", AR_EBADPARAM); + return AR_EBADPARAM; + } + + switch (pkt_type) + { + case AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM: + log_header_size = (uint32_t)sizeof(ar_data_log_pkt_bit_stream_t); + break; + case AR_DATA_LOG_PKT_TYPE_AUDIO_PCM: + log_header_size = (uint32_t)sizeof(ar_data_log_pkt_pcm_t); + break; + case AR_DATA_LOG_PKT_TYPE_GENERIC: + log_header_size = (uint32_t)sizeof(ar_data_log_pkt_generic_t); + break; + case AR_DATA_LOG_PKT_TYPE_RAW: + break; + default: + status = AR_EUNSUPPORTED; + + AR_DATA_LOG_ERR("Status[%d]: Unsupported packet type %d", + status, pkt_type); + max_log_pkt_size = 0; + log_header_size = 0; + } + + *max_log_pkt_data_size = max_log_pkt_size - log_header_size; + + return status; +} + +void *_log_alloc_pkt( + uint32_t buffer_size, uint32_t log_code, + bool_t handle_fragments, ar_log_pkt_type_t pkt_type) +{ + uint32_t log_pkt_size = 0; + uint32_t log_header_size = 0; + void *log_pkt_ptr = NULL; + void *log_pkt_payload_ptr = NULL; + + switch (pkt_type) + { + case AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM: + log_header_size = (sizeof(ar_data_log_pkt_bit_stream_t)); + break; + case AR_DATA_LOG_PKT_TYPE_AUDIO_PCM: + log_header_size = (sizeof(ar_data_log_pkt_pcm_t)); + break; + case AR_DATA_LOG_PKT_TYPE_GENERIC: + log_header_size = (sizeof(ar_data_log_pkt_generic_t)); + break; + case AR_DATA_LOG_PKT_TYPE_RAW: + break; + default: + AR_DATA_LOG_ERR("Status[%d]: Unsupported packet type %d", + AR_EUNSUPPORTED, pkt_type); + + return NULL; + } + + /* Caclulate total packet size including the data payload */ + log_pkt_size = (log_header_size + buffer_size); + + /* Allocate the log packet + * log_alloc() returns pointer to the allocated log packet + * Returns NULL if log code is disabled on the GUI + */ + + //AR_DATA_LOG_DBG("Req Pkt Size %u : bytes for log code 0x%X", + // log_pkt_size, log_code); + + log_pkt_ptr = ar_log_pkt_alloc((uint16_t)log_code, log_pkt_size); + if (!log_pkt_ptr) + return NULL; + + if (handle_fragments) + return log_pkt_ptr; + + log_pkt_payload_ptr = (void*)((uint8_t*)log_pkt_ptr + log_header_size); + + return log_pkt_payload_ptr; +} + +static int32_t _log_bitsream_pkt( + void *log_pkt, int8_t *buffer, uint32_t buffer_size, + fragment_info_t *fragment, + ar_data_log_submit_info_t *info) + +{ + int32_t status = AR_EOK; + ar_log_pkt_cmn_audio_header_t *log_header_cmn; + ar_log_pkt_bitstream_data_format_t *bs_data_fmt; + uint8_t *log_dst_ptr = NULL; + ar_data_log_pkt_bit_stream_t *bs_log_pkt; + ar_data_log_pcm_pkt_info_t *pcm_log_pkt_info = NULL; + + if (!log_pkt || !buffer || !fragment || !info) + { + AR_DATA_LOG_ERR("Status[%d]: Bad input parameter(s)", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (info->pkt_type != AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM) + { + AR_DATA_LOG_ERR("Status[%d]: Invalid packet type: " + "%u for log code 0x%X", AR_EBADPARAM, + info->pkt_type, + info->log_code); + return AR_EBADPARAM; + } + + if (!info->pkt_info) + { + AR_DATA_LOG_ERR("Status[%d]: Packet info is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + pcm_log_pkt_info = (ar_data_log_pcm_pkt_info_t*)info->pkt_info; + + bs_log_pkt = (ar_data_log_pkt_bit_stream_t *)log_pkt; + bs_data_fmt = (ar_log_pkt_bitstream_data_format_t *)( + &(bs_log_pkt->header.bs_data_fmt)); + log_header_cmn = &(bs_log_pkt->header.cmn_struct); + + /*************** AUDIO_LOG_HEADER ***************/ + log_header_cmn->tag = AR_AUDIOLOG_CNTR_LOG_HEADER; + log_header_cmn->size = sizeof(ar_log_pkt_bitstream_header_t); + log_header_cmn->log_session_id = info->session_id; + log_header_cmn->fragment_size = buffer_size; + log_header_cmn->fragment_offset = fragment->offset; + + /* if pcm_log_pkt_info->seq_number_ptr is null, use + * default fragment numbering scheme */ + if (!pcm_log_pkt_info->seq_number_ptr) + log_header_cmn->log_fragment_number = fragment->number; + else + log_header_cmn->log_fragment_number = + (*(pcm_log_pkt_info->seq_number_ptr))++; + + /*************** AUDIO_LOG_USER_SESSION ***************/ + log_header_cmn->user_session_info.tag = AR_AUDIOLOG_CNTR_USER_SESSION; + log_header_cmn->user_session_info.size = sizeof(ar_log_pkt_user_session_t); + /* User session ID is un-used */ + log_header_cmn->user_session_info.user_session_id = 0; + log_header_cmn->user_session_info.time_stamp = + pcm_log_pkt_info->log_time_stamp; + + /********** AUDIOLOG_BITSTREAM_DATA_FORAMT *************/ + bs_data_fmt->tag = AR_AUDIOLOG_CNTR_BS_DATA_FORMAT; + bs_data_fmt->size = sizeof(ar_log_pkt_bitstream_data_format_t); + bs_data_fmt->log_tap_id = info->log_tap_id; + bs_data_fmt->media_fmt_id = pcm_log_pkt_info->data_info.media_fmt_id; + + log_dst_ptr = ((ar_data_log_pkt_bit_stream_t *)log_pkt)->payload; + + /* Populate the log packet payload with the buffer to be logged */ + status = ar_mem_cpy( + log_dst_ptr, buffer_size, + buffer, buffer_size); + if (AR_FAILED(status)) + { + AR_DATA_LOG_DBG("Status[%d]: Failed to mem-copy buffer " + "fragment to log packet", status); + return status; + } + + status = ar_log_pkt_commit(log_pkt); + if (AR_FAILED(status)) + { + AR_DATA_LOG_ERR("Status[%d]: Unable to commit bitstream log packet.", + status); + } + + return status; +} + +static int32_t _log_pcm_pkt( + void *log_pkt, int8_t *buffer, uint32_t buffer_size, + fragment_info_t *fragment, + ar_data_log_submit_info_t *info) + +{ + int32_t status = AR_EOK; + ar_log_pkt_cmn_audio_header_t *log_header_cmn = NULL; + ar_log_pkt_pcm_data_format_t *pcm_data_fmt = NULL; + ar_data_log_pcm_info_t *pcm_data_info_ptr = NULL; + uint16_t i = 0; + uint8_t *log_dst_ptr = NULL; + ar_data_log_pkt_pcm_t *pcm_log_pkt = NULL; + bool_t is_seg_pkt = FALSE; + uint16_t num_channels = 0; + uint32_t num_bytes_per_channel = 0; + uint32_t total_num_bytes_per_channel = 0; + ar_data_log_pcm_pkt_info_t *pcm_log_pkt_info = NULL; + __UNREFERENCED_PARAM(buffer_size); + if (!log_pkt || !buffer || !fragment || !info) + { + AR_DATA_LOG_ERR("Status[%d]: Bad input parameter(s)", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + if (info->pkt_type != AR_DATA_LOG_PKT_TYPE_AUDIO_PCM) + { + AR_DATA_LOG_ERR("Status[%d]: Invalid packet type: " + "%u for log code 0x%X", AR_EBADPARAM, + info->pkt_type, + info->log_code); + return AR_EBADPARAM; + } + + if (!info->pkt_info) + { + AR_DATA_LOG_ERR("Status[%d]: Packet info is null", + AR_EBADPARAM); + return AR_EBADPARAM; + } + + pcm_log_pkt = (ar_data_log_pkt_pcm_t *)log_pkt; + pcm_log_pkt_info = (ar_data_log_pcm_pkt_info_t*)info->pkt_info; + pcm_data_fmt = (ar_log_pkt_pcm_data_format_t *)( + &(pcm_log_pkt->header.pcm_data_fmt)); + pcm_data_info_ptr = (ar_data_log_pcm_info_t *)( + &pcm_log_pkt_info->data_info.pcm_data_fmt); + + log_header_cmn = &(pcm_log_pkt->header.cmn_struct); + num_channels = pcm_data_info_ptr->num_channels; + + if (AR_SEG_PKT == fragment->number) + { + is_seg_pkt = TRUE; + + total_num_bytes_per_channel = + info->buffer_size / num_channels; + } + + /*************** AUDIO_LOG_HEADER ***************/ + log_header_cmn->tag = AR_AUDIOLOG_CNTR_LOG_HEADER; + log_header_cmn->size = sizeof(ar_log_pkt_pcm_header_t); + log_header_cmn->log_session_id = info->session_id; + log_header_cmn->fragment_size = fragment->length; + log_header_cmn->fragment_offset = fragment->offset; + + /* if pcm_log_pkt_info->seq_number_ptr is null, use + * default fragment numbering scheme */ + if (!pcm_log_pkt_info->seq_number_ptr) + log_header_cmn->log_fragment_number = fragment->number; + else + log_header_cmn->log_fragment_number = + (*(pcm_log_pkt_info->seq_number_ptr))++; + + /*************** AUDIO_LOG_USER_SESSION ***************/ + log_header_cmn->user_session_info.tag = AR_AUDIOLOG_CNTR_USER_SESSION; + log_header_cmn->user_session_info.size = sizeof(ar_log_pkt_user_session_t); + /* User session ID is un-used */ + log_header_cmn->user_session_info.user_session_id = 0; + log_header_cmn->user_session_info.time_stamp = + pcm_log_pkt_info->log_time_stamp; + + /*************** AUDIOLOG_PCM_DATA_FORAMT ***************/ + pcm_data_fmt->tag = AR_AUDIOLOG_CNTR_PCM_DATA_FORMAT; + pcm_data_fmt->size = sizeof(ar_log_pkt_pcm_data_format_t); + pcm_data_fmt->log_tap_id = info->log_tap_id; + pcm_data_fmt->sampling_rate = pcm_data_info_ptr->sampling_rate; + pcm_data_fmt->num_channels = pcm_data_info_ptr->num_channels; + pcm_data_fmt->pcm_width = pcm_data_info_ptr->bits_per_sample; + pcm_data_fmt->interleaved = (pcm_data_info_ptr->interleaved == 0) ? 1 : 0; + + if (NULL != pcm_data_info_ptr->channel_mapping) + { + for (i = 0; i < pcm_data_info_ptr->num_channels; i++) + { + pcm_data_fmt->channel_mapping[i] = (uint8_t)( + pcm_data_info_ptr->channel_mapping[i]); + } + } + else /* Provide the default mapping */ + { + for (i = 0; i < pcm_data_info_ptr->num_channels; i++) + { + pcm_data_fmt->channel_mapping[i] = (uint8_t)(i + 1); + } + } + + /* Set the remaining channels elements as un-used */ + for (i = pcm_data_info_ptr->num_channels; i < AR_LOGGING_MAX_NUM_CH; i++) + { + pcm_data_fmt->channel_mapping[i] = 0; + } + + log_dst_ptr = ((ar_data_log_pkt_pcm_t *)log_pkt)->payload; + + + /* Populate the log packet payload with the buffer to be logged */ + + if (FALSE == is_seg_pkt) + { + status = ar_mem_cpy( + log_dst_ptr, fragment->length, + buffer, fragment->length); + } + else /* True */ + { + num_bytes_per_channel = (fragment->length / num_channels); + + for (i = 0; i < num_channels; i++) + { + status = ar_mem_cpy( + log_dst_ptr, num_bytes_per_channel, + buffer, num_bytes_per_channel); + log_dst_ptr += num_bytes_per_channel; + buffer += total_num_bytes_per_channel; + + if (AR_FAILED(status)) + break; + } + } + + if (AR_FAILED(status)) + { + if (is_seg_pkt) + { + AR_DATA_LOG_DBG("Status[%d]: Failed to mem-copy buffer " + "fragment to log packet", AR_EFAILED); + } + else + { + AR_DATA_LOG_DBG("Status[%d]: Failed to mem-copy buffer " + "fragment to log packet while looping through channels", + AR_EFAILED); + } + } + + status = ar_log_pkt_commit(log_pkt); + if (AR_FAILED(status)) + { + AR_DATA_LOG_ERR("Status[%d]: Unable to commit pcm log packet.", + status); + } + + return status; +} + +static int32_t _log_generic_pkt( + void *log_pkt, int8_t *buffer, uint32_t buffer_size, + fragment_info_t *fragment, + ar_data_log_submit_info_t *info) +{ + int32_t status = AR_EOK; + ar_data_log_generic_pkt_info_t *pkt_info = NULL; + ar_data_log_pkt_generic_t *generic_log_pkt = NULL; + + if (info->pkt_type != AR_DATA_LOG_PKT_TYPE_GENERIC) + { + AR_DATA_LOG_ERR("Status[%d]: Invalid packet type: " + "%u for log code 0x%X", AR_EBADPARAM, + info->pkt_type, + info->log_code); + return AR_EBADPARAM; + } + + pkt_info = + (ar_data_log_generic_pkt_info_t*)info->pkt_info; + generic_log_pkt = + (ar_data_log_pkt_generic_t *)log_pkt; + + generic_log_pkt->header.info.header_length = + sizeof(ar_log_pkt_fragment_info_t) - sizeof(uint32_t); + generic_log_pkt->header.info.fragment_count = (uint16_t)fragment->total_count; + generic_log_pkt->header.info.buffer_length = buffer_size; + generic_log_pkt->header.info.session_id = info->session_id; + generic_log_pkt->header.info.tap_point_id = info->log_tap_id; + generic_log_pkt->header.info.token_id = pkt_info->token_id; + generic_log_pkt->header.info.reserved = 0; + generic_log_pkt->header.info.fragment_num = (uint16_t)fragment->number; + generic_log_pkt->header.info.fragment_length = (uint16_t)fragment->length; + generic_log_pkt->header.info.fragment_offset = fragment->offset; + generic_log_pkt->header.info.time_stamp = pkt_info->log_time_stamp; + + generic_log_pkt->header.cmd.header_length = sizeof(ar_log_pkt_data_format_header_t) - sizeof(uint32_t); + generic_log_pkt->header.cmd.version = 1; + generic_log_pkt->header.cmd.format_id = (uint32_t)pkt_info->format; + + status = ar_mem_cpy( + (uint8_t*)log_pkt + sizeof(ar_data_log_pkt_generic_t), fragment->length, + (void*)buffer, fragment->length); + if (AR_FAILED(status)) + { + AR_DATA_LOG_DBG("Status[%d]: Failed to mem-copy buffer " + "fragment to log packet", status); + return status; + } + + status = ar_log_pkt_commit(log_pkt); + if (AR_FAILED(status)) + { + AR_DATA_LOG_ERR("Status[%d]: Unable to commit generic log packet.", + status); + } + + return status; +} + +static int32_t _log_raw_pkt( + void *log_pkt, int8_t *buffer, uint32_t buffer_size) +{ + int32_t status = AR_EOK; + uint32_t max_log_pkt_size = ar_log_pkt_get_max_size(); + + if (buffer_size > max_log_pkt_size) + { + return AR_EBADPARAM; + } + + status = ar_mem_cpy( + log_pkt, buffer_size, + buffer, buffer_size); + if (AR_FAILED(status)) + { + AR_DATA_LOG_DBG("Status[%d]: Failed to mem-copy buffer " + "fragment to log packet", status); + return status; + } + + status = ar_log_pkt_commit(log_pkt); + if (AR_FAILED(status)) + { + AR_DATA_LOG_ERR("Status[%d]: Unable to commit raw log packet.", + status); + } + + return status; +} diff --git a/ar_util/src/ar_util_err_detection.c b/ar_util/src/ar_util_err_detection.c new file mode 100644 index 0000000..581cf18 --- /dev/null +++ b/ar_util/src/ar_util_err_detection.c @@ -0,0 +1,277 @@ +/** + * \file ar_util_err_detection.c + * + * \brief + * SPF error detection framework + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ar_util_err_detection.h" +#include "ar_osal_error.h" +#include "ar_util_list.h" +#include "ar_osal_log.h" +#include "ar_osal_heap.h" +#include "ar_osal_timer.h" +#include "apm_api.h" + +#define MAX_TIMEOUTS_IN_PERIOD 7 +#define MAX_EDUPLICATE_IN_PERIOD 60 +#define ACCUMULATION_PERIOD_MS (30*1000) /* 30 secs */ +#define MIN_TIME_ANY_RESTART_MS (60*1000) /* 1 minute */ +#define MIN_TIME_EDUPLICATE_RESTART_MS (10*60*1000) /* 10 minutes */ + +/* Goes to zero if would overflow. Only used to compare to cur time (> zero) */ +#define overflow_safe_add(x,y) (UINT64_MAX - (x) > (y)) ? ((x) + (y)) : 0; + +#define AR_ERR_DET_LOG_TAG "AR Error Detection Logger" +#define AR_ERR_DET_ERR(...) AR_LOG_ERR(AR_ERR_DET_LOG_TAG, __VA_ARGS__) +#define AR_ERR_DET_DBG(...) AR_LOG_DEBUG(AR_ERR_DET_LOG_TAG, __VA_ARGS__) +#define AR_ERR_DET_INFO(...) AR_LOG_INFO(AR_ERR_DET_LOG_TAG, __VA_ARGS__) + +//TODO move this into the ar list header. Use name from GSL verison? +#define get_struc_base(p, type, member) ((type *)( \ + (int8_t *)(p)- \ + (uintptr_t)(&((type *)0)->member))) + +typedef struct err_det_ctxt err_det_ctxt; + +struct err_det_ctxt { + ar_list_node_t node; + + uint32_t master_proc_handle; + uint64_t last_restart_time_ms; + + uint32_t num_timeouts_curr_period; + uint64_t first_timeout_time_ms; + + uint32_t num_eduplicate_curr_period; + uint64_t first_eduplicate_time_ms; + + void* client_data; +}; + +static ar_list_t context_list; +static bool_t list_inited = false; + +static err_det_ctxt* find_ctxt_by_proc_handle(uint32_t proc_handle) { + ar_list_node_t *curr; + err_det_ctxt *ctxt = NULL; + + if (!list_inited || ar_list_is_empty(&context_list)) + return NULL; + + ar_list_for_each_entry(curr, &context_list) { + ctxt = get_struc_base(curr, err_det_ctxt, node); + if (ctxt->master_proc_handle == proc_handle) + return ctxt; + } + + AR_ERR_DET_ERR("Unable to find context for proc ID %d", proc_handle); + return NULL; +} + +int32_t ar_err_det_init_ctxt(uint32_t proc_handle, void *client_data) +{ + int32_t status = AR_EOK; + err_det_ctxt *new_ctxt; + ar_heap_info heap_info = { + .align_bytes = AR_HEAP_ALIGN_DEFAULT, + .pool_type = AR_HEAP_POOL_DEFAULT, + .heap_id = AR_HEAP_ID_DEFAULT, + .tag = AR_HEAP_TAG_DEFAULT + }; + + if (!list_inited) { + status = ar_list_init(&context_list, NULL, NULL); + if (AR_EOK != status) + goto end; + + list_inited = true; + } + + if (find_ctxt_by_proc_handle(proc_handle) != NULL) { + status = AR_EALREADY; + goto end; + } + + new_ctxt = ar_heap_calloc(sizeof(struct err_det_ctxt), &heap_info); + if (!new_ctxt) { + status = AR_ENOMEMORY; + goto end; + } + + new_ctxt->master_proc_handle = proc_handle; + new_ctxt->client_data = client_data; + status = ar_list_init_node(&new_ctxt->node); + if (status) + goto free_new_ctxt; + + status = ar_list_add_tail(&context_list, &new_ctxt->node); + if (status) + goto free_new_ctxt; + + /* don't free in success case */ + goto end; + +free_new_ctxt: + ar_heap_free(new_ctxt, &heap_info); + +end: + return status; +} + +int32_t ar_err_det_destroy_ctxt(uint32_t proc_handle) +{ + err_det_ctxt *ctxt; + ar_heap_info heap_info = { + .align_bytes = AR_HEAP_ALIGN_DEFAULT, + .pool_type = AR_HEAP_POOL_DEFAULT, + .heap_id = AR_HEAP_ID_DEFAULT, + .tag = AR_HEAP_TAG_DEFAULT + }; + + ctxt = find_ctxt_by_proc_handle(proc_handle); + + if (!ctxt) + return AR_EBADPARAM; + + ar_list_delete(&context_list, &ctxt->node); + ar_heap_free(ctxt->client_data, &heap_info); + ar_heap_free(ctxt, &heap_info); + + return AR_EOK; +} + +int32_t ar_err_det_reset_ctxt(uint32_t proc_handle) +{ + err_det_ctxt *ctxt = find_ctxt_by_proc_handle(proc_handle); + + if (!ctxt) + return AR_EBADPARAM; + + ctxt->first_timeout_time_ms = 0; + ctxt->num_timeouts_curr_period = 0; + ctxt->first_eduplicate_time_ms = 0; + ctxt->num_eduplicate_curr_period = 0; + + return AR_EOK; +} + +int32_t ar_err_det_detect_spf_error(uint32_t proc_handle, int32_t err_code, + uint32_t opcode, bool_t *do_restart, void **client_data) +{ + err_det_ctxt *ctxt = find_ctxt_by_proc_handle(proc_handle); + uint64_t curr_time = ar_timer_get_time_in_ms(); + uint64_t sum = 0; + uint32_t rc = AR_EOK; + + *do_restart = false; + + /* Don't trigger SSR if we don't find the context */ + if (!ctxt) + return AR_EBADPARAM; + + *client_data = ctxt->client_data; + + switch (err_code) { + /* + * For timeout we have specific handling for OPEN/CLOSE operations, and + * a case for other generic operations + */ + case AR_ETIMEOUT: + switch (opcode) { + /* + * For graph OPEN and CLOSE, any timeout can create desync between + * SPF and GSL, resulting in SGs being open by mistake. + * Thus, on any timeout for graph OPEN or CLOSE, treat it as a fatal + * error and immediately restart. + */ + case APM_CMD_GRAPH_OPEN: + case APM_CMD_GRAPH_CLOSE: + AR_ERR_DET_ERR("Graph open/close timeout. Desync likely. Restarting"); + *do_restart = true; + break; + + /* + * Timeout with generic commands is not immediately a problem. However + * if a lot of timeouts come in at once, likely there is something wrong + * on SPF. + * Thus, if we get enough timeouts in a short period of time, restart. + * + * If we get a few timeouts and then another one much later, we want to + * count these separately, so we will reset the number of timeouts counter + * and start our accumulation period from the later time. + */ + default: + sum = overflow_safe_add(ctxt->first_timeout_time_ms, ACCUMULATION_PERIOD_MS); + if (curr_time < sum) { + ++(ctxt->num_timeouts_curr_period); + if (ctxt->num_timeouts_curr_period >= MAX_TIMEOUTS_IN_PERIOD) { + AR_ERR_DET_ERR("Too many timeouts in short time. Restarting"); + *do_restart = true; + } + } else { + ctxt->first_timeout_time_ms = curr_time; + ctxt->num_timeouts_curr_period = 1; + } + } + break; + + /* + * EDUPLICATE indicates either 1) GSL + SPF are out of sync and we should restart + * or 2) the graph being opened is badly drawn and we can't do anything at + * runtime to fix it. + * Thus, if we get enough EDUPLICATE in a short period of time, assume it's + * case 1) and restart. + * However, if we continue getting EDUPLICATE after restarting, we can be reasonably + * sure it's case 2) and we ignore it for some time. Eventually, the probability + * of case 1) goes up and we can try restarting again. + * + * As with timeouts, if we get a few EDUPLICATE and then another one much later, + * we want to count these separately, so we will reset the number of EDUPLICATE + * counter and start our accumulation period from the later time. + */ + case AR_EDUPLICATE: + sum = overflow_safe_add(ctxt->first_eduplicate_time_ms, ACCUMULATION_PERIOD_MS); + if (curr_time < sum){ + ++(ctxt->num_eduplicate_curr_period); + if (ctxt->num_eduplicate_curr_period >= MAX_EDUPLICATE_IN_PERIOD) { + AR_ERR_DET_ERR("Too many EDuplicate. GSL/SPF desync or bad graph. Restarting"); + *do_restart = true; + } + } else { + ctxt->first_eduplicate_time_ms = curr_time; + ctxt->num_eduplicate_curr_period = 1; + } + + if (*do_restart) { + /* not all 1 if to avoid calculating this sum when no rc*/ + sum = overflow_safe_add(ctxt->last_restart_time_ms, MIN_TIME_EDUPLICATE_RESTART_MS); + if (curr_time < sum) { + AR_ERR_DET_INFO("Last DUPLICATE restart too recent. Silencing detected error"); + *do_restart = false; + } + } + break; + } + + /* + * We don't want to get stuck in a loop of constantly restarting, so we check + * that some time has passed since the last restart and avoid restarting if + * it's still too soon since. + */ + if (*do_restart) { + /* not all 1 if to avoid calculating this sum when no rc*/ + sum = overflow_safe_add(ctxt->last_restart_time_ms, MIN_TIME_ANY_RESTART_MS); + if (curr_time < sum) { + AR_ERR_DET_INFO("Last restart too recent. Silencing detected error"); + *do_restart = false; + } else { + ctxt->last_restart_time_ms = curr_time; + } + } + + return rc; +} + diff --git a/ar_util/src/ar_util_list.c b/ar_util/src/ar_util_list.c new file mode 100644 index 0000000..9c11e72 --- /dev/null +++ b/ar_util/src/ar_util_list.c @@ -0,0 +1,352 @@ +/** + * \file ar_util_list.c + * \brief + * This file contains the implementation for double linked list. + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_util_list.h" +#include "ar_osal_error.h" + + /* Verify that the header of the linking node points to itself. This helps + * catch programming errors where the same node is inserted more than once on + * a linked list. + */ +static int32_t ar_list_secure_node_is_unlinked(ar_list_t *list, ar_list_node_t *node) +{ + if ((list->en_secure) && ((node->next != node) || (node->prev != node))) + { + return AR_EBADPARAM; + } + + return AR_EOK; +} + +/* Verify that the header of the de-linking node is linked to a linked list. + * This helps catch memory corruption issues, and programming errors where + * the same node was inserted twice (i.e. init_node(node1), + * insert(list1, node1), insert(list2, node1), error). + */ +static int32_t ar_list_node_is_linked(ar_list_node_t *node) +{ + if ((node->prev->next != node) || (node->next->prev != node)) + { + return AR_EBADPARAM; + } + + return AR_EOK; +} + +static int32_t ar_list_insert_node_before(ar_list_t *list, + ar_list_node_t *ref_node, + ar_list_node_t *new_node) +{ + int32_t status = AR_EOK; + + status = ar_list_node_is_linked(ref_node); + if (status != AR_EOK) + { + goto end; + } + + status = ar_list_secure_node_is_unlinked(list, new_node); + if (status != AR_EOK) + { + goto end; + } + + new_node->list = list; + ref_node->prev->next = new_node; + new_node->prev = ref_node->prev; + new_node->next = ref_node; + ref_node->prev = new_node; + +end: + + return status; +} + +static int32_t ar_list_delete_node(ar_list_node_t *node) +{ + int32_t status = AR_EOK; + + status = ar_list_node_is_linked(node); + if (status != AR_EOK) + { + goto end; + } + + /* Verify that the header of the unlinking node was not already corrupted. + * This helps catch buffer overflow attacks targeting the linked list */ + node->prev->next = node->next; + node->next->prev = node->prev; + node->prev = node; + node->next = node; + +end: + return status; +} + + + +static int32_t ar_list_is_not_empty(ar_list_t *list) +{ + return (list->dummy.next != &list->dummy); +} + + +/** + * \brief ar_list_init: Initialize a list to itself. + * if lock_fn and unlock_fn are not provided + * client has to synchronize the list operations. + * + * \param[in] list: pointer to ar_list_t. + * \param[in_opt] lock_fn: lock function pointer. + * \param[in_opt] unlock_fn: unlock function pointer. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_init(ar_list_t *list, + ar_list_lock_enter_fn_t lock_fn, + ar_list_lock_leave_fn_t unlock_fn) +{ + int32_t status = AR_EOK; + + if (list == NULL) + { + status = AR_EBADPARAM; + goto end; + } + + list->dummy.prev = &list->dummy; + list->dummy.next = &list->dummy; + list->size = 0; + list->en_secure = 1; + list->unlock_fn = NULL; + list->lock_fn = NULL; + + if ((NULL != lock_fn) && (NULL != unlock_fn)) + { + list->lock_fn = lock_fn; + list->unlock_fn = unlock_fn; + } + +end: + return status; +} + +/** + * \brief ar_list_init_node: initialize the list node. + * + * \param[in] node: pointer to ar_list_node_t. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_init_node(ar_list_node_t *node) +{ + if (NULL == node) + { + return AR_EBADPARAM; + } + + node->list = NULL; + node->prev = node; + node->next = node; + + return AR_EOK; +} +/** + * \brief ar_list_add_tail: Add a node tot he tail of list. + * + * \param[in] list: pointer to ar_list_t. + * \param[in] node: node to be added to the list. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_add_tail(ar_list_t *list, ar_list_node_t *node) +{ + int32_t status = AR_EOK; + if ((list == NULL) || (node == NULL)) + { + status = AR_EBADPARAM; + goto end; + } + + if (list->lock_fn) + { + list->lock_fn(); + } + + status = ar_list_insert_node_before(list, &list->dummy, node); + if (AR_EOK == status) + { + list->size += 1; + } + + if (list->unlock_fn) + { + list->unlock_fn(); + } +end: + return status; +} +/** + * \brief ar_list_remove_head: Remove a node from head of the list. + * + * \param[in] list: pointer to ar_list_t. + * \param[out]ret_node: pointer to the removed node. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_remove_head(ar_list_t *list, ar_list_node_t **ret_node) +{ + int32_t status = AR_EOK; + ar_list_node_t *node = NULL; + + if (list == NULL || ret_node == NULL) + { + status = AR_EBADPARAM; + goto end; + } + + if (list->lock_fn) + { + list->lock_fn(); + } + + if (ar_list_is_empty(list)) + { + if (list->unlock_fn) + { + list->unlock_fn(); + } + status = AR_ENOTEXIST; + goto end; + } + + node = list->dummy.next; + + status = ar_list_delete_node(node); + if (AR_EOK != status) + { + if (list->unlock_fn) + { + list->unlock_fn(); + } + goto end; + } + + list->size -= 1; + if (list->unlock_fn) + { + list->unlock_fn(); + } + + *ret_node = node; + +end: + return status; +} + + +/** + * \brief ar_list_delete: delete a node from list. + * + * \param[in] list: pointer to ar_list_t. + * \param[in] node: pointer to node to be deleted. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_delete(ar_list_t *list, ar_list_node_t *node) +{ + int32_t status = AR_EOK; + + if (list == NULL || node == NULL) + { + status = AR_EBADPARAM; + goto end; + } + + if (list->lock_fn) + { + list->lock_fn(); + } + + status = ar_list_delete_node(node); + if (AR_EOK != status) + { + if (list->unlock_fn) + { + list->unlock_fn(); + } + goto end; + } + + list->size -= 1; + if (list->unlock_fn) + { + list->unlock_fn(); + } + +end: + return status; +} +/** + * \brief ar_list_clear: clear the list + * + * \param[in] list: pointer to ar_list_t. + * + * \return + * 0 -- Success + * Nonzero -- Failure + */ +int32_t ar_list_clear(ar_list_t *list) +{ + int32_t status = AR_EOK; + ar_list_node_t *node = NULL; + + if (list == NULL) + { + status = AR_EBADPARAM; + goto end; + } + + if (list->lock_fn) + { + list->lock_fn(); + } + + while (ar_list_is_not_empty(list)) + { + node = list->dummy.next; + status = ar_list_delete_node(node); + if (AR_EOK != status) + { + if (list->unlock_fn) + { + list->unlock_fn(); + } + goto end; + } + } + list->size = 0; + if (list->unlock_fn) + { + list->unlock_fn(); + } + +end: + return status; +} diff --git a/ar_util/test/inc/ar_osal_test.h b/ar_util/test/inc/ar_osal_test.h new file mode 100644 index 0000000..16bfc20 --- /dev/null +++ b/ar_util/test/inc/ar_osal_test.h @@ -0,0 +1,30 @@ +/** +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#pragma once + +#define LOG_TAG "ar_osal_test" + +void ar_test_file_main(); + +void ar_test_shmem_main(); + +void ar_test_util_list_main(); + +void ar_test_mutex_thread_main(); + +void ar_test_signal_thread_main(); + +void ar_test_sleep_main(); + +void ar_test_servreg_main(); + +void ar_test_heap_main(); + +void ar_test_mem_op_main(); + +void ar_test_string_main(); + +void ar_test_data_log_main(); + diff --git a/ar_util/test/src/ar_osal_mutex_thread.c b/ar_util/test/src/ar_osal_mutex_thread.c new file mode 100644 index 0000000..8ed1887 --- /dev/null +++ b/ar_util/test/src/ar_osal_mutex_thread.c @@ -0,0 +1,117 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include +#include "ar_osal_types.h" +#include "ar_osal_mutex.h" +#include "ar_osal_thread.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#include "ar_osal_test.h" + +#define THREADCOUNT (2) + +void *ghMutex = NULL; + +int32_t WriteToDatabase(void*); + +void ar_test_mutex_thread_main() +{ + int32_t status = 0; + void *aThread[THREADCOUNT] = { NULL }; + int32_t ThreadID = 0; + int32_t i = 0; + ar_osal_thread_attr_t osal_thread_attr = { NULL, 1024, 0 }; + int32_t test = 0; + + // Create a mutex + status = ar_osal_mutex_create(&ghMutex); // unnamed mutex + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_mutex_create error: %d", status); + goto end; + } + + // Create worker threads + for (i = 0; i < THREADCOUNT; i++) + { + status = ar_osal_thread_attr_init(&osal_thread_attr); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_thread_attr_init error: %d", status); + goto end; + } + + status = ar_osal_thread_create( + &aThread[i], + &osal_thread_attr, + (ar_osal_thread_start_routine)WriteToDatabase, + NULL); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_thread_create error: %d", status); + goto end; + } + } + + // Wait for all threads to terminate + for (i = 0; i < THREADCOUNT; i++) + { + status = ar_osal_thread_join_destroy(aThread[i]); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_thread_join_destroy for thread(%d) destroy failed (%d(", i, status); + goto end; + } + } + + // Close mutex handles + status = ar_osal_mutex_destroy(ghMutex); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_mutex_destroy destroy failed(%d)", status); + } + + /* fuzz test*/ + ar_osal_mutex_lock(NULL); + ar_osal_mutex_unlock(NULL); + ar_osal_mutex_lock(&test); + ar_osal_mutex_unlock(&test); +end: + return; +} + +int32_t WriteToDatabase(void* lpParam) +{ + // lpParam not used in this example,suppress warning + __UNREFERENCED_PARAM(lpParam); + + int32_t dwCount = 0; + int32_t status = AR_EOK; + + // Request ownership of mutex. + while (dwCount < 20) + { + status = ar_osal_mutex_lock( + ghMutex); // no time-out interval + if (AR_EOK == status) + { + dwCount++; + AR_LOG_INFO(LOG_TAG,"Thread 0x%Ix writing to database %d ", + ar_osal_thread_get_id(), dwCount); + // Release ownership of the mutex object + if (AR_EOK != ar_osal_mutex_unlock(ghMutex)) + { + AR_LOG_ERR(LOG_TAG,"Thread 0x%Ix osal_mutex_unlock failed", + ar_osal_thread_get_id()); + } + } + else + { + AR_LOG_ERR(LOG_TAG,"Thread 0x%Ix osal_mutex_lock failed", + ar_osal_thread_get_id()); + } + } + return AR_EOK; +} diff --git a/ar_util/test/src/ar_osal_signal_thread.c b/ar_util/test/src/ar_osal_signal_thread.c new file mode 100644 index 0000000..3c996d2 --- /dev/null +++ b/ar_util/test/src/ar_osal_signal_thread.c @@ -0,0 +1,152 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include +#include "ar_osal_types.h" +#include "ar_osal_signal.h" +#include "ar_osal_thread.h" +#include "ar_osal_error.h" +#include "ar_osal_test.h" +#include "ar_osal_log.h" + +#define THREADCOUNT (4) + +void* ghWriteEvent = NULL; +void* ghThreads[THREADCOUNT] = { NULL }; + +int32_t ThreadProc(void*); + +void CreateEventsAndThreads(void) +{ + int32_t i; + ar_osal_thread_attr_t osal_thread_attr = { NULL, 1024, 0 }; + + int32_t status = AR_EOK; + // Create a manual-reset event object. The write thread sets this + // object to the signaled state when it finishes writing to a + // shared buffer. + + status = ar_osal_signal_create(&ghWriteEvent); + if (NULL == ghWriteEvent || AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_signal_create failed (%d)", status); + return; + } + + status = ar_osal_signal_clear(ghWriteEvent); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_signal_clear failed (%d)", status); + return; + } + + // Create multiple threads to read from the buffer. + for (i = 0; i < THREADCOUNT; i++) + { + status = ar_osal_thread_attr_init(&osal_thread_attr); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_thread_attr_init error: %d", status); + return; + } + + status = ar_osal_thread_create( + &ghThreads[i], + &osal_thread_attr, + (ar_osal_thread_start_routine)ThreadProc, + NULL); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_thread_create error: %d", status); + return; + } + } +} + +void WriteToBuffer(void) +{ + int32_t status = AR_EOK; + + AR_LOG_INFO(LOG_TAG,"Main thread writing to the shared buffer..."); + + // Set ghWriteEvent to signaled + status = ar_osal_signal_set(ghWriteEvent); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_signal_set failed (%d)", status); + return; + } +} + +void CloseEvents() +{ + // Close all event handles (currently, only one global handle). + int32_t status = ar_osal_signal_destroy(ghWriteEvent); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"ar_osal_signal_destroy failed (%d)", status); + return; + } + + /*fuzz test*/ + ar_osal_signal_set(ghWriteEvent); + ar_osal_signal_destroy(ghWriteEvent); + ar_osal_signal_clear(ghWriteEvent); + ar_osal_signal_wait(ghWriteEvent); +} + +void ar_test_signal_thread_main() +{ + int32_t status = AR_EOK; + int32_t test = 0; + ar_osal_signal_t test_signal = NULL; + + // Create events and THREADCOUNT threads to read from the buffer + CreateEventsAndThreads(); + + WriteToBuffer(); + + AR_LOG_INFO(LOG_TAG,"Main thread waiting for threads to exit..."); + + for (int32_t i = 0; i < THREADCOUNT; i++) + { + status = ar_osal_thread_join_destroy(ghThreads[i]); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG," Thread[%d] ar_osal_thread_join_destroy() failed, err: %d ", i, status); + } + } + + if (AR_EOK == ar_osal_signal_clear(ghWriteEvent)) + { + AR_LOG_INFO(LOG_TAG, "Thread 0x%Ix thread cleared ", + ar_osal_thread_get_id()); + } + + /* fuzz test */ + ar_osal_signal_timedwait(ghWriteEvent,100000); + + CloseEvents(); + + /*fuzz test*/ + ar_osal_signal_wait(NULL); + + return; +} + +int32_t ThreadProc(void *lpParam) +{ + // lpParam not used in this example, suppress warning. + lpParam; + + AR_LOG_INFO(LOG_TAG,"Thread 0x%Ix waiting for write event...", ar_osal_thread_get_id()); + + if (AR_EOK == ar_osal_signal_wait(ghWriteEvent)) // indefinite wait + { + AR_LOG_INFO(LOG_TAG,"Thread 0x%Ix reading from buffer ", + ar_osal_thread_get_id()); + } + AR_LOG_INFO(LOG_TAG,"Thread 0x%Ix exiting ", ar_osal_thread_get_id()); + return 1; +} diff --git a/ar_util/test/src/ar_osal_test.c b/ar_util/test/src/ar_osal_test.c new file mode 100644 index 0000000..27e11a5 --- /dev/null +++ b/ar_util/test/src/ar_osal_test.c @@ -0,0 +1,73 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include +#include "ar_osal_test.h" +#include "ar_osal_log.h" + +void main() +{ + ar_log_init(); + + AR_LOG_DEBUG(NULL,"*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG," mutex thread test case starting "); + /* mutex thread test case*/ + ar_test_mutex_thread_main(); + AR_LOG_DEBUG(LOG_TAG," mutex thread test case ended "); + AR_LOG_DEBUG(LOG_TAG,"*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG," signal thread test case starting "); + /* signal thread test case*/ + ar_test_signal_thread_main(); + AR_LOG_DEBUG(LOG_TAG," signal thread test case ended "); + AR_LOG_DEBUG(LOG_TAG,"*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG," list test case starting "); + /* list test case*/ + ar_test_util_list_main(); + AR_LOG_DEBUG(LOG_TAG," list test case ended "); + AR_LOG_DEBUG(LOG_TAG,"*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG," shmem test case starting "); + /* shmem test case*/ + ar_test_shmem_main(); + AR_LOG_DEBUG(LOG_TAG," shmem test case ended "); + AR_LOG_DEBUG(LOG_TAG,"*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG," file IO test case starting "); + /* file io test case*/ + ar_test_file_main(); + AR_LOG_DEBUG(LOG_TAG," file IO test case ended "); + AR_LOG_DEBUG(LOG_TAG, "*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG, " sleep test case starting "); + /* sleep test case*/ + ar_test_sleep_main(); + AR_LOG_DEBUG(LOG_TAG, " sleep test case ended "); + AR_LOG_DEBUG(LOG_TAG, "*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG, " Servreg test case starting "); + /* Servreg test case*/ + ar_test_servreg_main(); + AR_LOG_DEBUG(LOG_TAG, " Servreg test case ended "); + AR_LOG_DEBUG(LOG_TAG, "*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG, " heap test case starting "); + /* Heap test case*/ + ar_test_heap_main(); + AR_LOG_DEBUG(LOG_TAG, " heap test case ended "); + AR_LOG_DEBUG(LOG_TAG, "*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG, " mem op test case starting "); + /* Mem op test case*/ + ar_test_mem_op_main(); + AR_LOG_DEBUG(LOG_TAG, " mem op test case ended "); + AR_LOG_DEBUG(LOG_TAG, "*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG, " string test case starting "); + /* string test case*/ + ar_test_string_main(); + AR_LOG_DEBUG(LOG_TAG, " string test case ended "); + AR_LOG_DEBUG(LOG_TAG, "*******************************************************************"); + AR_LOG_DEBUG(LOG_TAG, " data logging test case starting "); + /* data log test case*/ + ar_test_data_log_main(); + AR_LOG_DEBUG(LOG_TAG, " data logging test case ended "); + AR_LOG_DEBUG(LOG_TAG, "*******************************************************************"); + + + ar_log_deinit(); + return; +} diff --git a/ar_util/test/src/ar_osal_test_service.c b/ar_util/test/src/ar_osal_test_service.c new file mode 100644 index 0000000..2d29384 --- /dev/null +++ b/ar_util/test/src/ar_osal_test_service.c @@ -0,0 +1,250 @@ + /* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include +#include "ar_osal_types.h" +#include "ar_osal_signal.h" +#include "ar_osal_thread.h" +#include "ar_osal_error.h" +#include "ar_osal_test.h" +#include "ar_osal_log.h" +#include "ar_osal_servreg.h" +#include "ar_osal_sleep.h" +#include "ar_osal_sys_id.h" + +#define THREADCOUNT (4) + +void* gh_srv_Threads[THREADCOUNT] = { NULL }; +uint32_t ActiveThreads = 0; + +uint32_t svc_cb_context = 0xFFFF; + +void CreateTestThread(uint32_t thread_idx, ar_osal_thread_start_routine thread_func) +{ + ar_osal_thread_attr_t osal_thread_attr = { NULL, 1024, 0 }; + + int32_t status = AR_EOK; + + status = ar_osal_thread_attr_init(&osal_thread_attr); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "ar_osal_thread_attr_init error: %d", status); + return; + } + status = ar_osal_thread_create( + &gh_srv_Threads[thread_idx], + &osal_thread_attr, + thread_func, + NULL); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "ar_osal_thread_create, thread_idx(%d) error: %d", thread_idx, status); + return; + } +} + +//Service listener callback for service state updates. +void service_state_cb(ar_osal_servreg_t servreg_handle, ar_osal_servreg_cb_event_type event_id, + void *cb_context, void *payload, uint32_t payload_size) +{ + if (event_id == AR_OSAL_SERVICE_STATE_NOTIFY) + { + ar_osal_servreg_state_notify_payload_type *state = (ar_osal_servreg_state_notify_payload_type*)payload; + if (state->service_state == AR_OSAL_SERVICE_STATE_DOWN) + { + AR_LOG_ERR(LOG_TAG, "service_state_cb Service UP servreg_handle(0x%x), service(%s) service_instance(%d) domain(%s) domain_instance(%d)", + servreg_handle, state->service.name, state->service.instance_id, state->domain.name, state->domain.instance_id ); + } + else if (state->service_state == AR_OSAL_SERVICE_STATE_UP) + { + AR_LOG_ERR(LOG_TAG, "service_state_cb Service DOWN servreg_handle(0x%x), service(%s) service_instance(%d) domain(%s) domain_instance(%d)", + servreg_handle, state->service.name, state->service.instance_id, state->domain.name, state->domain.instance_id); + } + else + { + //error + AR_LOG_ERR(LOG_TAG, "service_state_cb Service INVALID state!!!!"); + } + } + return; +} + +//service provider to register service states +int32_t ServiceStateUpate(void *context) +{ + int32_t status = AR_EOK; + ar_osal_servreg_t sHandle = NULL; + ar_osal_servreg_entry_type svc_name = { "avs/audio", 0 }; + ar_osal_servreg_entry_type dmn_name[AR_SUB_SYS_ID_LAST] = { 0, 0 }; + uint32_t num_domains = 0; + + status = ar_osal_servreg_init(); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, "clientServiceListener ar_osal_servreg_init failed (0x%x)...", status); + goto end; + } + + status = ar_osal_servreg_get_domainlist(&svc_name, NULL, &num_domains); + if (status == AR_ENOMEMORY && AR_SUB_SYS_ID_LAST >= num_domains) + { + status = ar_osal_servreg_get_domainlist(&svc_name, dmn_name, &num_domains); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, " ServiceStateUpate ar_osal_servreg_get_domainlist failed, err: %d ", status); + goto end; + } + + for (uint8_t idx = 0; idx < num_domains; idx++) + { + AR_LOG_INFO(LOG_TAG, " ServiceStateUpate service_name:%s domain_name:%s ", svc_name.name, dmn_name[idx].name); + } + } + + svc_name.instance_id = dmn_name[AR_AUDIO_DSP].instance_id; + + sHandle = ar_osal_servreg_register(AR_OSAL_CLIENT_SERVICE_PROVIDER, NULL, NULL, + &dmn_name[AR_AUDIO_DSP], &svc_name); + if (NULL == sHandle) + { + AR_LOG_ERR(LOG_TAG, " ServiceStateUpate ar_osal_servreg_register failed, err: %d ", status); + goto end; + } + + status = ar_osal_servreg_set_state(sHandle, AR_OSAL_SERVICE_STATE_UP); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, " ServiceStateUpate ar_osal_servreg_set_state UP failed, err: %d ", status); + goto end; + } + + status = ar_osal_servreg_set_state(sHandle, AR_OSAL_SERVICE_STATE_DOWN); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, " ServiceStateUpate ar_osal_servreg_set_state DOWN failed, err: %d ", status); + goto end; + } + + status = ar_osal_servreg_set_state(sHandle, AR_OSAL_SERVICE_STATE_UP); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, " ServiceStateUpate ar_osal_servreg_set_state UP failed, err: %d ", status); + goto end; + } + + status = ar_osal_servreg_set_state(sHandle, AR_OSAL_SERVICE_STATE_DOWN); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, " ServiceStateUpate ar_osal_servreg_set_state DOWN failed, err: %d ", status); + goto end; + } + + status = ar_osal_servreg_deregister(sHandle); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, " ServiceStateUpate ar_osal_servreg_deregister failed, err: %d ", status); + goto end; + } + + status = ar_osal_servreg_deinit(); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, "ServiceStateUpate ar_osal_servreg_deinit failed (0x%x)...", status); + goto end; + } +end: + return status; +} + +int32_t clientServiceListener(void *context) +{ + int32_t status = AR_EOK; + ar_osal_servreg_t sHandle = NULL; + ar_osal_servreg_entry_type svc_name = { "avs/audio", 0 }; + ar_osal_servreg_entry_type dmn_name[AR_SUB_SYS_ID_LAST] = { 0, 0 }; + uint32_t num_domains = 0; + + status = ar_osal_servreg_init(); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, "clientServiceListener ar_osal_servreg_init failed (0x%x)...", status); + goto end; + } + + status = ar_osal_servreg_get_domainlist(&svc_name, NULL, &num_domains); + if (status == AR_ENOMEMORY && AR_SUB_SYS_ID_LAST >= num_domains) + { + status = ar_osal_servreg_get_domainlist(&svc_name, dmn_name, &num_domains); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, " clientServiceListener failed, err: %d ", status); + goto end; + } + } + + svc_name.instance_id = dmn_name[AR_AUDIO_DSP].instance_id; + + sHandle = ar_osal_servreg_register(AR_OSAL_CLIENT_LISTENER, service_state_cb, + (void*)&svc_cb_context, &dmn_name[AR_AUDIO_DSP], &svc_name); + if (NULL == sHandle) + { + AR_LOG_ERR(LOG_TAG, " clientServiceListener ar_osal_servreg_register failed, err: %d ", status); + goto end; + } + + //create state update sim thread + CreateTestThread(ActiveThreads++, ServiceStateUpate); + + //sleep for service to notify,before deregister. + ar_osal_micro_sleep(300000); + + /* To test case client doesn`t deregister. + status = ar_osal_servreg_deregister(sHandle); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, " clientServiceListener ar_osal_servreg_deregister failed, err: %d ", status); + goto end; + }*/ + status = ar_osal_servreg_deinit(); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, "clientServiceListener ar_osal_servreg_deinit failed (0x%x)...", status); + goto end; + } +end: + return status; +} + +void ar_test_servreg_main() +{ + int32_t status = AR_EOK; + int32_t test = 0; + ar_osal_signal_t test_signal = NULL; + ActiveThreads = 0; + + status = ar_osal_servreg_init(); + if (AR_FAILED(status)) + { + AR_LOG_ERR(LOG_TAG, "ar_test_service_thread_main ar_osal_servreg_init failed (0x%x)...", status); + goto end; + } + + // create first thread to get domain list and register for service notification. + CreateTestThread(ActiveThreads++, clientServiceListener); + + AR_LOG_INFO(LOG_TAG, "Main thread waiting for threads to exit..."); + for (uint32_t i = 0; i < ActiveThreads; i++) + { + status = ar_osal_thread_join_destroy(gh_srv_Threads[i]); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG, " Thread[%d] ar_osal_thread_join_destroy() failed, err: %d ", i, status); + } + } + //deinit + ar_osal_servreg_deinit(); +end: + return; +} + diff --git a/ar_util/test/src/ar_test_data_log.c b/ar_util/test/src/ar_test_data_log.c new file mode 100644 index 0000000..0a1ea98 --- /dev/null +++ b/ar_util/test/src/ar_test_data_log.c @@ -0,0 +1,1459 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause +*/ +#include +#include "ar_osal_file_io.h" +#include "ar_osal_error.h" +#include "ar_osal_types.h" +#include "ar_osal_test.h" +#include "ar_osal_log.h" +#include "ar_osal_heap.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_string.h" +#include "ar_osal_log_pkt_op.h" +#include "ar_util_data_log.h" +#include "ar_util_data_log_codes.h" +#include "ar_util_log_pkt_i.h" + +/* Test Notes +* +* +*/ + +#define AR_DATA_LOG_TEST_LOG_TAG "AR Data Logger Test" +#define AR_DATA_LOG_TEST_ERR(...) AR_LOG_ERR(AR_DATA_LOG_TEST_LOG_TAG, __VA_ARGS__) +#define AR_DATA_LOG_TEST_DBG(...) AR_LOG_DEBUG(AR_DATA_LOG_TEST_LOG_TAG, __VA_ARGS__) +#define AR_DATA_LOG_TEST_INFO(...) AR_LOG_INFO(AR_DATA_LOG_TEST_LOG_TAG, __VA_ARGS__) + +#define AR_TEST_DATA_LOG_FILE "ar_util_data_log_commit.bin" +#define AR_TEST_DIAG_PKT_HEADER_LENGTH 12 + +typedef struct ar_test_buffer_t +{ + size_t size; + uint32_t offset; + void* buffer; +}ar_test_buffer_t; + +/***************************************************************************** +* Function Callbacks +******************************************************************************/ + +typedef int32_t (*ar_test_read_pkt_callback_t)( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + void *info, + ar_test_buffer_t *rsp_buffer); + +typedef int32_t(*ar_test_reassemble_msg_callback_t)( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func); + +/***************************************************************************** +* Function Prototypes +******************************************************************************/ + +int32_t ar_test_pcm_data_logging(ar_heap_info *heap_info); +int32_t ar_test_bitstream_data_logging(ar_heap_info *heap_info); +int32_t ar_test_generic_data_logging(ar_heap_info *heap_info); +int32_t ar_test_raw_data_logging(ar_heap_info *heap_info); +int32_t ar_util_test_data_log_file_read( + const char_t *file, uint32_t file_access, + void *read_data, size_t read_size, size_t *file_size, size_t *bytes_read); +int32_t ar_test_verify_message(ar_heap_info *heap_info, + ar_test_buffer_t *expected_buffer, + ar_test_read_pkt_callback_t read_pkt_func, + ar_test_reassemble_msg_callback_t reassemble_pkt_buffer_func); + +int32_t ar_test_read_pcm_pkt( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + ar_log_pkt_cmn_audio_header_t *info, + ar_test_buffer_t *rsp_buffer); +int32_t ar_test_read_bitstream_pkt( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + ar_log_pkt_cmn_audio_header_t *info, + ar_test_buffer_t *rsp_buffer); +int32_t ar_test_read_generic_pkt( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + ar_log_pkt_fragment_info_t *info, + ar_test_buffer_t *rsp_buffer); +int32_t ar_test_read_raw_pkt( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + void *info, + ar_test_buffer_t *rsp_buffer); + +int32_t ar_test_reassemble_pcm_msg( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func); +int32_t ar_test_reassemble_bitstream_msg( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func); +int32_t ar_test_reassemble_generic_msg( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func); +int32_t ar_test_reassemble_raw_msg( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func); + +void ar_test_data_log_submit(); +void ar_test_data_log_commit(); + +int32_t ar_test_pcm_data_logging_commit(ar_heap_info *heap_info); +int32_t ar_test_bitstream_data_logging_commit(ar_heap_info *heap_info); +int32_t ar_test_generic_data_logging_commit(ar_heap_info *heap_info); +int32_t ar_test_raw_data_logging_commit(ar_heap_info *heap_info); + +/***************************************************************************** +* Test Functions +******************************************************************************/ + +void ar_test_data_log_main() +{ + AR_DATA_LOG_TEST_DBG("START: Data Logging 'Submit' tests"); + ar_test_data_log_submit(); + AR_DATA_LOG_TEST_DBG("END: Data Logging 'Submit' tests"); + + AR_DATA_LOG_TEST_DBG("START: Data Logging 'Commit' tests"); + ar_test_data_log_commit(); + AR_DATA_LOG_TEST_DBG("END: Data Logging 'Commit' tests"); +} + +void ar_test_data_log_submit() +{ + // Create *.bin file to store test data + char_t *file = "ar_util_data_log_commit.bin"; + int32_t status = AR_EOK; + uint32_t num_tests = 0; + //Heap + ar_heap_info heap_info = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + /* PCM Logging: Submit a buffer */ + ar_fdelete(file); + ar_test_pcm_data_logging(&heap_info); + if (AR_SUCCEEDED(status)) num_tests++; + + /* Bitstream Logging: Submit a buffer */ + ar_fdelete(file); + ar_test_bitstream_data_logging(&heap_info); + if (AR_SUCCEEDED(status)) num_tests++; + + /* Generic Logging: Submit a buffer */ + ar_fdelete(file); + ar_test_generic_data_logging(&heap_info); + if (AR_SUCCEEDED(status)) num_tests++; + + /* RAW Logging: Submit a buffer */ + ar_fdelete(file); + ar_test_raw_data_logging(&heap_info); + if (AR_SUCCEEDED(status)) num_tests++; +} + +void ar_test_data_log_commit() +{ + // Create *.bin file to store test data + char_t *file = "ar_util_data_log_commit.bin"; + int32_t status = AR_EOK; + uint32_t num_tests = 0; + //Heap + ar_heap_info heap_info = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + /* PCM Logging: Commit a packet */ + ar_fdelete(file); + status = ar_test_pcm_data_logging_commit(&heap_info); + if (AR_SUCCEEDED(status)) num_tests++; + + /* Bitstream Logging: Commit a packet */ + ar_fdelete(file); + status = ar_test_bitstream_data_logging_commit(&heap_info); + if (AR_SUCCEEDED(status)) num_tests++; + + /* Generic Logging: Commit a packet */ + ar_fdelete(file); + status = ar_test_generic_data_logging_commit(&heap_info); + if (AR_SUCCEEDED(status)) num_tests++; + + /* Raw Logging: Commit a packet */ + ar_fdelete(file); + status = ar_test_raw_data_logging_commit(&heap_info); + if (AR_SUCCEEDED(status)) num_tests++; +} +/***************************************************************************** +* Data logging 'Commit' Tests +******************************************************************************/ + +int32_t ar_test_pcm_data_logging_commit(ar_heap_info *heap_info) +{ + int32_t status = AR_EOK; + uint32_t max_pkt_length = ar_data_log_get_max_packet_size(); + uint32_t data_length = max_pkt_length - sizeof(ar_data_log_pkt_pcm_t); + ar_test_buffer_t expected_buffer = { 0 }; + ar_data_log_pcm_pkt_info_t pkt_info = { 0 }; + ar_data_log_commit_info_t commit_info = { 0 }; + ar_data_log_alloc_info_t dla_info = { 0 }; + void* log_pkt_data = NULL; + + const int16_t square_wave[] = + { + /* Start of channel 1 */ + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, + }; + + expected_buffer.buffer = (void*)square_wave; + expected_buffer.size = sizeof(square_wave); + + /* Allocate one log packet */ + dla_info.log_code = AR_DATA_LOG_CODE_UNUSED; + dla_info.pkt_type = AR_DATA_LOG_PKT_TYPE_AUDIO_PCM; + dla_info.buffer_size = data_length; + log_pkt_data = ar_data_log_alloc(&dla_info); + + ar_mem_cpy(log_pkt_data, sizeof(square_wave), + square_wave, sizeof(square_wave)); + + /* Set up packet information */ + uint32_t seq_number = 0xFEED0000; + pkt_info.seq_number_ptr = &seq_number; + pkt_info.log_time_stamp = 0; + pkt_info.data_info.media_fmt_id = 0; + pkt_info.data_info.pcm_data_fmt.num_channels = 2; + pkt_info.data_info.pcm_data_fmt.bits_per_sample = 16; + pkt_info.data_info.pcm_data_fmt.sampling_rate = 8000; + pkt_info.data_info.pcm_data_fmt.interleaved = 0; + /* use default channel map */ + pkt_info.data_info.pcm_data_fmt.channel_mapping = NULL; + + commit_info.buffer_size = max_pkt_length; + commit_info.log_pkt_data = log_pkt_data; + commit_info.log_tap_id = 0; + commit_info.pkt_info = &pkt_info; + commit_info.pkt_type = dla_info.pkt_type; + commit_info.session_id = 0; + + status = ar_data_log_commit(&commit_info); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to commit buffer", status); + goto end; + } + + //parse pkt_data and compare payload + status = ar_test_verify_message(heap_info, + &expected_buffer, ar_test_read_pcm_pkt, + ar_test_reassemble_pcm_msg); + +end: + + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "PCM Packet Logging 'commit' test failed", status); + } + + return status; +} + +int32_t ar_test_bitstream_data_logging_commit(ar_heap_info *heap_info) +{ + int32_t status = AR_EOK; + uint32_t max_pkt_length = ar_data_log_get_max_packet_size(); + uint32_t data_length = max_pkt_length - sizeof(ar_data_log_pkt_bit_stream_t); + ar_test_buffer_t expected_buffer = { 0 }; + ar_data_log_pcm_pkt_info_t pkt_info = { 0 }; + ar_data_log_commit_info_t commit_info = { 0 }; + ar_data_log_alloc_info_t dla_info = { 0 }; + void* log_pkt_data = NULL; + + const int16_t square_wave[] = + { + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, + }; + + expected_buffer.buffer = (void*)square_wave; + expected_buffer.size = sizeof(square_wave); + + /* Allocate one log packet */ + dla_info.log_code = AR_DATA_LOG_CODE_UNUSED; + dla_info.pkt_type = AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM; + dla_info.buffer_size = data_length; + log_pkt_data = ar_data_log_alloc(&dla_info); + + ar_mem_cpy(log_pkt_data, sizeof(square_wave), + square_wave, sizeof(square_wave)); + + /* Set up packet information */ + uint32_t seq_number = 0xFEED0000; + pkt_info.seq_number_ptr = &seq_number; + pkt_info.log_time_stamp = 0; + pkt_info.data_info.media_fmt_id = 0; + pkt_info.data_info.pcm_data_fmt.num_channels = 2; + pkt_info.data_info.pcm_data_fmt.bits_per_sample = 16; + pkt_info.data_info.pcm_data_fmt.sampling_rate = 8000; + pkt_info.data_info.pcm_data_fmt.interleaved = 0; + /* use default channel map */ + pkt_info.data_info.pcm_data_fmt.channel_mapping = NULL; + + commit_info.buffer_size = dla_info.buffer_size; + commit_info.log_pkt_data = log_pkt_data; + commit_info.log_tap_id = 0; + commit_info.pkt_info = &pkt_info; + commit_info.pkt_type = dla_info.pkt_type; + commit_info.session_id = 0; + + status = ar_data_log_commit(&commit_info); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to commit buffer", status); + goto end; + } + + //parse pkt_data and compare payload + status = ar_test_verify_message(heap_info, + &expected_buffer, ar_test_read_bitstream_pkt, + ar_test_reassemble_bitstream_msg); + +end: + + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Bitstream Packet Logging 'commit' test failed", status); + } + + return status; +} + +int32_t ar_test_generic_data_logging_commit(ar_heap_info *heap_info) +{ + int32_t status = AR_EOK; + uint32_t max_pkt_length = ar_data_log_get_max_packet_size(); + uint32_t data_length = max_pkt_length - sizeof(ar_data_log_pkt_generic_t); + ar_test_buffer_t expected_buffer = { 0 }; + ar_data_log_generic_pkt_info_t pkt_info = { 0 }; + ar_data_log_commit_info_t commit_info = { 0 }; + ar_data_log_alloc_info_t dla_info = { 0 }; + void* log_pkt_data = NULL; + + const char_t msg[] = + "This is a carefully written 68 byte" + " message to test generic packets"; + + expected_buffer.buffer = (void*)msg; + expected_buffer.size = sizeof(msg); + + /* Allocate one log packet */ + dla_info.log_code = AR_DATA_LOG_CODE_UNUSED; + dla_info.pkt_type = AR_DATA_LOG_PKT_TYPE_GENERIC; + dla_info.buffer_size = data_length; + log_pkt_data = ar_data_log_alloc(&dla_info); + + ar_mem_cpy(log_pkt_data, sizeof(msg), + msg, sizeof(msg)); + + /* Set up packet information */ + pkt_info.format = AR_LOG_PKT_GENERIC_FMT_RAW; + pkt_info.log_time_stamp = 0; + + commit_info.buffer_size = dla_info.buffer_size; + commit_info.log_pkt_data = log_pkt_data; + commit_info.log_tap_id = 0; + commit_info.pkt_info = &pkt_info; + commit_info.pkt_type = dla_info.pkt_type; + commit_info.session_id = 0; + + status = ar_data_log_commit(&commit_info); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to commit buffer", status); + goto end; + } + + //parse pkt_data and compare payload + status = ar_test_verify_message(heap_info, + &expected_buffer, ar_test_read_generic_pkt, + ar_test_reassemble_generic_msg); + +end: + + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Bitstream Packet Logging 'commit' test failed", status); + } + + return status; +} + +int32_t ar_test_raw_data_logging_commit(ar_heap_info *heap_info) +{ + int32_t status = AR_EOK; + uint32_t max_pkt_length = ar_data_log_get_max_packet_size(); + ar_test_buffer_t expected_buffer = { 0 }; + ar_data_log_commit_info_t commit_info = { 0 }; + ar_data_log_alloc_info_t dla_info = { 0 }; + void* log_pkt_data = NULL; + + const char_t msg[] = + "This is a carefully written 116 byte message for testing" + "the raw packet 'commit' functionality for sending a packet."; + + expected_buffer.buffer = (void*)msg; + expected_buffer.size = sizeof(msg); + + /* Allocate one log packet */ + dla_info.log_code = AR_DATA_LOG_CODE_UNUSED; + dla_info.pkt_type = AR_DATA_LOG_PKT_TYPE_RAW; + dla_info.buffer_size = max_pkt_length; + log_pkt_data = ar_data_log_alloc(&dla_info); + + ar_mem_cpy(log_pkt_data, sizeof(msg), + msg, sizeof(msg)); + + /* Set up packet information */ + commit_info.buffer_size = dla_info.buffer_size; + commit_info.log_pkt_data = log_pkt_data; + commit_info.log_tap_id = 0; + commit_info.pkt_info = NULL; + commit_info.pkt_type = dla_info.pkt_type; + commit_info.session_id = 0; + + status = ar_data_log_commit(&commit_info); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to commit buffer", status); + goto end; + } + + //parse pkt_data and compare payload + status = ar_test_verify_message(heap_info, + &expected_buffer, ar_test_read_raw_pkt, + ar_test_reassemble_raw_msg); + +end: + + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Raw Packet Logging 'commit' test failed", status); + } + + return status; +} + +/***************************************************************************** +* Data logging 'Submit' Tests +******************************************************************************/ + +int32_t ar_test_pcm_data_logging(ar_heap_info *heap_info) +{ + int32_t status = AR_EOK; + ar_test_buffer_t data_buffer = { 0 }; + ar_test_buffer_t expected_buffer = { 0 }; + ar_data_log_pcm_pkt_info_t pkt_info = { 0 }; + ar_data_log_submit_info_t submit_info = { 0 }; + + /* Generate data to submit */ + const int16_t square_wave[] = + { + /* Start of channel 1 */ + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + + /* Start of channel 2 */ + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, + }; + + const int16_t expected_square_wave[] = + { + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021,/*Channel 1*/ + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA,/*Channel 2*/ + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021,/*Channel 1*/ + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA,/*Channel 2*/ + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021,/*Channel 1*/ + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA,/*Channel 2*/ + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021,/*Channel 1*/ + 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA, 0xDDAA,/*Channel 2*/ + }; + + data_buffer.buffer = (void*)square_wave; + data_buffer.size = sizeof(square_wave); + + expected_buffer.buffer = (void*)expected_square_wave; + expected_buffer.size = sizeof(square_wave); + + /* Set up packet information */ + uint32_t seq_number = 0xFEED0000; + pkt_info.seq_number_ptr = &seq_number; + pkt_info.log_time_stamp = 0; + pkt_info.data_info.media_fmt_id = 0; + pkt_info.data_info.pcm_data_fmt.num_channels = 2; + pkt_info.data_info.pcm_data_fmt.bits_per_sample = 16; + pkt_info.data_info.pcm_data_fmt.sampling_rate = 8000; + pkt_info.data_info.pcm_data_fmt.interleaved = 0; + /* use default channel map */ + pkt_info.data_info.pcm_data_fmt.channel_mapping = NULL; + + submit_info.buffer = (int8_t*)data_buffer.buffer; + submit_info.buffer_size = (uint32_t)data_buffer.size; + submit_info.pkt_info = &pkt_info; + submit_info.pkt_type = AR_DATA_LOG_PKT_TYPE_AUDIO_PCM; + submit_info.log_code = AR_DATA_LOG_CODE_UNUSED; + submit_info.log_tap_id = 0; + submit_info.session_id = 0; + + status = ar_data_log_submit(&submit_info); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to submit buffer", status); + goto end; + } + + //parse pkt_data and compare payload + status = ar_test_verify_message(heap_info, + &expected_buffer, ar_test_read_pcm_pkt, + ar_test_reassemble_pcm_msg); + +end: + + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "PCM Packet Logging test failed", status); + } + + return status; +} + +int32_t ar_test_bitstream_data_logging(ar_heap_info *heap_info) +{ + int32_t status = AR_EOK; + ar_test_buffer_t data_buffer = { 0 }; + ar_data_log_pcm_pkt_info_t pkt_info = { 0 }; + ar_data_log_submit_info_t submit_info = { 0 }; + + /* Generate data to submit */ + const int16_t square_wave[] = + { + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, 0x0021, + + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, 0xFFDF, + + 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, + 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, + 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, + 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, + + 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, + 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, + 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, + 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, 0xCCDF, + + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + + 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, + 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, + 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, + 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, 0xAADF, + }; + + data_buffer.buffer = (void*)square_wave; + data_buffer.size = sizeof(square_wave); + + /* Set up packet information */ + uint32_t seq_number = 0xFEED0000; + pkt_info.seq_number_ptr = &seq_number; + pkt_info.log_time_stamp = 0; + pkt_info.data_info.media_fmt_id = 0; + pkt_info.data_info.pcm_data_fmt.num_channels = 2; + pkt_info.data_info.pcm_data_fmt.bits_per_sample = 16; + pkt_info.data_info.pcm_data_fmt.sampling_rate = 8000; + pkt_info.data_info.pcm_data_fmt.interleaved = 1; + /* use default channel map */ + pkt_info.data_info.pcm_data_fmt.channel_mapping = NULL; + + submit_info.buffer = (int8_t*)data_buffer.buffer; + submit_info.buffer_size = (uint32_t)data_buffer.size; + submit_info.pkt_info = &pkt_info; /* Null for RAW packets */ + submit_info.pkt_type = AR_DATA_LOG_PKT_TYPE_AUDIO_BITSTREAM; + submit_info.log_code = AR_DATA_LOG_CODE_UNUSED; + submit_info.log_tap_id = 0; + submit_info.session_id = 0; + + status = ar_data_log_submit(&submit_info); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to submit buffer", status); + goto end; + } + + //parse pkt_data and compare payload + status = ar_test_verify_message(heap_info, + &data_buffer, ar_test_read_bitstream_pkt, + ar_test_reassemble_bitstream_msg); + +end: + + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Bitstream Packet Logging test failed", status); + } + + return status; +} + +int32_t ar_test_generic_data_logging(ar_heap_info *heap_info) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t param_count = 5; + uint32_t param_data_size = 2 * sizeof(uint32_t); + ar_test_buffer_t cal_data_buffer = { 0 }; + ar_data_log_generic_pkt_info_t pkt_info = { 0 }; + ar_data_log_submit_info_t submit_info = { 0 }; + + struct test_param { + uint32_t value; + uint32_t reserved; + }; + + struct spf_cal_data_header { + uint32_t instance_id; + uint32_t param_id; + uint32_t size; + uint32_t error_code; + }; + + struct spf_cal_data_header param_cal_header = { 0 }; + struct test_param param_cal = { 0 }; + + /* Generate data to submit */ + cal_data_buffer.size = param_count * (sizeof(struct spf_cal_data_header) + param_data_size); + cal_data_buffer.buffer = ar_heap_malloc( + cal_data_buffer.size, heap_info); + + param_cal_header.param_id = 0xfeeddead;//Feed Dead + param_cal_header.error_code = AR_EOK; + param_cal_header.size = param_data_size; + param_cal.value = 0xfade0000;//Fade + + for (uint32_t i = 0; i < param_count; i++) + { + param_cal_header.instance_id = i; + + status = ar_mem_cpy( + (uint8_t*)cal_data_buffer.buffer + offset, sizeof(param_cal_header), + (void*)¶m_cal_header, sizeof(param_cal_header)); + offset += sizeof(param_cal_header); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR( + "Status[%d]: Unable to memcpy cal data header", status); + goto end; + } + + status = ar_mem_cpy( + (uint8_t*)cal_data_buffer.buffer + offset, sizeof(param_cal), + (void*)¶m_cal, sizeof(param_cal)); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR( + "Status[%d]: Unable to memcpy cal data", status); + goto end; + } + + offset += param_data_size; + param_cal.value++; + } + + /* Set up packet information */ + pkt_info.format = AR_LOG_PKT_GENERIC_FMT_CAL_BLOB; + pkt_info.log_time_stamp = 0; + + submit_info.buffer = (int8_t*)cal_data_buffer.buffer; + submit_info.buffer_size = (uint32_t)cal_data_buffer.size; + submit_info.pkt_info = &pkt_info; + submit_info.pkt_type = AR_DATA_LOG_PKT_TYPE_GENERIC; + submit_info.log_code = AR_DATA_LOG_CODE_ATS; + submit_info.log_tap_id = 0; + submit_info.session_id = 0; + + status = ar_data_log_submit(&submit_info); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to submit buffer", status); + goto end; + } + + //parse pkt_data and compare payload + status = ar_test_verify_message(heap_info, + &cal_data_buffer, ar_test_read_generic_pkt, + ar_test_reassemble_generic_msg); + +end: + if(cal_data_buffer.buffer) + ar_heap_free(cal_data_buffer.buffer, heap_info); + + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Generic Packet Logging test failed", status); + } + return status; +} + +int32_t ar_test_raw_data_logging(ar_heap_info *heap_info) +{ + int32_t status = AR_EOK; + ar_test_buffer_t data_buffer = { 0 }; + ar_data_log_submit_info_t submit_info = { 0 }; + char_t *phrase = NULL; + + /* Generate data to submit + * + * The message needs to be long enough to make the data logging + * utility split the message into multiple packets + * + * Lorem ipsum text + */ + phrase = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " + "do eiusmod tempor incididunt ut labore et dolore magna " + "aliqua. Ut enim ad minim veniam, quis nostrud exercitation " + "ullamco laboris nisi ut aliquip ex ea commodo consequat. " + "Duis aute irure dolor in reprehenderit in voluptate velit " + "esse cillum dolore eu fugiat nulla pariatur. Excepteur " + "sint occaecat cupidatat non proident, sunt in culpa qui " + "officia deserunt mollit anim id est laborum."; + + data_buffer.buffer = phrase; + data_buffer.size = 446; + + /* Set up packet information */ + submit_info.buffer = (int8_t*)data_buffer.buffer; + submit_info.buffer_size = (uint32_t)data_buffer.size; + submit_info.pkt_info = NULL; /* Null for RAW packets */ + submit_info.pkt_type = AR_DATA_LOG_PKT_TYPE_RAW; + submit_info.log_code = AR_DATA_LOG_CODE_ATS; + submit_info.log_tap_id = 0; + submit_info.session_id = 0; + + status = ar_data_log_submit(&submit_info); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to submit buffer", status); + goto end; + } + + //parse pkt_data and compare payload + status = ar_test_verify_message(heap_info, + &data_buffer, ar_test_read_raw_pkt, + ar_test_reassemble_raw_msg); + +end: + + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Raw Packet Logging test failed", status); + } + + return status; +} + +/***************************************************************************** +* Parse Packets and return the submitted message buffer +******************************************************************************/ + +int32_t ar_test_read_pcm_pkt( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + ar_log_pkt_cmn_audio_header_t *info, + ar_test_buffer_t *rsp_buffer) +{ + int32_t status = AR_EOK; + uint8_t *pkt_ptr = NULL; + ar_data_log_pkt_pcm_t *log_pkt = NULL; + + if (!pkt_buffer || !heap_info || !info || !rsp_buffer) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "One ore more input parameters are null", status); + return AR_EBADPARAM; + } + + pkt_ptr = (uint8_t*)pkt_buffer->buffer + pkt_buffer->offset; + + pkt_ptr += AR_TEST_DIAG_PKT_HEADER_LENGTH; + pkt_buffer->offset += AR_TEST_DIAG_PKT_HEADER_LENGTH; + log_pkt = (ar_data_log_pkt_pcm_t*)pkt_ptr; + + pkt_ptr += sizeof(ar_data_log_pkt_pcm_t) + + log_pkt->header.cmn_struct.fragment_size; + pkt_buffer->offset += sizeof(ar_data_log_pkt_pcm_t) + + log_pkt->header.cmn_struct.fragment_size; + + info->fragment_size = log_pkt->header.cmn_struct.fragment_size; + info->log_fragment_number = log_pkt->header.cmn_struct.log_fragment_number; + info->fragment_offset = log_pkt->header.cmn_struct.fragment_offset; + + if (!rsp_buffer->buffer) + { + rsp_buffer->buffer = ar_heap_malloc(rsp_buffer->size, heap_info); + if (!rsp_buffer->buffer) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Not enough memory to allocate buffer", status); + return AR_ENOMEMORY; + } + } + + status = ar_mem_cpy( + (uint8_t*)rsp_buffer->buffer + info->fragment_offset, + info->fragment_size, + log_pkt->payload, info->fragment_size); + if (AR_FAILED(status)) + { + ar_heap_free(rsp_buffer->buffer, heap_info); + + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to copy packet to response buffer", status); + } + + return status; +} + +int32_t ar_test_read_bitstream_pkt( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + ar_log_pkt_cmn_audio_header_t *info, + ar_test_buffer_t *rsp_buffer) +{ + int32_t status = AR_EOK; + uint8_t *pkt_ptr = NULL; + ar_data_log_pkt_bit_stream_t *log_pkt = NULL; + + if (!pkt_buffer || !heap_info || !info || !rsp_buffer) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "One ore more input parameters are null", status); + return AR_EBADPARAM; + } + + pkt_ptr = (uint8_t*)pkt_buffer->buffer + pkt_buffer->offset; + + pkt_ptr += AR_TEST_DIAG_PKT_HEADER_LENGTH; + pkt_buffer->offset += AR_TEST_DIAG_PKT_HEADER_LENGTH; + log_pkt = (ar_data_log_pkt_bit_stream_t*)pkt_ptr; + + pkt_ptr += sizeof(ar_data_log_pkt_bit_stream_t) + + log_pkt->header.cmn_struct.fragment_size; + pkt_buffer->offset += sizeof(ar_data_log_pkt_bit_stream_t) + + log_pkt->header.cmn_struct.fragment_size; + + info->fragment_size = log_pkt->header.cmn_struct.fragment_size; + info->log_fragment_number = log_pkt->header.cmn_struct.log_fragment_number; + info->fragment_offset = log_pkt->header.cmn_struct.fragment_offset; + + if (!rsp_buffer->buffer) + { + rsp_buffer->buffer = ar_heap_malloc(rsp_buffer->size, heap_info); + if (!rsp_buffer->buffer) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Not enough memory to allocate buffer", status); + return AR_ENOMEMORY; + } + } + + status = ar_mem_cpy( + (uint8_t*)rsp_buffer->buffer + info->fragment_offset, + info->fragment_size, + log_pkt->payload, info->fragment_size); + if (AR_FAILED(status)) + { + ar_heap_free(rsp_buffer->buffer, heap_info); + + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to copy packet to response buffer", status); + } + + return status; +} + +int32_t ar_test_read_generic_pkt( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + ar_log_pkt_fragment_info_t *info, + ar_test_buffer_t *rsp_buffer) +{ + int32_t status = AR_EOK; + uint8_t *pkt_ptr = NULL; + ar_data_log_pkt_generic_t *log_pkt = NULL; + + if (!pkt_buffer || !heap_info || !info || !rsp_buffer) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "One ore more input parameters are null", status); + return AR_EBADPARAM; + } + + pkt_ptr = (uint8_t*)pkt_buffer->buffer + *pkt_buffer_offset; + + pkt_ptr += AR_TEST_DIAG_PKT_HEADER_LENGTH; + *pkt_buffer_offset += AR_TEST_DIAG_PKT_HEADER_LENGTH; + log_pkt = (ar_data_log_pkt_generic_t*)pkt_ptr; + + pkt_ptr += sizeof(ar_data_log_pkt_generic_t) + + log_pkt->header.info.fragment_length; + *pkt_buffer_offset += sizeof(ar_data_log_pkt_generic_t) + + log_pkt->header.info.fragment_length; + + //pkt_buffer->offset += *pkt_buffer_offset; + + info->buffer_length = log_pkt->header.info.buffer_length; + info->fragment_count = log_pkt->header.info.fragment_count; + info->fragment_length = log_pkt->header.info.fragment_length; + info->fragment_num = log_pkt->header.info.fragment_num; + info->fragment_offset = log_pkt->header.info.fragment_offset; + + if (!rsp_buffer->buffer) + { + rsp_buffer->size = info->buffer_length; + rsp_buffer->buffer = ar_heap_malloc(info->buffer_length, heap_info); + if (!rsp_buffer->buffer) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Not enough memory to allocate buffer", status); + return AR_ENOMEMORY; + } + } + + status = ar_mem_cpy( + (uint8_t*)rsp_buffer->buffer + info->fragment_offset, + info->fragment_length, + log_pkt->payload, info->fragment_length); + if (AR_FAILED(status)) + { + ar_heap_free(rsp_buffer->buffer, heap_info); + + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to copy packet to response buffer", status); + } + + return status; +} + +int32_t ar_test_read_raw_pkt( + ar_heap_info *heap_info, + ar_test_buffer_t *pkt_buffer, + uint32_t *pkt_buffer_offset, + void *info, + ar_test_buffer_t *rsp_buffer) +{ + __UNREFERENCED_PARAM(info); + + int32_t status = AR_EOK; + uint8_t *pkt_ptr = NULL; + uint8_t *log_pkt = NULL; + uint32_t pkt_data_length = 0; + uint32_t pkt_length = 0; + uint32_t size_remaining = 0; + + if (!pkt_buffer || !heap_info || !rsp_buffer) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "One ore more input parameters are null", status); + return AR_EBADPARAM; + } + + size_remaining = (uint32_t)pkt_buffer->size - *pkt_buffer_offset; + pkt_data_length = ar_log_pkt_get_max_size(); + pkt_length = AR_TEST_DIAG_PKT_HEADER_LENGTH + pkt_data_length; + pkt_ptr = (uint8_t*)pkt_buffer->buffer + *pkt_buffer_offset; + + pkt_ptr += AR_TEST_DIAG_PKT_HEADER_LENGTH; + *pkt_buffer_offset += AR_TEST_DIAG_PKT_HEADER_LENGTH; + log_pkt = pkt_ptr; + + if (!rsp_buffer->buffer) + { + rsp_buffer->buffer = ar_heap_malloc(rsp_buffer->size, heap_info); + if (!rsp_buffer->buffer) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Not enough memory to allocate buffer", status); + return AR_ENOMEMORY; + } + } + + if (size_remaining < pkt_data_length) + pkt_data_length = size_remaining - AR_TEST_DIAG_PKT_HEADER_LENGTH; + + status = ar_mem_cpy( + (uint8_t*)rsp_buffer->buffer + rsp_buffer->offset, + pkt_data_length, + log_pkt, pkt_data_length); + if (AR_FAILED(status)) + { + ar_heap_free(rsp_buffer->buffer, heap_info); + + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to copy packet to response buffer", status); + } + + *pkt_buffer_offset += pkt_data_length; + + return status; +} + + +//int32_t ar_test_parse_generic_pkt_file(ar_heap_info *heap_info, ar_test_buffer_t *expected_buffer) +//{ +// int32_t status = AR_EOK; +// size_t bytes_read = 0; +// uint32_t offset = 0; +// uint32_t pkt_buffer_offset = 0; +// char_t *file = "ar_util_data_log_commit.bin"; +// ar_test_buffer_t pkt_buffer = { 0 }; +// ar_test_buffer_t rsp_buffer = { 0 }; +// ar_log_pkt_fragment_info_t info = { 0 }; +// +// if (!heap_info || !expected_buffer) +// { +// AR_DATA_LOG_TEST_ERR("Status[%d]: " +// "One ore more input parameters are null", status); +// return AR_EBADPARAM; +// } +// +// /* Read file and reassemble buffer to ensure the same +// * contents were sent successfully */ +// status = ar_util_test_data_log_file_read( +// file, AR_FOPEN_READ_ONLY, pkt_buffer.buffer, +// 0, &pkt_buffer.size, &bytes_read); +// if (AR_FAILED(status)) +// { +// AR_DATA_LOG_TEST_ERR("Status[%d]: " +// "Failed to get file size: %s", status, file); +// } +// +// pkt_buffer.buffer = ar_heap_malloc(pkt_buffer.size, heap_info); +// +// status = ar_util_test_data_log_file_read( +// file, AR_FOPEN_READ_ONLY, pkt_buffer.buffer, +// pkt_buffer.size, &pkt_buffer.size, &bytes_read); +// if (AR_FAILED(status)) +// { +// AR_DATA_LOG_TEST_ERR("Status[%d]: " +// "Failed to read file: %s", status, file); +// } +// +// /* Reassemble buffer by extracting payload from each packet. +// * Get the first packet */ +// status = ar_test_read_generic_pkt(heap_info, &pkt_buffer, +// &pkt_buffer_offset, &info, &rsp_buffer); +// if (AR_FAILED(status)) +// { +// AR_DATA_LOG_TEST_ERR("Status[%d]: " +// "Failed to read file: %s", status, file); +// return status; +// } +// +// //Read remaining packets if any +// offset = info.fragment_length; +// while (offset < info.buffer_length) +// { +// status = ar_test_read_generic_pkt(heap_info, &pkt_buffer, +// &pkt_buffer_offset, &info, &rsp_buffer); +// if (AR_FAILED(status)) +// { +// AR_DATA_LOG_TEST_ERR("Status[%d]: " +// "Failed to read file: %s", status, file); +// } +// +// offset += info.fragment_length; +// } +// +// //Compare response from packet to expected response +// if ((expected_buffer->size != rsp_buffer.size) || +// 0 != ar_mem_cmp( +// expected_buffer->buffer, rsp_buffer.buffer, expected_buffer->size)) +// { +// status = AR_EFAILED; +// AR_DATA_LOG_TEST_ERR("Status[%d]: The expected response and " +// "the packet response are different", status); +// } +// +// ar_heap_free(rsp_buffer.buffer, heap_info); +// +// status = ar_fdelete(file); +// if (AR_FAILED(status)) +// { +// AR_DATA_LOG_TEST_ERR("Status[%d]: Failed to delete file", status); +// } +// +// return status; +//} + +int32_t ar_test_reassemble_pcm_msg( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t pkt_buffer_offset = 0; + ar_log_pkt_cmn_audio_header_t info = { 0 }; + uint32_t pkt_data_length = ar_log_pkt_get_max_size() + - sizeof(ar_log_pkt_pcm_header_t); + uint32_t max_pkt_size = ar_log_pkt_get_max_size() + + AR_TEST_DIAG_PKT_HEADER_LENGTH; + uint32_t last_pkt_size = pkt_buffer->size % max_pkt_size; + uint32_t last_pkt_data_length = last_pkt_size == 0 ? 0 : + last_pkt_size + - AR_TEST_DIAG_PKT_HEADER_LENGTH + - sizeof(ar_log_pkt_pcm_header_t); + uint32_t num_pkts = last_pkt_size == 0 ? + (uint32_t)pkt_buffer->size / max_pkt_size : + (uint32_t)pkt_buffer->size / max_pkt_size + 1; + uint32_t pkt_index = 0; + + //determine total size of response msg buffer + rsp_buffer->size = last_pkt_size == 0 ? + (pkt_data_length)* num_pkts : + (pkt_data_length) * (num_pkts - 1) + + last_pkt_data_length; + + /* Reassemble buffer by extracting payload from each packet. + * Get the first packet */ + status = read_pkt_func(heap_info, pkt_buffer, + &pkt_buffer_offset, &info, rsp_buffer); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to generic pkt buffer", status); + return status; + } + + //Read remaining packets if any + while (pkt_buffer->offset < pkt_buffer->size) + { + status = read_pkt_func(heap_info, pkt_buffer, + &pkt_buffer_offset, &info, rsp_buffer); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to read raw pkt buffer", status); + } + } + + return status; +} + +int32_t ar_test_reassemble_bitstream_msg( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t pkt_buffer_offset = 0; + ar_log_pkt_cmn_audio_header_t info = { 0 }; + uint32_t pkt_data_length = ar_log_pkt_get_max_size() + - sizeof(ar_log_pkt_bitstream_header_t); + uint32_t max_pkt_size = ar_log_pkt_get_max_size() + + AR_TEST_DIAG_PKT_HEADER_LENGTH; + uint32_t last_pkt_size = pkt_buffer->size % max_pkt_size; + uint32_t last_pkt_data_length = last_pkt_size == 0 ? 0 : + last_pkt_size + - AR_TEST_DIAG_PKT_HEADER_LENGTH + - sizeof(ar_log_pkt_bitstream_header_t); + uint32_t num_pkts = last_pkt_size == 0 ? + (uint32_t)pkt_buffer->size / max_pkt_size : + (uint32_t)pkt_buffer->size / max_pkt_size + 1; + uint32_t pkt_index = 0; + + //determine total size of response msg buffer + rsp_buffer->size = last_pkt_size == 0 ? + (pkt_data_length)* num_pkts : + (pkt_data_length) * (num_pkts - 1) + + last_pkt_data_length; + + /* Reassemble buffer by extracting payload from each packet. + * Get the first packet */ + status = read_pkt_func(heap_info, pkt_buffer, + &pkt_buffer_offset, &info, rsp_buffer); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to generic pkt buffer", status); + return status; + } + + //Read remaining packets if any + while (pkt_buffer->offset < pkt_buffer->size) + { + status = read_pkt_func(heap_info, pkt_buffer, + &pkt_buffer_offset, &info, rsp_buffer); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to read raw pkt buffer", status); + } + } + + return status; +} + +int32_t ar_test_reassemble_generic_msg( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t pkt_buffer_offset = 0; + ar_log_pkt_fragment_info_t info = { 0 }; + + /* Reassemble buffer by extracting payload from each packet. + * Get the first packet */ + status = read_pkt_func(heap_info, pkt_buffer, + &pkt_buffer_offset, &info, rsp_buffer); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to generic pkt buffer", status); + return status; + } + + //Read remaining packets if any + offset = info.fragment_length; + while (offset < info.buffer_length) + { + status = read_pkt_func(heap_info, pkt_buffer, + &pkt_buffer_offset, &info, rsp_buffer); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to generic pkt buffer", status); + } + + offset += info.fragment_length; + } + + return status; +} + +int32_t ar_test_reassemble_raw_msg( + ar_test_buffer_t *pkt_buffer, ar_test_buffer_t *rsp_buffer, + ar_heap_info *heap_info, ar_test_read_pkt_callback_t read_pkt_func) +{ + int32_t status = AR_EOK; + uint32_t offset = 0; + uint32_t pkt_buffer_offset = 0; + uint32_t pkt_data_length = ar_log_pkt_get_max_size(); + uint32_t max_pkt_size = ar_log_pkt_get_max_size() + + AR_TEST_DIAG_PKT_HEADER_LENGTH; + uint32_t last_pkt_size = pkt_buffer->size % max_pkt_size; + uint32_t last_pkt_data_length = last_pkt_size == 0? 0: + last_pkt_size - AR_TEST_DIAG_PKT_HEADER_LENGTH; + uint32_t num_pkts = last_pkt_size == 0 ? + (uint32_t)pkt_buffer->size / max_pkt_size : + (uint32_t)pkt_buffer->size / max_pkt_size + 1; + uint32_t pkt_index = 0; + //determine total size of response buffer for raw packet data + rsp_buffer->size = last_pkt_size == 0 ? + (pkt_data_length) * num_pkts: + (pkt_data_length) * (num_pkts - 1) + + last_pkt_data_length; + + //Read remaining packets if any + while (offset < pkt_buffer->size) + { + status = read_pkt_func(heap_info, pkt_buffer, + &pkt_buffer_offset, NULL, rsp_buffer); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to read raw pkt buffer", status); + } + + if(pkt_index == num_pkts - 1 && last_pkt_size != 0) + rsp_buffer->offset += last_pkt_data_length; + else + rsp_buffer->offset += pkt_data_length; + + + offset += max_pkt_size; + pkt_index++; + } + + return status; +} + +int32_t ar_test_verify_message(ar_heap_info *heap_info, + ar_test_buffer_t *expected_msg, + ar_test_read_pkt_callback_t read_pkt_func, + ar_test_reassemble_msg_callback_t reassemble_msg_func) +{ + int32_t status = AR_EOK; + size_t bytes_read = 0; + uint32_t offset = 0; + uint32_t pkt_buffer_offset = 0; + char_t *file = "ar_util_data_log_commit.bin"; + ar_test_buffer_t pkt_buffer = { 0 }; + ar_test_buffer_t rsp_buffer = { 0 }; + + if (!heap_info || !expected_msg) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "One ore more input parameters are null", status); + return AR_EBADPARAM; + } + + /* Read file and reassemble buffer to ensure the same + * contents were sent successfully */ + status = ar_util_test_data_log_file_read( + file, AR_FOPEN_READ_ONLY, pkt_buffer.buffer, + 0, &pkt_buffer.size, &bytes_read); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to get file size: %s", status, file); + } + + pkt_buffer.buffer = ar_heap_malloc(pkt_buffer.size, heap_info); + + status = ar_util_test_data_log_file_read( + file, AR_FOPEN_READ_ONLY, pkt_buffer.buffer, + pkt_buffer.size, &pkt_buffer.size, &bytes_read); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to read file: %s", status, file); + } + + /* Reassemble buffer by extracting payload from each packet */ + status = reassemble_msg_func( + &pkt_buffer, &rsp_buffer, heap_info, read_pkt_func); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: " + "Failed to reassemble buffer", status); + return status; + } + + /* Compare response from packet to expected response */ + if ((expected_msg->size != rsp_buffer.size) || + 0 != ar_mem_cmp( + expected_msg->buffer, rsp_buffer.buffer, expected_msg->size)) + { + status = AR_EFAILED; + AR_DATA_LOG_TEST_ERR("Status[%d]: The expected response and " + "the packet response are different", status); + } + + ar_heap_free(rsp_buffer.buffer, heap_info); + + status = ar_fdelete(file); + if (AR_FAILED(status)) + { + AR_DATA_LOG_TEST_ERR("Status[%d]: Failed to delete file", status); + } + + return status; +} + +/***************************************************************************** +* Read Operations +******************************************************************************/ + +int32_t ar_util_test_data_log_file_read( + const char_t *file, uint32_t file_access, + void *read_data, size_t read_size, size_t *file_size, size_t *bytes_read) +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + + status = ar_fopen(&fhandle, file, file_access); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to open the file:%s:error:%d ", file, status); + goto end; + } + + if (!read_data) + { + *file_size = ar_fsize(fhandle); + goto end; + } + + /* read data */ + status = ar_fread(fhandle, read_data, read_size, bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to read the file %d ", status); + goto end; + } + + *file_size = ar_fsize(fhandle); + +end: + if (fhandle) + { + // close file + status = ar_fclose(fhandle); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to close file %d ", status); + } + } + return status; +} diff --git a/ar_util/test/src/ar_test_file_io.c b/ar_util/test/src/ar_test_file_io.c new file mode 100644 index 0000000..ee20a11 --- /dev/null +++ b/ar_util/test/src/ar_test_file_io.c @@ -0,0 +1,506 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include +#include "ar_osal_file_io.h" +#include "ar_osal_error.h" +#include "ar_osal_types.h" +#include "ar_osal_test.h" +#include "ar_osal_log.h" + +int32_t ar_osal_test_file_write(const char_t *file, uint32_t file_access, void *write_data, size_t data_size) +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t bytes_written = 0; + + /* open file*/ + status = ar_fopen(&fhandle, file, file_access); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to open the file %s:error:%d ", file, status); + goto end; + } + + /* write into file */ + AR_LOG_INFO(LOG_TAG, "write data: %s", write_data); + + /* write data */ + status = ar_fwrite(fhandle, write_data, data_size, &bytes_written); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to write into the file %d ", status); + goto end; + } + if (bytes_written != data_size) + { + //print + AR_LOG_INFO(LOG_TAG, "failed write file size not matching "); + } + +end: + if (fhandle) + { + // close file + status = ar_fclose(fhandle); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to close file %d ", status); + } + } + return status; +} + +int32_t ar_osal_test_file_read(const char_t *file, uint32_t file_access, void *read_data, size_t read_size, size_t *bytes_read) +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + + status = ar_fopen(&fhandle, file, file_access); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to open the file:%s:error:%d ", file, status); + goto end; + } + + /* read data */ + status = ar_fread(fhandle, read_data, read_size, bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to read the file %d ", status); + goto end; + } + +end: + if (fhandle) + { + // close file + status = ar_fclose(fhandle); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to close file %d ", status); + } + } + return status; +} + + +void ar_test_file_read_only() +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t bytes_read = 0; + char_t data_read[50] = { 0 }; + char_t data[] = "File read only test"; + char_t *file = "read_only_file.txt"; + + status = ar_fopen(&fhandle, file, AR_FOPEN_READ_ONLY); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to open the file:%s:error:%d for read (**expected) ", file, status); + } + + status = ar_osal_test_file_write(file, AR_FOPEN_WRITE_ONLY, data, sizeof(data)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to created a test file error:%d ", status); + goto end; + } + + status = ar_osal_test_file_read(file, AR_FOPEN_READ_ONLY, data_read, sizeof(data_read), &bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_ONLY error:%d ", status); + goto end; + } + + AR_LOG_INFO(LOG_TAG, "read data: %s", data_read); +end: + ar_fdelete(file); + return; +} + +void ar_test_file_write_only() +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t bytes_read = 0; + char_t data_read[50] = { 0 }; + char_t data[] = "File write only test"; + char_t *file = "write_only_file.txt"; + + // write data first time. + status = ar_osal_test_file_write(file, AR_FOPEN_WRITE_ONLY, data, sizeof(data)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to created a test file error:%d ", status); + goto end; + } + + //write data second time + status = ar_osal_test_file_write(file, AR_FOPEN_WRITE_ONLY, data, sizeof(data)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to created a test file error:%d ", status); + goto end; + } + + status = ar_osal_test_file_read(file, AR_FOPEN_READ_ONLY, data_read, sizeof(data_read), &bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_ONLY error:%d ", status); + goto end; + } + + AR_LOG_INFO(LOG_TAG, "read data: %s", data_read); + AR_LOG_INFO(LOG_TAG, "AR_FOPEN_WRITE_ONLY data size(%d)|bytes_read(%d)", sizeof(data), bytes_read); + + if (bytes_read != sizeof(data)) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_WRITE_ONLY Operation"); + } + +end: + ar_fdelete(file); + return; +} + +void ar_test_file_write_only_append() +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t bytes_read = 0; + char_t data[] = "File write only append test"; + char_t data_read[2* sizeof(data)] = { 0 }; + char_t *file = "write_only_append_file.txt"; + + // write data firs time. + status = ar_osal_test_file_write(file, AR_FOPEN_WRITE_ONLY, data, sizeof(data)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to created a test file error:%d ", status); + goto end; + } + + //write data second time + status = ar_osal_test_file_write(file, AR_FOPEN_WRITE_ONLY_APPEND, data, sizeof(data)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to created a test file error:%d ", status); + goto end; + } + + status = ar_osal_test_file_read(file, AR_FOPEN_READ_ONLY, data_read, sizeof(data_read), &bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_ONLY error:%d ", status); + goto end; + } + + AR_LOG_INFO(LOG_TAG, "read data: %s", data_read); + AR_LOG_INFO(LOG_TAG, "AR_FOPEN_WRITE_ONLY_APPEND data size(%d)|bytes_read(%d)", (2*sizeof(data)), bytes_read); + + if (bytes_read != (2* sizeof(data))) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_WRITE_ONLY_APPEND Operation"); + } + +end: + ar_fdelete(file); + return; +} + +void ar_test_file_read_write_append() +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t bytes_read = 0; + char_t data1[] = "File read write append test 1"; + char_t data2[] = "File read write append test 2"; + char_t data_read[2 * sizeof(data1)] = { 0 }; + char_t *file = "read_write_append_file.txt"; + + // write data first time. + status = ar_osal_test_file_write(file, AR_FOPEN_WRITE_ONLY, data1, sizeof(data1)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to created a test file error:%d ", status); + goto end; + } + + //Append data now. + status = ar_osal_test_file_write(file, AR_FOPEN_READ_WRITE_APPEND, data2, sizeof(data2)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to created a test file error:%d ", status); + goto end; + } + + //read the data now. + status = ar_osal_test_file_read(file, AR_FOPEN_READ_WRITE_APPEND, data_read, sizeof(data_read), &bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_WRITE_APPEND error:%d ", status); + goto end; + } + AR_LOG_INFO(LOG_TAG, "read data: %s", data_read); + AR_LOG_INFO(LOG_TAG, "AR_FOPEN_READ_WRITE_APPEND data size(%d)|bytes_read(%d)", (2 * sizeof(data2)), bytes_read); + + if (bytes_read != (2 * sizeof(data2))) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_WRITE_APPEND Operation"); + } + +end: + ar_fdelete(file); + return; +} + +void ar_test_file_read_only_write() +{ + /*file must exists and contents will be overwritten*/ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t bytes_read = 0; + char_t data1[] = "File read only write test 1"; + char_t data2[] = "File read only write test 2"; + char_t data_read[2 * sizeof(data1)] = { 0 }; + char_t *file = "read_only_write_file.txt"; + + status = ar_fopen(&fhandle, file, AR_FOPEN_READ_ONLY_WRITE); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to open the file:%s:error:%d for read only write (**expected) ", file, status); + } + + // write data first time. + status = ar_osal_test_file_write(file, AR_FOPEN_WRITE_ONLY, data1, sizeof(data1)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to created a test file error:%d ", status); + goto end; + } + + //read the data now. + status = ar_osal_test_file_read(file, AR_FOPEN_READ_ONLY_WRITE, data_read, sizeof(data_read), &bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_ONLY_WRITE error:%d ", status); + goto end; + } + AR_LOG_INFO(LOG_TAG, "read data: %s", data_read); + AR_LOG_INFO(LOG_TAG, "AR_FOPEN_READ_ONLY_WRITE data size(%d)|bytes_read(%d)", sizeof(data1), bytes_read); + + if (bytes_read != sizeof(data1)) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_ONLY_WRITE Operation"); + } + + // write data again. + status = ar_osal_test_file_write(file, AR_FOPEN_READ_ONLY_WRITE, data2, sizeof(data2)); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to write in AR_FOPEN_READ_ONLY_WRITE serror:%d ", status); + goto end; + } + + //read the data again. + status = ar_osal_test_file_read(file, AR_FOPEN_READ_ONLY_WRITE, data_read, sizeof(data_read), &bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_ONLY_WRITE error:%d ", status); + goto end; + } + AR_LOG_INFO(LOG_TAG, "read data: %s", data_read); + AR_LOG_INFO(LOG_TAG, "AR_FOPEN_READ_ONLY_WRITE data size(%d)|bytes_read(%d)", sizeof(data2), bytes_read); + + if (bytes_read != sizeof(data2)) + { + AR_LOG_ERR(LOG_TAG, "failed AR_FOPEN_READ_ONLY_WRITE Operation"); + } + +end: + ar_fdelete(file); + return; +} + +void ar_test_file_read_write() +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t fsize = 0; + size_t bytes_read = 0; + size_t bytes_written = 0; + char_t data1[] = "File read write test 1"; + char_t data2[] = "File read write test 2"; + char_t data_read[2 * sizeof(data1)] = { 0 }; + char_t *file = "read_write_file.txt"; + + /* open file*/ + status = ar_fopen(&fhandle, file, AR_FOPEN_READ_WRITE); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to open the file %s:error:%d ", file, status); + goto end; + } + + fsize = ar_fsize(NULL); + + fsize = ar_fsize(&fhandle); + + fsize = ar_fsize(fhandle); + // print fsize + AR_LOG_INFO(LOG_TAG, "file size %d ", fsize); + + AR_LOG_INFO(LOG_TAG, "write data: %s", data1); + /* write data */ + status = ar_fwrite(fhandle, data1, sizeof(data1), &bytes_written); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to write into the file %d ", status); + goto end; + } + if (bytes_written != sizeof(data1)) + { + //print + AR_LOG_INFO(LOG_TAG, "failed write file size not matching "); + } + /* get file size */ + fsize = ar_fsize(fhandle); + // print fsize + AR_LOG_INFO(LOG_TAG, "file size after write %d ", fsize); + + /* seek file */ + status = ar_fseek(fhandle, 0, AR_FSEEK_END); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to seek file %d ", status); + goto end; + } + + /* seek file */ + status = ar_fseek(fhandle, fsize, AR_FSEEK_BEGIN); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to seek file %d ", status); + goto end; + } + + status = ar_fclose(fhandle); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to seek file %d ", status); + goto end; + } + fhandle = NULL; + + /* open file*/ + status = ar_fopen(&fhandle, file, AR_FOPEN_READ_WRITE); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to re-open the file:%s:error:%d ", file, status); + goto end; + } + + /* read data */ + status = ar_fread(fhandle, data_read, sizeof(data1), &bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to read the file %d ", status); + goto end; + } + if (bytes_read != 0) + { + AR_LOG_ERR(LOG_TAG, "failed to read the right size bytes_read(%d) expected (0)", bytes_read); + goto end; + } + + AR_LOG_INFO(LOG_TAG, "write data: %s", data2); + /* write data */ + status = ar_fwrite(fhandle, data2, sizeof(data2), &bytes_written); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to write into the file %d ", status); + goto end; + } + if (bytes_written != sizeof(data2)) + { + //print + AR_LOG_INFO(LOG_TAG, "failed write file size not matching "); + } + + status = ar_fclose(fhandle); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to close file %d ", status); + } + fhandle = NULL; + + /* open file*/ + status = ar_fopen(&fhandle, file, AR_FOPEN_READ_ONLY); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to re-open the file:%s:error:%d ", file, status); + goto end; + } + + /* read data */ + status = ar_fread(fhandle, data_read, sizeof(data2), &bytes_read); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to read the file %d ", status); + goto end; + } + if (bytes_read != sizeof(data2)) + { + AR_LOG_ERR(LOG_TAG, "failed to read the right size bytes_read(%d) file_data(%d)", bytes_read, sizeof(data2)); + goto end; + } + AR_LOG_INFO(LOG_TAG, "read data: %s", data_read); + +end: + if (NULL != fhandle) + { + status = ar_fclose(fhandle); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to close file %d ", status); + } + status = ar_fdelete(file); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to delete file %d ", status); + } + } + return; +} + +void ar_test_file_main() +{ + AR_LOG_INFO(LOG_TAG, "******Test start*******ar_test_file_read_only********"); + ar_test_file_read_only(); + AR_LOG_INFO(LOG_TAG, "******Test end*******ar_test_file_read_only******** \n "); + + AR_LOG_INFO(LOG_TAG, "******Test start*******ar_test_file_write_only********"); + ar_test_file_write_only(); + AR_LOG_INFO(LOG_TAG, "******Test end*******ar_test_file_write_only********\n"); + + AR_LOG_INFO(LOG_TAG, "******Test start*******ar_test_file_write_only_append********"); + ar_test_file_write_only_append(); + AR_LOG_INFO(LOG_TAG, "******Test end*******ar_test_file_write_only_append********\n"); + + AR_LOG_INFO(LOG_TAG, "******Test start*******ar_test_file_read_write_append********"); + ar_test_file_read_write_append(); + AR_LOG_INFO(LOG_TAG, "******Test end*******ar_test_file_read_write_append********\n"); + + AR_LOG_INFO(LOG_TAG, "******Test start*******ar_test_file_read_only_write********"); + ar_test_file_read_only_write(); + AR_LOG_INFO(LOG_TAG, "******Test end*******ar_test_file_read_only_write********\n"); + + AR_LOG_INFO(LOG_TAG, "******Test start*******ar_test_file_read_write********"); + ar_test_file_read_write(); + AR_LOG_INFO(LOG_TAG, "******Test end*******ar_test_file_read_write********\n"); + + return; +} diff --git a/ar_util/test/src/ar_test_heap.c b/ar_util/test/src/ar_test_heap.c new file mode 100644 index 0000000..c617cb0 --- /dev/null +++ b/ar_util/test/src/ar_test_heap.c @@ -0,0 +1,59 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include "ar_osal_test.h" +#include "ar_osal_heap.h" +#include "ar_osal_log.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" + +void ar_test_heap_main() +{ + int32_t status = AR_EOK; + void* pBuff = NULL; + size_t BuffSize = 4096; + ar_heap_info heap_info = { AR_HEAP_ALIGN_DEFAULT, AR_HEAP_ID_DEFAULT,AR_HEAP_POOL_DEFAULT, AR_HEAP_TAG_DEFAULT }; + int32_t* IntPtr; + status = ar_heap_init(); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG, "failed ar_heap_init %d ", status); + goto end; + } + + pBuff = ar_heap_malloc(BuffSize, &heap_info); + if (NULL == pBuff) + { + AR_LOG_ERR(LOG_TAG, "failed ar_heap_malloc: size%d ", BuffSize); + goto end; + } + IntPtr = (int32_t*)pBuff; + AR_LOG_DEBUG(LOG_TAG, "allocated address: 0x%p, size: 0x%x alignment:8 0x%p", pBuff, BuffSize, ((uintptr_t)pBuff % 8)); + AR_LOG_DEBUG(LOG_TAG, " value [0]:%d,[1]:%d,[2]:%d,[3]:%d, ", IntPtr[0], IntPtr[1], IntPtr[2], IntPtr[3]); + ar_heap_free(pBuff, &heap_info); + + pBuff = NULL; + BuffSize = 32; + pBuff = ar_heap_calloc(BuffSize, &heap_info); + if (NULL == pBuff) + { + AR_LOG_ERR(LOG_TAG, "failed ar_heap_calloc: size%d ", BuffSize); + goto end; + } + + IntPtr = (int32_t*)pBuff; + AR_LOG_DEBUG(LOG_TAG, "allocated address: 0x%p, size: 0x%x alignment:8 0x%p", pBuff, BuffSize, ((uintptr_t)pBuff % 8)); + AR_LOG_DEBUG(LOG_TAG, " value [0]:%d,[1]:%d,[2]:%d,[3]:%d, ", IntPtr[0], IntPtr[1], IntPtr[2], IntPtr[3]); + + ar_heap_free(pBuff, &heap_info); + + status = ar_heap_deinit(); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG, "failed ar_heap_deinit %d ", status); + goto end; + } +end: + return; +} diff --git a/ar_util/test/src/ar_test_list.c b/ar_util/test/src/ar_test_list.c new file mode 100644 index 0000000..2b198f1 --- /dev/null +++ b/ar_util/test/src/ar_test_list.c @@ -0,0 +1,154 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include "ar_osal_test.h" +#include "ar_util_list.h" +#include "ar_osal_log.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" +#include "ar_osal_mutex.h" +#include + +void * mutex_handle = NULL; +#define AR_NODES_MAX (10) + +static void list_lock_enter_fn_t(void) +{ + if (NULL != mutex_handle) + { + if (AR_EOK != ar_osal_mutex_lock(mutex_handle)) + { + AR_LOG_ERR(LOG_TAG,"failed to acquire mutex "); + } + } +} + +static void list_lock_leave_fn_t(void) +{ + if (NULL != mutex_handle) + { + if (AR_EOK != ar_osal_mutex_unlock(mutex_handle)) + { + AR_LOG_ERR(LOG_TAG,"failed to release mutex "); + } + } +} + +void ar_test_util_list_main() +{ + int32_t status = AR_EOK; + ar_list_node_t *nodes[AR_NODES_MAX] = { NULL }; + int32_t list_count = 0; + ar_list_node_t *removed_node = NULL; + ar_list_t test_list = {0}; + + status = ar_osal_mutex_create(&mutex_handle); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"mutex creation failed %d ", status); + goto end; + } + + status = ar_list_init(&test_list, list_lock_enter_fn_t, list_lock_leave_fn_t); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"list init failed %d ", status); + goto end; + } + + AR_LOG_INFO(LOG_TAG,"check if list is empty %d ", ar_list_is_empty(&test_list)); + AR_LOG_INFO(LOG_TAG,"list head 0x%p ", ar_list_get_head(&test_list)); + AR_LOG_INFO(LOG_TAG,"list tail 0x%p ", ar_list_get_tail(&test_list)); + + for (list_count = 0; list_count < AR_NODES_MAX; ) + { + nodes[list_count] = malloc(sizeof(ar_list_node_t)); + if (NULL == nodes[list_count]) + { + AR_LOG_ERR(LOG_TAG,"node[%d] allocation failed ", list_count); + status = AR_ENOMEMORY; + goto end; + } + + list_count++; + + status = ar_list_init_node(nodes[list_count - 1]); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"list node[%d] init failed %d ", list_count - 1, status); + goto end; + } + AR_LOG_INFO(LOG_TAG,"list node[%d]:0x%p created ", list_count - 1, nodes[list_count - 1]); + } + + for (int32_t i = 0; i < list_count; i++) + { + status = ar_list_add_tail(&test_list, nodes[i]); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to add node[%d] to list err:%d ", i, status); + goto end; + } + AR_LOG_INFO(LOG_TAG," node[%d][0x%p] added to the list ", i, nodes[i]); + } + AR_LOG_INFO(LOG_TAG,"list size %d ", test_list.size); + + status = ar_list_remove_head(&test_list, &removed_node); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to remove node from list head %d ", status); + goto end; + } + + AR_LOG_INFO(LOG_TAG,"node[0x%p] removed from the list head ", removed_node); + AR_LOG_INFO(LOG_TAG,"list size %d ", test_list.size); + + removed_node = NULL; + status = ar_list_remove_head(&test_list, &removed_node); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to remove node from list head %d ", status); + goto end; + } + AR_LOG_INFO(LOG_TAG,"node[0x%p] removed from the list head ", removed_node); + AR_LOG_INFO(LOG_TAG,"delete node[0x%p] from the list", nodes[5]); + AR_LOG_INFO(LOG_TAG,"list size %d ", test_list.size); + + status = ar_list_delete(&test_list, nodes[5]); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to delete node[0x%p], err: %d ", nodes[5], status); + } + + AR_LOG_INFO(LOG_TAG,"node[0x%p] deleted from list ", nodes[5]); + AR_LOG_INFO(LOG_TAG,"list size %d ", test_list.size); + + AR_LOG_INFO(LOG_TAG,"check if list is empty %d ", ar_list_is_empty(&test_list)); + AR_LOG_INFO(LOG_TAG,"list head 0x%p ", ar_list_get_head(&test_list)); + AR_LOG_INFO(LOG_TAG,"list tail 0x%p ", ar_list_get_tail(&test_list)); + + + status = ar_list_clear(&test_list); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to clear the list "); + } + AR_LOG_INFO(LOG_TAG,"list cleared "); + AR_LOG_INFO(LOG_TAG,"list size %d ", test_list.size); +end: + for (int32_t i = 0; i < list_count; i++) + { + if (nodes[i]) + { + AR_LOG_INFO(LOG_TAG," free node[%d][0x%p] ", i, nodes[i]); + free(nodes[i]); + } + } + if (NULL != mutex_handle) + { + ar_osal_mutex_destroy(mutex_handle); + mutex_handle = NULL; + } + return; +} diff --git a/ar_util/test/src/ar_test_log_pkt_op.c b/ar_util/test/src/ar_test_log_pkt_op.c new file mode 100644 index 0000000..85601a2 --- /dev/null +++ b/ar_util/test/src/ar_test_log_pkt_op.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause +*/ +#include +#include "ar_osal_file_io.h" +#include "ar_osal_error.h" +#include "ar_osal_types.h" +#include "ar_osal_test.h" +#include "ar_osal_log.h" +#include "ar_util_data_log.h" +#include "ar_util_data_log_codes.h" +#include "ar_osal_log_pkt_op.h" +#include "ar_osal_heap.h" + +#define AR_OSAL_LOG_DIAG_HEADER_LENGTH 12 + +uint32_t glb_curr_packet_length = 0; + +int32_t ar_log_pkt_op_init(ar_log_pkt_op_init_info_t *info) +{ + __UNREFERENCED_PARAM(info); + int32_t status = 0; + + ar_fhandle fhandle = NULL; + //ar_fopen(&fhandle, ") + + return AR_EOK; +} + +int32_t ar_log_pkt_op_deinit() +{ + return AR_EUNSUPPORTED; +} + +uint32_t ar_log_pkt_get_max_size() +{ + return 128 - AR_OSAL_LOG_DIAG_HEADER_LENGTH; +} + +void *ar_log_pkt_alloc(uint16_t logcode, uint32_t length) +{ + int32_t packet_length = + AR_OSAL_LOG_DIAG_HEADER_LENGTH + length; + uint8_t* pkt_ptr = NULL; + ar_heap_info heap_info = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + glb_curr_packet_length = packet_length; + pkt_ptr = ar_heap_malloc(packet_length, &heap_info); + + if (pkt_ptr) + { + *(uint32_t*)pkt_ptr = 0; + *(uint16_t*)pkt_ptr = logcode; + return pkt_ptr + AR_OSAL_LOG_DIAG_HEADER_LENGTH; + } + + return pkt_ptr; +} + +int32_t ar_log_pkt_commit(void *ptr) +{ + int32_t status = AR_EOK; + ar_fhandle fhandle = NULL; + size_t bytes_written = 0; + char_t *file = "ar_util_data_log_commit.bin"; + void *pkt_ptr = NULL; + + pkt_ptr = (uint8_t*)ptr - AR_OSAL_LOG_DIAG_HEADER_LENGTH; + + status = ar_fopen(&fhandle, file, AR_FOPEN_WRITE_ONLY_APPEND); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to open the file %s:error:%d ", file, status); + } + + status = ar_fwrite(fhandle, pkt_ptr, + glb_curr_packet_length, + &bytes_written); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to write into the file %d ", status); + goto end; + } + + if (bytes_written != glb_curr_packet_length) + { + //print + AR_LOG_INFO(LOG_TAG, "failed write file size not matching "); + } + +end: + if (fhandle) + { + // close file + status = ar_fclose(fhandle); + if (status != AR_EOK) + { + AR_LOG_ERR(LOG_TAG, "failed to close file %d ", status); + } + } + + ar_log_pkt_free(ptr); + return status; +} + +void ar_log_pkt_free(void *ptr) +{ + ar_heap_info heap_info = + { + AR_HEAP_ALIGN_DEFAULT, + AR_HEAP_POOL_DEFAULT, + AR_HEAP_ID_DEFAULT, + AR_HEAP_TAG_DEFAULT + }; + + ar_heap_free( + (uint8_t*)ptr - AR_OSAL_LOG_DIAG_HEADER_LENGTH, &heap_info); +} + +bool_t ar_log_code_status(uint16_t logcode) +{ + return TRUE; +} diff --git a/ar_util/test/src/ar_test_mem_op.c b/ar_util/test/src/ar_test_mem_op.c new file mode 100644 index 0000000..60b5974 --- /dev/null +++ b/ar_util/test/src/ar_test_mem_op.c @@ -0,0 +1,48 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include "ar_osal_test.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_log.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" + +void ar_test_mem_op_main() +{ + int32_t status = AR_EOK; + int8_t BufA[10] = { 1 }; + int8_t BufB[10] = { 2 }; + int32_t cmpSize = 0; + + AR_LOG_DEBUG(LOG_TAG, "ar_mem_cmp(%d), expected < 0", ar_mem_cmp(BufA, BufB, sizeof(BufA))); + AR_LOG_DEBUG(LOG_TAG, "ar_mem_cmp(%d), expected > 0", ar_mem_cmp(BufB, BufA, sizeof(BufB))); + AR_LOG_DEBUG(LOG_TAG, "ar_mem_cpy(%d) ", ar_mem_cpy(BufA, sizeof(BufA), BufB, sizeof(BufB))); + AR_LOG_DEBUG(LOG_TAG, "ar_mem_cmp(%d), expected == 0 ", ar_mem_cmp(BufA, BufB, sizeof(BufA))); + + for (int8_t i = 0; i < sizeof(BufA) / sizeof(BufA[0]); i++) + { + BufA[i] = i + 1; + } + + for (int8_t i = 0; i < sizeof(BufA)/sizeof(BufA[0]); i++) + { + AR_LOG_DEBUG(LOG_TAG, "BufA[%d]: %d ",i, BufA[i]); + } + + AR_LOG_DEBUG(LOG_TAG, "ar_mem_move(%d) ", ar_mem_move(&BufA[2], (sizeof(BufA) - sizeof(int8_t)*2), &BufA[4], sizeof(int8_t)*5)); + + for (int8_t i = 0; i < sizeof(BufA) / sizeof(BufA[0]); i++) + { + AR_LOG_DEBUG(LOG_TAG, "BufA[%d]: %d ", i, BufA[i]); + } + + AR_LOG_DEBUG(LOG_TAG, "ar_mem_set(%d) ", ar_mem_set(BufA, 3, sizeof(BufA))); + + for (int8_t i = 0; i < sizeof(BufA) / sizeof(BufA[0]); i++) + { + AR_LOG_DEBUG(LOG_TAG, "BufA[%d]: %d ", i, BufA[i]); + } + + return; +} diff --git a/ar_util/test/src/ar_test_shmem.c b/ar_util/test/src/ar_test_shmem.c new file mode 100644 index 0000000..4118a54 --- /dev/null +++ b/ar_util/test/src/ar_test_shmem.c @@ -0,0 +1,51 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include "ar_osal_test.h" +#include "ar_osal_shmem.h" +#include "ar_osal_log.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" + +void ar_test_shmem_main() +{ + int32_t status = AR_EOK; + uint8_t sys_id = AR_AUDIO_DSP; + uint32_t num_master_procs = 1; + ar_shmem_info shmem_info = { AR_SHMEM_VIRTUAL_MEMORY/*virtual & cached*/, 4096, AR_SHMEM_CACHED, AR_SHMEM_BUFFER_ADDRESS, 0,0,0,0, NULL,0, 1, &sys_id}; + status = ar_shmem_init(); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to shmem init %d ", status); + goto end; + } + + status = ar_shmem_init_v2(num_master_procs, &sys_id); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to shmem init %d ", status); + goto end; + } + + status = ar_shmem_alloc(&shmem_info); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to shmem alloc(%d): size%d ", status, shmem_info.buf_size); + goto end; + } + + AR_LOG_INFO(LOG_TAG,"shmem allocated address: 0x%p, size: 0x%x ", shmem_info.vaddr, shmem_info.buf_size); + AR_LOG_INFO(LOG_TAG,"shmem allocated address ipa_msw:ipa_lsw: (0x%08X:%08X) ", shmem_info.ipa_msw, shmem_info.ipa_lsw); + AR_LOG_INFO(LOG_TAG,"shmem allocated address pa_msw:pa_lsw: (0x%08X:%08X) ", shmem_info.pa_msw, shmem_info.pa_lsw); + AR_LOG_INFO(LOG_TAG, "shmem allocated mem_type(0x%x), cache_type(0x%x), index_type(0x%x) ", shmem_info.mem_type, shmem_info.cache_type, shmem_info.index_type); + + status = ar_shmem_free(&shmem_info); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to shmem free %d ", status); + goto end; + } +end: + return; +} diff --git a/ar_util/test/src/ar_test_sleep.c b/ar_util/test/src/ar_test_sleep.c new file mode 100644 index 0000000..8361e35 --- /dev/null +++ b/ar_util/test/src/ar_test_sleep.c @@ -0,0 +1,66 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include "ar_osal_test.h" +#include "ar_osal_sleep.h" +#include "ar_osal_log.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" + +void ar_test_sleep_main() +{ + int32_t status = AR_EOK; + uint64_t usec_sleep = 0; + + // 0 usec sleep, on win32 A value of zero causes the thread to relinquish + // the remainder of its time slice to any other thread that is ready to run. + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) start", usec_sleep); + status = ar_osal_micro_sleep(usec_sleep); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG,"failed to sleep(%llu usec): status(0x%x) ", usec_sleep, status); + } + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) end", usec_sleep); + + // 1 usec sleep, on win32 A value of zero causes the thread to relinquish + // the remainder of its time slice to any other thread that is ready to run + usec_sleep = 1; + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) start", usec_sleep); + status = ar_osal_micro_sleep(usec_sleep); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG, "failed to sleep(%llu usec): status(0x%x) ", usec_sleep, status); + } + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) end", usec_sleep); + + usec_sleep = 1000; // 1 msec + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) start", usec_sleep); + status = ar_osal_micro_sleep(usec_sleep); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG, "failed to sleep(%llu usec): status(0x%x) ", usec_sleep, status); + } + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) end", usec_sleep); + + + usec_sleep = 10000;//10 msec + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) start", usec_sleep); + status = ar_osal_micro_sleep(usec_sleep); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG, "failed to sleep(%llu usec): status(0x%x) ", usec_sleep, status); + } + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) end", usec_sleep); + + usec_sleep = 100000; //100msec + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) start", usec_sleep); + status = ar_osal_micro_sleep(usec_sleep); + if (AR_EOK != status) + { + AR_LOG_ERR(LOG_TAG, "failed to sleep(%llu usec): status(0x%x) ", usec_sleep, status); + } + AR_LOG_INFO(LOG_TAG, "sleep for usec(%llu) end", usec_sleep); + + return; +} diff --git a/ar_util/test/src/ar_test_string.c b/ar_util/test/src/ar_test_string.c new file mode 100644 index 0000000..5532ecf --- /dev/null +++ b/ar_util/test/src/ar_test_string.c @@ -0,0 +1,38 @@ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +*/ +#include "ar_osal_test.h" +#include "ar_osal_string.h" +#include "ar_osal_log.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" + +void ar_test_string_main() +{ + int32_t status = AR_EOK; + char_t pStr[] = "test 0 string "; + char_t pStr1[29] = "test 1 string "; + char_t pStr2[24] = "test 2 string "; + char_t pStr3[] = "test string "; + char_t* pStrTemp = NULL; + char_t pStr4[40] = { 0 }; + char_t pStr5[40] = { 0 }; + + + AR_LOG_DEBUG(LOG_TAG, "ar_strlen(%d), pStr:size(%d) String:%s", ar_strlen(pStr,sizeof(pStr)), sizeof(pStr), pStr); + AR_LOG_DEBUG(LOG_TAG, "ar_strcat(%d), pStr1:size(%d) String:%s", ar_strcat(pStr1, sizeof(pStr1), pStr, sizeof(pStr)), sizeof(pStr1), pStr1); + AR_LOG_DEBUG(LOG_TAG, "ar_strcat(%d), pStr2:size(%d) String:%s", ar_strcat(pStr2, sizeof(pStr2), pStr, sizeof(pStr)), sizeof(pStr2), pStr2); + AR_LOG_DEBUG(LOG_TAG, "ar_strcpy(%d), pStr2:size(%d) String:%s", ar_strcpy(pStr2, sizeof(pStr2), pStr, sizeof(pStr)), sizeof(pStr2), pStr2); + AR_LOG_DEBUG(LOG_TAG, "ar_strcpy(%d), pStr3:size(%d) String:%s", ar_strcpy(pStr3, sizeof(pStr3), pStr, sizeof(pStr)), sizeof(pStr3), pStr3); + pStrTemp = ar_strstr(pStr1, "1"); + AR_LOG_DEBUG(LOG_TAG, "ar_strstr(), pStrTemp:size(%d) String:%s", sizeof(pStrTemp), pStrTemp); + + ar_sprintf(pStr4, sizeof(pStr4), "%s", "test 4 string "); + AR_LOG_DEBUG(LOG_TAG, "ar_sprintf(), pStr4:size(%d) String:%s", sizeof(pStr4), pStr4); + + ar_sscanf(pStr4, "%14c", pStr5, (unsigned int)sizeof(pStr5)); + AR_LOG_DEBUG(LOG_TAG, "ar_sscanf(), pStr5:size(%d) String:%s", sizeof(pStr5), pStr5); + + return; +} diff --git a/ci/apply_patch.sh b/ci/apply_patch.sh new file mode 100644 index 0000000..2aaed90 --- /dev/null +++ b/ci/apply_patch.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +set -e +# This script synchronizes the repositories and patches defined in config.sh. +CONFIG_SCRIPT_PATH="${CONFIG_SCRIPT:-$(dirname "${BASH_SOURCE[0]}")/config.sh}" +source "$CONFIG_SCRIPT_PATH" + +for entry in "${PATCHES[@]}"; do + IFS='|' read -r name patch <<< "$entry" + dir="$GITHUB_WORKSPACE/../$name" + echo "Applying patch from $name..." + git -C "$GITHUB_WORKSPACE" apply --check "$dir/$patch" && git -C "$GITHUB_WORKSPACE" apply "$dir/$patch" || echo "Patch already applied or failed." + echo "Done applying patch from $name." +done diff --git a/ci/build.sh b/ci/build.sh new file mode 100644 index 0000000..960fc9a --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +set -ex +PREBUILD_SCRIPT_PATH="${PREBUILD_SCRIPT:-$(dirname "${BASH_SOURCE[0]}")/pre_build.sh}" +source "$PREBUILD_SCRIPT_PATH" + +# load build args from file if environment variable is not set +if [ -z "${BUILD_ARGS:-}" ]; then + BUILD_OPTIONS_FILE="${GITHUB_WORKSPACE}/ci/build_options.txt" + BUILD_ARGS="$(sed -E 's/#.*$//' "$BUILD_OPTIONS_FILE" | sed '/^[[:space:]]*$/d' | tr '\n' ' ')" +fi + +echo "Running build script..." +# Build/Compile audioreach-graphservices +source ${GITHUB_WORKSPACE}/install/environment-setup-armv8-2a-qcom-linux + +# make sure we are in the right directory +cd ${GITHUB_WORKSPACE} + +# Run autoreconf to generate the configure script +autoreconf -Wcross --verbose --install --force --exclude=autopoint +autoconf --force + +# Run the configure script with the specified arguments +./configure ${BUILD_ARGS} +# make +make DESTDIR=${GITHUB_WORKSPACE}/build install diff --git a/ci/build_options.txt b/ci/build_options.txt new file mode 100644 index 0000000..d82700a --- /dev/null +++ b/ci/build_options.txt @@ -0,0 +1,27 @@ +--build=x86_64-linux +--host=aarch64-poky-linux +--prefix=/usr +--exec_prefix=/usr +--bindir=/usr/bin +--sbindir=/usr/sbin +--libexecdir=/usr/libexec +--datadir=/usr/share +--sysconfdir=/etc +--sharedstatedir=/com +--localstatedir=/var +--libdir=/usr/lib +--includedir=/usr/include +--oldincludedir=/usr/include +--infodir=/usr/share/info +--mandir=/usr/share/man +--disable-silent-rules +--disable-dependency-tracking +--with-syslog +--with-glib +--without-cutils +--with-dummy_diag +--with-qcom +--with-audio_dma_support +--without-ats_transport_tcp_ip +--without-ats_data_logging +--disable-static diff --git a/ci/config.sh b/ci/config.sh new file mode 100644 index 0000000..67d947f --- /dev/null +++ b/ci/config.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# This file is part of the Audioreach CI configuration. +# It defines the repositories and patches used in the CI process. +REPOS=( + "meta-ar|https://github.com/Audioreach/meta-ar.git" +) + +PATCHES=( + "meta-ar|recipes/audio/audioreach-graphservices/0001-ar_osal-update-msm_audio.h-header-include-path.patch" +) diff --git a/ci/files_to_copy.sh b/ci/files_to_copy.sh new file mode 100644 index 0000000..d20035c --- /dev/null +++ b/ci/files_to_copy.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + +# Move outside the github workspace to avoid conflicts +cd .. + +# copy the build artifacts to a temporary directory +cp -R build/usr/lib* /tmp/rootfs/usr/lib/ diff --git a/ci/knp_build.sh b/ci/knp_build.sh new file mode 100644 index 0000000..7655d28 --- /dev/null +++ b/ci/knp_build.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +set -ex +echo "Running build script..." +# Build/Compile audioreach-graphservices +source ${GITHUB_WORKSPACE}/install/environment-setup-armv8-6a-qcom-linux + +# make sure we are in the right directory +cd ${GITHUB_WORKSPACE} + +# Run autoreconf to generate the configure script +autoreconf -Wcross --verbose --install --force --exclude=autopoint +autoconf --force +# Run the configure script with the specified arguments +./configure ${BUILD_ARGS} +# make +make DESTDIR=${GITHUB_WORKSPACE}/build install diff --git a/ci/pkl_build.sh b/ci/pkl_build.sh new file mode 100644 index 0000000..bf04b7c --- /dev/null +++ b/ci/pkl_build.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +set -ex +echo "Running build script..." +# Build/Compile audioreach-graphservices +source ${GITHUB_WORKSPACE}/install/environment-setup-armv8-7a-qcom-linux + +# make sure we are in the right directory +cd ${GITHUB_WORKSPACE} + +# Run autoreconf to generate the configure script +autoreconf -Wcross --verbose --install --force --exclude=autopoint +autoconf --force +# Run the configure script with the specified arguments +./configure ${BUILD_ARGS} +# make +make DESTDIR=${GITHUB_WORKSPACE}/build install diff --git a/ci/pre_build.sh b/ci/pre_build.sh new file mode 100644 index 0000000..7cf0316 --- /dev/null +++ b/ci/pre_build.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +set -euo pipefail +echo "Running pre-build script..." + +# Define target_image.json url +url="https://raw.githubusercontent.com/AudioReach/audioreach-workflows/master/.github/actions/loading/target_image.json" + +# Download .sh from aws s3 bucket and install the sdk +if [ ! -d "${GITHUB_WORKSPACE}/install" ]; then + echo "SDK_NAME environment variable is not set. Fetching from JSON." + if curl -fsSL -o target_image.json "${url}"; then + SDK=$(jq -r 'to_entries[0].value.SDK_name' target_image.json) + if [ -n "$SDK" ] && [ "$SDK" != "null" ]; then + export SDK_NAME="$SDK" + echo "SDK_NAME set to ${SDK_NAME}" + else + echo "Error: SDK_name not found in JSON." >&2 + exit 3 + fi + else + echo "Failed to fetch target_image.json from $url" >&2 + exit 1 + fi + if aws s3 cp s3://qli-prd-audior-gh-artifacts/AudioReach/meta-audioreach/post_merge_build/${SDK_NAME} "${GITHUB_WORKSPACE}"; then + echo "SDK downloaded successfully." + chmod 777 "${GITHUB_WORKSPACE}/${SDK_NAME}" + else + echo "Failed to download SDK from S3. Exiting." + exit 1 + fi + # Setup directory for sdk installation + mkdir -p "${GITHUB_WORKSPACE}/install" + orig_dir=$(pwd) + cd "${GITHUB_WORKSPACE}" + # Install the sdk + echo "Running SDK script..." + if echo "./install" | ./"${SDK_NAME}" ; then + echo "SDK Script ran successfully." + else + echo "Error running SDK script. Exiting." + exit 1 + fi + cd "$orig_dir" +else + echo "SDK already installed. Skipping download and installation." +fi diff --git a/ci/rpi_build.sh b/ci/rpi_build.sh new file mode 100644 index 0000000..4b10bad --- /dev/null +++ b/ci/rpi_build.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +set -ex +echo "Running build script..." +# Build/Compile audioreach-graphservices +source ${GITHUB_WORKSPACE}/install/environment-setup-cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi + +# make sure we are in the right directory +cd ${GITHUB_WORKSPACE} + +# Run autoreconf to generate the configure script +autoreconf -Wcross --verbose --install --force --exclude=autopoint +autoconf --force +# Run the configure script with the specified arguments +./configure ${BUILD_ARGS} +# make +make DESTDIR=${GITHUB_WORKSPACE}/build install diff --git a/ci/rpi_build_options.txt b/ci/rpi_build_options.txt new file mode 100644 index 0000000..adc2b67 --- /dev/null +++ b/ci/rpi_build_options.txt @@ -0,0 +1,26 @@ +--build=x86_64-linux +--host=arm-poky-linux-gnueabi +--target=arm-poky-linux-gnueabi +--prefix=/usr +--exec_prefix=/usr +--bindir=/usr/bin +--sbindir=/usr/sbin +--libexecdir=/usr/libexec +--datadir=/usr/share +--sysconfdir=/etc +--sharedstatedir=/com +--localstatedir=/var +--libdir=/usr/lib +--includedir=/usr/include +--oldincludedir=/usr/include +--infodir=/usr/share/info +--mandir=/usr/share/man +--disable-silent-rules +--disable-dependency-tracking +--with-syslog +--with-glib +--without-cutils +--with-dummy_diag +--disable-static +--with-are-on-apps +--without-qcom diff --git a/ci/sync.sh b/ci/sync.sh new file mode 100644 index 0000000..d28bb36 --- /dev/null +++ b/ci/sync.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +set -ex +# This script synchronizes the repositories and patches defined in config.sh. +CONFIG_SCRIPT_PATH="${CONFIG_SCRIPT:-$(dirname "${BASH_SOURCE[0]}")/config.sh}" +source "$CONFIG_SCRIPT_PATH" + +for entry in "${REPOS[@]}"; do + IFS='|' read -r name url <<< "$entry" + dir="$GITHUB_WORKSPACE/../$name" + if [ -d "$dir" ]; then + echo "Updating $name..." + git -C "$dir" fetch origin + git -C "$dir" reset --hard origin/main + git -C "$dir" clean -fdx + else + echo "Cloning $name..." + git clone "$url" "$dir" + fi +done diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..3814ba7 --- /dev/null +++ b/configure.ac @@ -0,0 +1,158 @@ +# -*- Autoconf -*- +# configure.ac -- Autoconf script for args +# + +# Process this file with autoconf to produce a configure script + +# Requires autoconf tool later than 2.61 +AC_PREREQ(2.69) + +AC_INIT([arosp],1.0.0) +# Does not strictly follow GNU Coding standards +AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) +LT_INIT +AC_PROG_CC +AC_PROG_CXX +AC_PROG_LIBTOOL +AM_PROG_AR + +m4_define([LT_MAJOR], [1]) +m4_define([LT_MINOR], [0]) +m4_define([LT_PATCH], [0]) + +AC_SUBST([LT_VERSION], LT_MAJOR.LT_MINOR.LT_PATCH) +AC_SUBST([LT_VERSION_NUMBER], LT_MAJOR:LT_MINOR:LT_PATCH) + +AC_ARG_WITH([qcom], + AS_HELP_STRING([install qcom header files (default is no)]), + [with_qcom=$withval], + [with_qcom=no]) + AM_CONDITIONAL([ARGS_VENDOR_QCOM], [test "x${with_qcom}" = "xyes"]) + +AC_ARG_WITH([syslog], + AS_HELP_STRING([use syslog (default is no)]), + [with_syslog=$withval], + [with_syslog=no]) + AM_CONDITIONAL([ARGS_USE_SYSLOG], [test "x${with_syslog}" = "xyes"]) + +AC_ARG_WITH([kernelheader], + AS_HELP_STRING([use kernelheader (default is no)]), + [with_kernelheader=$withval], + [with_kernelheader=no]) + AM_CONDITIONAL([KERNEL_HEADER], [test "x${with_kernelheader}" = "xyes"]) + + +AC_ARG_WITH([glib], + AC_HELP_STRING([--with-glib], + [enable glib, Build against glib. Use this when building for HLOS systems which use glib])) + +AC_ARG_WITH(sanitized-headers, + AS_HELP_STRING([--with-sanitized-headers=DIR], + [Specify the location of the sanitized Linux headers]), + [CFLAGS="$CFLAGS -I$withval"]) + +if (test "x${with_glib}" = "xyes"); then + PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes, + AC_MSG_ERROR(GThread >= 2.16 is required)) + PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes, + AC_MSG_ERROR(GLib >= 2.16 is required)) + GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS" + GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS" + + AC_SUBST(GLIB_CFLAGS) + AC_SUBST(GLIB_LIBS) +fi + +AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes") + +AC_ARG_WITH([cutils], + AS_HELP_STRING([Use cutils (default is yes)]), + [with_cutils=$withval], + [with_cutils=yes]) +AM_CONDITIONAL([CUTILS_SUPPORTED], [test "x${with_cutils}" = "xyes"]) + +AC_ARG_WITH([ats_transport_tcp_ip], + AS_HELP_STRING([Use ats transport TCP/IP (default is yes)]), + [with_ats_transport_tcp_ip=$withval], + [with_ats_transport_tcp_ip=yes]) +AM_CONDITIONAL([USES_ATS_TRANSPORT_TCPIP], [test "x${with_ats_transport_tcp_ip}" = "xyes"]) + +AC_ARG_WITH([dummy_diag], + AC_HELP_STRING([--with-dummy_diag], + [use dummy diag instead of libdiag (default is yes)]), + [with_dummy_diag=$withval], + [with_dummy_diag=yes]) + +if (test "x${with_dummy_diag}" = "xno"); then + PKG_CHECK_MODULES([DIAG], [diag]) + AC_SUBST([DIAG_CFLAGS]) + AC_SUBST([DIAG_LIBS]) +fi + +AM_CONDITIONAL(USE_DUMMY_DIAG, test "x${with_dummy_diag}" = "xyes") + +AC_ARG_WITH([audio_dma_support], + AS_HELP_STRING([use audio_dma_support (default is no)]), + [with_audio_dma_support=$withval], + [with_audio_dma_support=no]) +AM_CONDITIONAL([AUDIO_DMA_SUPPORT], [test "x${with_audio_dma_support}" = "xyes"]) + +AC_ARG_WITH([libdiag_headers], + AS_HELP_STRING([--with-libdiag_headers],[use libdiag headers only (default is no)]), + [with_libdiag_headers=$withval], + [with_libdiag_headers=no]) +AM_CONDITIONAL([LIBDIAG_HEADERS], [test "x${with_libdiag_headers}" = "xyes"]) + +AC_ARG_WITH([libion], + AS_HELP_STRING([use libion (default is no)]), + [with_libion=$withval], + [with_libion=no]) + +if (test "x${with_libion}" = "xyes"); then + PKG_CHECK_MODULES([LIBION], [libion]) + AC_SUBST([LIBION_CFLAGS]) +fi + +AM_CONDITIONAL([LIBION_SUPPORTED], [test "x${with_libion}" = "xyes"]) + +AC_CHECK_FUNCS([strlcpy]) +AM_CONDITIONAL(USE_G_STR_FUNC, ! test "x$ac_cv_func_strlcpy" = "xyes") + +AC_ARG_WITH([are_on_apps], + AS_HELP_STRING([--with-are-on-apps],[Enable ARE (SPF) on APPS support (default is no)]), + [with_are_on_apps=$withval], + [with_are_on_apps=no]) +AM_CONDITIONAL([USE_ARE_ON_APPS], [test "x${with_are_on_apps}" = "xyes"]) + +AC_ARG_WITH([msm_audio_ion_disable], + AS_HELP_STRING([MSM audio ion disable (default is no)]), + [with_msm_audio_ion_disable=$withval], + [with_msm_audio_ion_disable=no]) +AM_CONDITIONAL([ION_DRIVER_NOT_SUPPORTED], [test "x${with_msm_audio_ion_disable}" = "xyes"]) + +AC_ARG_WITH([ats_data_logging], + AS_HELP_STRING([Use ATS data logging using Data Logging Service(DLS) (default is yes)]), + [with_ats_data_logging=$withval], + [with_ats_data_logging=yes]) +AM_CONDITIONAL([USES_ATS_DATA_LOGGING], [test "x${with_ats_data_logging}" = "xyes"]) + +AC_CONFIG_FILES( +Makefile +spf/Makefile +ar_osal/Makefile +ar_util/Makefile +acdb/Makefile +acdb/ats/Makefile +gpr/Makefile +gsl/Makefile +spf/spf.pc +ar_osal/ar_osal.pc +ar_util/ar_util.pc +acdb/acdb.pc +acdb/ats/ats.pc +gpr/gpr.pc +gsl/gsl.pc +) + + +AC_OUTPUT diff --git a/debian/changelog b/debian/changelog index bb0b1af..42b932b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +audioreach-graphservices (1.0.0-1) UNRELEASED; urgency=medium + + * New upstream release + + -- GitHub Service Bot Thu, 11 Jun 2026 18:40:38 +0000 + audioreach-graphservices (1.0.0-1) unstable; urgency=low * Initial release. diff --git a/gpr/Android.mk b/gpr/Android.mk new file mode 100644 index 0000000..f5ab35f --- /dev/null +++ b/gpr/Android.mk @@ -0,0 +1,51 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := libar-gpr +LOCAL_MODULE_OWNER := qti +LOCAL_MODULE_TAGS := optional +LOCAL_VENDOR_MODULE := true + +LOCAL_SRC_FILES := \ + core/src/gpr_drv.c \ + core/src/gpr_list.c \ + core/src/gpr_main.c \ + core/src/gpr_memq.c \ + core/src/gpr_drv_island.c \ + core/src/gpr_list_island.c \ + core/src/gpr_memq_island.c \ + core/src/hash_based/gpr_session.c \ + core/src/hash_based/gpr_session_island.c \ + ext/dynamic_allocation/src/gpr_dynamic_allocation.c \ + ext/logging/src/gpr_log_generic.c \ + ext/logging/stub_src/gpr_log_diag_stub.c \ + datalinks/gpr_lx/src/gpr_lx.c \ + platform/linux/gpr_init_lx_wrapper.c + +LOCAL_SHARED_LIBRARIES := \ + liblx-osal\ + libcutils\ + liblog + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/inc \ + $(LOCAL_PATH)/logging/inc \ + $(LOCAL_PATH)/api \ + $(LOCAL_PATH)/api/private \ + $(LOCAL_PATH)/core/inc \ + $(LOCAL_PATH)/core/inc/ar_utils/generic \ + $(LOCAL_PATH)/core/src \ + $(LOCAL_PATH)/ext/dynamic_allocation/inc \ + $(LOCAL_PATH)/ext/logging/inc \ + $(LOCAL_PATH)/datalinks/gpr_lx/inc + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/api +LOCAL_CFLAGS := -D_ANDROID_ \ + -DSESSION_ARRAY_SIZE=200 \ + -DGPR_USE_CUTILS + +ifeq ($(TARGET_SUPPORTS_WEAR_AON),true) +LOCAL_CFLAGS += -DPLATFORM_SLATE +endif + +include $(BUILD_SHARED_LIBRARY) diff --git a/gpr/LICENSE b/gpr/LICENSE new file mode 100644 index 0000000..7991c11 --- /dev/null +++ b/gpr/LICENSE @@ -0,0 +1,151 @@ +This text file is provided to comply with the attribution requirements of the licenses herein, but see NOTICE for license terms of this software.The Apache 2.0 license can be found at http://www.apache.org/licenses/LICENSE-2.0.html +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +1. Definitions. +"License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. +"Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. +"Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. +"You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. +"Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. +"Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. +"Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). +"Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. +"Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." +"Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: +(a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and +(b) You must cause any modified files to carry prominent notices + stating that You changed the files; and +(c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and +(d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. +You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. +END OF TERMS AND CONDITIONS diff --git a/gpr/Makefile.am b/gpr/Makefile.am new file mode 100644 index 0000000..c586007 --- /dev/null +++ b/gpr/Makefile.am @@ -0,0 +1,82 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gpr.pc +EXTRA_DIST = $(pkgconfig_DATA) + +AM_CFLAGS = -Wall + +AM_CFLAGS += -I$(srcdir)/api +AM_CFLAGS += -I$(srcdir)/api/private +AM_CFLAGS += -I$(srcdir)/core/inc +AM_CFLAGS += -I$(srcdir)/core/inc/ar_utils/generic +AM_CFLAGS += -I$(srcdir)/core/src +AM_CFLAGS += -I$(srcdir)/datalinks/gpr_lx/inc +AM_CFLAGS += -I$(srcdir)/ext/logging/inc +AM_CFLAGS += -I$(srcdir)/ext/dynamic_allocation/inc +AM_CFLAGS += -I$(top_srcdir)/ar_osal/api +AM_CFLAGS += -I$(top_srcdir)/ar_util/api +AM_CFLAGS += -I$(top_srcdir)/gpr/api +AM_CFLAGS += -I$(top_srcdir)/acdb/api +AM_CFLAGS += -I$(top_srcdir)/spf/api/ar_utils -I$(top_srcdir)/spf/api/apm -I$(top_srcdir)/spf/api/modules + +AM_CFLAGS += -DSESSION_ARRAY_SIZE=200 +AM_CFLAGS += -D_GNU_SOURCE + +gpr_sources = ./api/gpr_api.h \ + ./api/gpr_api_inline.h \ + ./api/gpr_comdef.h \ + ./api/gpr_ids_domains.h \ + ./api/gpr_msg_if.h \ + ./api/gpr_pack_begin.h \ + ./api/gpr_pack_end.h \ + ./api/gpr_packet.h \ + ./api/ipc_dl_api.h \ + ./api/ar_guids.h \ + ./api/ar_types.h \ + ./core/inc/gpr_api_i.h \ + ./core/inc/gpr_list.h \ + ./core/src/gpr_memq.h \ + ./datalinks/gpr_lx/inc/gpr_lx.h + +gpr_c_sources = ./core/src/gpr_drv.c \ + ./core/src/gpr_list.c \ + ./core/src/gpr_main.c \ + ./core/src/gpr_memq.c \ + ./core/src/gpr_drv_island.c \ + ./core/src/gpr_list_island.c \ + ./core/src/gpr_memq_island.c \ + ./core/src/hash_based/gpr_session.c \ + ./core/src/hash_based/gpr_session_island.c \ + ./ext/dynamic_allocation/src/gpr_dynamic_allocation.c \ + ./ext/logging/src/gpr_log_generic.c \ + ./ext/logging/stub_src/gpr_log_diag_stub.c \ + ./datalinks/gpr_lx/src/gpr_lx.c \ + ./platform/linux/gpr_init_lx_wrapper.c + +lib_includedir = $(includedir) +lib_include_HEADERS = $(gpr_sources) + +lib_LTLIBRARIES = libar-gpr.la +libar_gpr_la_CC = @CC@ +libar_gpr_la_LIBADD = -lpthread $(top_builddir)/ar_osal/libar-osal.la +if USE_GLIB +libar_gpr_la_LIBADD += -lglib-2.0 +AM_CFLAGS += $(GLIB_CFLAGS) -include glib.h +endif + +if USE_G_STR_FUNC +AM_CFLAGS += -Dstrlcpy=g_strlcpy +endif + +if CUTILS_SUPPORTED +libar_gpr_la_LIBADD += -lcutils +AM_CFLAGS += -DGPR_USE_CUTILS +endif + +if USE_ARE_ON_APPS +AM_CFLAGS += -DARE_ON_APPS +endif + +libar_gpr_la_SOURCES = $(gpr_c_sources) +libar_gpr_la_CFLAGS = $(AM_CFLAGS) +libar_gpr_la_LDFLAGS = -shared -version-number @LT_VERSION_NUMBER@ + diff --git a/gpr/api/ar_guids.h b/gpr/api/ar_guids.h new file mode 100644 index 0000000..df3b968 --- /dev/null +++ b/gpr/api/ar_guids.h @@ -0,0 +1,122 @@ +#ifndef AR_GUIDS_H_ +#define AR_GUIDS_H_ +/** + * \file gpr_list.h + * \brief + * This file contains GUID definitions + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/** + * GUIDs are 32 bit numbers. + * + */ + +/** + * An empty macro to mark non-GUIDs so that GUID script doesn't mistake the ID for a GUID + * + */ +#define AR_NON_GUID(x) x + +/** + * GUID Owners + */ +/** + * GUID owner is Qualcomm. + */ +#define AR_GUID_OWNER_QC 0x0 +/** + * GUID owner is not-Qualcomm. + * All ISVs, OEMs & Customers must use this range. + */ +#define AR_GUID_OWNER_NON_QC 0x1 + /** Rest are reserved */ + +/** + * Mask for Owner + */ +#define AR_GUID_OWNER_MASK AR_NON_GUID(0xF0000000) +/** + * Shift for Owner + */ +#define AR_GUID_OWNER_SHIFT 28 + +/** + * GUID types + */ +/** + * Reserved GUID type. Used for legacy IDs. + */ +#define AR_GUID_TYPE_RESERVED 0x0 + +/** + * GUID type for Control commands. + */ +#define AR_GUID_TYPE_CONTROL_CMD 0x1 +/** + * GUID type for command responses of control commands. + */ +#define AR_GUID_TYPE_CONTROL_CMD_RSP 0x2 +/** + * GUID type for control events. + */ +#define AR_GUID_TYPE_CONTROL_EVENT 0x3 +/** + * GUID type for data commands + */ +#define AR_GUID_TYPE_DATA_CMD 0x4 +/** + * GUID type for data command responses. + */ +#define AR_GUID_TYPE_DATA_CMD_RSP 0x5 +/** + * GUID type for data events + */ +#define AR_GUID_TYPE_DATA_EVENT 0x6 +/** + * GUID type for module-id + */ +#define AR_GUID_TYPE_MODULE_ID 0x7 +/** + * GUID type for module's param & event-id + */ +#define AR_GUID_TYPE_PARAM_EVENT_ID 0x8 +/** + * GUID type for media format-id. + */ +#define AR_GUID_TYPE_FORMAT_ID 0x9 +/** + * GUID type is CAPI. + * All CAPI framework extensions, interface extensions + * their events, params use this. + * + * All module params & events must use AR_GUID_TYPE_PARAM_EVENT_ID + */ +#define AR_GUID_TYPE_CAPI 0xA + +/** Rest are reserved */ + +/** + * Mask for GUID type + */ +#define AR_GUID_TYPE_MASK AR_NON_GUID(0x0F000000) +/** + * Shift for GUID type + */ +#define AR_GUID_TYPE_SHIFT 24 + +/** + * Zero is an invalid ID. + * To be used like NULL value for pointers. + */ +#define AR_GUID_INVALID 0 + + + +#endif /* AR_GUIDS_H_ */ + diff --git a/gpr/api/ar_types.h b/gpr/api/ar_types.h new file mode 100644 index 0000000..bca5703 --- /dev/null +++ b/gpr/api/ar_types.h @@ -0,0 +1,32 @@ +#ifndef _AR_TYPES_H_ +#define _AR_TYPES_H_ + +/** + * \file ar_types.h + * \brief + * This file contains type definitions + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +#include "ar_osal_types.h" + +/** @addtogroup ar_types +@{ */ + +/** Status messages (error codes) returned by command responses. */ +typedef uint32_t ar_result_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _AR_TYPES_H_ */ diff --git a/gpr/api/gpr_api.h b/gpr/api/gpr_api.h new file mode 100644 index 0000000..78d30db --- /dev/null +++ b/gpr/api/gpr_api.h @@ -0,0 +1,281 @@ +#ifndef __GPR_API_H__ +#define __GPR_API_H__ + +/** + * @file gpr_api.h + * @brief This file contains GPR APIs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_packet.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/***************************************************************************** + * Definitions * + ****************************************************************************/ + +/* Deafult heap index - its an 8 Bit value */ +#define GPR_HEAP_INDEX_DEFAULT 0 + +/* Heap index 1 - its an 8 Bit value */ +#define GPR_HEAP_INDEX_1 1 + +/* GPR Heap index type definition + Supported Values: + 1. GPR_HEAP_INDEX_DEFAULT + 2. GPR_HEAP_INDEX_1 */ +typedef uint8_t gpr_heap_index_t; + +/** @ingroup gpr_func_proto_callback + Prototype of a packet callback function. + + @datatypes + #gpr_packet_t + + @param[in] packet Pointer to the incoming packet. + The packet is guaranteed to have a non-NULL value. + @param[in] callback_data Client-supplied data pointer that the service + provided at registration time. + + @return + #AR_EOK -- When successful, indicates that the callee has taken ownership of + the packet. + @par + Otherwise, an error (see @xref{hdr:StatusCodes}) -- The packet ownership is + returned to the caller. +*/ +typedef uint32_t (*gpr_callback_fn_t)(gpr_packet_t *packet, void *callback_data); + +/* Structure to define the information related to a single packet pool. */ +typedef struct gpr_packet_pool_info_v2_t gpr_packet_pool_info_v2_t; + +struct gpr_packet_pool_info_v2_t +{ + gpr_heap_index_t heap_index; + /* heap index from which packet pool has to be allocated. + @valid_values + 0 - GPR_HEAP_INDEX_DEFAULT + 1 - GPR_HEAP_INDEX_1 */ + + uint8_t is_dynamic; + /* Flag to indicate if the packets in the pool need to be allocated dynamically or statcially at init.*/ + + uint16_t reserved; + /* Reserved field for alignment, must be set to 0*/ + + uint32_t num_packets; + /* Max number of packets in the pool. + + If is_dynamic is set to 0: indicates number of packets to be statically allocated + If is_dynamic > 0: indicates maximum number of packets that can be dynamically allocated at any given time. + */ + + uint32_t packet_size; + /* Size of each packet in the pool.*/ +}; + +/***************************************************************************** + * Core Routines * + ****************************************************************************/ + +/** @addtogroup gpr_core_routines +@{ */ + +/** + Performs external initialization of the GPR infrastructure. + + Each supported domain calls this function once during system bring-up or + during runtime to initialize the GPR infrastructure for that domain. The GPR + infrastructure must be initialized before any other GPR APIs can be called. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + + @codeexample + @lstlisting +#include "gpr_api.h" + +int32_t rc = gpr_init(); +if ( rc ) +{ + printf( "Could not initialize the GPR infrastructure" ); +} + @endlstlisting + @newpage +*/ +GPR_EXTERNAL uint32_t gpr_init(void); + +/** + To initialize GPR with particular domain. + + @return + #AR_EOK -- When successful. + + @dependencies + None. +*/ +GPR_EXTERNAL uint32_t gpr_init_domain(uint32_t domain_id); + +/** + Performs external deinitialization of the GPR infrastructure. + + Each supported domain calls this function once during system shutdown or + during runtime to deinitialize the GPR infrastructure for that domain. No + functions except for gpr_init() can be called after the GPR infrastructure is + deinitialized. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + + @codeexample + @lstlisting +#include "gpr_api.h" + +int32_t rc = gpr_deinit(); +if ( rc ) +{ + printf( "Could not deinitialize the GPR infrastructure" ); +} + @endlstlisting @newpage +*/ +GPR_EXTERNAL uint32_t gpr_deinit(void); + +/** @} */ /* end_addtogroup gpr_core_routines */ + + +/***************************************************************************** + * Fundamental Controls * + ****************************************************************************/ +/* Queries for the GPR's packet pool information. */ + +typedef struct gpr_cmd_gpr_packet_pool_info_t gpr_cmd_gpr_packet_pool_info_t; +/** @endcond */ + +/** @weakgroup weakb_gpr_cmd_gpr_packet_pool_info_t +@{ */ +/** Contains the packet pool information for __gpr_cmd_get_gpr_packet_info(). +*/ +struct gpr_cmd_gpr_packet_pool_info_t +{ + uint32_t bytes_per_min_size_packet; + /**< Minimum size (in bytes) of a GPR packet. */ + + uint32_t num_min_size_packets; + /**< Number of packets of the minimum size allocated at initialization. */ + + uint32_t bytes_per_max_size_packet; + /**< Maximum size (in bytes) of a GPR packet. */ + + uint32_t num_max_size_packets; + /**< Number of packets of the maximum size allocated at initialization. */ +}; +/** @} */ /* end_weakgroup weakb_gpr_cmd_gpr_packet_pool_info_t */ + + +/***************************************************************************** + * Utility Controls * + ****************************************************************************/ +/** @cond */ +/* Allocates a preformatted free packet for delivery. */ + +typedef struct gpr_cmd_alloc_ext_t gpr_cmd_alloc_ext_t; +/** @endcond */ + +/** @weakgroup weakb_gpr_cmd_alloc_ext_t +@{ */ +/** Contains the allocated packet information for __gpr_cmd_alloc_ext(). +*/ +struct gpr_cmd_alloc_ext_t +{ + uint8_t src_domain_id; /**< Domain ID of the sender service. */ + uint32_t src_port; /**< Registered unique ID of the sender service. */ + uint8_t dst_domain_id; /**< Domain ID of the receiver service. */ + uint32_t dst_port; /**< Registered unique ID of the receiver service. */ + uint8_t client_data; /**< Reserved for use by client. */ + uint32_t token; /**< Value attached by the sender to determine + when command messages are processed by the + receiver after they receive response messages. */ + uint32_t opcode; /**< Defines both the action and the payload + structure to the receiver. */ + uint32_t payload_size; /**< Actual number of bytes required for the + payload. */ + gpr_packet_t **ret_packet; /**< Double pointer to the formatted packet + returned by the function. */ +}; +/** @} */ /* end_weakgroup weak_gpr_cmd_alloc_ext_t */ + +typedef struct gpr_cmd_alloc_ext_v2_t gpr_cmd_alloc_ext_v2_t; +/** @endcond */ + +/** @weakgroup weakb_gpr_cmd_alloc_ext_v2_t +@{ */ +/** Contains the allocated packet information for __gpr_cmd_alloc_ext_v2(). +*/ +struct gpr_cmd_alloc_ext_v2_t +{ + uint8_t src_domain_id; /**< Domain ID of the sender service. */ + uint32_t src_port; /**< Registered unique ID of the sender service. */ + uint8_t dst_domain_id; /**< Domain ID of the receiver service. */ + uint32_t dst_port; /**< Registered unique ID of the receiver service. */ + uint8_t client_data; /**< Reserved for use by client. */ + uint32_t token; /**< Value attached by the sender to determine + when command messages are processed by the + receiver after they receive response messages. */ + gpr_heap_index_t heap_index; /**< heap index of the packet pool. '0' is default value. + Must be set to 0 if not applicable. */ + uint32_t opcode; /**< Defines both the action and the payload + structure to the receiver. */ + uint32_t payload_size; /**< Actual number of bytes required for the + payload. */ + gpr_packet_t **ret_packet; /**< Double pointer to the formatted packet + returned by the function. */ +}; +/** @} */ /* end_weakgroup weakb_gpr_cmd_alloc_ext_v2_t */ + +/** @cond */ +/* Allocates and sends a formatted packet. */ + +typedef struct gpr_cmd_alloc_send_t gpr_cmd_alloc_send_t; +/** @endcond */ + +/** @weakgroup weakb_gpr_cmd_alloc_send_t +@{ */ +/** Contains the allocated packet information for __gpr_cmd_alloc_send(). +*/ +struct gpr_cmd_alloc_send_t +{ + uint8_t src_domain_id; /**< Domain ID of the sender service. */ + uint32_t src_port; /**< Registered unique ID of the sender service. */ + uint8_t dst_domain_id; /**< Domain ID of the receiver service. */ + uint32_t dst_port; /**< Registered unique ID of the receiver service. */ + uint8_t client_data; /**< Reserved for use by the client. */ + uint32_t token; /**< Value attached by the sender to determine when + command messages have been processed by the + receiver after having received response messages. */ + uint32_t opcode; /**< Operation code defines both the action and the + payload structure to the receiver. */ + uint32_t payload_size; /**< Actual number of bytes needed for the payload. */ + void *payload; /**< Pointer to the payload to send. */ +}; +/** @} */ /* end_weakgroup weakb_gpr_cmd_alloc_send_t */ + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_API_H__ */ diff --git a/gpr/api/gpr_api_inline.h b/gpr/api/gpr_api_inline.h new file mode 100644 index 0000000..ce74a1f --- /dev/null +++ b/gpr/api/gpr_api_inline.h @@ -0,0 +1,816 @@ +#ifndef __GPR_API_INLINE_H__ +#define __GPR_API_INLINE_H__ + +/** + * @file gpr_api_inline.h + * @brief This file contains GPR APIs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "ar_osal_error.h" +#include "gpr_api.h" +#include "gpr_msg_if.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +//#define GPR_DEBUG_MSG +/***************************************************************************** + * Inline Fundamental Controls * + ****************************************************************************/ + +/** @ingroup gpr_cmd_register + Registers a service, by its unique service ID, with the GPR. + + @datatypes + #gpr_callback_fn_t + + @param[in] src_port Unique ID (within a domain) of the service to be + registered. + @param[in] callback_fn Callback function of the service to be registered. + @param[in] callback_data Pointer to the client-supplied data pointer for the + callback function. + + @detdesc + Services call this command once during system bring-up or runtime to register + their presence with the GPR. + @par + A service is any functional block, such as a module, that is required to send + or receive GPR packets. Services must be registered with the GPR before they + can send or receive any messages. + + @return + #AR_EOK -- When successful. + @par + #AR_EALREADY -- Service has already been registered. + + @dependencies + GPR initialization must be completed via gpr_init(). @newpage + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +//Example of a test client service (with service ID GPR_TESTCLIENT_SERVICE_ID) +//trying to register with GPR. +uint32_t service_callback_fn(gpr_packet_t *packet, void *callback_data); +void * callback_data = NULL; + +int main ( void ) +{ + int32_t rc = __gpr_cmd_register(GPR_TESTCLIENT_SERVICE_ID, + callback_fn, + callback_data); + if ( rc ) + { + printf( "Could not register the test client service with GPR" ); + } + return 0; +} + +//Example of a callback function for a service. It is invoked by GPR +//every time a message is sent or received, to or from that service. +static int32_t service_callback_fn( gpr_packet_t* packet, + void* callback_data ) +{ + // Accept command by replying to the sender that the message is accepted. + // The usage is optional. + __gpr_cmd_accept_command( packet ); + + switch ( packet->opcode ) + { + case TEST_CLIENT_CMD_FUNCTION: + { + // Handle accordingly based on operation code and send response to + // the sender that command is completed. + __gpr_cmd_end_command( packet, AR_EOK ); + break; + } + case TEST_CLIENT_RSP_FUNCTION: + { + // Notify command completion. + // Response may contain payload, free the packet after handling. + __gpr_cmd_free( packet ); + break; + } + case GPR_IBASIC_RSP_RESULT: + { + // Notify command completion, response contains the error status. + __gpr_cmd_free( packet ); + break; + } + default: + { + // Free unsupported events and command responses. + __gpr_cmd_free( packet ); + break; + } + } + return AR_EOK; + // AR_EOK tells the caller that the packet was consumed (freed). +} + @endlstlisting + */ +uint32_t __gpr_cmd_register(uint32_t src_port, gpr_callback_fn_t callback_fn, void *callback_data); + +/** @ingroup gpr_cmd_deregister + Deregisters a service from the GPR. + + @param[in] src_port Unique ID of the service. + + @detdesc + Services call this function once during system teardown or runtime to + deregister their presence from the GPR. + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +//Example of a test client service (with service ID GPR_TESTCLIENT_SERVICE_ID) +//trying to deregister from GPR. +uint32_t callback_fn(gpr_packet_t *packet, void *callback_data); +void * callback_data = NULL; + +int32_t rc = __gpr_cmd_register(GPR_TESTCLIENT_SERVICE_ID, + callback_fn, + callback_data); +if ( rc ) +{ + printf( "Could not register the client service with GPR" ); +} +... +rc = __gpr_cmd_deregister(GPR_TESTCLIENT_SERVICE_ID); +if ( rc ) +{ + printf( "Could not deregister the client service from GPR" ); +} + @endlstlisting + */ +uint32_t __gpr_cmd_deregister(uint32_t src_port); + +/** @ingroup gpr_cmd_is_registered + Called by the framework to check whether a service is registered with the GPR. + + @param[in] port Unique ID of the service. + @param[out] is_registered Pointer to the client-supplied flag that returns + TRUE if service is registered and FALSE if the + service is not registered. + + @return + #AR_EOK. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +//Example to check if test client service (with service ID GPR_TESTCLIENT_SERVICE_ID) +// is registered with GPR. +bool_t is_registered = FALSE; +__gpr_cmd_is_registered(GPR_TESTCLIENT_SERVICE_ID, &is_registered); +if(TRUE == is_registered) +{ + printf( "Client service registered with GPR" ); +} +else +{ + printf( "Client service not registered with GPR" ); +} + @endlstlisting @newpage + */ +uint32_t __gpr_cmd_is_registered(uint32_t port, bool_t *is_registered); + +/** @ingroup gpr_cmd_get_host_dom_id + Queries the GPR to get the local or host domain ID. + + @param[out] host_domain_id Pointer to the GPR's host domain ID. + + @return + #AR_EOK always.- Returns the host domain ID + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +uint32_t host_domain_id; +__gpr_cmd_host_domain_id( &host_domain_id ); +printf( "GPR is in domain ID: %d ", host_domain_id ); + @endlstlisting + */ +uint32_t __gpr_cmd_get_host_domain_id(uint32_t *host_domain_id); + +/** @ingroup gpr_cmd_get_dest_domain_ids +Utility to query list of destination domain ids with which GPR communication is supported from the current domain. + +@param[out] num_domains - Pointer to the num of destination domains. +@param[out] domain_ids - Pointer to the GPR's destination domain IDs. + +@return +#AR_EOK always.- Returns the number of destination domains on requesting first time. +#AR_EOK always.- When called again with memory allocated for domain array, fills destination domain ids info. + +@dependencies +GPR initialization must be completed via gpr_init(). + +@codeexample +@lstlisting + +#include "gpr_api_inline.h" + +uint32_t num_domains = 0; +uint32_t *dest_domains = NULL; +__gpr_cmd_get_dest_domain_ids(&num_domains, dest_domains); +dest_domains = (uint32_t *)malloc(sizeof(num_domains*sizeof(uint32_t))); +__gpr_cmd_get_dest_domain_ids(&num_domains, dest_domains); + + @endlstlisting +*/ +uint32_t __gpr_cmd_get_dest_domain_ids(uint32_t *num_domains, uint32_t *domain_ids); + +/** @ingroup gpr_cmd_is_shared_mem_supported + Utility to query if shared memory is supported from the current domain to a given dest_domain_id. + + @param[in] dest_domain_id - Destination domain id. + @param[out] supports_shared_mem - Pointer to know if domain supports shared memory + + @return + #AR_EOK always.- Returns if a destination domain supports shared memory. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + @lstlisting + #include "gpr_api_inline.h" + + uint32_t dest_domain_id = GPR_IDS_DOMAIN_ID_ADSP_V; + bool_t supports_shared_mem = true; + __gpr_cmd_is_shared_mem_supported(dest_domain_id, &supports_shared_mem); + if (supports_shared_mem) + // do something + else + // do something + @endlstlisting +*/ +uint32_t __gpr_cmd_is_shared_mem_supported(uint32_t dest_domain_id, bool_t *supports_shared_mem); + +/** @ingroup gpr_cmd_get_pkt_pool + Queries for the GPR's packet pool information. + + @datatypes + #gpr_cmd_gpr_packet_pool_info_t + + @param[out] args Pointer to the packet pool information, such as the number + and sizes of the packets. + + @detdesc + This function returns following information: + - Minimum and maximum sizes (in bytes) of the packets allocated by the GPR. + - Maximum number of each packet. + @par + The number of packets does not translate to the packets that are currently + available. The number is the total or maximum number of packets allocated + during initialization. + @par + Clients can use this information to decide whether to send inband or + out-of-band commands. + + @return + #AR_EOK -- Returns the GPR packet pool information. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +gpr_cmd_gpr_packet_pool_info_t packet_info; +__gpr_cmd_get_gpr_packet_info( &packet_info ); + +printf( "GPR packet pool information: + Bytes in minimum-sized gpr packet: %d, + Number of minimum-sized gpr packets allocated at initialization: %d, + Bytes in maximum-sized gpr packet: %d, + Number of maximum-sized gpr packets allocated at initialization: %d ", + packet_info.bytes_per_min_size_packet, + packet_info.num_min_size_packets, + packet_info.bytes_per_max_size_packet, + packet_info.num_max_size_packets); + @endlstlisting + + @inputfile{group__weakb__gpr__cmd__gpr__packet__pool__info__t.tex} + */ +uint32_t __gpr_cmd_get_gpr_packet_info(gpr_cmd_gpr_packet_pool_info_t *args); + +/** @ingroup gpr_cmd_get_pkt_pool_v2 + Queries for the GPR's V2 packet pool information. + + @datatypes + #gpr_packet_pool_info_v2_t + + @param[out] num_packet_pools Number of packet pools that are created. + @param[out] packet_pool_info_arr Packet pool info array, with each element in array containing pool related info like + number of packets, packet size, heap index and if the packets are dynamically/statically + allocated. + + @detdesc + 1. Number of packet pools present + 2. Arrays of packet pool info. Each element of the array has info related to the pool like + • Size(in bytes) of each packet in the pool + • Max number of packets in the pool. + • Heap index of the packet pool. + • IS_DYNAMIC – flag indicating if the packet in the pool are created dynamically or statically at init. + + @par + The number of packets in each pool does not translate to the packets that are currently + available. The number is the total or maximum number of packets allocated during initialization. + + @par + Clients can use this information to decide whether to send inband or + out-of-band commands. + + @return + #AR_EOK always.- Returns the number of packet pools on requesting first time. + #AR_EOK always.- When called again with memory allocated for Packet pool info array, fills the array elements with the pool info. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +gpr_packet_pool_info_v2_t *packet_pool_info_arr = NULL; +uint32_t num_packet_pools = 0; + +// Calling first time, to gets number of packet pools and allocates the array accordingly. +__gpr_cmd_get_gpr_packet_info_v2( &num_packet_pools, packet_pool_info_arr ); +packet_pool_info_arr = (gpr_packet_pool_info_v2_t *)malloc(sizeof(num_packet_pools*sizeof(gpr_packet_pool_info_v2_t))); + +// Calling second time to the get the populated packet_pool_info_arr +__gpr_cmd_get_gpr_packet_info_v2( &num_packet_pools, packet_pool_info_arr ); + + @endlstlisting + + @inputfile{group__weakb__gpr__cmd__gpr__packet__pool__info__v2__t.tex} + */ +uint32_t __gpr_cmd_get_gpr_packet_info_v2(uint32_t *num_packet_pools, gpr_packet_pool_info_v2_t *packet_pool_info_arr); + +/** @ingroup gpr_cmd_send_async + Sends an asynchronous message to other services. + + @datatypes + #gpr_packet_t + + @param[in] packet Pointer to the packet (message) to send. + + @detdesc + This function provides the caller with low-level control over the sending + process. For general use, consider using a simplified helper function, such as + __gpr_cmd_alloc_send(). + @par + Before calling this function, use __gpr_cmd_alloc() or __gpr_cmd_alloc_ext() + to allocate free messages for sending. If delivery fails, the caller must + either try to resend the messages or abort-and-free the messages + + @par Notes + The sender must always anticipate failures, even when this function returns no + errors. The #GPR_IBASIC_RSP_RESULT response messages are to be checked for + any error statuses that are returned. + @par + The sender can locally abort any remotely pending operations by implementing + timeouts. The sender must still expect and handle receipt of response messages + for those aborted operations. + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + @par + The source and destination services must be registered with the GPR. + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +int32_t rc; +gpr_packet_t* packet_ptr; +uint32_t payload_size; +uint32_t packet_size; + +//Example of a payload structure that needs to be populated and sent. +test_client_cmd_function_t payload; +payload_size = sizeof( test_client_cmd_function_t ); +packet_size = payload_size + GPR_PKT_HEADER_WORD_SIZE_V; + +// Allocate a free packet. +rc = __gpr_cmd_alloc( payload_size, &packet ); +if ( rc ) +{ + return AR_ENORESOURCE; +} + +// Fill in the packet details. +packet->header GPR_SET_FIELD(GPR_PKT_VERSION, GPR_PKT_VERSION_V) | + GPR_SET_FIELD(GPR_PKT_HEADER_SIZE, GPR_PKT_HEADER_WORD_SIZE_V) | + GPR_SET_FIELD(GPR_PKT_PACKET_SIZE, packet_size); +packet->dst_domain = GPR_CLIENT_SERVICE_DOMAIN_ID_DESTINATION; +packet->src_domain = GPR_CLIENT_SERVICE_DOMAIN_ID_SOURCE; +packet->dst_port = GPR_CLIENT_SERVICE_PORT_ID_DESTINATION; +packet->src_port = GPR_CLIENT_SERVICE_PORT_ID_SOURCE; +packet->token = 0x12345678; +packet->opcode = TEST_CLIENT_CMD_FUNCTION; + +// Fill in the payload. +payload.param1 = 1; +payload.param2 = 2; +memscpy( GPR_PKT_GET_PAYLOAD( void, packet ), payload_size, payload, payload_size ); + +// Send the packet. +rc = __gpr_cmd_async_send( packet_ptr ); +if ( rc ) +{ + // Free the packet when delivery fails. + ( void ) __gpr_cmd_free( packet_ptr ); + return rc; +} + @endlstlisting + */ +uint32_t __gpr_cmd_async_send(gpr_packet_t *packet); + +/** @ingroup gpr_cmd_alloc + Allocates a free message for delivery. + + @datatypes + #gpr_packet_t + + @param[in] alloc_size Amount of memory (in bytes) required for allocation. + @param[out] ret_packet Double pointer to the allocated packet that is + returned by this function. + + @detdesc + This function allocates a packet from the GPR's free packet queue. It provides + the caller with low-level control over the allocation process. + @par + For general use, consider using a simplified helper function, such as + __gpr_cmd_alloc_ext(). + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + See the code example for __gpr_cmd_async_send(). + */ +uint32_t __gpr_cmd_alloc(uint32_t alloc_size, gpr_packet_t **ret_packet); + +/** @ingroup gpr_cmd_alloc + Allocates a free message for delivery from a specified heap. + + @datatypes + #gpr_packet_t + + @param[in] alloc_size Amount of memory (in bytes) required for allocation. + @param[in] heap_index Heap index of the packet pool. + @param[out] ret_packet Double pointer to the allocated packet that is + returned by this function. + + @detdesc + This function allocates a packet from the GPR's free packet queue from the specified heap. + It provides the caller with low-level control over the allocation process. + @par + For general use, consider using a simplified helper function, such as + __gpr_cmd_alloc_ext_v2(). + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + See the code example for __gpr_cmd_async_send(). + */ +uint32_t __gpr_cmd_alloc_v2(uint32_t alloc_size, gpr_heap_index_t heap_index, gpr_packet_t **ret_packet); + +/** @ingroup gpr_cmd_free + Frees a specified GPR packet and returns it to the owner. + + @datatypes + #gpr_packet_t + + @param[in] packet Pointer to the GPR packet to be freed. + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + See the code example for __gpr_cmd_async_send(). + */ +uint32_t __gpr_cmd_free(gpr_packet_t *packet); + +/***************************************************************************** + * Inline Utility Controls * + ****************************************************************************/ + + +/** @ingroup gpr_cmd_alloc_ext + Allocates a formatted free packet for delivery. + + @datatypes + #gpr_cmd_alloc_ext_t + + @param[in] args Pointer to the allocated packet information, such as domain + and port IDs, token and opcode values, and payload size. + + @detdesc + This helper function partially creates a packet for delivery. It performs the + packet allocation and initialization, but the packet payload is dependent on + the caller to fill in. + @par + This two-step process allows the caller to avoid multiple memscpy() operations + on the packet payload. + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + @par + The source and destination services must be registered with the GPR. + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +int32_t rc; +gpr_packet_t* packet_ptr; +uint32_t payload_size; + +//Example payload required to be sent. +test_client_cmd_function_t * payload; + +gpr_cmd_alloc_ext_t alloc_args; +alloc_args.src_domain_id = GPR_CLIENT_SERVICE_DOMAIN_ID_SOURCE; +alloc_args.src_port = GPR_CLIENT_SERVICE_PORT_ID_SOURCE; +alloc_args.dst_domain_id = GPR_CLIENT_SERVICE_DOMAIN_ID_DESTINATION; +alloc_args.dst_port = GPR_CLIENT_SERVICE_PORT_ID_DESTINATION; +alloc_args.token = 0x12345678; +alloc_args.opcode = TEST_CLIENT_CMD_FUNCTION; +alloc_args.payload_size = sizeof( test_client_cmd_function_t ); +alloc_args.ret_packet = &packet_ptr; + +// Allocate memory for the packet. +rc = __gpr_cmd_alloc_ext(alloc_args); +if ( rc ) +{ + printf( "Packet allocation failed" ); + return AR_EFAILED; +} + +// Fill in the payload. +payload = GPR_PKT_GET_PAYLOAD( test_client_cmd_function_t, packet_ptr ); +payload->param1 = 1; +payload->param2 = 2; + +// Send the packet. +rc = __gpr_cmd_async_send( packet_ptr ); +if ( rc ) +{ + printf( "Could not send the packet.\n" ); +} + @endlstlisting + + @inputfile{group__weakb__gpr__cmd__alloc__ext__t.tex} + */ +uint32_t __gpr_cmd_alloc_ext(gpr_cmd_alloc_ext_t *args); + +/** @ingroup gpr_cmd_alloc_ext_v2 + Allocates a formatted free packet for delivery from a specified heap. + + @datatypes + #gpr_cmd_alloc_ext_v2 + + @param[in] args Pointer to the allocated packet information, such as domain + and port IDs, token and opcode values, heap_index and payload size. + + @detdesc + This helper function partially creates a packet for delivery from a specified heap. It performs the + packet allocation and initialization, but the packet payload is dependent on + the caller to fill in. + + @par + This two-step process allows the caller to avoid multiple memscpy() operations + on the packet payload. + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + @par + The source and destination services must be registered with the GPR. + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +int32_t rc; +gpr_packet_t* packet_ptr; +uint32_t payload_size; + +//Example payload required to be sent. +test_client_cmd_function_t * payload; + +gpr_cmd_alloc_ext_v2_t alloc_args; +alloc_args.src_domain_id = GPR_CLIENT_SERVICE_DOMAIN_ID_SOURCE; +alloc_args.src_port = GPR_CLIENT_SERVICE_PORT_ID_SOURCE; +alloc_args.dst_domain_id = GPR_CLIENT_SERVICE_DOMAIN_ID_DESTINATION; +alloc_args.dst_port = GPR_CLIENT_SERVICE_PORT_ID_DESTINATION; +alloc_args.token = 0x12345678; +alloc_args.heap_index = GPR_HEAP_INDEX_DEFAULT; +alloc_args.opcode = TEST_CLIENT_CMD_FUNCTION; +alloc_args.payload_size = sizeof( test_client_cmd_function_t ); +alloc_args.ret_packet = &packet_ptr; + +// Allocate memory for the packet. +rc = __gpr_cmd_alloc_ext_v2(alloc_args); +if ( rc ) +{ + printf( "Packet allocation failed" ); + return AR_EFAILED; +} + +// Fill in the payload. +payload = GPR_PKT_GET_PAYLOAD( test_client_cmd_function_t, packet_ptr ); +payload->param1 = 1; +payload->param2 = 2; + +// Send the packet. +rc = __gpr_cmd_async_send( packet_ptr ); +if ( rc ) +{ + printf( "Could not send the packet.\n" ); +} + @endlstlisting + + @inputfile{group__weakb__gpr__cmd__alloc__ext__v2__t.tex} + */ +uint32_t __gpr_cmd_alloc_ext_v2(gpr_cmd_alloc_ext_v2_t *args); + +/** @ingroup gpr_cmd_alloc_send + Allocates and sends a formatted free packet. + + @datatypes + #gpr_cmd_alloc_send_t + + @param[in] args Pointer to the allocated packet information, such as domain + and port IDs, token and opcode values, and payload size. + + @detdesc + This helper function fully creates the packet, and it performs the packet + allocation and initialization. The caller supplies the packet payload as + an input if you do not want to it use up front. For comparison, see + __gpr_cmd_async_send(). + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + @par + The source and destination services must be registered with the GPR. + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +int32_t rc; +gpr_packet_t* packet_ptr; +uint32_t payload_size; + +//Example payload required to be sent. +test_client_cmd_function_t payload; + +// Fill in the payload. +payload.param1 = 1; +payload.param2 = 2; + +gpr_cmd_alloc_send_t alloc_send_args; +alloc_send_args.src_domain_id = GPR_CLIENT_SERVICE_DOMAIN_ID_SOURCE; +alloc_send_args.src_port = GPR_CLIENT_SERVICE_PORT_ID_SOURCE; +alloc_send_args.dst_domain_id = GPR_CLIENT_SERVICE_DOMAIN_ID_DESTINATION; +alloc_send_args.dst_port = GPR_CLIENT_SERVICE_PORT_ID_DESTINATION; +alloc_send_args.token = 0x12345678; +alloc_send_args.opcode = TEST_CLIENT_CMD_FUNCTION; +alloc_send_args.payload_size = sizeof( test_client_cmd_function_t ); +alloc_send_args.payload = &payload; + +// Create and send packet. +rc = __gpr_cmd_alloc_send(alloc_send_args); +if ( rc ) +{ + printf( "Packet allocation and send failed" ); + return AR_EFAILED; +} + @endlstlisting + + @inputfile{group__weakb__gpr__cmd__alloc__send__t.tex} + */ +uint32_t __gpr_cmd_alloc_send(gpr_cmd_alloc_send_t *args); + +/** @ingroup gpr_cmd_accept_cmd + Accepts a command packet by replying with a #GPR_IBASIC_EVT_ACCEPTED + message to the sender. + + @datatypes + #gpr_packet_t + + @param[in] packet Pointer to the command packet to be accepted. + + @detdesc + The required routing information is extracted from the specified + packet. + @par + The same procedure can be performed manually by swapping the source and + destination fields, and then inserting a GPR_IBASIC_EVT_ACCEPTED + payload. + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + @par + The source and destination services must be registered with the GPR. + + @codeexample + See the code example for __gpr_cmd_register(). + */ +uint32_t __gpr_cmd_accept_command(gpr_packet_t *packet); +/** @ingroup gpr_cmd_end_cmd + Completes a command message by replying with a #GPR_IBASIC_RSP_RESULT command + response message to the sender. The indicated packet is then freed. + + @datatypes + #gpr_packet_t + + @param[in] packet Pointer to the command message to complete. + @param[in] status Completion or error status to respond to the client (see + Section @xref{hdr:StatusCodes}). + + @detdesc + This function both sends an GPR_IBASIC_RSP_RESULT command response back to + the sender and frees the specified command packet. The required routing + information is extracted from the command packet. + @par + The same procedure can be done manually by swapping the source and + destination fields and then inserting an #GPR_IBASIC_RSP_RESULT command + response payload. + + @return + #AR_EOK -- When successful. + @par + #AR_EBADPARAM -- When the input parameter is invalid. The packet to be + delivered is not freed. + + @dependencies + GPR initialization must be completed via gpr_init(). + @par + The source and destination services must be registered with the GPR. + + @codeexample + See the code example for __gpr_cmd_register(). + + */ +uint32_t __gpr_cmd_end_command(gpr_packet_t *packet, uint32_t status); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_API_INLINE_H__ */ diff --git a/gpr/api/gpr_comdef.h b/gpr/api/gpr_comdef.h new file mode 100644 index 0000000..ac0daa8 --- /dev/null +++ b/gpr/api/gpr_comdef.h @@ -0,0 +1,65 @@ +#ifndef __GPR_COMDEF_H__ +#define __GPR_COMDEF_H__ + +/** + * @file gpr_comdef.h + * @brief This file contains GPR common defs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "ar_osal_types.h" + + +/****************************************************************************/ +//GPR Core Export Macros + +/****************************************************************************/ + +/** @addtogroup gpr_macros +@{ */ +/** @name GPR Core Export Macros +@{ */ + +#ifdef __cplusplus + #define GPR_INTERNAL extern "C" + /**< Export macro that indicates a function is internal to the GPR. */ +#else + #define GPR_INTERNAL extern + /**< Export macro that indicates a function is internal to the GPR. */ +#endif /* __cplusplus */ + + +#ifdef __cplusplus + #define GPR_EXTERNAL extern "C" + /**< Export macro that indicates an external function, which is intended + for client use. */ +#else + #define GPR_EXTERNAL extern + /**< Export macro that indicates an external function, which is intended + for client use. */ +#endif /* __cplusplus */ + +/** @} */ /* end_name APR Core Export Macros */ +/** @} */ /* end_addtogroup gpr_macros */ + + +/****************************************************************************/ +/* Compiler-specific Macros*/ +/****************************************************************************/ + +#ifndef inline + #if defined( __ARMCC_VERSION ) + #define inline __inline + #elif defined( _MSC_VER ) + //#define inline __inline + #endif +#endif /* inline */ + +#endif /* __GPR_COMDEF_H__ */ + diff --git a/gpr/api/gpr_ids_domains.h b/gpr/api/gpr_ids_domains.h new file mode 100644 index 0000000..00d63e8 --- /dev/null +++ b/gpr/api/gpr_ids_domains.h @@ -0,0 +1,73 @@ +#ifndef __GPR_IDS_DOMAINS_H__ +#define __GPR_IDS_DOMAINS_H__ + +#include "ar_guids.h" + +/** + * @file gpr_ids_domains.h + * @brief This file contains GPR IDs and domains + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/** @addtogroup gpr_macros +@{ */ +/** @name GPR Domain IDs +@xreflabel{hdr:DomainIds} +A domain ID is to a unique ID that identifies a process, a processor, or an +off-target location that houses GPR. The transport mechanism between the +published domains can vary. + +Domain IDs are directly used as port indices to access GPR routing arrays. +Hence they have to always have values starting from 0 such as 0,1,2,3 and +not Globally Unique IDs (GUIDS). +@{ */ + +/** Invalid domain. */ +#define GPR_IDS_DOMAIN_ID_INVALID_V 0 + +/** Modem DSP (mDSP) domain. */ +#define GPR_IDS_DOMAIN_ID_MODEM_V 1 + +/** Audio DSP (aDSP) domain. */ +#define GPR_IDS_DOMAIN_ID_ADSP_V 2 + +/** Applications domain. */ +#define GPR_IDS_DOMAIN_ID_APPS_V 3 + +/** Sensors DSP (sDSP) domain. */ +#define GPR_IDS_DOMAIN_ID_SDSP_V 4 + +/** Compute DSP (cDSP) domain. */ +#define GPR_IDS_DOMAIN_ID_CDSP_V 5 + +/** Companion chip DSP (CC_DSP) domain */ +#define GPR_IDS_DOMAIN_ID_CC_DSP_V 6 + +/** Reserved domain */ +#define GPR_IDS_DOMAIN_ID_RESERVED_1 7 +#define GPR_IDS_DOMAIN_ID_RESERVED_2 8 +#define GPR_IDS_DOMAIN_ID_RESERVED_3 9 + +/** Generic chip DSP (gDSP0) domain */ +#define GPR_IDS_DOMAIN_ID_GDSP0_V 0xA + +/** Generic chip DSP (gDSP1) domain */ +#define GPR_IDS_DOMAIN_ID_GDSP1_V 0xB + +/** SPF-on-ARM HLOS (APPS2) domain */ +#define GPR_IDS_DOMAIN_ID_APPS2_V 0xC + +/** Highest domain ID. @hideinitializer */ +#define GPR_PL_MAX_DOMAIN_ID_V AR_NON_GUID( GPR_IDS_DOMAIN_ID_APPS2_V ) + +/** Total number of domains. @hideinitializer */ +#define GPR_PL_NUM_TOTAL_DOMAINS_V ( GPR_PL_MAX_DOMAIN_ID_V + 1 ) + +/** @} */ /* end_name GPR Domain IDs */ +/** @} */ /* end_addtogroup gpr_macros */ + +#endif /* __GPR_IDS_DOMAINS_H__ */ + diff --git a/gpr/api/gpr_msg_if.h b/gpr/api/gpr_msg_if.h new file mode 100644 index 0000000..5016b2e --- /dev/null +++ b/gpr/api/gpr_msg_if.h @@ -0,0 +1,80 @@ +#ifndef __GPR_MSG_IF_H__ +#define __GPR_MSG_IF_H__ + +/** + * @file gpr_msg_if.h + * @brief This file contains GPR list APIs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_comdef.h" + +/***************************************************************************** + * Core Messages * + ****************************************************************************/ + +/** @addtogroup gpr_resp_opcodes +@{ */ + +/** + Response message opcode that indicates a command has completed. All services + and clients must handle this response opcode. + + @par Payload (gpr_ibasic_rsp_result_t) + @table{weak__gpr__ibasic__rsp__result__t} +*/ +#define GPR_IBASIC_RSP_RESULT ( 0x02001005 ) + +#include "gpr_pack_begin.h" + +/* Payload of the GPR_IBASIC_RSP_RESULT command response message. */ +typedef struct gpr_ibasic_rsp_result_t gpr_ibasic_rsp_result_t; + +/** @weakgroup weak_gpr_ibasic_rsp_result_t +@{ */ +struct gpr_ibasic_rsp_result_t +{ + uint32_t opcode; /**< Command operation code that completed. */ + uint32_t status; /**< Completion status (see Section + @xref{hdr:StatusCodes}). */ +} +#include "gpr_pack_end.h" +; +/** @} */ /* end_weakgroup weak_gpr_ibasic_rsp_result_t */ + + +/** + Standard message opcode that indicates a command was accepted. + + The generation and processing of this event is optional. Clients that do not + understand this event must drop it by freeing the received packet. + + @par Payload (gpr_ibasic_evt_accepted_t) + @table{weak__gpr__ibasic__evt__accepted__t} +*/ +#define GPR_IBASIC_EVT_ACCEPTED ( 0x02001006 ) + +#include "gpr_pack_begin.h" + +/* Payload of the GPR_IBASIC_EVT_ACCEPTED message. */ +typedef struct gpr_ibasic_evt_accepted_t gpr_ibasic_evt_accepted_t; + +/** @weakgroup weak_gpr_ibasic_evt_accepted_t +@{ */ +struct gpr_ibasic_evt_accepted_t +{ + uint32_t opcode; /**< Operation code of the command that was accepted. */ +} +#include "gpr_pack_end.h" +; +/** @} */ /* end_weakgroup weak_gpr_ibasic_evt_accepted_t */ +/** @} */ /* end_addtogroup gpr_resp_opcodes */ + +#endif /* __GPR_MSG_IF_H__ */ + diff --git a/gpr/api/gpr_pack_begin.h b/gpr/api/gpr_pack_begin.h new file mode 100644 index 0000000..fb7524d --- /dev/null +++ b/gpr/api/gpr_pack_begin.h @@ -0,0 +1,25 @@ +/** + * \file gpr_pack_begin.h + * \brief + * This file contains GPR pack begin + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#if defined( __qdsp6__ ) +/* No packing atrributes for Q6 compiler; all structs manually packed */ +#elif defined( __GNUC__ ) +#elif defined( __arm__ ) + __packed +#elif defined( _MSC_VER ) && !defined(_KERNEL_MODE) + #pragma warning( disable:4103 ) /* Another header changing "pack". */ + #pragma pack( push, 1 ) +#elif defined( __H2XML__) +#elif defined( _KERNEL_MODE) +#else + #error "Unsupported compiler." +#endif /* __GNUC__ */ diff --git a/gpr/api/gpr_pack_end.h b/gpr/api/gpr_pack_end.h new file mode 100644 index 0000000..d8dd035 --- /dev/null +++ b/gpr/api/gpr_pack_end.h @@ -0,0 +1,27 @@ + +/** + * \file gpr_pack_end.h + * \brief + * This file contains GPR pack end + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#if defined( __qdsp6__ ) +/* No packing atrributes for Q6 compiler; all structs manually packed */ +#elif defined( __GNUC__ ) + __attribute__((packed)); +#elif defined( __arm__ ) +#elif defined( _MSC_VER )&& !defined(_KERNEL_MODE) + #pragma pack( pop ) +#elif defined (__H2XML__) + __attribute__((packed)) +#elif defined( _KERNEL_MODE) +#else + #error "Unsupported compiler." +#endif /* __GNUC__ */ + diff --git a/gpr/api/gpr_packet.h b/gpr/api/gpr_packet.h new file mode 100644 index 0000000..e1925ca --- /dev/null +++ b/gpr/api/gpr_packet.h @@ -0,0 +1,251 @@ +#ifndef __GPR_PACKET_H__ +#define __GPR_PACKET_H__ + +/** + * @file gpr_packet.h + * @brief This file contains GPR packet definitions + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_comdef.h" +#include "ar_guids.h" + +/** @addtogroup gpr_macros +@{ */ +/** @name GPR Packet Definitions +@{ */ + +/****************************************************************************/ +//Header Field Definitions +/****************************************************************************/ + +/** Defines the layout of the packet structure. @hideinitializer */ +#define GPR_PKT_VERSION_V ( 0 ) + +/** Uninitialized port value. @hideinitializer */ +#define GPR_PKT_INIT_PORT_V ( ( uint32_t ) 0 ) + +/** Uninitialized reserved field value. @hideinitializer */ +#define GPR_PKT_INIT_RESERVED_V ( ( uint16_t ) 0 ) + +/** Uninitialized domain ID value. @hideinitializer */ +#define GPR_PKT_INIT_DOMAIN_ID_V ( ( uint8_t ) 0 ) + +/** Header size in number of 32-bit words. @hideinitializer */ +#define GPR_PKT_HEADER_WORD_SIZE_V ( ( sizeof( gpr_packet_t ) + 3 ) >> 2 ) + +/** Header size in number of bytes. @hideinitializer */ +#define GPR_PKT_HEADER_BYTE_SIZE_V ( GPR_PKT_HEADER_WORD_SIZE_V << 2 ) + +/** Undefined value where a valid GUID is expected. @hideinitializer */ +#define GPR_UNDEFINED_ID_V AR_NON_GUID( ( uint32_t ) 0xFFFFFFFF ) + +/** Uninitialized client data value. @hideinitializer */ +#define GPR_PKT_INIT_CLIENT_DATA_V ( ( uint8_t ) 0 ) + +/****************************************************************************/ +// GPR Packet Bitfield Macros for Header Fields +/****************************************************************************/ + +/** Bitmask of the version field. */ +#define GPR_PKT_VERSION_MASK AR_NON_GUID( 0x0000000F ) + +/** Bit shift of the version field. */ +#define GPR_PKT_VERSION_SHFT ( 0 ) + +/** Bitmask of the header size field. */ +#define GPR_PKT_HEADER_SIZE_MASK AR_NON_GUID( 0x000000F0 ) + +/** Bit shift of the header size field. */ +#define GPR_PKT_HEADER_SIZE_SHFT ( 4 ) + +/** Bitmask of the reserved field. Includes four reserved bits from the client + data field. */ +#define GPR_PKT_RESERVED_MASK AR_NON_GUID( 0xFFF00000 ) + +/** Bit shift of the reserved field. */ +#define GPR_PKT_RESERVED_SHFT ( 20 ) + +/** Bitmask of the packet size field. */ +#define GPR_PKT_PACKET_SIZE_MASK AR_NON_GUID( 0xFFFFFF00 ) + +/** Bit shift of the packet size field. */ +#define GPR_PKT_PACKET_SIZE_SHFT ( 8 ) + + +/****************************************************************************/ +//Packet Helper Macros +/****************************************************************************/ + +/** Gets the value of a field, including the specified mask and shift. + @hideinitializer +*/ +#define GPR_GET_BITMASK( mask, shift, value ) \ + ( ( ( value ) & ( mask ) ) >> ( shift ) ) + +/** Sets a value in a field, including the specified mask and shift. + @hideinitializer +*/ +#define GPR_SET_BITMASK( mask, shift, value ) \ + ( ( ( value ) << ( shift ) ) & ( mask ) ) + +/** Gets the value of a field. @hideinitializer +*/ +#define GPR_GET_FIELD( field, value ) \ + GPR_GET_BITMASK( ( field##_MASK ), ( field##_SHFT ), ( value ) ) + +/** Sets a value in a field. @hideinitializer */ +#define GPR_SET_FIELD( field, value ) \ + GPR_SET_BITMASK( ( field##_MASK ), ( field##_SHFT ), ( value ) ) + +/** Returns an 8-bit aligned pointer to a base address pointer plus an + offset in bytes. + @hideinitializer +*/ +#define GPR_PTR_END_OF( base_ptr, offset ) \ + ( ( ( uint8_t* ) base_ptr ) + ( offset ) ) + +/** Given the packet header, returns the packet's current size in bytes. + + The current packet byte size is the sum of the base packet structure and + the used portion of the payload. + @hideinitializer +*/ +#define GPR_PKT_GET_PACKET_BYTE_SIZE( header ) \ + ( GPR_GET_FIELD( GPR_PKT_PACKET_SIZE, header ) ) + +/** Given the packet header, returns the header's current size in bytes. + @hideinitializer +*/ +#define GPR_PKT_GET_HEADER_BYTE_SIZE( header ) \ + ( (size_t)GPR_GET_FIELD( GPR_PKT_HEADER_SIZE, header ) << 2 ) + +/** Given the packet header, returns the payload's current size in bytes. + + The current payload byte size is the difference between the packet size and + the header size. + @hideinitializer +*/ +#define GPR_PKT_GET_PAYLOAD_BYTE_SIZE( header ) \ + ( GPR_PKT_GET_PACKET_BYTE_SIZE( header ) - \ + GPR_PKT_GET_HEADER_BYTE_SIZE( header ) ) + +/** Given the packet, returns a pointer to the beginning of the packet's + payload. + @hideinitializer +*/ +#define GPR_PKT_GET_PAYLOAD( type, packet_ptr ) \ + ( ( type* ) GPR_PTR_END_OF( packet_ptr, \ + GPR_PKT_GET_HEADER_BYTE_SIZE( \ + ( ( struct gpr_packet_t* ) packet_ptr )->header ) ) ) + +/** @} */ /* end_name GPR Packet Definitions */ +/** @} */ /* end_addtogroup gpr_macros */ + + +/*************************************************************************** +Packet Structure Definition +***************************************************************************/ + +/* Packet structure type definition. */ +typedef struct gpr_packet_t gpr_packet_t; + +/** @ingroup gpr_packet_struct + Core header structure necessary to route a packet from a source to a + destination. +*/ +struct gpr_packet_t +{ + uint32_t header; + /**< Contains the following subfield information for the header field. + + @subhead{version} + - Bits 3 to 0 (four bits). + - Defines the layout of the packet structure. + + @subhead{header\_size} + - Bits 7 to 4 (four bits). + - The header size is the number of 32-bit header words starting. + from the beginning of the packet. + + @subhead{packet\_size} + - Bits 31 to 8 (twenty-four bits). + - The total packet size in bytes. + - The total packet size includes both the header and payload size. + @tablebulletend */ + + uint8_t dst_domain_id; + /**< Domain ID of the destination where the packet is to be delivered. + + - Bits 0 to 7 (eight bits). + - The domain ID refers to a process, a processor, or an off-target + location that houses GPR. + - The transport layer used may differ depending on the physical + link between domains. + - All domain ID values are reserved by GPR. @tablebulletend */ + + uint8_t src_domain_id; + /**< Domain ID of the source from where the packet came. + + - Bits 8 to 15 (eight bits). + - The domain ID refers to a process, a processor, or an off-target + location that houses GPR. + - The transport layer used may differ depending on the physical + link between domains. + - All domain ID values are reserved by the GPR. @tablebulletend */ + + uint8_t client_data; + /**< Used for client-specific needs. + + - Bits 16 to 23 (eight bits). + - 4 bits for use by client. + - 4 bits are reserved and to be set to 0. + - Default value to be set to 0. @tablebulletend */ + + uint8_t reserved; + /**< Reserved field. + + - Bits 24 to 31 (eight bits). + - Set the value to 0. @tablebulletend */ + + uint32_t src_port; + /**< Unique ID of the service from where the packet came. + + - Bits 31 to 0 (thirty-two bits). + - The src_port refers to the ID that the sender service registers with + the GPR. This ID must be unique to the service within a given domain. + - Service refers to any functional block, such as a module, that is + required to send or receive packets through the GPR. @tablebulletend */ + + uint32_t dst_port; + /**< Unique ID of the service where the packet is to be delivered. + + - Bits 31 to 0 (thirty-two bits). + - The dst_port refers to the ID that the receiver service registers with + the GPR. This ID must be unique to the service within a given domain. + - Service refers to any functional block, fsuch as a module, that is + required to send or receive packets through the GPR. @tablebulletend */ + + uint32_t token; + /**< Client transaction ID provided by the sender. + + Bits 31 to 0 (thirty-two bits). */ + + uint32_t opcode; + /**< Defines both the action and the payload structure. + + @valuesbul + - Bits 31 to 0 (thirty-two bits). + - This operation code is a Globally Unique ID (GUID) and must be a valid + value. @tablebulletend */ +}; + + +#endif /* __GPR_PACKET_H__ */ + diff --git a/gpr/api/gpr_proc_info_api.h b/gpr/api/gpr_proc_info_api.h new file mode 100644 index 0000000..d0c5e29 --- /dev/null +++ b/gpr/api/gpr_proc_info_api.h @@ -0,0 +1,56 @@ +#ifndef __GPR_PROC_INFO_H__ +#define __GPR_PROC_INFO_H__ + +/** + * @file gpr_packet.h + * @brief This file contains GPR packet definitions + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_comdef.h" +#include "ar_guids.h" +#include "gpr_ids_domains.h" +/** @addtogroup gpr_macros +@{ */ +/** @name GPR Packet Definitions +@{ */ + +/****************************************************************************/ +// Header Field Definitions +/****************************************************************************/ +#define GPR_PD_SUBSTRING_MAX_SIZE 20 +typedef struct gpr_proc_info_t +{ + int32_t proc_id; + char_t proc_name[GPR_PD_SUBSTRING_MAX_SIZE]; +} gpr_proc_info_t; + +/** + Returns the proc name, if proc id is a input. + Returns the proc id, if proc name is a input. + + @param[in] gpr_proc_info_t structure + + + @return + #proc_id, proc_name -- When successful. + + @dependencies + None. +*/ +GPR_EXTERNAL uint32_t gpr_get_audio_service_name(char_t *service_name, uint32_t string_size); + +GPR_EXTERNAL uint32_t gpr_get_pd_str_from_id(uint32_t proc_domain_id, + char_t * proc_domain_string, + uint32_t proc_domain_string_size); + +GPR_EXTERNAL uint32_t gpr_get_pd_id_from_str(uint32_t *proc_domain_id_ptr, + char_t * proc_domain_string, + uint32_t proc_domain_string_size); + +#endif /* __GPR_PACKET_H__ */ diff --git a/gpr/api/ipc_dl_api.h b/gpr/api/ipc_dl_api.h new file mode 100644 index 0000000..4fa128e --- /dev/null +++ b/gpr/api/ipc_dl_api.h @@ -0,0 +1,274 @@ +#ifndef _IPC_DL_API_H_ +#define _IPC_DL_API_H_ + +/** + * @file ipc_dl_api.h + * @brief This file contains IPC APIs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_comdef.h" +#include "gpr_ids_domains.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/****************************************************************************** + * Defines * + *****************************************************************************/ +typedef struct gpr_to_ipc_vtbl_t gpr_to_ipc_vtbl_t; + +/** @addtogroup ipc_gpr_ipc_callbk_functions +To enable remote communication, both the GPR and IPC data link layers must +implement and exchange callback functions during initialization. +*/ + +/** @ingroup ipc_gpr_ipc_callbk_functions + Table of callback functions exposed by the GPR to the IPC data link layers. + The GPR sends this table to the data link layers during data link layer + initialization. +*/ +struct gpr_to_ipc_vtbl_t +{ + /** + Prototype of the %receive() callback function for the GPR. + + @param[in] buf Pointer to the packet. + @param[in] length Size of the packet. + + @detdesc + When the data link layer receives a packet, it calls this GPR + function to handle and route the packet to its final destination. + + @return + #AR_EOK -- When successful. + + @dependencies + None. @newpage + */ + uint32_t (*receive)(void* buf, uint32_t length); + + /** + Prototype of the %send_done() callback function for the GPR. + + @param[in] buf Pointer to the packet. + @param[in] length Size of the packet. + + @detdesc + When the data link layer finishes sending a packet, it uses this function + to signal the GPR to free the packet. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + */ + uint32_t (*send_done)(void *buf, uint32_t length); +}; + +typedef struct ipc_to_gpr_vtbl_t ipc_to_gpr_vtbl_t; + +/** @addtogroup ipc_ipc_gpr_func_wrapper +To enable remote communication, both the GPR and IPC data link layers must +implement and exchange callback functions during initialization time. +*/ + +/** @ingroup ipc_ipc_gpr_func_wrapper + Table of functions exposed by data link layers to the GPR. + The functions must be populated by every data link layer when gpr_init() calls + for data link layer initialization. +*/ +struct ipc_to_gpr_vtbl_t +{ + /** + Prototype of the %send() function for a data link layer. + + @param[in] domain_id ID of the domain to which packet is being sent. + @param[in] buf Pointer to the packet. + @param[in] length Size of the packet. + + @detdesc + When the GPR sends a packet to a destination domain, it calls this + function of the corresponding data link layer. + + @return + #AR_EOK -- When successful. + + @dependencies + None. @newpage + */ + uint32_t (*send)(uint32_t domain_id, void *buf, uint32_t length); + + /** + Prototype of the %receive_done() function for a data link layer. + + @param[in] domain_id ID of the domain from which packet was sent. + @param[in] buf Pointer to the packet. + + @detdesc + When the GPR finishes processing a packet it received from the data link + layer, it returns the packet to the data link layer for it to free the + buffer. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + */ + uint32_t (*receive_done)(uint32_t domain_id, void *buf); +}; + + +/** @addtogroup ipc_dlink_function_protos +A data link layer is used for two-way communication between a given source +domain and a destination domain. The source domain can set up communication +with multiple destination domains through different data link layers. + +This section outlines the function prototypes used for initialization and +de-initialization of any data link layer. +*/ + +/** @addtogroup ipc_dlink_function_protos +@{ */ +/** + Initializes a data link or IPC layer that communicates between two domains. + + @datatypes + #gpr_to_ipc_vtbl_t \n + #ipc_to_gpr_vtbl_t + + @param[in] src_domain_id Domain ID of the source. + @param[in] dest_domain_id Domain ID of the destination with which the + given src_domain_id is to establish + communication. + @param[in] p_gpr_to_ipc_vtbl Pointer to the function table that contains + the callback functions the GPR provides to + each IPC data link layer during + initialization. + This function table argument is defined as a + constant because the same GPR callback + functions are sent to each data link layer. + @param[out] pp_ipc_to_gpr_vtbl Double pointer to the function table that + contains the functions each IPC data link + layer provides to the GPR. It is populated by + each data link during initialization. + + @detdesc + This function is called for each data link layer during GPR initialization. It + sets up all the necessary function handlers to receive and send packets in the + GPR and data link layers. + @par + The GPR registers callback functions to each data link layer, and in turn, a + data link layer registers its callback functions with the GPR. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + + @codeexample + @lstlisting +#include "ipc_dl_api.h" + +//Example of initializing a datalink layer to communicate between +// two domains - ADSP and APPS. + +//Datalink layer entry point function. +GPR_EXTERNAL uint32_t ipc_datalink_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl); + +//Functions are defined in gpr. +static gpr_to_ipc_vtbl_t gpr_to_datalink_vtbl = {gpr_receive, + gpr_send_done, + }; + +//Functions are defined inside the datalink layer and to be populated and +//sent back to gpr in the ipc_datalink_init function. +static ipc_to_gpr_vtbl_t datalink_layer_to_gpr_vtbl = {datalink_send, + datalink_receive_done, + }; + +int main() +{ + uint32_t src_domain_id = GPR_IDS_DOMAIN_ID_ADSP_V; + uin32_t dest_domain_id = GPR_IDS_DOMAIN_ID_APPS_V; + + rc = ipc_datalink_init(src_domain_id, + dest_domain_id, + &gpr_to_datalink_vtbl, + &datalink_layer_to_gpr_vtbl); + if (rc) + { + AR_MSG(DBG_ERROR_PRIO, "Initialization failed for destination domain id %lu", dest_domain_id); + } + return rc; + } + @endlstlisting @newpage +*/ +typedef uint32_t (*ipc_dl_init_fn_t)(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t **pp_ipc_to_gpr_vtbl); + +/** + Deinitializes a data link or IPC layer that was set up to communicate between + two domains. + + @param[in] src_domain_id Domain ID of the source. + @param[in] dest_domain_id Domain ID of the destination with which the + src_domain_id must close communication. + + @detdesc + This function is called for each data link layer during GPR deinitialization. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + + @codeexample + @lstlisting +#include "ipc_dl_api.h" + +//Example of deinitializing a datalink layer to close communication between +//two domains - ADSP and APPS. + +GPR_EXTERNAL uint32_t ipc_datalink_deinit (uint32_t src_domain_id, + uint32_t dest_domain_id); + +int main() +{ + uint32_t src_domain_id = GPR_IDS_DOMAIN_ID_ADSP_V; + uin32_t dest_domain_id = GPR_IDS_DOMAIN_ID_APPS_V; + + rc = ipc_datalink_deinit(src_domain_id,dest_domain_id); + if (rc) + { + AR_MSG(DBG_ERROR_PRIO, "Deinitialization failed for destination domain id %lu", dest_domain_id); + } + return rc; +} + @endlstlisting +*/ +typedef uint32_t (*ipc_dl_deinit_fn_t)(uint32_t src_domain_id, uint32_t dest_domain_id); + +/** @} */ /* end_addtogroup ipc_dlink_function_protos */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif //_IPC_DL_API_H_ diff --git a/gpr/api/private/gpr_private_api.h b/gpr/api/private/gpr_private_api.h new file mode 100644 index 0000000..0170d2f --- /dev/null +++ b/gpr/api/private/gpr_private_api.h @@ -0,0 +1,170 @@ +#ifndef __GPR_PRIVATE_API_H__ +#define __GPR_PRIVATE_API_H__ + +/** + * @file gpr_private_api.h + * @brief This file contains GPR Private APIs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_packet.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/***************************************************************************** + * Function Definitions * + ****************************************************************************/ + +/** @ingroup gpr_cmd_register_v2 + Registers a service, by its unique service ID, with the GPR. + + @datatypes + #gpr_callback_fn_t + + @param[in] src_port Unique ID (within a domain) of the service to be + registered. + @param[in] callback_fn Callback function of the service to be registered. + @param[in] callback_data Pointer to the client-supplied data pointer for the + callback function. + @param[in] heap_index Heap index of the client registering with GPR. + + @detdesc + Services call this command once during system bring-up or runtime to register + their presence with the GPR. + @par + A service is any functional block, such as a module, that is required to send + or receive GPR packets. Services must be registered with the GPR before they + can send or receive any messages. + + @return + #AR_EOK -- When successful. + @par + #AR_EALREADY -- Service has already been registered. + + @dependencies + GPR initialization must be completed via gpr_init(). @newpage + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +//Example of a test client service (with service ID GPR_TESTCLIENT_SERVICE_ID) +//trying to register with GPR. +uint32_t service_callback_fn(gpr_packet_t *packet, void *callback_data); +void * callback_data = NULL; + +int main ( void ) +{ + int32_t rc = __gpr_cmd_register_v2(GPR_TESTCLIENT_SERVICE_ID, + callback_fn, + callback_data, + GPR_HEAP_INDEX_DEFAULT); + if ( rc ) + { + printf( "Could not register the test client service with GPR" ); + } + return 0; +} + +//Example of a callback function for a service. It is invoked by GPR +//every time a message is sent or received, to or from that service. +static int32_t service_callback_fn( gpr_packet_t* packet, + void* callback_data ) +{ + // Accept command by replying to the sender that the message is accepted. + // The usage is optional. + __gpr_cmd_accept_command( packet ); + + switch ( packet->opcode ) + { + case TEST_CLIENT_CMD_FUNCTION: + { + // Handle accordingly based on operation code and send response to + // the sender that command is completed. + __gpr_cmd_end_command( packet, AR_EOK ); + break; + } + case TEST_CLIENT_RSP_FUNCTION: + { + // Notify command completion. + // Response may contain payload, free the packet after handling. + __gpr_cmd_free( packet ); + break; + } + case GPR_IBASIC_RSP_RESULT: + { + // Notify command completion, response contains the error status. + __gpr_cmd_free( packet ); + break; + } + default: + { + // Free unsupported events and command responses. + __gpr_cmd_free( packet ); + break; + } + } + return AR_EOK; + // AR_EOK tells the caller that the packet was consumed (freed). +} + @endlstlisting + */ +uint32_t __gpr_cmd_register_v2(uint32_t src_port, + gpr_callback_fn_t callback_fn, + void * callback_data, + gpr_heap_index_t heap_index); + +/** @ingroup gpr_cmd_deregister + Deregisters a service from the GPR. + + @param[in] src_port Unique ID of the service. + + @detdesc + Services call this function once during system teardown or runtime to + deregister their presence from the GPR. + + @return + #AR_EOK -- When successful. + + @dependencies + GPR initialization must be completed via gpr_init(). + + @codeexample + @lstlisting +#include "gpr_api_inline.h" + +//Example of a test client service (with service ID GPR_TESTCLIENT_SERVICE_ID) +//trying to deregister from GPR. +uint32_t callback_fn(gpr_packet_t *packet, void *callback_data); +void * callback_data = NULL; + +int32_t rc = __gpr_cmd_register_v2(GPR_TESTCLIENT_SERVICE_ID, + callback_fn, + callback_data, + GPR_HEAP_INDEX_DEFAULT); +if ( rc ) +{ + printf( "Could not register the client service with GPR" ); +} +... +rc = __gpr_cmd_deregister_v2(GPR_TESTCLIENT_SERVICE_ID, GPR_HEAP_INDEX_DEFAULT); +if ( rc ) +{ + printf( "Could not deregister the client service from GPR" ); +} + @endlstlisting + */ +uint32_t __gpr_cmd_deregister_v2(uint32_t src_port, gpr_heap_index_t heap_index); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_PRIVATE_API_H__ */ diff --git a/gpr/core/inc/ar_utils/audioss/ar_msg.h b/gpr/core/inc/ar_utils/audioss/ar_msg.h new file mode 100644 index 0000000..c066a2f --- /dev/null +++ b/gpr/core/inc/ar_utils/audioss/ar_msg.h @@ -0,0 +1,118 @@ +/** + * \file ar_msg.h + * \brief + * This file contains mm msg APIs + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _AR_MSG_H +#define _AR_MSG_H + +/* ======================================================================= +INCLUDE FILES FOR MODULE +========================================================================== */ +#include "ar_osal_log.h" +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#ifndef DBG_LOG_FIRM +#define DBG_LOG_FIRM +#endif +#ifndef DBG_LOG_MAX_LEVEL +#define DBG_LOG_MAX_LEVEL 5 +#endif + +/** Enable (1) or disable (0) the debug messagef */ +#define ar_log_debugmsg_enable 1 + +//*************************************************************************** +// Debug message features +//*************************************************************************** + +/** @addtogroup ar_logging +@{ */ + +/* Supporting macros for AR_MSG() logging utility. + * AR_MSG is supported on both target and simulation builds. */ +#undef AR_MSG + +#if !defined(SIM) && (defined(__hexagon__) || defined(__XTENSA__)) + +//#include "msg.h" +//#include "msgcfg.h" + +#include "dbg_diag_common.h" + +#define DBG_LOW_PRIO MSG_LEGACY_LOW /**< Low priority debug message. */ +#define DBG_MED_PRIO MSG_LEGACY_MED /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO MSG_LEGACY_HIGH /**< High priority debug message. */ +#define DBG_ERROR_PRIO MSG_LEGACY_ERROR /**< Error priority debug message. */ +#define DBG_FATAL_PRIO MSG_LEGACY_FATAL /**< Fatal priority debug message. */ + +/* Utility to get variable argument + * Slide the variable arguments to get the string '_N' to be appended */ +#define AR_VA_NUM_ARGS_IMPL(a, b, c, d, e, f, g, h, i, j, _N, ...) _N +#define AR_VA_NUM_ARGS(...) AR_VA_NUM_ARGS_IMPL(, ##__VA_ARGS__, _9, _8, _7, _6, _5, _4, _3, _2, _1, ) +/* Concatenates string x with y*/ +#define AR_TOKENPASTE(x, y) x##y + +/*Macro parses the text to MSG with _N as suffix, where N = {1, 2, 3, .... ,9} */ +#define AR_MSG_x(_N) AR_TOKENPASTE(MSG, _N) + +#ifndef MSG_SSID_DFLT +#define MSG_SSID_DFLT MSG_SSID_QDSP6 +#endif // MSG_SSID_DFLT + +/* This Logging macro supports variable arguments*/ +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + if (ar_log_debugmsg_enable) \ + { \ + AR_MSG_x(AR_VA_NUM_ARGS(__VA_ARGS__))(MSG_SSID_WEAR_AON_AUDIOSS, xx_ss_mask, xx_fmt, ##__VA_ARGS__); \ + } +#else // !defined(SIM) && defined(__hexagon__) + +/*For simultation purposes */ +#define DBG_LOW_PRIO 0 /**< Low priority debug message. */ +#define DBG_MED_PRIO 1 /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO 2 /**< High priority debug message. */ +#define DBG_ERROR_PRIO 3 /**< Error priority debug message. */ +#define DBG_FATAL_PRIO 4 /**< Fatal priority debug message. */ + +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + if (xx_ss_mask == DBG_LOW_PRIO) { \ + AR_LOG_LOW("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_MED_PRIO) \ + { \ + AR_LOG_MED("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_HIGH_PRIO) \ + { \ + AR_LOG_HIGH("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_ERROR_PRIO) \ + { \ + AR_LOG_ERROR("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_FATAL_PRIO) \ + { \ + AR_LOG_FATAL("GPR:",xx_fmt, ##__VA_ARGS__); \ + } + +/** @} */ /* end_addtogroup ar_logging */ + +#endif // !defined(SIM) && defined(__hexagon__) + + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif // #ifndef _AR_MSG_H diff --git a/gpr/core/inc/ar_utils/generic/ar_msg.h b/gpr/core/inc/ar_utils/generic/ar_msg.h new file mode 100644 index 0000000..d5c7101 --- /dev/null +++ b/gpr/core/inc/ar_utils/generic/ar_msg.h @@ -0,0 +1,117 @@ +/** + * \file ar_msg.h + * \brief + * This file contains mm msg APIs + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _AR_MSG_H +#define _AR_MSG_H + +/* ======================================================================= +INCLUDE FILES FOR MODULE +========================================================================== */ +#include "ar_osal_log.h" +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +/** Enable (1) or disable (0) the debug messagef */ +#define ar_log_debugmsg_enable 1 + +//*************************************************************************** +// Debug message features +//*************************************************************************** + +/** @addtogroup ar_logging +@{ */ + +/* Supporting macros for AR_MSG() logging utility. + * AR_MSG is supported on both target and simulation builds. */ +#undef AR_MSG + +#if !defined(SIM) && (defined(__hexagon__) || defined(__XTENSA__)) + +#include "msg.h" +#include "msgcfg.h" + +#define DBG_LOW_PRIO MSG_LEGACY_LOW /**< Low priority debug message. */ +#define DBG_MED_PRIO MSG_LEGACY_MED /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO MSG_LEGACY_HIGH /**< High priority debug message. */ +#define DBG_ERROR_PRIO MSG_LEGACY_ERROR /**< Error priority debug message. */ +#define DBG_FATAL_PRIO MSG_LEGACY_FATAL /**< Fatal priority debug message. */ + +/* Utility to get variable argument + * Slide the variable arguments to get the string '_N' to be appended */ +#define AR_VA_NUM_ARGS_IMPL(a, b, c, d, e, f, g, h, i, j, _N, ...) _N +#define AR_VA_NUM_ARGS(...) AR_VA_NUM_ARGS_IMPL(, ##__VA_ARGS__, _9, _8, _7, _6, _5, _4, _3, _2, _1, ) +/* Concatenates string x with y*/ +#define AR_TOKENPASTE(x, y) x##y + +/*Macro parses the text to MSG with _N as suffix, where N = {1, 2, 3, .... ,9} */ +#define AR_MSG_x(_N) AR_TOKENPASTE(MSG, _N) + +#ifndef MSG_SSID_DFLT +#define MSG_SSID_DFLT MSG_SSID_QDSP6 +#endif // MSG_SSID_DFLT + +/* This Logging macro supports variable arguments*/ +#if defined(__XTENSA__) +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + if (ar_log_debugmsg_enable) \ + { \ + AR_MSG_x(AR_VA_NUM_ARGS(__VA_ARGS__))(MSG_SSID_WEAR_AON_AUDIOSS, xx_ss_mask, xx_fmt, ##__VA_ARGS__); \ + } +#else +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + if (ar_log_debugmsg_enable) \ + { \ + AR_MSG_x(AR_VA_NUM_ARGS(__VA_ARGS__))(MSG_SSID_QDSP6, xx_ss_mask, xx_fmt, ##__VA_ARGS__); \ + } +#endif +#else // !defined(SIM) && defined(__hexagon__) + +/*For simultation purposes */ +#define DBG_LOW_PRIO 0 /**< Low priority debug message. */ +#define DBG_MED_PRIO 1 /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO 2 /**< High priority debug message. */ +#define DBG_ERROR_PRIO 3 /**< Error priority debug message. */ +#define DBG_FATAL_PRIO 4 /**< Fatal priority debug message. */ + +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + if (xx_ss_mask == DBG_LOW_PRIO) { \ + AR_LOG_LOW("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_MED_PRIO) \ + { \ + AR_LOG_MED("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_HIGH_PRIO) \ + { \ + AR_LOG_HIGH("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_ERROR_PRIO) \ + { \ + AR_LOG_ERROR("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_FATAL_PRIO) \ + { \ + AR_LOG_FATAL("GPR:",xx_fmt, ##__VA_ARGS__); \ + } + +/** @} */ /* end_addtogroup ar_logging */ + +#endif // !defined(SIM) && defined(__hexagon__) + + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif // #ifndef _AR_MSG_H diff --git a/gpr/core/inc/ar_utils/hexagon/ar_msg.h b/gpr/core/inc/ar_utils/hexagon/ar_msg.h new file mode 100644 index 0000000..31a96f8 --- /dev/null +++ b/gpr/core/inc/ar_utils/hexagon/ar_msg.h @@ -0,0 +1,109 @@ +/** + * \file ar_msg.h + * \brief + * This file contains mm msg APIs + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _AR_MSG_H +#define _AR_MSG_H + +/* ======================================================================= +INCLUDE FILES FOR MODULE +========================================================================== */ +#include "ar_osal_log.h" +#include "ar_osal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +/** Enable (1) or disable (0) the debug messagef */ +#define ar_log_debugmsg_enable 1 + +//*************************************************************************** +// Debug message features +//*************************************************************************** + +/** @addtogroup ar_logging +@{ */ + +/* Supporting macros for AR_MSG() logging utility. + * AR_MSG is supported on both target and simulation builds. */ +#undef AR_MSG + +#if !defined(SIM) && (defined(__hexagon__) || defined(__XTENSA__)) + +#include "msg.h" +#include "msgcfg.h" + +#define DBG_LOW_PRIO MSG_LEGACY_LOW /**< Low priority debug message. */ +#define DBG_MED_PRIO MSG_LEGACY_MED /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO MSG_LEGACY_HIGH /**< High priority debug message. */ +#define DBG_ERROR_PRIO MSG_LEGACY_ERROR /**< Error priority debug message. */ +#define DBG_FATAL_PRIO MSG_LEGACY_FATAL /**< Fatal priority debug message. */ + +/* Utility to get variable argument + * Slide the variable arguments to get the string '_N' to be appended */ +#define AR_VA_NUM_ARGS_IMPL(a, b, c, d, e, f, g, h, i, j, _N, ...) _N +#define AR_VA_NUM_ARGS(...) AR_VA_NUM_ARGS_IMPL(, ##__VA_ARGS__, _9, _8, _7, _6, _5, _4, _3, _2, _1, ) +/* Concatenates string x with y*/ +#define AR_TOKENPASTE(x, y) x##y + +/*Macro parses the text to MSG with _N as suffix, where N = {1, 2, 3, .... ,9} */ +#define AR_MSG_x(_N) AR_TOKENPASTE(MSG, _N) + +#ifndef MSG_SSID_DFLT +#define MSG_SSID_DFLT MSG_SSID_QDSP6 +#endif // MSG_SSID_DFLT + +/* This Logging macro supports variable arguments*/ +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + if (ar_log_debugmsg_enable) \ + { \ + AR_MSG_x(AR_VA_NUM_ARGS(__VA_ARGS__))(MSG_SSID_QDSP6, xx_ss_mask, xx_fmt, ##__VA_ARGS__); \ + } +#else // !defined(SIM) && defined(__hexagon__) + +/*For simultation purposes */ +#define DBG_LOW_PRIO 0 /**< Low priority debug message. */ +#define DBG_MED_PRIO 1 /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO 2 /**< High priority debug message. */ +#define DBG_ERROR_PRIO 3 /**< Error priority debug message. */ +#define DBG_FATAL_PRIO 4 /**< Fatal priority debug message. */ + +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + if (xx_ss_mask == DBG_LOW_PRIO) { \ + AR_LOG_LOW("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_MED_PRIO) \ + { \ + AR_LOG_MED("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_HIGH_PRIO) \ + { \ + AR_LOG_HIGH("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_ERROR_PRIO) \ + { \ + AR_LOG_ERROR("GPR:",xx_fmt, ##__VA_ARGS__); \ + } \ + else if(xx_ss_mask == DBG_FATAL_PRIO) \ + { \ + AR_LOG_FATAL("GPR:",xx_fmt, ##__VA_ARGS__); \ + } + +/** @} */ /* end_addtogroup ar_logging */ + +#endif // !defined(SIM) && defined(__hexagon__) + + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif // #ifndef _AR_MSG_H diff --git a/gpr/core/inc/gpr_api_i.h b/gpr/core/inc/gpr_api_i.h new file mode 100644 index 0000000..6dbf2be --- /dev/null +++ b/gpr/core/inc/gpr_api_i.h @@ -0,0 +1,467 @@ +#ifndef __GPR_API_I_H__ +#define __GPR_API_I_H__ + +/** + * @file gpr_api_i.h + * \brief This file contains GPR internal APIs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_api.h" +#include "ipc_dl_api.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/***************************************************************************** + * Core Routines * + ****************************************************************************/ + +/** @addtogroup gpr_core_routines +@{ */ + +/** + Called from gpr_init() to initialize the GPR infrastructure. + + This function is defined in each platform wrapper( see Section + @xref{mpg:PlatformSpecificCfgWrappers}) and further calls + gpr_drv_internal_init() to perform GPR internal initialization. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + */ +GPR_EXTERNAL uint32_t gpr_drv_init(void); + +/** + Called from gpr_init_domain(domain_id) to GPR infrastructure for + particular domain. + + @return + #AR_EOK -- When successful. + + @dependencies + None. +*/ +GPR_EXTERNAL uint32_t gpr_drv_init_domain(uint32_t domain_id); + +/** + Called from gpr_deinit() to deinitialize the GPR infrastructure. + + @return + #AR_EOK -- When successful. + + @dependencies + None. +*/ +GPR_INTERNAL uint32_t gpr_drv_deinit(void); + +/** @} */ /* end_addtogroup gpr_core_routines */ + +/***************************************************************************** + * IPC Implementations * + ****************************************************************************/ + +/* IPC datalink table structure*/ +typedef struct ipc_dl_t ipc_dl_t; + +/** @addtogroup ipc_platform_cfg_wrappers +The platform-specific configuration wrappers allow each platform to provide +specific configuration and perform GPR instantiation with this configuration. +GPR instantiation is done by calling gpr_drv_internal_init(). + +The platform wrapper provides control over the following aspects. +- Number and size of GPR packets to be allocated by the GPR instance on this + platform. The GPR currently supports creation and maintenance of two such + packet pools. +- Domains with which the current platform or domain wants to establish + communication with and the corresponding data link layer to be used. +- This information is provided through the gpr_ipc_dl_table (see + gpr_drv_internal_init()), which has multiple entries, each of type #ipc_dl_t. +- The gpr_ipc_dl_table has as many entries as the domain IDs with which the + given processor is to establish communication. +- The maximum size of the table is the maximum number of processor domains that + are present. +*/ + +/** @addtogroup ipc_platform_cfg_wrappers +@{ */ +/** + Contains the domain ID to which communication is to be established through + a specified IPC data link layer. This structure includes the corresponding + data link initialization and deinitialization functions to be called. + */ +struct ipc_dl_t +{ + uint16_t domain_id; + /**< Domain ID to establish communication with. */ + + ipc_dl_init_fn_t init_fn; + /**< Initialization function in the IPC data link layer. */ + + ipc_dl_deinit_fn_t deinit_fn; + /**< Deinitialization function in the IPC data link layer. @newpagetable */ +}; + +/* IPC datalink table structure*/ +typedef struct ipc_dl_v2_t ipc_dl_v2_t; + +/** @addtogroup ipc_platform_cfg_wrappers +The platform-specific configuration wrappers allow each platform to provide +specific configuration and perform GPR instantiation with this configuration. +GPR instantiation is done by calling gpr_drv_internal_init(). + +The platform wrapper provides control over the following aspects. +- Number and size of GPR packets to be allocated by the GPR instance on this + platform. The GPR currently supports creation and maintenance of two such + packet pools. +- Domains with which the current platform or domain wants to establish + communication with and the corresponding data link layer to be used. + And also indicates if shared memory is supported with the destination domain. +- This information is provided through the gpr_ipc_dl_table (see + gpr_drv_internal_init()), which has multiple entries, each of type #ipc_dl_v2_t. +- The gpr_ipc_dl_table has as many entries as the domain IDs with which the + given processor is to establish communication. +- The maximum size of the table is the maximum number of processor domains that + are present. +*/ + +/** @addtogroup ipc_platform_cfg_wrappers +@{ */ +/** + Contains the domain ID to which communication is to be established through + a specified IPC data link layer. This structure includes the corresponding + data link initialization and deinitialization functions to be called. + */ +struct ipc_dl_v2_t +{ + uint16_t domain_id; + /**< Domain ID to establish communication with. */ + + ipc_dl_init_fn_t init_fn; + /**< Initialization function in the IPC data link layer. */ + + ipc_dl_deinit_fn_t deinit_fn; + /**< Deinitialization function in the IPC data link layer. @newpagetable */ + + bool_t supports_shared_mem; + /**< Indicates availability of shared memory with the destination domain. */ +}; + +/** + Performs internal initialization of the GPR infrastructure. + + @datatypes + #ipc_dl_t + + @param[in] gpr_ipc_dl_table Array of domain IDs to which communication is to + be established. + @param[in] num_domains Number of domain IDs in the array. + @param[in] default_domain_id Host domain ID. + @param[in] buf_size_1 Size (in bytes) of each packet to be created in + the first packet pool. + @param[in] num_packets_1 Number of packets of size buf_size_1 to be + created. + @param[in] buf_size_2 Size (in bytes) of each packet to be created in + the second packet pool. + @param[in] num_packets_2 Number of packets of size buf_size_2 to be + created. + + @detdesc + This function must be called from all platform wrappers to perform GPR + internal initialization, which sets up the entire GPR functionality. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + + @codeexample + @lstlisting +//Example platform wrapper for GPR in ADSP domain. + +#include "ipc_dl_api.h" +#include "gpr_api_i.h" +#include "gpr_glink.h" +#include "gpr_qsocket.h" + +GPR_EXTERNAL uint32_t ipc_dl_local_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl); + +GPR_EXTERNAL uint32_t ipc_dl_local_deinit(uint32_t src_domain_id, uint32_t dest_domain_id); + +GPR_EXTERNAL uint32_t ipc_dl_glink_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl); + +GPR_EXTERNAL uint32_t ipc_dl_glink_deinit(uint32_t src_domain_id, + uint32_t dest_domain_id); + +GPR_EXTERNAL uint32_t ipc_dl_qsocket_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl); + +GPR_EXTERNAL uint32_t ipc_dl_qsocket_deinit(uint32_t src_domain_id, + uint32_t dest_domain_id); + +//This example creates the following gpr packet pools: +// 100 packets of size 512 bytes and 4 packets of size 4096 bytes. +#define GPR_NUM_PACKETS_1 ( 100 ) +#define GPR_DRV_BYTES_PER_PACKET_1 ( 512 ) +#define GPR_NUM_PACKETS_2 ( 4 ) +#define GPR_DRV_BYTES_PER_PACKET_2 ( 4096 ) + +//In this example, ADSP wants to open communication with MODEM domain(through qsocket datalink layer), +//with APPS domain (through glink datalink layer) as well as +//set up local transmission of packets within the same domain. + +//Thus the GPR IPC table has four entries, two for each domain and one for the local domain +//containing initialization, deinitialization functions for each of their datalink layers. +static struct ipc_dl_t gpr_adsp_ipc_dl_table[GPR_PL_NUM_TOTAL_DOMAINS_V]= { + {GPR_IDS_DOMAIN_ID_MODEM_V, ipc_dl_qsocket_init, ipc_dl_qsocket_deinit}, + {GPR_IDS_DOMAIN_ID_ADSP_V, ipc_dl_local_init, ipc_dl_local_deinit}, + {GPR_IDS_DOMAIN_ID_APPS_V, ipc_dl_glink_init, ipc_dl_glink_deinit}}; + +GPR_EXTERNAL uint32_t gpr_drv_init(void) +{ + uint32_t rc; + uint32_t num_domains = sizeof(gpr_adsp_ipc_dl_table) / sizeof(ipc_dl_t); + + rc = gpr_drv_internal_init(gpr_adsp_ipc_dl_table, + num_domains, + GPR_IDS_DOMAIN_ID_ADSP_V, //host_domain_id + GPR_NUM_PACKETS_1, + GPR_DRV_BYTES_PER_PACKET_1, + GPR_NUM_PACKETS_2, + GPR_DRV_BYTES_PER_PACKET_2); + + if ( rc ) + { + printf( "Could not initialize the GPR infrastructure and datalink layers"); + } + return rc; +} + @endlstlisting + @newpage +*/ +GPR_EXTERNAL uint32_t gpr_drv_internal_init(struct ipc_dl_t gpr_ipc_dl_table[], + uint32_t num_domains, + uint32_t default_domain_id, + uint32_t buf_size_1, + uint32_t num_packets_1, + uint32_t buf_size_2, + uint32_t num_packets_2); + +/** + Performs internal initialization of the GPR infrastructure. + + @datatypes + #ipc_dl_t + + @param[in] default_domain_id Host domain ID. + @param[in] num_domains Number of destiantion domain IDs that are supported. + @param[in] gpr_ipc_dl_v2_table Array of domain IDs specific info to which communication is to + be established. Size of the array is specified in the previous agrument. + @param[in] num_packet_pools Number of packet pools that need to allocated. + @param[in] packet_pool_info List of packet pool info. Includes heap_index, if the packet pool + needs to be statically or dynamically allocated, num packets and + packet size of each of the pool to be allocated. + + @detdesc + This function must be called from all platform wrappers to perform GPR + internal initialization, which sets up the entire GPR functionality. + + @return + #AR_EOK -- When successful. + + @dependencies + None. + + @codeexample + @lstlisting +//Example platform wrapper for GPR in ADSP domain. + +#include "ipc_dl_api.h" +#include "gpr_api_i.h" +#include "gpr_glink.h" +#include "gpr_qsocket.h" + +GPR_EXTERNAL uint32_t ipc_dl_local_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl); + +GPR_EXTERNAL uint32_t ipc_dl_local_deinit(uint32_t src_domain_id, uint32_t dest_domain_id); + +GPR_EXTERNAL uint32_t ipc_dl_glink_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl); + +GPR_EXTERNAL uint32_t ipc_dl_glink_deinit(uint32_t src_domain_id, + uint32_t dest_domain_id); + +GPR_EXTERNAL uint32_t ipc_dl_qsocket_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl); + +GPR_EXTERNAL uint32_t ipc_dl_qsocket_deinit(uint32_t src_domain_id, + uint32_t dest_domain_id); + +//This example creates the following gpr packet pools: +// 100 packets of size 512 bytes and 4 packets of size 4096 bytes, and these +// two pools are allocated statically. So set is_dynamic to FALSE. +#define GPR_NUM_PACKET_POOLS 2 +#define GPR_NUM_PACKETS_1 ( 100 ) +#define GPR_DRV_BYTES_PER_PACKET_1 ( 512 ) +#define GPR_NUM_PACKETS_2 ( 4 ) +#define GPR_DRV_BYTES_PER_PACKET_2 ( 4096 ) + +//In this example, ADSP wants to open communication with MODEM domain(through qsocket datalink layer), +//with APPS domain (through glink datalink layer) as well as +//set up local transmission of packets within the same domain. + +//Thus the GPR IPC table has four entries, two for each domain and one for the local domain +//containing initialization, deinitialization functions for each of their datalink layers. +// Since all the domains support shared memory in this case, set support_shared_mem to TRUE. +static struct ipc_dl_v2_t gpr_adsp_ipc_dl_v2_table[GPR_PL_NUM_TOTAL_DOMAINS_V]= { + {GPR_IDS_DOMAIN_ID_MODEM_V, ipc_dl_qsocket_init, ipc_dl_qsocket_deinit, TRUE}, + {GPR_IDS_DOMAIN_ID_ADSP_V, ipc_dl_local_init, ipc_dl_local_deinit, TRUE}, + {GPR_IDS_DOMAIN_ID_APPS_V, ipc_dl_glink_init, ipc_dl_glink_deinit, TRUE}}; + +GPR_EXTERNAL uint32_t gpr_drv_init(void) +{ + uint32_t rc; + uint32_t num_domains = sizeof(gpr_adsp_ipc_dl_v2_table) / sizeof(ipc_dl_v2_t); + + gpr_packet_pool_info_v2_t packet_pool_info[GPR_NUM_PACKET_POOLS]; + + // init pool info + packet_pool_info[0].heap_index = GPR_HEAP_INDEX_DEFAULT; + packet_pool_info[0].is_dynamic = FALSE; + packet_pool_info[0].num_packets =GPR_NUM_PACKETS_1; + packet_pool_info[0].packet_size =GPR_DRV_BYTES_PER_PACKET_1; + packet_pool_info[0].reserved = 0; + + packet_pool_info[1].heap_index = GPR_HEAP_INDEX_DEFAULT; + packet_pool_info[1].is_dynamic = FALSE; + packet_pool_info[1].num_packets =GPR_NUM_PACKETS_2; + packet_pool_info[1].packet_size =GPR_DRV_BYTES_PER_PACKET_2; + packet_pool_info[1].reserved = 0; + + rc = gpr_drv_internal_init_v2(GPR_IDS_DOMAIN_ID_ADSP_V, //host_domain_id + num_domains, + gpr_adsp_ipc_dl_v2_table, + GPR_NUM_PACKET_POOLS, + &packet_pool_info[0]); + + if ( rc ) + { + printf( "Could not initialize the GPR infrastructure and datalink layers"); + } + return rc; +} + @endlstlisting + @newpage +*/ +GPR_EXTERNAL uint32_t gpr_drv_internal_init_v2(uint32_t default_domain_id, + uint32_t num_domains, + struct ipc_dl_v2_t gpr_ipc_dl_v2_table[], + uint32_t num_packet_pools, + gpr_packet_pool_info_v2_t packet_pool_info[]); + +/** @} */ /* end_addtogroup ipc_platform_cfg_wrappers */ + +/** @addtogroup ipc_gpr_function_loc_rout +GPR functions used for local routing, which is routing between two services on +the same domain, should also follow IPC data link function prototype (see +Section @xref{mpg:IpcDlinkFunctionProtos}). +*/ + +/** @addtogroup ipc_gpr_function_loc_rout +@{ */ +/** + Performs initialization of the GPR functionality used for local routing of + packets. + + @datatypes + #gpr_to_ipc_vtbl_t \n + #ipc_to_gpr_vtbl_t + + @param[in] src_domain_id Domain ID for the source. + @param[in] dest_domain_id Domain ID for the destination. + @param[in] p_gpr_to_ipc_vtbl Pointer to the GPR-to-IPC virtual function + table. + @param[in] pp_ipc_to_gpr_vtbl Double pointer to the IPC-to-GPR virtual + function table. + + @detdesc + This function is of type ipc_dl_init_fn_t(). It sets up the GPR for + transferring and receiving packets within the same domain or processor, when + there is no need for a data link layer. + @par + This function must be specified as the initialization function for the local + or host domain in the array of type ipc_dl_t in the platform-specific + configuration wrappers (see Section @xref{mpg:PlatformSpecificCfgWrappers}). + + @return + #AR_EOK -- When successful. + + @dependencies + None. + + @codeexample + See the code example for gpr_drv_internal_init(). @newpage +*/ +GPR_EXTERNAL uint32_t ipc_dl_local_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t **pp_ipc_to_gpr_vtbl); + +/** + Performs deinitialization of the GPR functionality used for local routing of + packets. + + @param[in] src_domain_id Domain ID for the source. + @param[in] dest_domain_id Domain ID for the destination. + + @detdesc + This function is of type ipc_dl_deinit_fn_t(). It deinitializes the GPR for + transferring and receiving packets within the same domain or processor. + @par + This function must be specified as the initialization function for the local + or host domain in the array of type ipc_dl_t in the platform-specific + configuration wrappers (see Section @xref{mpg:PlatformSpecificCfgWrappers}). + + @return + #AR_EOK -- When successful. + + @dependencies + None. + + @codeexample + See the code example for gpr_drv_internal_init(). +*/ +GPR_EXTERNAL uint32_t ipc_dl_local_deinit(uint32_t src_domain_id, uint32_t dest_domain_id); + +/** @} */ /* end_addtogroup ipc_gpr_function_loc_rout */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_API_I_H__ */ diff --git a/gpr/core/inc/gpr_heap_i.h b/gpr/core/inc/gpr_heap_i.h new file mode 100644 index 0000000..d1b6bd4 --- /dev/null +++ b/gpr/core/inc/gpr_heap_i.h @@ -0,0 +1,47 @@ +#ifndef __GPR_HEAP_I_H__ +#define __GPR_HEAP_I_H__ + +/** + * \file gpr_heap_i.h + * \brief + * This file contains GPR heap utils + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_heap.h" +#include "gpr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +// Populates output argument ar_heap_info based on the input GPR heap index and alignment. +static inline uint32_t gpr_populate_ar_heap_info(gpr_heap_index_t gpr_heap_index, + ar_heap_align_bytes alignment, + ar_heap_info *heap_info_ptr) +{ + heap_info_ptr->align_bytes = alignment; + heap_info_ptr->tag = AR_HEAP_TAG_DEFAULT; + heap_info_ptr->pool_type = AR_HEAP_POOL_DEFAULT; + + if (GPR_HEAP_INDEX_1 == gpr_heap_index) + { + heap_info_ptr->heap_id = AR_HEAP_ID_1; + } + else + { + heap_info_ptr->heap_id = AR_HEAP_ID_DEFAULT; + } + + return AR_EOK; +} + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_HEAP_I_H__ */ diff --git a/gpr/core/inc/gpr_list.h b/gpr/core/inc/gpr_list.h new file mode 100644 index 0000000..25438a7 --- /dev/null +++ b/gpr/core/inc/gpr_list.h @@ -0,0 +1,80 @@ +#ifndef __GPR_LIST_H__ +#define __GPR_LIST_H__ + +/** + * \file gpr_list.h + * \brief + * This file contains GPR list APIs + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gpr_comdef.h" +#include "ar_osal_error.h" +#include "ar_msg.h" +#include "ar_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +typedef struct gpr_list_node_t gpr_list_node_t; +typedef struct gpr_list_t gpr_list_t; + +typedef void (*gpr_list_lock_enter_fn_t)(void); +typedef void (*gpr_list_lock_leave_fn_t)(void); + +struct gpr_list_node_t +{ + gpr_list_t *list; + /**< Indicates the last known list for which this node belonged. */ + gpr_list_node_t *prev; + /**< The previous node. */ + gpr_list_node_t *next; + /**< The next node. */ +}; + +struct gpr_list_t +{ + gpr_list_node_t dummy; + /**< A special dummy node to implement the NULL object pattern. */ + uint32_t size; + /**< The number of nodes linked to this linked list. */ + gpr_list_lock_enter_fn_t lock_fn; + /**< The user supplied lock implementation function. */ + gpr_list_lock_leave_fn_t unlock_fn; + /**< The user supplied unlock implementation function. */ + bool_t en_secure; + /**< Enable secure linked list flag. */ +}; + +GPR_EXTERNAL uint32_t gpr_list_init(gpr_list_t *list, + gpr_list_lock_enter_fn_t lock_fn, + gpr_list_lock_leave_fn_t unlock_fn); + +GPR_EXTERNAL uint32_t gpr_list_init_v2(gpr_list_t *list, + gpr_list_lock_enter_fn_t lock_fn, + gpr_list_lock_leave_fn_t unlock_fn); + +GPR_EXTERNAL bool_t gpr_list_raw_is_empty(gpr_list_t *list); + +GPR_EXTERNAL uint32_t gpr_list_init_node(gpr_list_node_t *node); + +GPR_EXTERNAL uint32_t gpr_list_add_tail(gpr_list_t *list, gpr_list_node_t *node); + +GPR_EXTERNAL uint32_t gpr_list_remove_head(gpr_list_t *list, gpr_list_node_t **ret_node); + +GPR_EXTERNAL uint32_t gpr_list_get_head(gpr_list_t *list, gpr_list_node_t **ret_node); + +GPR_EXTERNAL uint32_t gpr_list_delete(gpr_list_t *list, gpr_list_node_t *node); + +GPR_EXTERNAL uint32_t gpr_list_clear(gpr_list_t *list); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_LIST_H__ */ diff --git a/gpr/core/inc/gpr_session.h b/gpr/core/inc/gpr_session.h new file mode 100644 index 0000000..fbcce92 --- /dev/null +++ b/gpr/core/inc/gpr_session.h @@ -0,0 +1,69 @@ +#ifndef _GPR_SESSION_H_ +#define _GPR_SESSION_H_ + +/** + * \file gpr_session.h + * \brief + * This file contains GPR drv session APIs + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_mem_op.h" +#include "ar_osal_mutex.h" +#include "ar_osal_heap.h" +#include "ar_guids.h" +#include "gpr_api_i.h" +#include "gpr_msg_if.h" +#include "gpr_api_inline.h" +#include "ar_msg.h" + +//#define SESSION_ARRAY_SIZE 200 +#define SESSION_HASH(RANGE, x) ((x) % (RANGE - 1)) // always a prime number + +/* Forward declaration for the gpr_module_entry_t structure. */ +typedef struct gpr_module_entry_t gpr_module_entry_t; + +/* Structure for a session for each (domain id, port) set*/ +struct gpr_module_entry_t +{ + gpr_callback_fn_t callback_fn; + void *callback_data; +}; + +/* Forward declaration for the gpr_module_node_t structure. */ +typedef struct gpr_module_node_t gpr_module_node_t; + +/*Structure for each linked list node to store callback function and + * corresponding argument*/ +struct gpr_module_node_t +{ + uint32_t my_module_port; + gpr_module_entry_t session; + gpr_module_node_t *next; +}; + +/* Structures to store the registered module nodes, heap index provided will be used to + allocate the nodes. Client must allocate memory for the cb_list[] */ +struct gpr_module_node_list_t +{ + gpr_heap_index_t heap_index; // heap index from which module nodes need to be allocated + uint32_t max_cb_list_size; // max size of the cb_list array + gpr_module_node_t *cb_list[1]; // array containing the module node pointers. +}; +typedef struct gpr_module_node_list_t gpr_module_node_list_t; + +GPR_INTERNAL uint32_t gpr_init_session(uint32_t my_module_port, + gpr_module_entry_t **ret_entry, + gpr_module_node_list_t *list_handle); + +GPR_INTERNAL uint32_t gpr_get_session(uint32_t my_module_port, + gpr_module_entry_t **ret_entry, + gpr_module_node_list_t *list_handle); + +GPR_INTERNAL uint32_t gpr_deinit_session(uint32_t my_module_port, gpr_module_node_list_t *list_handle); + +#endif /* _GPR_SESSION_H_ */ diff --git a/gpr/core/src/array_based/gpr_session.c b/gpr/core/src/array_based/gpr_session.c new file mode 100644 index 0000000..0b32b42 --- /dev/null +++ b/gpr/core/src/array_based/gpr_session.c @@ -0,0 +1,136 @@ +/** + * \file gpr_session.c + * \brief + * This file contains GPR session implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_session.h" +#include "gpr_heap_i.h" + +/** + @brief Allocates memory and returns a pointer to a session + (contains callback function, callback argument) for a given + src_port + + @param[in] src_port Address/port of src module trying to register + @param[out] ret_entry Double pointer to the session created + + @detdesc + Allocates a new node in the linked list for each src port. Each node + represents a session which points to a callback function and corresponding + callback argument which will be populated by the caller of this function. + This is how a module registers to the GPR service. + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_init_session(uint32_t src_port, + gpr_module_entry_t **ret_entry, + gpr_module_node_list_t *list_handle) +{ + if (NULL == list_handle) + { + return AR_EFAILED; + } + + gpr_heap_index_t heap_index = list_handle->heap_index; + ar_heap_info heap_info; + gpr_populate_ar_heap_info(heap_index, AR_HEAP_ALIGN_8_BYTES, &heap_info); + + gpr_module_node_t *new_node = (gpr_module_node_t *)ar_heap_malloc(sizeof(gpr_module_node_t), &heap_info); + if (NULL == new_node) + { + AR_MSG(DBG_ERROR_PRIO, + "Error: Failed to allocate gpr module node of size %d port 0x%lx heap index %lu", + sizeof(gpr_module_node_t), + src_port, + heap_index); + return AR_ENOMEMORY; + } + + gpr_module_node_t **chain = &list_handle->cb_list[0]; + uint32_t free_index = 0xFFFF; + + for (uint32_t i = 0; i < list_handle->max_cb_list_size; i++) + { + if (chain[i] == NULL) + { + free_index = i; + } + else // Error handling mechanism, may be removed + { + gpr_module_node_t *temp = chain[i]; + if (temp->my_module_port == src_port) + { + AR_MSG(DBG_ERROR_PRIO, "Error: Trying to register with source port %lu again, failing", src_port); + ar_heap_free(new_node, &heap_info); + return AR_EFAILED; + } + } + } + + if (free_index == 0xFFFF) // Error handling mechanism, may be removed + { + AR_MSG(DBG_ERROR_PRIO, + "Error: Finding any free space, increase session_array_size cur_size: %lu", + list_handle->max_cb_list_size); + return AR_EFAILED; + } + + // Fill up the new node + chain[free_index] = new_node; + new_node->my_module_port = src_port; + *ret_entry = &new_node->session; + + chain[free_index]->next = NULL; // as it is array based (next node is not required) + + return AR_EOK; +} + +/** + @brief De-allocates session memory for a given src_port + + @param[in] src_port Address/port of src module trying to de-register + + @detdesc + De-allocates a node in the linked list for a given src_port. + Make sure not to delet other nodes in the linked list. + This is how a local module registers to the GPR service. + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_deinit_session(uint32_t src_port, gpr_module_node_list_t *list_handle) +{ + if (NULL == list_handle) + { + return AR_EFAILED; + } + + gpr_heap_index_t heap_index = list_handle->heap_index; + ar_heap_info heap_info; + gpr_populate_ar_heap_info(heap_index, AR_HEAP_ALIGN_8_BYTES, &heap_info); + + gpr_module_node_t **cb_list = &list_handle->cb_list[0]; + + for (uint32_t i = 0; i < list_handle->max_cb_list_size; i++) + { + if ((cb_list[i] != NULL) && (cb_list[i]->my_module_port == src_port)) + { + ar_heap_free(cb_list[i], &heap_info); + cb_list[i] = NULL; + return AR_EOK; + } + } + + AR_MSG(DBG_HIGH_PRIO, "No such module port (%lu) found to deinit", src_port); + return AR_ENOTEXIST; // NOT exists +} diff --git a/gpr/core/src/array_based/gpr_session_island.c b/gpr/core/src/array_based/gpr_session_island.c new file mode 100644 index 0000000..f35a440 --- /dev/null +++ b/gpr/core/src/array_based/gpr_session_island.c @@ -0,0 +1,53 @@ +/** + * \file gpr_session.c + * \brief + * This file contains GPR session implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_session.h" + +/** + @brief Searches for callback function based on src port + + @param[in] my_port Address/port of module + @param[out] ret_entry Double pointer to the session found + + @detdesc + Searches the linked list until node matching + given src_port is found and returns pointer to the corresponding session + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_get_session(uint32_t my_port, + gpr_module_entry_t **ret_entry, + gpr_module_node_list_t *list_handle) +{ + if (NULL == list_handle) + { + return AR_EFAILED; + } + gpr_module_node_t **cb_list = &list_handle->cb_list[0]; + for (uint32_t i = 0; i < list_handle->max_cb_list_size; i++) + { + if ((cb_list[i] != NULL) && (cb_list[i]->my_module_port == my_port)) + { + *ret_entry = &cb_list[i]->session; + return AR_EOK; + } + } + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_ERROR_PRIO, "No such module port (%lu) found in linked list", my_port); +#endif + + return AR_ENOTEXIST; +} diff --git a/gpr/core/src/gpr_drv.c b/gpr/core/src/gpr_drv.c new file mode 100644 index 0000000..e86dbeb --- /dev/null +++ b/gpr/core/src/gpr_drv.c @@ -0,0 +1,1209 @@ +/** + * \file gpr_drv.c + * \brief + * This file contains GPR driver implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_drv_i.h" +#include "gpr_heap_i.h" + +/***************************************************************************** + * Local function definitions * + ****************************************************************************/ + +GPR_INTERNAL uint32_t gpr_ipc_send_done(void *buf, uint32_t length); + +GPR_INTERNAL uint32_t gpr_ipc_receive(void *buf, uint32_t length); + +/***************************************************************************** + * Global variables * + ****************************************************************************/ + +#ifndef HEAP1_SESSION_ARRAY_SIZE +#define HEAP1_SESSION_ARRAY_SIZE 2 +#endif + +// clang-format off +gpr_proc_info_t gpr_proc_info[GPR_PL_NUM_TOTAL_DOMAINS_V] = { + { GPR_IDS_DOMAIN_ID_MODEM_V, "modem" }, + { GPR_IDS_DOMAIN_ID_ADSP_V, "adsp" }, + { GPR_IDS_DOMAIN_ID_APPS_V, "apps" }, + { GPR_IDS_DOMAIN_ID_SDSP_V, "slpi" }, + { GPR_IDS_DOMAIN_ID_CDSP_V, "cdsp" }, + { GPR_IDS_DOMAIN_ID_CC_DSP_V, "ccdsp" }, + { GPR_IDS_DOMAIN_ID_RESERVED_1, "res1" }, + { GPR_IDS_DOMAIN_ID_RESERVED_2, "res2" }, + { GPR_IDS_DOMAIN_ID_RESERVED_3, "res3" }, + { GPR_IDS_DOMAIN_ID_GDSP0_V, "gpdsp0" }, + { GPR_IDS_DOMAIN_ID_GDSP1_V, "gpdsp1" }, + { GPR_IDS_DOMAIN_ID_APPS2_V, "apps" }, //adsp + }; +// clang-format on + +/* Local GPR IPC table containing init,deinit functions and vtbl function pointer to be populated for all domains*/ +extern struct ipc_dl_local_t local_gpr_ipc_dl_table[GPR_PL_NUM_TOTAL_DOMAINS_V]; + +/* local ipc vtbl functions */ +extern ipc_to_gpr_vtbl_t local_vtbl; + +// global context variable +extern gpr_ctxt_struct_type gpr_ctxt_struct_t; + +// de-init context flag +static bool_t gpr_deinit_flag = FALSE; + +/***************************************************************************** + * Helper functions * + ****************************************************************************/ + +static uint32_t gpr_alloc_and_get_proc_domain_list(ar_osal_servreg_entry_type **domain_list_pptr, + uint32_t *num_domains_ptr, + ar_heap_info *heap_info_ptr) +{ + uint32_t result = AR_EOK; + uint32_t domain_list_size = 2; + ar_osal_servreg_entry_type *domain_list_ptr = NULL; + ar_osal_servreg_entry_type service; + + if (NULL == domain_list_pptr) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: NULL domain_list_pptr"); + return AR_EBADPARAM; + } + + ar_mem_set((void *)&service, 0, sizeof(ar_osal_servreg_entry_type)); + result = gpr_get_audio_service_name(&service.name[0], AR_OSAL_SERVREG_NAME_LENGTH_MAX); + if (AR_EOK != result) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: failed to get audio service name from ar osal %lu", result); + return result; + } + + // With domain list null, this api return the size for number of domain list + result = ar_osal_servreg_get_domainlist(&service, NULL /*domain_list*/, &domain_list_size); + if (AR_EOK != result) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: failed to get size for num of domains from ar osal %lu", result); + return result; + } + + AR_MSG(DBG_HIGH_PRIO, "GPR: rcved size %d (%d) ", domain_list_size, result); + + domain_list_ptr = (ar_osal_servreg_entry_type *)ar_heap_malloc(domain_list_size * sizeof(ar_osal_servreg_entry_type), + heap_info_ptr); + if (NULL == domain_list_ptr) + { + AR_MSG(DBG_HIGH_PRIO, "GPR: failed to malloc"); + return AR_ENOMEMORY; + } + + ar_mem_set((void *)domain_list_ptr, 0, (domain_list_size * sizeof(ar_osal_servreg_entry_type))); + + result = ar_osal_servreg_get_domainlist(&service, domain_list_ptr, &domain_list_size); + if (AR_EOK != result) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: failed to get domains with ar_osal %lu", result); + ar_heap_free(domain_list_ptr, heap_info_ptr); + return result; + } + for (uint32_t i = 0; i < domain_list_size; i++) + { + AR_MSG(DBG_MED_PRIO, "GPR: Domain list string[%lu] %s", i, domain_list_ptr[i].name); + // MSG_SPRINTF_1(MSG_SSID_QDSP6,MSG_LEGACY_HIGH,"Domain name fetched %s ", domain_list_ptr[i].name); + } + + *domain_list_pptr = domain_list_ptr; + *num_domains_ptr = domain_list_size; + return result; +} + +static inline bool_t gpr_is_sub_string(char_t *main_string, char_t *sub_string) +{ + return (NULL != ar_strstr(main_string, sub_string)); +} + +GPR_EXTERNAL uint32_t gpr_get_audio_service_name(char_t *service_name, uint32_t string_size) +{ + uint32_t result = AR_EOK; + if (NULL != service_name) + { + char_t audio_service_name[] = "avs/audio"; + if (string_size < sizeof(audio_service_name)) + { + AR_MSG(DBG_ERROR_PRIO, + "GPR: Service string size not enough %lu, required %lu", + string_size, + sizeof(audio_service_name)); + return result; + } + result = ar_mem_cpy(service_name, string_size, audio_service_name, sizeof(audio_service_name)); + } + else + { + AR_MSG(DBG_ERROR_PRIO, "GPR: Service name is NULL"); + result = AR_EBADPARAM; + } + return result; +} + +GPR_EXTERNAL uint32_t gpr_get_pd_str_from_id(uint32_t proc_domain_id, + char_t *proc_domain_string, + uint32_t proc_domain_string_size) +{ + uint32_t result = AR_EOK; + uint32_t num_proc_domain = 0; + ar_osal_servreg_entry_type *domain_list_ptr = NULL; + int32_t audio_pd_idx = -1; + int32_t root_pd_idx = -1; + ar_heap_info heap_info; + char_t audio_pd_string[] = "audio_pd"; + char_t root_pd_string[] = "root_pd"; + + if (NULL == proc_domain_string) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: null proc domain string "); + return AR_EBADPARAM; + } + + if ((GPR_IDS_DOMAIN_ID_INVALID_V >= proc_domain_id) || (GPR_PL_MAX_DOMAIN_ID_V < proc_domain_id)) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: Invalid proc domain id, %lu ", proc_domain_id); + return AR_EBADPARAM; + } + + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + heap_info.tag = AR_HEAP_TAG_DEFAULT; + heap_info.align_bytes = AR_HEAP_ALIGN_8_BYTES; + + result = gpr_alloc_and_get_proc_domain_list(&domain_list_ptr, &num_proc_domain, &heap_info); + if (AR_EOK != result) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: Failed to get proc domain list,result %lu ", result); + return result; + } + + // Get the proc name from the proc id.. + for (uint32_t cur_pd_id = GPR_IDS_DOMAIN_ID_INVALID_V; cur_pd_id <= GPR_PL_MAX_DOMAIN_ID_V; cur_pd_id++) + { + if (gpr_proc_info[cur_pd_id].proc_id == (int32_t)proc_domain_id) + { + // search for the string "gpr_proc_info[i].proc_name" + for (uint32_t domain_list_idx = 0; domain_list_idx < num_proc_domain; domain_list_idx++) + { + // Check if "core"(adsp, modem, slpi) string related to proc domain ID is present. + if (gpr_is_sub_string(domain_list_ptr[domain_list_idx].name, gpr_proc_info[cur_pd_id].proc_name)) + { + // Check if the domain string containing "core"(adsp, modem, slpi) string + // has audio_pd or root_pd and saave the idx + if (gpr_is_sub_string(domain_list_ptr[domain_list_idx].name, &audio_pd_string[0])) + { + audio_pd_idx = domain_list_idx; + } + else if (gpr_is_sub_string(domain_list_ptr[domain_list_idx].name, &root_pd_string[0])) + { + root_pd_idx = domain_list_idx; + } + } + } + } + } + + char_t *pd_string = NULL; + if (-1 != audio_pd_idx) // Found the string with "core"(adsp, modem, slpi) substring and "audio_pd" + { + AR_MSG(DBG_MED_PRIO, "GPR: matching string with audio_pd found "); + pd_string = &domain_list_ptr[audio_pd_idx].name[0]; + } + else if (-1 != root_pd_idx) // Found the string with "core"(adsp, modem, slpi) substring and "root_pd" + { + AR_MSG(DBG_MED_PRIO, "GPR: matching string with root_pd found "); + pd_string = &domain_list_ptr[root_pd_idx].name[0]; + } + else // Nothing found, don't immediately return, free the domain_list_ptr + { + AR_MSG(DBG_ERROR_PRIO, "GPR: Failed to get proc domain string from id %lu ", proc_domain_id); + result = AR_EFAILED; + } + + if (NULL != pd_string) + { + uint32_t string_len = (uint32_t)ar_strlen(pd_string, AR_OSAL_SERVREG_NAME_LENGTH_MAX); + + if (proc_domain_string_size < string_len) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: Inp string size %lu not enough, need %lu ", proc_domain_string_size, string_len); + result = AR_EFAILED; + } + ar_mem_cpy(proc_domain_string, proc_domain_string_size, pd_string, string_len + 1); + } + ar_heap_free((void *)domain_list_ptr, &heap_info); + + return result; +} + +GPR_EXTERNAL uint32_t gpr_get_pd_id_from_str(uint32_t *proc_domain_id_ptr, + char_t *proc_domain_string, + uint32_t proc_domain_string_size) +{ + uint32_t result = AR_EOK; + uint32_t num_proc_domain = 0; + ar_osal_servreg_entry_type *domain_list_ptr = NULL; + ar_heap_info heap_info; + + if (NULL == proc_domain_string) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: null proc domain string "); + return AR_EBADPARAM; + } + + if (NULL == proc_domain_id_ptr) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: null proc domain id "); + return AR_EBADPARAM; + } + + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + heap_info.tag = AR_HEAP_TAG_DEFAULT; + heap_info.align_bytes = AR_HEAP_ALIGN_8_BYTES; + + result = gpr_alloc_and_get_proc_domain_list(&domain_list_ptr, &num_proc_domain, &heap_info); + if (AR_EOK != result) + { + AR_MSG(DBG_ERROR_PRIO, "GPR: Failed to get proc domain list,result %lu ", result); + return result; + } + + *proc_domain_id_ptr = GPR_IDS_DOMAIN_ID_INVALID_V; + bool_t found = FALSE; + // search for the string "gpr_proc_info[i].proc_name" + for (uint32_t domain_list_idx = 0; (domain_list_idx < num_proc_domain) && (FALSE == found); domain_list_idx++) + { + if (0 == ar_strcmp(domain_list_ptr[domain_list_idx].name, proc_domain_string, proc_domain_string_size)) + { + for (uint32_t cur_pd_id = GPR_IDS_DOMAIN_ID_INVALID_V; cur_pd_id <= GPR_PL_MAX_DOMAIN_ID_V; cur_pd_id++) + { + if (gpr_is_sub_string(domain_list_ptr[domain_list_idx].name, gpr_proc_info[cur_pd_id].proc_name)) + { + *proc_domain_id_ptr = gpr_proc_info[cur_pd_id].proc_id; + found = TRUE; + break; + } + } + } + } + + if (FALSE == found) + { + result = AR_EFAILED; + AR_MSG(DBG_ERROR_PRIO, "GPR: Failed to find pd id from string %s ", proc_domain_string); + } + + ar_heap_free((void *)domain_list_ptr, &heap_info); + return result; +} + +/***************************************************************************** + * IPC Callback Implementation * + ****************************************************************************/ +/*@brief Callback function in gpr that datalink layer calls when it receives a packet + @param[in] domain_id Index to retrieve remote ssid, corresponding channel name and datalink type + @param[in] buf Buffer received by datalink layer + @param[in] length Size of buffer + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_ipc_receive(void *buf, uint32_t length) +{ + uint32_t rc = AR_EOK; + gpr_packet_t *packet = (gpr_packet_t *)buf; + uint32_t packet_size = GPR_PKT_GET_PACKET_BYTE_SIZE(packet->header); + + if ((NULL == buf) || (length != packet_size)) + { + AR_MSG(DBG_ERROR_PRIO, "gpr received null buffer or invalid buffer size "); + return AR_EBADPARAM; + } + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_HIGH_PRIO, + "GPR received message over datalink layer with opcode %lx, dst port %lx, \ + src_port %lx token \ + 0x%lx ", + packet->opcode, + packet->dst_port, + packet->src_port, + packet->token); +#endif + + rc = __gpr_cmd_async_send(packet); + if (rc) + { + AR_MSG(DBG_ERROR_PRIO, "gpr send failed"); + __gpr_cmd_free(packet); + } + return AR_EOK; +} + +/*@brief Callback function in gpr that datalink layer calls once it finishes sending GPR packet across + @param[in] domain_id Domain id of destination + @param[in] buf Buffer sent by datalink layer + @param[in] length Size of buffer + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_ipc_send_done(void *buf, uint32_t length) +{ + gpr_packet_t *packet = (gpr_packet_t *)buf; + uint32_t packet_size = GPR_PKT_GET_PACKET_BYTE_SIZE(packet->header); + + if ((NULL == buf) || (length != packet_size)) + { + AR_MSG(DBG_ERROR_PRIO, "Received NULL buffer or buffer of incorrect size"); + return AR_EBADPARAM; + } + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_HIGH_PRIO, + "GPR finished sending message over datalink layer with opcode %lx, dst port %lx src port %lx token %lx", + packet->opcode, + packet->dst_port, + packet->src_port, + packet->token); +#endif + + __gpr_cmd_free(packet); + return AR_EOK; +} + +// Utility to create packet pool info arrays, called at the time of init +static uint32_t gpr_drv_util_create_packet_pool_info_arrs(uint32_t num_packet_pools, + gpr_packet_pool_info_v2_t packet_pool_info[]) +{ + // find num static and dynamic pools and allocate packet pool info structure arrays. + // Also, find out the heap index from which array pointer should be allocated. + uint32_t num_static_packet_pools = 0; + uint32_t num_dyn_packet_pools = 0; + gpr_heap_index_t gpr_heap_index = GPR_HEAP_INDEX_DEFAULT; + for (uint32_t idx = 0; idx < num_packet_pools; idx++) + { + if (packet_pool_info[idx].is_dynamic) + { + num_dyn_packet_pools++; + } + else + { + num_static_packet_pools++; + } + + // check validity of heap index + if (packet_pool_info[idx].heap_index > GPR_HEAP_INDEX_1) + { + return AR_EFAILED; + } + + // if atleast one heap is from index 1, then use index 1 for allocating the array + if (GPR_HEAP_INDEX_1 == packet_pool_info[idx].heap_index) + { + gpr_heap_index = GPR_HEAP_INDEX_1; + } + } + + // cache heap index + gpr_ctxt_struct_t.drv_heap_index = gpr_heap_index; + + // assign appropriate ar heap id + ar_heap_info heap_info; + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + gpr_populate_ar_heap_info(gpr_ctxt_struct_t.drv_heap_index, AR_HEAP_ALIGN_DEFAULT, &heap_info); + + // malloc static pool array if needed + if (num_static_packet_pools) + { + gpr_ctxt_struct_t.static_pool_arr = (gpr_drv_pkt_static_pool_info_t *) + ar_heap_malloc(num_static_packet_pools * sizeof(gpr_drv_pkt_static_pool_info_t), &heap_info); + if (NULL == gpr_ctxt_struct_t.static_pool_arr) + { + return AR_EFAILED; + } + ar_mem_set((void *)gpr_ctxt_struct_t.static_pool_arr, + 0, + num_static_packet_pools * sizeof(gpr_drv_pkt_static_pool_info_t)); + } + + // malloc dynamic pool array if needed + if (num_dyn_packet_pools) + { + gpr_ctxt_struct_t.dyn_pool_arr = (gpr_drv_pkt_dynamic_pool_info_t *) + ar_heap_malloc(num_dyn_packet_pools * sizeof(gpr_drv_pkt_dynamic_pool_info_t), &heap_info); + if (NULL == gpr_ctxt_struct_t.dyn_pool_arr) + { + return AR_EFAILED; + } + ar_mem_set((void *)gpr_ctxt_struct_t.dyn_pool_arr, + 0, + num_dyn_packet_pools * sizeof(gpr_drv_pkt_dynamic_pool_info_t)); + } + + /* Allocate Default heap CB lists */ + gpr_populate_ar_heap_info(GPR_HEAP_INDEX_DEFAULT, AR_HEAP_ALIGN_DEFAULT, &heap_info); + + uint32_t default_list_size = sizeof(gpr_module_node_list_t) + (SESSION_ARRAY_SIZE * sizeof(gpr_module_node_t *)); + gpr_ctxt_struct_t.default_list = (gpr_module_node_list_t *)ar_heap_malloc(default_list_size, &heap_info); + if (NULL == gpr_ctxt_struct_t.default_list) + { + return AR_EFAILED; + } + ar_mem_set((void *)gpr_ctxt_struct_t.default_list, 0, default_list_size); + gpr_ctxt_struct_t.default_list->max_cb_list_size = SESSION_ARRAY_SIZE; + gpr_ctxt_struct_t.default_list->heap_index = GPR_HEAP_INDEX_DEFAULT; + + /* Allocate Non-Default heap CB list if required */ + gpr_populate_ar_heap_info(GPR_HEAP_INDEX_1, AR_HEAP_ALIGN_DEFAULT, &heap_info); + + uint32_t list_size = sizeof(gpr_module_node_list_t) + (HEAP1_SESSION_ARRAY_SIZE * sizeof(gpr_module_node_t *)); + gpr_ctxt_struct_t.heap1_list = (gpr_module_node_list_t *)ar_heap_malloc(list_size, &heap_info); + if (NULL == gpr_ctxt_struct_t.heap1_list) + { + return AR_EFAILED; + } + ar_mem_set((void *)gpr_ctxt_struct_t.heap1_list, 0, list_size); + gpr_ctxt_struct_t.heap1_list->max_cb_list_size = HEAP1_SESSION_ARRAY_SIZE; + gpr_ctxt_struct_t.heap1_list->heap_index = GPR_HEAP_INDEX_1; + + return AR_EOK; +} + +#ifndef DISABLE_DEINIT +// Utility to destory the packet pool info arrays, called at the time of de-init +static uint32_t gpr_drv_util_free_packet_pool_info_arrs(void) +{ + // Get the heap index in which the structures have been allocated + gpr_heap_index_t gpr_heap_index = gpr_ctxt_struct_t.drv_heap_index; + + ar_heap_info heap_info; + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + gpr_populate_ar_heap_info(gpr_heap_index, AR_HEAP_ALIGN_DEFAULT, &heap_info); + + // free the pointers from corresponding heap. + if (gpr_ctxt_struct_t.static_pool_arr) + { + ar_heap_free((void *)gpr_ctxt_struct_t.static_pool_arr, &heap_info); + } + + if (gpr_ctxt_struct_t.dyn_pool_arr) + { + ar_heap_free((void *)gpr_ctxt_struct_t.dyn_pool_arr, &heap_info); + } + + if (gpr_ctxt_struct_t.default_list) + { + gpr_populate_ar_heap_info(AR_HEAP_ID_DEFAULT, AR_HEAP_ALIGN_DEFAULT, &heap_info); + ar_heap_free((void *)gpr_ctxt_struct_t.default_list, &heap_info); + } + + if (gpr_ctxt_struct_t.heap1_list) + { + gpr_populate_ar_heap_info(AR_HEAP_ID_1, AR_HEAP_ALIGN_DEFAULT, &heap_info); + ar_heap_free((void *)gpr_ctxt_struct_t.heap1_list, &heap_info); + } + + return AR_EOK; +} +#endif +/*@brief Creating memory for GPR packets and initializing all datalink layers + + @return + #AR_EOK when successful. +*/ + +GPR_EXTERNAL uint32_t gpr_drv_internal_init_v2(uint32_t default_domain_id, + uint32_t num_domains, + struct ipc_dl_v2_t gpr_ipc_dl_v2_table[], + uint32_t num_packet_pools, + gpr_packet_pool_info_v2_t packet_pool_info[]) +{ + uint32_t rc; + uint32_t port_index = 0; + uint32_t domain_id = 0; + memset(&gpr_ctxt_struct_t, 0, sizeof(gpr_ctxt_struct_t)); + gpr_deinit_flag = FALSE; + + // DSP gpr supports upto 3 packet pools. + if (num_packet_pools > MAX_GPR_PKT_POOLS) + { + goto bailout; + } + + /* Create gpr mutexes */ + rc = ar_osal_mutex_create((ar_osal_mutex_t *)&gpr_ctxt_struct_t.gpr_drv_task_lock); + if (rc) + { + goto bailout; + } + rc = ar_osal_mutex_create((ar_osal_mutex_t *)&gpr_ctxt_struct_t.gpr_drv_isr_lock); + if (rc) + { + goto bailout; + } + + // allocate packet pool info arrays. + rc = gpr_drv_util_create_packet_pool_info_arrs(num_packet_pools, packet_pool_info); + if (rc) + { + goto bailout; + } + + // allocate packets for static pools and cache packet size info for dynamic allocation. + for (uint32_t idx = 0; idx < num_packet_pools; idx++) + { + if (packet_pool_info[idx].is_dynamic) + { + // if there is dynamic pool in the input args, the arr must have been allocated in fn + // gpr_drv_util_create_packet_pool_info_arrs + if (NULL == gpr_ctxt_struct_t.dyn_pool_arr) + { + goto bailout; + } + + gpr_ctxt_struct_t.num_dyn_packet_pools++; + uint32_t new_pool_index = gpr_ctxt_struct_t.num_dyn_packet_pools - 1; + + gpr_ctxt_struct_t.dyn_pool_arr[new_pool_index].max_num_packets = packet_pool_info[idx].num_packets; + gpr_ctxt_struct_t.dyn_pool_arr[new_pool_index].buf_size = packet_pool_info[idx].packet_size; + gpr_ctxt_struct_t.dyn_pool_arr[new_pool_index].curr_num_packets = 0; + gpr_ctxt_struct_t.dyn_pool_arr[new_pool_index].heap_index = packet_pool_info[idx].heap_index; + } + else + { + + // if there is static pool in the input args, the arr must have been allocated in fn + // gpr_drv_util_create_packet_pool_info_arrs + if (NULL == gpr_ctxt_struct_t.static_pool_arr) + { + goto bailout; + } + + gpr_ctxt_struct_t.num_static_packet_pools++; + uint32_t new_pool_index = gpr_ctxt_struct_t.num_static_packet_pools - 1; + + /* static packets info*/ + uint32_t buf_size = packet_pool_info[idx].packet_size; + uint32_t num_packets = packet_pool_info[idx].num_packets; + + ar_heap_info heap_info; + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + gpr_populate_ar_heap_info(packet_pool_info[idx].heap_index, AR_HEAP_ALIGN_8_BYTES, &heap_info); + + gpr_ctxt_struct_t.static_pool_arr[new_pool_index].buf_size = buf_size; + gpr_ctxt_struct_t.static_pool_arr[new_pool_index].num_packets = num_packets; + gpr_ctxt_struct_t.static_pool_arr[new_pool_index].heap_index = packet_pool_info[idx].heap_index; + + uint32_t gpr_memq_size_per_packet = + GPR_MEMQ_UNIT_OVERHEAD_V + buf_size + (GPR_DRV_METADATA_ITEMS_V * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V); + + uint32_t gpr_memq_size = (num_packets * gpr_memq_size_per_packet); + + /* Allocate memory for GPR packets of different sizes */ + gpr_ctxt_struct_t.static_pool_arr[new_pool_index].packet_heap = + (char *)ar_heap_malloc((gpr_memq_size * sizeof(char)), &heap_info); + if (NULL == gpr_ctxt_struct_t.static_pool_arr[new_pool_index].packet_heap) + { + goto bailout; + } + + gpr_ctxt_struct_t.static_pool_arr[new_pool_index].packet_heap_end = + (gpr_ctxt_struct_t.static_pool_arr[new_pool_index].packet_heap) + (gpr_memq_size - 1); + + gpr_ctxt_struct_t.static_pool_arr[new_pool_index].free_packets_memq = + (gpr_memq_block_t *)ar_heap_malloc(sizeof(gpr_memq_block_t), &heap_info); + if (NULL == gpr_ctxt_struct_t.static_pool_arr[new_pool_index].free_packets_memq) + { + goto bailout; + } + + rc = gpr_memq_init(gpr_ctxt_struct_t.static_pool_arr[new_pool_index].free_packets_memq, + gpr_ctxt_struct_t.static_pool_arr[new_pool_index].packet_heap, + (gpr_memq_size * sizeof(char)), + gpr_memq_size_per_packet, + GPR_DRV_METADATA_ITEMS_V, + gpr_drv_isr_lock_fn, + gpr_drv_isr_unlock_fn, + gpr_ctxt_struct_t.static_pool_arr[new_pool_index].heap_index); + if (rc) + { + goto bailout; + } + } + } + + /* Save default domain id and pass it through init*/ + gpr_ctxt_struct_t.default_domain_id = default_domain_id; + + /* Check for max number of domains */ + if (GPR_PL_NUM_TOTAL_DOMAINS_V < num_domains) + { + AR_MSG(DBG_ERROR_PRIO, + "Init failed for number of domain ids %lu > max supported %lu", + num_domains, + (GPR_PL_NUM_TOTAL_DOMAINS_V)); + goto bailout; + } + + /* Copy contents of user defined table to local table */ + gpr_ctxt_struct_t.num_user_defined_domains = num_domains; + for (port_index = 0; port_index < gpr_ctxt_struct_t.num_user_defined_domains; port_index++) + { + domain_id = gpr_ipc_dl_v2_table[port_index].domain_id; + local_gpr_ipc_dl_table[domain_id].domain_id = gpr_ipc_dl_v2_table[port_index].domain_id; + local_gpr_ipc_dl_table[domain_id].init_fn = gpr_ipc_dl_v2_table[port_index].init_fn; + local_gpr_ipc_dl_table[domain_id].deinit_fn = gpr_ipc_dl_v2_table[port_index].deinit_fn; + local_gpr_ipc_dl_table[domain_id].supports_shared_mem = gpr_ipc_dl_v2_table[port_index].supports_shared_mem; + } + + /* Populate GPR CB functions */ + gpr_to_ipc_vtbl_t gpr_to_ipc_tbl; + gpr_to_ipc_tbl.receive = &gpr_ipc_receive; + gpr_to_ipc_tbl.send_done = &gpr_ipc_send_done; + + /* Call init for all user defined dl's */ + for (domain_id = 0; domain_id < GPR_PL_NUM_TOTAL_DOMAINS_V; domain_id++) + { + if (NULL != (local_gpr_ipc_dl_table[domain_id].init_fn)) + { + rc = local_gpr_ipc_dl_table[domain_id].init_fn(default_domain_id, + domain_id, + &gpr_to_ipc_tbl, + &local_gpr_ipc_dl_table[domain_id].fn_ptr); + if (rc) + { + AR_MSG(DBG_ERROR_PRIO, "Init failed for domain id %lu", domain_id); + goto bailout; + } + } + } + + /* Initialize list of gpr packets allocated dynamically */ + if (gpr_dynamic_packet_init()) + { + AR_MSG(DBG_ERROR_PRIO, "Dynamic packet initialization failed"); + goto bailout; + } + + return AR_EOK; + +bailout: +#ifndef DISABLE_DEINIT + rc = gpr_drv_deinit(); +#endif + return AR_EFAILED; +} + +/*@brief Creating memory for GPR packets and initializing all datalink layers + + @return + #AR_EOK when successful. +*/ +#define MAX_PKT_POOLS_V1 2 +GPR_INTERNAL uint32_t gpr_drv_internal_init(struct ipc_dl_t gpr_ipc_dl_table[], + uint32_t num_domains, + uint32_t default_domain_id, + uint32_t num_packets_1, + uint32_t buf_size_1, + uint32_t num_packets_2, + uint32_t buf_size_2) +{ + gpr_packet_pool_info_v2_t packet_pool_info[MAX_PKT_POOLS_V1]; + packet_pool_info[0].heap_index = GPR_HEAP_INDEX_DEFAULT; + packet_pool_info[0].num_packets = num_packets_1; + packet_pool_info[0].packet_size = buf_size_1; + packet_pool_info[0].is_dynamic = FALSE; + packet_pool_info[0].reserved = 0; + + packet_pool_info[1].heap_index = GPR_HEAP_INDEX_DEFAULT; + packet_pool_info[1].num_packets = num_packets_2; + packet_pool_info[1].packet_size = buf_size_2; + packet_pool_info[1].is_dynamic = FALSE; + packet_pool_info[1].reserved = 0; + + struct ipc_dl_v2_t gpr_ipc_dl_v2_table[GPR_PL_NUM_TOTAL_DOMAINS_V]; + memset(&gpr_ipc_dl_v2_table[0], 0, (sizeof(struct ipc_dl_v2_t) * GPR_PL_NUM_TOTAL_DOMAINS_V)); + + /* Check for max number of domains */ + if (GPR_PL_NUM_TOTAL_DOMAINS_V < num_domains) + { + AR_MSG(DBG_ERROR_PRIO, + "Init failed for number of domain ids %lu > max supported %lu", + num_domains, + (GPR_PL_NUM_TOTAL_DOMAINS_V)); + return AR_EBADPARAM; + } + + for (uint32_t idx = 0; idx < num_domains; idx++) + { + gpr_ipc_dl_v2_table[idx].domain_id = gpr_ipc_dl_table[idx].domain_id; + gpr_ipc_dl_v2_table[idx].init_fn = gpr_ipc_dl_table[idx].init_fn; + gpr_ipc_dl_v2_table[idx].deinit_fn = gpr_ipc_dl_table[idx].deinit_fn; + gpr_ipc_dl_v2_table[idx].supports_shared_mem = TRUE; + } + + return gpr_drv_internal_init_v2(default_domain_id, + num_domains, + gpr_ipc_dl_v2_table, + MAX_PKT_POOLS_V1, + packet_pool_info); +} + +/*@brief Freeing memory for GPR packets and de-initializing all datalink layers + + @return + #AR_EOK when successful. +*/ +#ifndef DISABLE_DEINIT + +GPR_INTERNAL uint32_t gpr_drv_deinit(void) +{ + uint32_t domain_id; + uint32_t rc = AR_EOK; + + if (gpr_deinit_flag) + { + return AR_EOK; + } + + /* Calling ipc dl de-init for user defined domains */ + for (domain_id = 0; domain_id < GPR_PL_NUM_TOTAL_DOMAINS_V; domain_id++) + { + if (NULL != (local_gpr_ipc_dl_table[domain_id].deinit_fn)) + { + rc = local_gpr_ipc_dl_table[domain_id].deinit_fn(gpr_ctxt_struct_t.default_domain_id, domain_id); + if (rc) + { + AR_MSG(DBG_ERROR_PRIO, "de-init failed for domain id %lu", domain_id); + } + } + } + + // Free static packet pool heaps + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_static_packet_pools; idx++) + { + /* Freeing linked list nodes*/ + if (NULL != gpr_ctxt_struct_t.static_pool_arr[idx].free_packets_memq) + { + gpr_memq_deinit(gpr_ctxt_struct_t.static_pool_arr[idx].free_packets_memq, + gpr_ctxt_struct_t.static_pool_arr[idx].heap_index); + } + + /*Freeing packet memory*/ + ar_heap_info heap_info; + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + gpr_populate_ar_heap_info(gpr_ctxt_struct_t.static_pool_arr[idx].heap_index, AR_HEAP_ALIGN_8_BYTES, &heap_info); + + if (NULL != gpr_ctxt_struct_t.static_pool_arr[idx].free_packets_memq) + { + ar_heap_free((void *)gpr_ctxt_struct_t.static_pool_arr[idx].free_packets_memq, &heap_info); + } + + if (NULL != gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap) + { + ar_heap_free((void *)gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap, &heap_info); + } + } + + gpr_dynamic_packet_deinit(); + + // free packet pool info arrays + gpr_drv_util_free_packet_pool_info_arrs(); + + /* Free mutexes*/ + if (NULL != gpr_ctxt_struct_t.gpr_drv_isr_lock) + { + (void)ar_osal_mutex_destroy(gpr_ctxt_struct_t.gpr_drv_isr_lock); + gpr_ctxt_struct_t.gpr_drv_isr_lock = NULL; + } + if (NULL != gpr_ctxt_struct_t.gpr_drv_task_lock) + { + (void)ar_osal_mutex_destroy(gpr_ctxt_struct_t.gpr_drv_task_lock); + gpr_ctxt_struct_t.gpr_drv_task_lock = NULL; + } + + // memset the global gpr driver structure memory + memset(&gpr_ctxt_struct_t, 0, sizeof(gpr_ctxt_struct_t)); + gpr_deinit_flag = TRUE; + + return AR_EOK; +} + +#endif +/***************************************************************************** + * Local IPC Implementation * + ****************************************************************************/ +/*@brief Local datalink init + @param[in] domain_id Domain id of destination + @param[in] gpr_to_ipc_vtbl_t Pointer to function table sent from GPR to IPC datalink layers + @param[in] ipc_to_gpr_vtbl_t Double pointer to function table to be populated by IPC datalink layer + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t ipc_dl_local_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl __UNUSED, + ipc_to_gpr_vtbl_t **pp_ipc_to_gpr_vtbl) +{ + + __UNREFERENCED_PARAM(p_gpr_to_ipc_vtbl); + AR_MSG(DBG_LOW_PRIO, + "GPR Local init called with same src domain id %d, dest domain id %d", + src_domain_id, + dest_domain_id); + *pp_ipc_to_gpr_vtbl = &local_vtbl; + + return AR_EOK; +} + +/*@brief Local datalink de-init + @param[in] domain_id Domain id + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t ipc_dl_local_deinit(uint32_t src_domain_id, uint32_t dest_domain_id) +{ + AR_MSG(DBG_LOW_PRIO, + "GPR Local de-init called with same src domain id %d, dest domain id %d", + src_domain_id, + dest_domain_id); + return AR_EOK; +} + +/***************************************************************************** + * Fundamental Controls Implementation * + ****************************************************************************/ +/** + @brief Registers a module, by domain id and module port/address, to the GPR service. + Module must pass its heap index. + + @param[in] src_port Address of registering module + @param[in] rcallback_fn callback function to register. + @param[in] rcallback_data Client-supplied data pointer for the callback + function. + @param[in] heap_index Heap index + + @detdesc + This function is called by modules once during system bring-up or during + runtime to register its presence to the GPR service. The client and server + services must be registered with the GPR service before any messages can + be passed between them. + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_register_v2(uint32_t src_port, + gpr_callback_fn_t callback_fn, + void *callback_data, + gpr_heap_index_t heap_index) +{ + uint32_t rc = 0; + gpr_module_entry_t *session = NULL; + + if (NULL == callback_fn) + { + return AR_EBADPARAM; + } + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_HIGH_PRIO, "GPR Register: Source Port is %lu", src_port); +#endif + + AR_MSG(DBG_HIGH_PRIO, "GPR Register: Source Port is %lu heap_index: %lu", src_port, heap_index); + + gpr_module_node_list_t *list_handle = gpr_ctxt_struct_t.default_list; + if (GPR_HEAP_INDEX_1 == heap_index) + { + list_handle = gpr_ctxt_struct_t.heap1_list; + } + + ar_osal_mutex_lock(gpr_ctxt_struct_t.gpr_drv_task_lock); + + // saves src port in cb_list and returns pointer to session + rc = gpr_init_session(src_port, &session, list_handle); + + /* Save cb function and argument if any */ + if (session) + { + session->callback_fn = callback_fn; + if (callback_data) + { + session->callback_data = callback_data; + } + } + + ar_osal_mutex_unlock(gpr_ctxt_struct_t.gpr_drv_task_lock); + return rc; +} + +/** + @brief Registers a module, by domain id and module port/address, to the GPR service. + + @param[in] src_port Address of registering module + @param[in] rcallback_fn callback function to register. + @param[in] rcallback_data Client-supplied data pointer for the callback + function. + @detdesc + This function is called by modules once during system bring-up or during + runtime to register its presence to the GPR service. The client and server + services must be registered with the GPR service before any messages can + be passed between them. + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_register(uint32_t src_port, gpr_callback_fn_t callback_fn, void *callback_data) +{ + return __gpr_cmd_register_v2(src_port, callback_fn, callback_data, GPR_HEAP_INDEX_DEFAULT); +} + +/** + @brief De-registers a module from the GPR service. + + @param[in] src_port src_port + @detdesc + This function is called by modules once during system teardown or during + runtime to deregister its presence from the GPR service. + + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_deregister_v2(uint32_t src_port, gpr_heap_index_t heap_index) +{ + uint32_t rc = AR_EOK; + + gpr_module_node_list_t *list_handle = gpr_ctxt_struct_t.default_list; + if (GPR_HEAP_INDEX_1 == heap_index) + { + list_handle = gpr_ctxt_struct_t.heap1_list; + } + + ar_osal_mutex_lock(gpr_ctxt_struct_t.gpr_drv_task_lock); + + // free memory for node corresponding to the port + (void)gpr_deinit_session(src_port, list_handle); + + ar_osal_mutex_unlock(gpr_ctxt_struct_t.gpr_drv_task_lock); + + return rc; +} + +/** + @brief De-registers a module from the GPR service. + + @param[in] src_port src_port + @detdesc + This function is called by modules once during system teardown or during + runtime to deregister its presence from the GPR service. + + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_deregister(uint32_t src_port) +{ + return __gpr_cmd_deregister_v2(src_port, GPR_HEAP_INDEX_DEFAULT); +} + +/** + @brief Checks if a module is registered to the GPR service. + + @param[in] port port + @param[out] bool_t is_registered + @detdesc + This function is called by framework to check if module is still registered + to the GPR service. + + @return + #AR_EOK always with result in is_registered flag +*/ +uint32_t __gpr_cmd_is_registered(uint32_t port, bool_t *is_registered) +{ + gpr_module_entry_t *session = NULL; + uint32_t rc = AR_EOK; + + if (NULL == is_registered) + { + return AR_EBADPARAM; + } + + ar_osal_mutex_lock(gpr_ctxt_struct_t.gpr_drv_task_lock); + + rc = gpr_get_session_util(port, &session); + + ar_osal_mutex_unlock(gpr_ctxt_struct_t.gpr_drv_task_lock); + + if (NULL == session) + { + *is_registered = FALSE; + } + else + { + *is_registered = TRUE; + } + + return rc; +} + +uint32_t __gpr_cmd_is_shared_mem_supported(uint32_t domain_id, bool_t *supports_shared_mem) +{ + if (NULL == supports_shared_mem) + { + AR_MSG(DBG_ERROR_PRIO, + "Flag passed is NULL OR Domain ID out of bounds %lu, Max ID supported %lu", + domain_id, + GPR_PL_MAX_DOMAIN_ID_V); + return AR_EBADPARAM; + } + + *supports_shared_mem = local_gpr_ipc_dl_table[domain_id].supports_shared_mem; + + return AR_EOK; +} + +uint32_t __gpr_cmd_get_dest_domain_ids(uint32_t *num_domains, uint32_t *domain_ids) +{ + uint32_t domain_index = 0; + + if (NULL == num_domains) + { + return AR_EBADPARAM; + } + else if (*num_domains == 0) + { + *num_domains = gpr_ctxt_struct_t.num_user_defined_domains - 1; + return AR_EOK; + } + else + { + if (domain_ids != NULL) + { + for (domain_index = 0; domain_index < *num_domains; domain_index++) + { + if (local_gpr_ipc_dl_table[domain_index].domain_id != gpr_ctxt_struct_t.default_domain_id && + local_gpr_ipc_dl_table[domain_index].domain_id != GPR_IDS_DOMAIN_ID_INVALID_V) + { + domain_ids[domain_index] = local_gpr_ipc_dl_table[domain_index].domain_id; + } + } + return AR_EOK; + } + else + { + return AR_EBADPARAM; + } + } +} + +/** + @brief Retrieves gpr packet info. + + @detdesc + This function is called to query the gpr packet pool information + which returns the minimum and maximum size(in bytes) of packets + allocated by gpr as well as maximum number of each such packets. + + This is a V1 function so dynamic pools are not supported here. Hence we iterate + through only static pools to get the max and min sizes. + + If the client is using V2 api to allocate pools i.e gpr_drv_internal_init_v2(), + then this function should not be used, client must use __gpr_cmd_get_gpr_packet_info_v2() only. + + This info is sent to gpr through platform wrappers at the time of init + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_get_gpr_packet_info(gpr_cmd_gpr_packet_pool_info_t *args) +{ + if (NULL == args) + { + return AR_EBADPARAM; + } + + uint32_t min_buf_size = 0xFFFFFFFF; + uint32_t max_buf_size = 0; + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_static_packet_pools; idx++) + { + // Consider only non-island heap index for V1 get packet pool info function + if (GPR_HEAP_INDEX_DEFAULT != gpr_ctxt_struct_t.static_pool_arr[idx].heap_index) + { + continue; + } + + // track max + if (gpr_ctxt_struct_t.static_pool_arr[idx].buf_size > max_buf_size) + { + args->num_max_size_packets = gpr_ctxt_struct_t.static_pool_arr[idx].num_packets; + + args->bytes_per_max_size_packet = gpr_ctxt_struct_t.static_pool_arr[idx].buf_size; + max_buf_size = gpr_ctxt_struct_t.static_pool_arr[idx].buf_size; + } + + // track min + if (gpr_ctxt_struct_t.static_pool_arr[idx].buf_size < min_buf_size) + { + args->num_min_size_packets = gpr_ctxt_struct_t.static_pool_arr[idx].num_packets; + + args->bytes_per_min_size_packet = gpr_ctxt_struct_t.static_pool_arr[idx].buf_size; + min_buf_size = gpr_ctxt_struct_t.static_pool_arr[idx].buf_size; + } + } + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_HIGH_PRIO, + "GPR: Min packet pool (size,num_pkts)= (%lu,%lu) Max packet pool (size,num_pkts)= (%lu,%lu)", + args->bytes_per_min_size_packet, + args->num_min_size_packets, + args->bytes_per_max_size_packet, + args->num_max_size_packets); +#endif + + return AR_EOK; +} + +uint32_t __gpr_cmd_get_gpr_packet_info_v2(uint32_t *num_packet_pools, gpr_packet_pool_info_v2_t *packet_pool_info_arr) +{ + if (num_packet_pools) + { + *num_packet_pools = gpr_ctxt_struct_t.num_static_packet_pools + gpr_ctxt_struct_t.num_dyn_packet_pools; + } + + if (packet_pool_info_arr) + { + uint32_t idx = 0; + // populate static pool info + for (idx = 0; idx < gpr_ctxt_struct_t.num_static_packet_pools; idx++) + { + packet_pool_info_arr[idx].is_dynamic = FALSE; + packet_pool_info_arr[idx].heap_index = gpr_ctxt_struct_t.static_pool_arr[idx].heap_index; + packet_pool_info_arr[idx].num_packets = gpr_ctxt_struct_t.static_pool_arr[idx].num_packets; + packet_pool_info_arr[idx].packet_size = gpr_ctxt_struct_t.static_pool_arr[idx].buf_size; + packet_pool_info_arr[idx].reserved = 0; + } + + // populate dynamic pool info + for (; idx < gpr_ctxt_struct_t.num_dyn_packet_pools; idx++) + { + packet_pool_info_arr[idx].is_dynamic = TRUE; + packet_pool_info_arr[idx].heap_index = gpr_ctxt_struct_t.dyn_pool_arr[idx].heap_index; + packet_pool_info_arr[idx].num_packets = gpr_ctxt_struct_t.dyn_pool_arr[idx].max_num_packets; + packet_pool_info_arr[idx].packet_size = gpr_ctxt_struct_t.dyn_pool_arr[idx].buf_size; + packet_pool_info_arr[idx].reserved = 0; + } + } + + return AR_EOK; +} +//end of file diff --git a/gpr/core/src/gpr_drv_i.h b/gpr/core/src/gpr_drv_i.h new file mode 100644 index 0000000..d15f8d8 --- /dev/null +++ b/gpr/core/src/gpr_drv_i.h @@ -0,0 +1,133 @@ +#ifndef __GPR_DRV_I_H__ +#define __GPR_DRV_I_H__ +/** + * \file gpr_drv_i.h + * \brief + * This file contains GPR driver internal API header. + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_proc_info_api.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_mutex.h" +#include "ar_osal_heap.h" +#include "ar_guids.h" +#include "gpr_api_i.h" +#include "gpr_msg_if.h" +#include "gpr_memq.h" +#include "gpr_api_inline.h" +#include "gpr_log.h" +#include "gpr_session.h" +#include "ar_osal_servreg.h" +#include "ar_osal_string.h" +#include "gpr_dynamic_allocation.h" + +#if defined(WIN64) || defined(WIN32) +#include +#else +#include "gpr_private_api.h" +#endif + +/***************************************************************************** + * Structure definitions * + ****************************************************************************/ + +/* Structure for Local GPR IPC table containing init,deinit functions + * and vtbl function pointer to be populated for each datalink during init*/ +struct ipc_dl_local_t +{ + uint16_t domain_id; // store domain id for readability + ipc_dl_init_fn_t init_fn; // store the call back function here + ipc_dl_deinit_fn_t deinit_fn; + ipc_to_gpr_vtbl_t *fn_ptr; + bool_t supports_shared_mem; +}; + +/***************************************************************************** + * Defines * + ****************************************************************************/ +//#define GPR_DEBUG_MSG 1 +#define GPR_DRV_METADATA_ITEMS_V (1) + +/***************************************************************************** + * Global variables * + ****************************************************************************/ +/* GPR context structure contains all GPR globals */ + +// GPR driver internal MAX number of pools limit. +#define MAX_GPR_PKT_POOLS 128 + +// Info related to each of the static packet pool +typedef struct gpr_drv_pkt_static_pool_info_t +{ + char *packet_heap; + char *packet_heap_end; + gpr_memq_block_t *free_packets_memq; + uint32_t buf_size; + uint32_t num_packets; + gpr_heap_index_t heap_index; +} gpr_drv_pkt_static_pool_info_t; + +/* Info related to each of the dynamic packet pool, currently only one dynamic pool is supported.*/ +typedef struct gpr_drv_pkt_dynamic_pool_info_t +{ + uint32_t buf_size; + uint32_t max_num_packets; + uint32_t curr_num_packets; + gpr_heap_index_t heap_index; +} gpr_drv_pkt_dynamic_pool_info_t; + +typedef struct gpr_ctxt_struct_t +{ + ar_osal_mutex_t gpr_drv_isr_lock; + ar_osal_mutex_t gpr_drv_task_lock; + gpr_module_node_list_t *default_list; /* handle to manage registered module nodes for default heap */ + gpr_module_node_list_t *heap1_list; /* handle to manage registered module nodes for GPR heap index 1 */ + + uint32_t num_user_defined_domains; + uint32_t default_domain_id; + + /** Driver heap index is the index used for allocating, + * 1. globla structure arrays static_pool_arr and dyn_pool_arr + * 2. Creating session entry memory. + * + * This will allow accessing the client nodes and packet pool info structures in low power heaps. + * + * Note that this index is not used for allocating the packets. Packets are allocated + * based on per pool heap index. + * */ + gpr_heap_index_t drv_heap_index; + + /* Packets in each of static pool are allocated statically at init time. + The structure contains statically allocated num_packets, each packets size, packet heap info. */ + uint32_t num_static_packet_pools; + gpr_drv_pkt_static_pool_info_t *static_pool_arr; + + /* Packets in the dynamic pool are malloced when packet_alloc() is called. the info struct contains + max packets that can be dynamically allocated, current num of malloced packets and each packets size. */ + uint32_t num_dyn_packet_pools; + gpr_drv_pkt_dynamic_pool_info_t *dyn_pool_arr; +} gpr_ctxt_struct_type; + +/***************************************************************************** + * function definitions * + ****************************************************************************/ + +GPR_INTERNAL uint32_t gpr_local_send(uint32_t domain_id, void *buf, uint32_t length); + +GPR_INTERNAL uint32_t gpr_local_receive_done(uint32_t domain_id, void *buf); + +void gpr_drv_isr_lock_fn(void); + +void gpr_drv_isr_unlock_fn(void); + +GPR_INTERNAL uint32_t gpr_get_session_util(uint32_t my_module_port, gpr_module_entry_t **ret_entry); + +#endif /* __GPR_DRV_I_H__ */ diff --git a/gpr/core/src/gpr_drv_island.c b/gpr/core/src/gpr_drv_island.c new file mode 100644 index 0000000..0a0666d --- /dev/null +++ b/gpr/core/src/gpr_drv_island.c @@ -0,0 +1,772 @@ +/** + * \file gpr_drv_island.c + * \brief + * This file contains GPR driver implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_drv_i.h" + +/***************************************************************************** + * Global variables * + ****************************************************************************/ + +/* Local GPR IPC table containing init,deinit functions and vtbl function pointer to be populated for all domains*/ +struct ipc_dl_local_t local_gpr_ipc_dl_table[GPR_PL_NUM_TOTAL_DOMAINS_V] = { + { 0, NULL, NULL, NULL, true }, { 0, NULL, NULL, NULL, true }, { 0, NULL, NULL, NULL, true }, + { 0, NULL, NULL, NULL, true }, { 0, NULL, NULL, NULL, true }, { 0, NULL, NULL, NULL, true }, + { 0, NULL, NULL, NULL, true }, +}; + +/* local ipc vtbl functions */ +ipc_to_gpr_vtbl_t local_vtbl = { + gpr_local_send, + gpr_local_receive_done, +}; + +// global context variable +gpr_ctxt_struct_type gpr_ctxt_struct_t; + +/***************************************************************************** + * Helper functions * + ****************************************************************************/ + +void gpr_drv_isr_lock_fn(void) +{ + (void)ar_osal_mutex_lock(gpr_ctxt_struct_t.gpr_drv_isr_lock); +} + +void gpr_drv_isr_unlock_fn(void) +{ + (void)ar_osal_mutex_unlock(gpr_ctxt_struct_t.gpr_drv_isr_lock); +} + +/** + @brief Sends an asynchronous message to other modules. + + @param[in] packet Packet (message) to send. + + @detdesc + Calling #GPR_CMDID_ALLOC or #GPR_CMDID_ALLOC_EXT allocates free messages + for sending. The caller can try to resend messages, or abort and free + messages when delivery fails. + + This GPR_CMDID_ASYNC_SEND function provides the caller with low-level + control over the sending process. For general use, consider using a + simplified helper function, such as #GPR_CMDID_ALLOC_SEND. + + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_async_send(gpr_packet_t *packet) +{ + uint32_t rc = AR_EOK; + if (NULL == packet) + { + AR_MSG(DBG_ERROR_PRIO, "Param pointer is NULL"); + return AR_EBADPARAM; + } + + uint32_t domain_id = packet->dst_domain_id; + uint32_t packet_len = GPR_PKT_GET_PACKET_BYTE_SIZE(packet->header); + gpr_memq_block_t *block; + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_HIGH_PRIO, + "GPR async Send: Destination Domain ID %hhu, Destination Port %ld opcode 0x%lx token 0x%lx", + packet->dst_domain_id, + packet->dst_port, + packet->opcode, + packet->token); +#endif + + if (packet->src_domain_id != packet->dst_domain_id) + { + // Log incoming and outgoing packets + gpr_log_packet(packet); + } + + if (GPR_PL_MAX_DOMAIN_ID_V < domain_id) + { + AR_MSG(DBG_ERROR_PRIO, + "GPR send: Domain ID out of bounds %lu, Max ID supported %lu", + domain_id, + GPR_PL_MAX_DOMAIN_ID_V); + return AR_EBADPARAM; + } + + if ((NULL == local_gpr_ipc_dl_table[domain_id].fn_ptr) || (NULL == local_gpr_ipc_dl_table[domain_id].fn_ptr->send)) + { + AR_MSG(DBG_ERROR_PRIO, + "NULL Fn ptr, = 0x%lx -> if this is not NULL, the send ptr is NULL", + local_gpr_ipc_dl_table[domain_id].fn_ptr); + return AR_EFAILED; + } + + // check if the packet is from a static packet pool. + // if so, set memq metadata and then send the packet + // else, just call send + bool_t pkt_is_from_the_static_pool = false; + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_static_packet_pools; idx++) + { + /* Freeing linked list nodes*/ + if ((char *)packet > gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap && + (char *)packet < gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap_end) + { + pkt_is_from_the_static_pool = true; + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_HIGH_PRIO, + "gpr packet send: Destination Domain ID %hhu, Destination Port %ld", + packet->dst_domain_id, + packet->dst_port); +#endif + if (packet_len <= gpr_ctxt_struct_t.static_pool_arr[idx].buf_size) + { + block = gpr_ctxt_struct_t.static_pool_arr[idx].free_packets_memq; + } + else + { + AR_MSG(DBG_ERROR_PRIO, "Send error %lu", packet->dst_port); + return AR_EFAILED; + } + + /* Sets the packet ownership to destination before sending */ + gpr_memq_node_set_metadata(block, packet, 0, packet->dst_port); + + rc = local_gpr_ipc_dl_table[domain_id].fn_ptr->send(domain_id, packet, packet_len); + if (rc) + { + /* Sets the packet owner to source if send fails for any reason */ + gpr_memq_node_set_metadata(block, packet, 0, packet->src_port); + AR_MSG(DBG_ERROR_PRIO, + "gpr packet send failed rc %d: Destination Domain ID %hhu, Destination Port %ld Opcode %lx token " + "%lx", + rc, + packet->dst_domain_id, + packet->dst_port, + packet->opcode, + packet->token); + } + + // stop iterating the loop + break; + } + } + + // If the packet is not from static pool, it could be from datalink packet or dynamic packet pool. + if (!pkt_is_from_the_static_pool) + { +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_HIGH_PRIO, + "GPR datalink packet send: Destination Domain ID %hhu, Destination Port %ld", + packet->dst_domain_id, + packet->dst_port); +#endif + rc = local_gpr_ipc_dl_table[domain_id].fn_ptr->send(domain_id, packet, packet_len); + + if (rc) + { + AR_MSG(DBG_ERROR_PRIO, + "gpr packet send failed rc %d: Destination Domain ID %hhu, Destination Port %ld Opcode %lx token %lx", + rc, + packet->dst_domain_id, + packet->dst_port, + packet->opcode, + packet->token); + } + } + + return rc; +} +/** + @brief Allocates a free message for delivery. + + @param[in] alloc_size Amount of memory required for allocation, in bytes. + @param[out] ret_packet Returns the pointer to the allocated packet. + + @detdesc + This function allocates a packet from the indicated module's free packet + queue, and it provides the caller with low-level control over the allocation + process. For general use, consider using a simplified helper function, such + as #GPR_CMDID_ALLOC_EXT. + + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_alloc(uint32_t alloc_size, gpr_packet_t **ret_packet) +{ + return __gpr_cmd_alloc_v2(alloc_size, GPR_HEAP_INDEX_DEFAULT, ret_packet); +} + +/** + @brief Allocates a free message for delivery. + + @param[in] alloc_size Amount of memory required for allocation, in bytes. + @param[out] ret_packet Returns the pointer to the allocated packet. + + @detdesc + This function allocates a packet from the indicated module's free packet + queue, and it provides the caller with low-level control over the allocation + process. For general use, consider using a simplified helper function, such + as #GPR_CMDID_ALLOC_EXT. + + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_alloc_v2(uint32_t alloc_size, gpr_heap_index_t heap_index, gpr_packet_t **ret_packet) +{ + gpr_memq_block_t *block; + gpr_packet_t *new_packet = NULL; + uint32_t packet_size = (GPR_PKT_HEADER_BYTE_SIZE_V + alloc_size); + + if (NULL == ret_packet) + { + AR_MSG(DBG_ERROR_PRIO, "alloc_error, NULL packet"); + return AR_EBADPARAM; + } + + bool_t found_packet_pool = FALSE; + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_static_packet_pools; idx++) + { + if (packet_size <= gpr_ctxt_struct_t.static_pool_arr[idx].buf_size && + (heap_index == gpr_ctxt_struct_t.static_pool_arr[idx].heap_index)) + { + found_packet_pool = TRUE; + + block = gpr_ctxt_struct_t.static_pool_arr[idx].free_packets_memq; + new_packet = (gpr_packet_t *)gpr_memq_alloc(block); + break; + } + } + + // If packet couldnt not be allocated in static pool, check dynamic pool + if (NULL == new_packet) + { + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_dyn_packet_pools; idx++) + { + if ((packet_size <= gpr_ctxt_struct_t.dyn_pool_arr[idx].buf_size) && + (gpr_ctxt_struct_t.dyn_pool_arr[idx].curr_num_packets < + gpr_ctxt_struct_t.dyn_pool_arr[idx].max_num_packets) && + (heap_index == gpr_ctxt_struct_t.dyn_pool_arr[idx].heap_index)) + { + found_packet_pool = TRUE; + + gpr_allocate_dynamic_packet(&new_packet, packet_size); + if (new_packet == NULL) + { + AR_MSG(DBG_ERROR_PRIO, "alloc_error unsupported size %lu, heap_index: %lu", alloc_size, heap_index); + return AR_ENORESOURCE; + } + gpr_ctxt_struct_t.dyn_pool_arr[idx].curr_num_packets++; + } + } + } + + /* Check if packet has been allocated from a dynamic/static pool.*/ + if (new_packet == NULL) + { + AR_MSG(DBG_ERROR_PRIO, + "alloc_error, NULL packet found_packet_pool %lu, alloc size %lu heap_index %lu", + found_packet_pool, + alloc_size, + heap_index); + return AR_ENORESOURCE; + } + + ar_mem_set(new_packet, 0, sizeof(gpr_packet_t)); + new_packet->header = GPR_SET_FIELD(GPR_PKT_VERSION, GPR_PKT_VERSION_V) | + GPR_SET_FIELD(GPR_PKT_HEADER_SIZE, GPR_PKT_HEADER_WORD_SIZE_V) | + GPR_SET_FIELD(GPR_PKT_PACKET_SIZE, packet_size); + new_packet->opcode = GPR_UNDEFINED_ID_V; + new_packet->client_data = GPR_PKT_INIT_CLIENT_DATA_V; + new_packet->reserved = GPR_PKT_INIT_RESERVED_V; + *ret_packet = new_packet; + + return AR_EOK; +} + +/** + @brief Frees a packet from the indicated module's free packet queue. + + @param[in] packet Packet to return. + + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_free(gpr_packet_t *packet) +{ + if (NULL == packet) + { + AR_MSG(DBG_ERROR_PRIO, "Param pointer is NULL"); + return AR_EBADPARAM; + } + + gpr_memq_block_t *block = NULL; + uint32_t packet_size = GPR_PKT_GET_PACKET_BYTE_SIZE(packet->header); + uint32_t domain_id = packet->src_domain_id; + + bool_t pkt_is_from_static_pool = FALSE; + /* If the packet is from Static pool, mark it Free*/ + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_static_packet_pools; idx++) + { + if ((char *)packet > gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap && + (char *)packet < gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap_end) + { + /* If buffer is allocated by GPR*/ + if (packet_size <= gpr_ctxt_struct_t.static_pool_arr[idx].buf_size) + { + block = gpr_ctxt_struct_t.static_pool_arr[idx].free_packets_memq; + + /* Sets the packet owner to 0 before free the packet. */ + gpr_memq_node_set_metadata(block, packet, 0, 0); + gpr_memq_free(block, packet); + pkt_is_from_static_pool = TRUE; + return AR_EOK; + } + else + { + return AR_EBADPARAM; + } + } + } + + // If packet is not from static pool, it could be from Dynamic pool. + if (FALSE == pkt_is_from_static_pool) + { + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_dyn_packet_pools; idx++) + { + if ((packet_size <= gpr_ctxt_struct_t.dyn_pool_arr[idx].buf_size) && + (gpr_ctxt_struct_t.dyn_pool_arr[idx].curr_num_packets > 0)) + { + if (gpr_check_and_free_dynamic_packet(packet) == AR_EOK) + { + gpr_ctxt_struct_t.dyn_pool_arr[idx].curr_num_packets--; + return AR_EOK; + } + } + } + } + + if (GPR_PL_MAX_DOMAIN_ID_V < domain_id) + { + AR_MSG(DBG_ERROR_PRIO, + "GPR free: Domain ID out of bounds %lu, Max ID supported %lu", + domain_id, + GPR_PL_MAX_DOMAIN_ID_V); + return AR_EBADPARAM; + } + + /* If buffer belongs to datalink layer*/ + if ((NULL != local_gpr_ipc_dl_table[domain_id].fn_ptr) && + (NULL != local_gpr_ipc_dl_table[domain_id].fn_ptr->receive_done)) + { + return local_gpr_ipc_dl_table[domain_id].fn_ptr->receive_done(domain_id, (void *)packet); + } + else + { + AR_MSG(DBG_HIGH_PRIO, "Datalink free function pointer is NULL"); + return AR_EFAILED; + } +} + +/***************************************************************************** + * Utility Control Implementations * + ****************************************************************************/ +/** + @brief Allocates a pre-formatted free message for delivery. + + @param[in] src_domain_id Domain id of the sender. + @param[in] src_port Port address of the sender. + @param[in] dst_domain_id Domain id of the receiver + @param[in] dst_port Port address of the receiver. + @param[in] token Value attached by the sender to determine when + command messages have been processed by the receiver + after having received response messages. + @param[in] opcode Defines both the action and the payload structure to + the receiver. + @param[in] payload_size Actual number of bytes needed for the payload. + @param[out] ret_packet Return pointer to the allocated packet. + + @detdesc + This helper function partially creates a message for delivery. The message + allocation and initialization is performed by this function, but the message + payload is dependent on the caller to fill in. The two-step process allows + the caller to avoid multiple memcpy() operations on the message payload. + + @consid + The helper function allocates from the indicated service's free packet pool + based on the msg_type. + @par + - For CMDRSP messages, #GPR_ALLOC_TYPE_RESPONSE is used. + - For EVENT, SEQCMD, and NSEQCMD messages, #GPR_ALLOC_TYPE_COMMAND is used. + + @return + #AR_EOK when successful. + */ +uint32_t __gpr_cmd_alloc_ext(gpr_cmd_alloc_ext_t *args) +{ + gpr_cmd_alloc_ext_v2_t args_v2; + args_v2.heap_index = GPR_HEAP_INDEX_DEFAULT; + args_v2.dst_port = args->dst_port; + args_v2.dst_domain_id = args->dst_domain_id; + args_v2.src_port = args->src_port; + args_v2.src_domain_id = args->src_domain_id; + args_v2.token = args->token; + args_v2.opcode = args->opcode; + args_v2.client_data = args->client_data; + args_v2.payload_size = args->payload_size; + args_v2.ret_packet = args->ret_packet; + + return __gpr_cmd_alloc_ext_v2(&args_v2); +} + +uint32_t __gpr_cmd_alloc_ext_v2(gpr_cmd_alloc_ext_v2_t *args) +{ + uint32_t rc; + gpr_packet_t *new_packet; + gpr_memq_block_t *block; + + if ((NULL == args) || (NULL == args->ret_packet)) + { + return AR_EBADPARAM; + } + + rc = __gpr_cmd_alloc_v2(args->payload_size, args->heap_index, &new_packet); + if (rc) + { + return rc; + } + + new_packet->dst_port = args->dst_port; + new_packet->dst_domain_id = args->dst_domain_id; + new_packet->src_port = args->src_port; + new_packet->src_domain_id = args->src_domain_id; + new_packet->token = args->token; + new_packet->opcode = args->opcode; + new_packet->client_data = args->client_data; + + // set metadata in the corresponding packets memq. + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_static_packet_pools; idx++) + { + if ((char *)new_packet > gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap && + (char *)new_packet < gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap_end) + { + block = gpr_ctxt_struct_t.static_pool_arr[idx].free_packets_memq; + gpr_memq_node_set_metadata(block, new_packet, 0, new_packet->src_port); + break; + } + } + + *args->ret_packet = new_packet; + + return AR_EOK; +} + +/** + @brief Allocates and sends a formatted message. + + @param[in] src_domain_id Domain id of the sender. + @param[in] src_port Port of the sender. + @param[in] dst_domain_id Domain id of the receiver + @param[in] dst_port Port of the receiver. + @param[in] token Value attached by the sender to determine when + command messages have been processed by the + receiver after having received response messages. + @param[in] opcode Defines both the action and the payload structure + to the receiver. + @param[in] payload Payload to send. + @param[in] payload_size Actual number of bytes needed for the payload. + + @detdesc + This helper function fully creates and sends a message. The message + allocation and initialization is performed by this function, and the message + payload is supplied up front by the caller. See the examples in + #GPR_CMDID_ASYNC_SEND and #GPR_CMDID_FORWARD for comparison. + + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_alloc_send(gpr_cmd_alloc_send_t *args) +{ + uint32_t rc; + gpr_cmd_alloc_ext_t alloc_args; + gpr_packet_t *packet; + + if ((NULL == args) || ((args->payload_size > 0) && (NULL == args->payload))) + { + return AR_EBADPARAM; + } + + alloc_args.src_port = args->src_port; + alloc_args.src_domain_id = args->src_domain_id; + alloc_args.dst_port = args->dst_port; + alloc_args.dst_domain_id = args->dst_domain_id; + alloc_args.client_data = args->client_data; + alloc_args.token = args->token; + alloc_args.opcode = args->opcode; + alloc_args.payload_size = args->payload_size; + alloc_args.ret_packet = &packet; + + rc = __gpr_cmd_alloc_ext(&alloc_args); + if (rc) + { + return rc; + } + + if (args->payload_size > 0) + { + (void)ar_mem_cpy(GPR_PKT_GET_PAYLOAD(void, packet), args->payload_size, args->payload, args->payload_size); + } + + rc = __gpr_cmd_async_send(packet); + if (rc) + { + __gpr_cmd_free(packet); + } + + return rc; +} + +/** + @brief Accepts a command message by replying with an #GPR_IBASIC_EVT_ACCEPTED + message to the sender. + + @param[in] packet Command packet to accept. + + @detdesc + The same procedure can be performed manually by swapping the source and + destination fields, and then inserting an #GPR_IBASIC_EVT_ACCEPTED payload. + + @return + #AR_EOK when successful. +*/ +uint32_t __gpr_cmd_accept_command(gpr_packet_t *packet) +{ + gpr_cmd_alloc_send_t send_args; + gpr_ibasic_evt_accepted_t rsp; + + if (NULL == packet) + { + return AR_EBADPARAM; + } + + // Reverse the source and destination addresses to send a command accepted event. + send_args.dst_port = packet->src_port; + send_args.dst_domain_id = packet->src_domain_id; + send_args.src_port = packet->dst_port; + send_args.src_domain_id = packet->dst_domain_id; + send_args.token = packet->token; + send_args.client_data = packet->client_data; + send_args.opcode = GPR_IBASIC_EVT_ACCEPTED; + rsp.opcode = packet->opcode; + send_args.payload = &rsp; + send_args.payload_size = sizeof(rsp); + + (void)__gpr_cmd_alloc_send(&send_args); + + return AR_EOK; +} + +/** + @brief Completes a command message by replying with an #GPR_IBASIC_RSP_RESULT + command response message to the sender. The indicated packet is then freed. + + @param[in] packet Command message to complete. + @param[in] status Completion/error status (see Section + @xref{dox:AprCoreStatusErrorcodes} for available values). + + @detdesc + The same procedure can be done manually by swapping the source and + destination fields and then inserting an #GPR_IBASIC_RSP_RESULT command + response payload. + + @return + #AR_EOK when successful. +*/ +// NOTE: The command packet is freed irrespective of failing to send the command response. +uint32_t __gpr_cmd_end_command(gpr_packet_t *packet, uint32_t status) +{ + uint32_t rc = AR_EOK; + gpr_cmd_alloc_ext_v2_t alloc_args; + gpr_ibasic_rsp_result_t rsp; + gpr_packet_t *rsp_pkt_ptr = NULL; + + if (NULL == packet) + { + return AR_EBADPARAM; + } + + uint32_t opcode_type = ((packet->opcode & AR_GUID_TYPE_MASK) >> AR_GUID_TYPE_SHIFT); + + if (!(((opcode_type & AR_GUID_TYPE_CONTROL_CMD_RSP) == AR_GUID_TYPE_CONTROL_CMD_RSP) || + ((opcode_type & AR_GUID_TYPE_DATA_CMD_RSP) == AR_GUID_TYPE_DATA_CMD_RSP) || + ((opcode_type & AR_GUID_TYPE_CONTROL_EVENT) == AR_GUID_TYPE_CONTROL_EVENT) || + ((opcode_type & AR_GUID_TYPE_DATA_EVENT) == AR_GUID_TYPE_DATA_EVENT))) + { + // get GPR packet heap index + gpr_heap_index_t gpr_heap_index = GPR_HEAP_INDEX_DEFAULT; + for (uint32_t idx = 0; idx < gpr_ctxt_struct_t.num_static_packet_pools; idx++) + { + /* Freeing linked list nodes*/ + if ((char *)packet > gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap && + (char *)packet < gpr_ctxt_struct_t.static_pool_arr[idx].packet_heap_end) + { + gpr_heap_index = gpr_ctxt_struct_t.static_pool_arr[idx].heap_index; + } + } + + // Reverse the source and destination addresses to send a command response. + alloc_args.dst_port = packet->src_port; + alloc_args.dst_domain_id = packet->src_domain_id; + alloc_args.src_port = packet->dst_port; + alloc_args.src_domain_id = packet->dst_domain_id; + alloc_args.token = packet->token; + alloc_args.client_data = packet->client_data; + alloc_args.opcode = GPR_IBASIC_RSP_RESULT; + alloc_args.ret_packet = &rsp_pkt_ptr; + alloc_args.heap_index = gpr_heap_index; + alloc_args.payload_size = sizeof(rsp); + + rc = __gpr_cmd_alloc_ext_v2(&alloc_args); + if (rc) + { + AR_MSG(DBG_ERROR_PRIO, "gpr_unable to allocate packet"); + goto __bailout; + } + + rsp.opcode = packet->opcode; + rsp.status = status; + (void)ar_mem_cpy(GPR_PKT_GET_PAYLOAD(void, rsp_pkt_ptr), alloc_args.payload_size, &rsp, sizeof(rsp)); + + rc = __gpr_cmd_async_send(rsp_pkt_ptr); + if (rc) + { + AR_MSG(DBG_ERROR_PRIO, + "GPR_unable to send to dst domain %d, dst port %d, src domain %d src port %d", + packet->dst_domain_id, + packet->dst_port, + packet->src_domain_id, + packet->src_port); + __gpr_cmd_free(rsp_pkt_ptr); + goto __bailout; + } + } + else + { + AR_MSG(DBG_ERROR_PRIO, "Opcode 0x%lx is of unsupported type. Not sending basic response", packet->opcode); + } + +__bailout: + __gpr_cmd_free(packet); + return rc; +} +/*@brief Function to send gpr packet if its within the same domain + @param[in] domain_id Domain id of destination + @param[in] buf Buffer to be sent + @param[in] length Size of buffer + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_local_send(uint32_t domain_id __UNUSED, void *buf, uint32_t length __UNUSED) +{ + __UNREFERENCED_PARAM(domain_id); + __UNREFERENCED_PARAM(length); + + uint32_t rc, result; + gpr_module_entry_t *session = NULL; + gpr_packet_t *packet = (gpr_packet_t *)buf; + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_HIGH_PRIO, + "GPR local send: Destination Domain ID %hhu, Destination Port %ld opcode %lx, token %lx", + packet->dst_domain_id, + packet->dst_port, + packet->opcode, + packet->token); +#endif + + ar_osal_mutex_lock(gpr_ctxt_struct_t.gpr_drv_task_lock); + + result = gpr_get_session_util(packet->dst_port, &session); + + ar_osal_mutex_unlock(gpr_ctxt_struct_t.gpr_drv_task_lock); + + if (AR_ENOTEXIST == result) + { + AR_MSG(DBG_ERROR_PRIO, "Session not found, returning"); + /*GPR will return error to the caller if session is not found to ensure synchronous error reporting*/ + rc = AR_ENOTEXIST; + } + else if ((NULL != session) && (NULL != session->callback_fn)) + { + rc = session->callback_fn(packet, session->callback_data); + } + else + { + AR_MSG(DBG_ERROR_PRIO, "Sending packet failed, retrieved session is null"); + rc = AR_EFAILED; + } + return rc; +} + +/*@brief Local free function + @param[in] domain_id Domain id of destination + @param[in] buf Buffer to be sent + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_local_receive_done(uint32_t domain_id __UNUSED, void *buf __UNUSED) +{ + __UNREFERENCED_PARAM(domain_id); + __UNREFERENCED_PARAM(buf); + + return AR_EOK; +} + +/*@brief Internal utility to get the session handle for the given port. It searches + all the available cb lists in the gpr driver. + @param[in] port Module port number + @param[out] ret_entry Return node ptr + + @return + #AR_EOK when successful. + #AR_ENOTEXIST when the given port is not found in the lists. +*/ +GPR_INTERNAL uint32_t gpr_get_session_util(uint32_t port, gpr_module_entry_t **ret_entry) +{ + uint32_t result = AR_EOK; + + // Imp: Always check the non-deafult list first and then default. + if (AR_EOK != (result = gpr_get_session(port, ret_entry, gpr_ctxt_struct_t.heap1_list))) + { + result = gpr_get_session(port, ret_entry, gpr_ctxt_struct_t.default_list); + } + + if (AR_FAILED(result)) + { + AR_MSG(DBG_ERROR_PRIO, "No such module port (%lu) found in linked list", port); + } + + return result; +} + +uint32_t __gpr_cmd_get_host_domain_id(uint32_t *host_domain_id) +{ + if (NULL == host_domain_id) + { + return AR_EBADPARAM; + } + *host_domain_id = gpr_ctxt_struct_t.default_domain_id; + + return AR_EOK; +} diff --git a/gpr/core/src/gpr_list.c b/gpr/core/src/gpr_list.c new file mode 100644 index 0000000..40edd6d --- /dev/null +++ b/gpr/core/src/gpr_list.c @@ -0,0 +1,135 @@ +/** + * \file gpr_list.c + * \brief + * This file contains GPR list APIs + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_list.h" +#include "gpr_list_i.h" + +/****************************************************************************** + * Functions * + *****************************************************************************/ + +static inline uint32_t gpr_list_raw_is_not_empty(gpr_list_t *list) +{ + return (list->dummy.next != &list->dummy); +} + +static uint32_t gpr_list_init_internal(gpr_list_t *list, + gpr_list_lock_enter_fn_t lock_fn, + gpr_list_lock_leave_fn_t unlock_fn, + bool_t en_secure) +{ + if ((list == NULL) || (NULL == lock_fn) || (NULL == unlock_fn)) + { + return AR_EBADPARAM; + } + + list->dummy.prev = &list->dummy; + list->dummy.next = &list->dummy; + list->size = 0; + list->lock_fn = lock_fn; + list->unlock_fn = unlock_fn; + list->en_secure = en_secure; + + return AR_EOK; +} + +GPR_EXTERNAL uint32_t gpr_list_get_head(gpr_list_t *list, gpr_list_node_t **ret_node) +{ + if (list == NULL || ret_node == NULL) + { + return AR_EBADPARAM; + } + + list->lock_fn(); + + if (gpr_list_raw_is_empty(list)) + { + list->unlock_fn(); + + return AR_EFAILED; + } + + *ret_node = list->dummy.next; + list->unlock_fn(); + return AR_EOK; +} + +GPR_EXTERNAL uint32_t gpr_list_init(gpr_list_t *list, + gpr_list_lock_enter_fn_t lock_fn, + gpr_list_lock_leave_fn_t unlock_fn) +{ + return gpr_list_init_internal(list, lock_fn, unlock_fn, TRUE); +} + +GPR_EXTERNAL uint32_t gpr_list_init_v2(gpr_list_t *list, + gpr_list_lock_enter_fn_t lock_fn, + gpr_list_lock_leave_fn_t unlock_fn) +{ + return gpr_list_init_internal(list, lock_fn, unlock_fn, FALSE); +} + +GPR_EXTERNAL uint32_t gpr_list_init_node(gpr_list_node_t *node) +{ + if (node == NULL) + { + return AR_EBADPARAM; + } + + node->list = NULL; + node->prev = node; + node->next = node; + + return AR_EOK; +} + +GPR_EXTERNAL uint32_t gpr_list_delete(gpr_list_t *list, gpr_list_node_t *node) +{ + if ((list == NULL) || (node == NULL)) + { + return AR_EBADPARAM; + } + + list->lock_fn(); + + gpr_list_raw_delete_node(node); + list->size -= 1; + + list->unlock_fn(); + + return AR_EOK; +} + +GPR_EXTERNAL uint32_t gpr_list_clear(gpr_list_t *list) +{ + gpr_list_node_t *node; + + if (list == NULL) + { + return AR_EBADPARAM; + } + + list->lock_fn(); + + while (gpr_list_raw_is_not_empty(list)) + { + node = list->dummy.next; + gpr_list_raw_delete_node(node); + } + + list->size = 0; + + list->unlock_fn(); + + return AR_EOK; +} diff --git a/gpr/core/src/gpr_list_i.h b/gpr/core/src/gpr_list_i.h new file mode 100644 index 0000000..945e334 --- /dev/null +++ b/gpr/core/src/gpr_list_i.h @@ -0,0 +1,33 @@ +#ifndef __GPR_LIST_I_H__ +#define __GPR_LIST_I_H__ + +/** + * \file gpr_list_i.h + * \brief + * This file contains GPR list internal APIs + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gpr_list.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +uint32_t gpr_list_raw_assert_node_is_linked(gpr_list_node_t *node); + +void gpr_list_raw_delete_node(gpr_list_node_t *node); + +uint32_t gpr_list_raw_insert_node_before(gpr_list_t *list, gpr_list_node_t *ref_node, gpr_list_node_t *new_node); + +uint32_t gpr_list_raw_assert_secure_node_is_unlinked(gpr_list_t *list, gpr_list_node_t *node); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_LIST_I_H__ */ diff --git a/gpr/core/src/gpr_list_island.c b/gpr/core/src/gpr_list_island.c new file mode 100644 index 0000000..7427688 --- /dev/null +++ b/gpr/core/src/gpr_list_island.c @@ -0,0 +1,150 @@ +/** + * \file gpr_list.c + * \brief + * This file contains GPR list island utils + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_list.h" +#include "gpr_list_i.h" + +/****************************************************************************** + * Functions * + *****************************************************************************/ + +/* Verify that the header of the de-linking node is linked to a linked list. + * This helps catch memory corruption issues, and programming errors where + * the same node was inserted twice (i.e. init_node(node1), + * insert(list1, node1), insert(list2, node1), error). + */ +// Enhancement: Crash for double free scenarios on SIM +uint32_t gpr_list_raw_assert_node_is_linked(gpr_list_node_t *node) +{ + if ((node->prev->next != node) || (node->next->prev != node)) + { + AR_MSG(DBG_ERROR_PRIO, "Detected a corruption in the node trying to be inserted into the list"); + return AR_EFAILED; + } + return AR_EOK; +} + +void gpr_list_raw_delete_node(gpr_list_node_t *node) +{ + gpr_list_raw_assert_node_is_linked(node); + /* Verify that the header of the unlinking node was not already corrupted. + * This helps catch buffer overflow attacks targeting the linked list */ + + node->prev->next = node->next; + node->next->prev = node->prev; + node->prev = node; + node->next = node; +} + +GPR_EXTERNAL uint32_t gpr_list_remove_head(gpr_list_t *list, gpr_list_node_t **ret_node) +{ + gpr_list_node_t *node; + + if (list == NULL) + { + return AR_EBADPARAM; + } + + list->lock_fn(); + + if (gpr_list_raw_is_empty(list)) + { + list->unlock_fn(); + + return AR_EFAILED; + } + + node = list->dummy.next; + gpr_list_raw_delete_node(node); + list->size -= 1; + + list->unlock_fn(); + + if (ret_node != NULL) + { + *ret_node = node; + } + + return AR_EOK; +} + +GPR_EXTERNAL bool_t gpr_list_raw_is_empty(gpr_list_t *list) +{ + return ((list == NULL) || (list->dummy.next == &list->dummy)); +} + +GPR_EXTERNAL uint32_t gpr_list_add_tail(gpr_list_t *list, gpr_list_node_t *node) +{ + uint32_t rc = AR_EOK; + + if ((list == NULL) || (node == NULL)) + { + return AR_EBADPARAM; + } + + list->lock_fn(); + + rc = gpr_list_raw_insert_node_before(list, &list->dummy, node); + + if (AR_EOK != rc) + { + list->unlock_fn(); + return rc; + } + + list->size += 1; + list->unlock_fn(); + + return AR_EOK; +} + +uint32_t gpr_list_raw_insert_node_before(gpr_list_t *list, gpr_list_node_t *ref_node, gpr_list_node_t *new_node) +{ + uint32_t rc = AR_EOK; + + rc = gpr_list_raw_assert_node_is_linked(ref_node); + if (rc != AR_EOK) + { + return rc; + } + + rc = gpr_list_raw_assert_secure_node_is_unlinked(list, new_node); + if (rc != AR_EOK) + { + return rc; + } + + new_node->list = list; + ref_node->prev->next = new_node; + new_node->prev = ref_node->prev; + new_node->next = ref_node; + ref_node->prev = new_node; + + return AR_EOK; +} + +/* Verify that the header of the linking node points to itself. This helps + * catch programming errors where the same node is inserted more than once on + * a linked list. + */ +// Enhancement: Crash for double free scenarios on SIM +uint32_t gpr_list_raw_assert_secure_node_is_unlinked(gpr_list_t *list, gpr_list_node_t *node) +{ + if ((list->en_secure) && ((node->next != node) || (node->prev != node))) + { + AR_MSG(DBG_ERROR_PRIO, "Detected same node was already inserted or is corrupted"); + return AR_EFAILED; + } + return AR_EOK; +} \ No newline at end of file diff --git a/gpr/core/src/gpr_main.c b/gpr/core/src/gpr_main.c new file mode 100644 index 0000000..cd9b1a3 --- /dev/null +++ b/gpr/core/src/gpr_main.c @@ -0,0 +1,115 @@ +/** + * \file gpr_main.c + * \brief + * This file contains GPR main implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ + +#include "ar_osal_error.h" +#include "ar_types.h" +#include "gpr_log.h" +#include "gpr_api_i.h" +#include "ar_msg.h" + +/***************************************************************************** + * Variables * + ****************************************************************************/ +bool_t gpr_init_flag = FALSE; +bool_t gpr_init_domain_flags[GPR_PL_NUM_TOTAL_DOMAINS_V] = {FALSE}; + +/***************************************************************************** + * Core Routine Implementations * + ****************************************************************************/ +GPR_EXTERNAL uint32_t gpr_init(void) +{ + uint32_t rc; + for (uint32_t i=0; ifree_q, lock_fn, unlock_fn); + block->base_addr = heap_base; + block->unit_size = unit_size; + block->metadata_size = metadata_size; + + while (heap_size >= unit_size) + { + (void)gpr_list_init_node((gpr_list_node_t *)heap_base); + + rc = gpr_list_add_tail(&block->free_q, ((gpr_list_node_t *)heap_base)); + if (AR_EOK != rc) + { + AR_MSG(DBG_ERROR_PRIO, "GPR memq: Adding node to free queue failed, init failed rc %d", rc); + return rc; + } + + heap_base += unit_size; + heap_size -= unit_size; + } + + block->total_units = block->free_q.size; + + /*populate heap info*/ + ar_heap_info heap_info; + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + gpr_populate_ar_heap_info(heap_index, AR_HEAP_ALIGN_8_BYTES, &heap_info); + + /* Allocate memory to be used for out-of-memory detection */ + block->unique_metadata_ids = + ((uint32_t *)ar_heap_malloc(block->total_units * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V, &heap_info)); + + if (block->unique_metadata_ids == NULL) + { + AR_MSG(DBG_ERROR_PRIO, "Cannot allocate memory for oom analysis"); + return AR_EFAILED; + } + + ar_mem_set(block->unique_metadata_ids, 0, (block->total_units * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V)); + + block->unique_metadata_counts = + ((uint32_t *)ar_heap_malloc(block->total_units * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V, &heap_info)); + if (block->unique_metadata_counts == NULL) + { + AR_MSG(DBG_ERROR_PRIO, "Cannot allocate memory for oom analysis"); + return AR_EFAILED; + } + + ar_mem_set(block->unique_metadata_counts, 0, (block->total_units * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V)); + + return AR_EOK; +} + +#ifndef DISABLE_DEINIT + +GPR_EXTERNAL void gpr_memq_deinit(gpr_memq_block_t *block, gpr_heap_index_t heap_index) +{ + /*populate heap info*/ + ar_heap_info heap_info; + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + gpr_populate_ar_heap_info(heap_index, AR_HEAP_ALIGN_8_BYTES, &heap_info); + + if (block == NULL) + { + AR_MSG(DBG_ERROR_PRIO, "block is NULL"); + return; + } + + if (block->free_q.size != block->total_units) + { + AR_MSG(DBG_ERROR_PRIO, "memory leak detected"); + } + + gpr_list_clear(&block->free_q); + + if (NULL != block->unique_metadata_ids) + { + ar_heap_free(block->unique_metadata_ids, &heap_info); + block->unique_metadata_ids = NULL; + } + + if (NULL != block->unique_metadata_counts) + { + ar_heap_free(block->unique_metadata_counts, &heap_info); + block->unique_metadata_counts = NULL; + } +} + +#endif \ No newline at end of file diff --git a/gpr/core/src/gpr_memq.h b/gpr/core/src/gpr_memq.h new file mode 100644 index 0000000..52fa93d --- /dev/null +++ b/gpr/core/src/gpr_memq.h @@ -0,0 +1,64 @@ +#ifndef __GPR_MEMQ_H__ +#define __GPR_MEMQ_H__ +/** + * \file gpr_memq.h + * \brief + * This file contains GPR mem queue APIs + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gpr_list.h" +#include "gpr_api.h" + +typedef void (*gpr_memq_lock_enter_fn_t)(void); +typedef void (*gpr_memq_lock_leave_fn_t)(void); + +/* Memory Queue Definitions */ + +typedef struct gpr_memq_block_t +{ + gpr_list_t free_q; + char_t *base_addr; + uint32_t total_units; + uint32_t unit_size; + uint32_t metadata_size; + uint32_t *unique_metadata_ids; + uint32_t *unique_metadata_counts; +} gpr_memq_block_t; + +typedef struct gpr_memq_entry_t +{ + gpr_list_node_t link; /* Must be first */ +} gpr_memq_entry_t; + +#define GPR_MEMQ_BYTES_PER_METADATA_ITEM_V (sizeof(int32_t)) +#define GPR_MEMQ_UNIT_OVERHEAD_V (sizeof(gpr_memq_entry_t)) + +/* Memory Queue Prototypes */ +GPR_EXTERNAL int gpr_memq_init(gpr_memq_block_t *block, + char_t *heap_base, + uint32_t heap_size, + uint32_t unit_size, + uint32_t metadata_size, + gpr_memq_lock_enter_fn_t lock_fn, + gpr_memq_lock_leave_fn_t unlock_fn, + gpr_heap_index_t heap_index); + +GPR_EXTERNAL void gpr_memq_deinit(gpr_memq_block_t *block, gpr_heap_index_t heap_index); + +GPR_EXTERNAL void *gpr_memq_alloc(gpr_memq_block_t *block); + +GPR_EXTERNAL void gpr_memq_free(gpr_memq_block_t *block, void *mem_ptr); + +GPR_EXTERNAL uint32_t gpr_memq_node_set_metadata(gpr_memq_block_t *block, void *mem_ptr, uint32_t index, int32_t value); + +GPR_EXTERNAL uint32_t gpr_memq_node_get_metadata(gpr_memq_block_t *block, + void *mem_ptr, + uint32_t index, + int32_t *metadata); + +#endif /* __GPR_MEMQ_H__ */ diff --git a/gpr/core/src/gpr_memq_island.c b/gpr/core/src/gpr_memq_island.c new file mode 100644 index 0000000..ca2329a --- /dev/null +++ b/gpr/core/src/gpr_memq_island.c @@ -0,0 +1,132 @@ +/** + * \file gpr_memq.c + * \brief + * This file contains GPR memq implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_msg_if.h" +#include "gpr_memq.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_heap.h" + +/****************************************************************************** + * Functions * + *****************************************************************************/ + +uint32_t gpr_memq_is_metadata_unique(gpr_memq_block_t *block, uint32_t total_unique_mds, int32_t metadata) +{ + uint32_t md_index; + + for (md_index = 0; md_index < total_unique_mds; md_index++) + { + if (block->unique_metadata_ids[md_index] == (uint32_t)metadata) + { + block->unique_metadata_counts[md_index]++; + return 0; + } + } + return 1; +} + +/* Helper Functions */ +uint32_t gpr_memq_size_of_metadata_and_overhead(gpr_memq_block_t *block) +{ + return ((GPR_MEMQ_BYTES_PER_METADATA_ITEM_V * block->metadata_size) + GPR_MEMQ_UNIT_OVERHEAD_V); +} + +GPR_EXTERNAL uint32_t gpr_memq_node_set_metadata(gpr_memq_block_t *block, void *mem_ptr, uint32_t index, int32_t value) +{ + int32_t *metadata; + if (index >= block->metadata_size) + { + return AR_EBADPARAM; + } + metadata = + ((int32_t *)(((char_t *)mem_ptr) - ((block->metadata_size - index) * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V))); + + *metadata = value; + return AR_EOK; +} + +GPR_EXTERNAL uint32_t gpr_memq_node_get_metadata(gpr_memq_block_t *block, + void *mem_ptr, + uint32_t index, + int32_t *metadata) +{ + if (index >= block->metadata_size) + { + return AR_EBADPARAM; + } + *metadata = + *((int32_t *)(((char_t *)mem_ptr) - ((block->metadata_size - index) * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V))); + + return AR_EOK; +} + +GPR_EXTERNAL void *gpr_memq_alloc(gpr_memq_block_t *block) +{ + gpr_list_node_t *node; + char_t *mem_ptr; + uint32_t md_interator; + uint32_t md_index; + int32_t metadata = 0; + uint32_t total_unique_mds = 0; + + if (gpr_list_remove_head(&block->free_q, &node) == AR_EOK) + { + return (((char_t *)node) + gpr_memq_size_of_metadata_and_overhead(block)); + } + + AR_MSG(DBG_ERROR_PRIO, "Out of memory failure"); + + ar_mem_set(block->unique_metadata_ids, 0xFF, block->total_units * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V); + ar_mem_set(block->unique_metadata_counts, 0, block->total_units * GPR_MEMQ_BYTES_PER_METADATA_ITEM_V); + mem_ptr = block->base_addr + gpr_memq_size_of_metadata_and_overhead(block); + + for (md_interator = 0; md_interator < block->total_units; md_interator++) + { + gpr_memq_node_get_metadata(block, mem_ptr, 0, &metadata); + mem_ptr = mem_ptr + block->unit_size; + if (gpr_memq_is_metadata_unique(block, total_unique_mds, metadata)) + { + block->unique_metadata_ids[total_unique_mds] = metadata; + block->unique_metadata_counts[total_unique_mds] = 1; + total_unique_mds++; + } + } + + for (md_index = 0; md_index < total_unique_mds; md_index++) + { + AR_MSG(DBG_ERROR_PRIO, + "Out of GPR packets: Module with Instance ID: %lx holding number of gpr packets: %lu", + block->unique_metadata_ids[md_index], + block->unique_metadata_counts[md_index]); + } + return NULL; +} + +GPR_EXTERNAL void gpr_memq_free(gpr_memq_block_t *block, void *data_ptr) +{ + uint32_t rc = AR_EOK; + gpr_list_node_t *node; + + if ((block == NULL) || (data_ptr == NULL)) + { + AR_MSG(DBG_ERROR_PRIO, "GPR memq: block is NULL or data ptr is NULL"); + return; + } + node = ((gpr_list_node_t *)(((char_t *)data_ptr) - gpr_memq_size_of_metadata_and_overhead(block))); + rc = gpr_list_add_tail(&block->free_q, node); + if (AR_EOK != rc) + { + AR_MSG(DBG_ERROR_PRIO, "GPR memq: Cannot free packet, packet is corrupted or already freed rc %d", rc); + } +} diff --git a/gpr/core/src/hash_based/gpr_session.c b/gpr/core/src/hash_based/gpr_session.c new file mode 100644 index 0000000..f289266 --- /dev/null +++ b/gpr/core/src/hash_based/gpr_session.c @@ -0,0 +1,175 @@ +/** + * \file gpr_session.c + * \brief + * This file contains GPR session implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ + +#include "gpr_session.h" +#include "gpr_heap_i.h" + +/** + @brief Allocates memory and returns a pointer to a session + (contains callback function, callback argument) for a given + src_port + + @param[in] src_port Address/port of src module trying to register + @param[out] ret_entry Double pointer to the session created + + @detdesc + Allocates a new node in the linked list for each src port. Each node + represents a session which points to a callback function and corresponding + callback argument which will be populated by the caller of this function. + This is how a module registers to the GPR service. + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_init_session(uint32_t src_port, + gpr_module_entry_t **ret_entry, + gpr_module_node_list_t *list_handle) +{ + if (NULL == list_handle) + { + return AR_EFAILED; + } + + uint32_t hash_key; + + ar_heap_info heap_info; + gpr_heap_index_t heap_index = list_handle->heap_index; + gpr_populate_ar_heap_info(heap_index, AR_HEAP_ALIGN_8_BYTES, &heap_info); + + gpr_module_node_t *new_node = (gpr_module_node_t *)ar_heap_malloc(sizeof(gpr_module_node_t), &heap_info); + if (NULL == new_node) + { + AR_MSG(DBG_ERROR_PRIO, + "Error: Failed to allocate gpr module node of size %d port 0x%lx heap index %lu", + sizeof(gpr_module_node_t), + src_port, + heap_index); + return AR_ENOMEMORY; + } + + gpr_module_node_t **chain = &list_handle->cb_list[0]; + + // Calculate the hash index.. + uint32_t MAX_LIST_SIZE = list_handle->max_cb_list_size; + hash_key = SESSION_HASH(MAX_LIST_SIZE, src_port); + + // Check if the hashed index is empty. + if (chain[hash_key] == NULL) + { + chain[hash_key] = new_node; + } + // collision + else + { + // add the node at the end of chain[hash_key]. + gpr_module_node_t *temp = chain[hash_key]; + + if (temp->my_module_port == src_port) + { + AR_MSG(DBG_ERROR_PRIO, "Error: Trying to register with source port %lu again, failing", src_port); + ar_heap_free(new_node, &heap_info); + return AR_EFAILED; + } + + while (temp->next != NULL) + { + // Check for duplicate registration + if (temp->next->my_module_port == src_port) + { + AR_MSG(DBG_ERROR_PRIO, "Error: Trying to register with source port %lu again, failing", src_port); + ar_heap_free(new_node, &heap_info); + return AR_EFAILED; + } + temp = temp->next; + } + temp->next = new_node; + } + + // Fill up the new node + new_node->my_module_port = src_port; + new_node->next = NULL; + + *ret_entry = &new_node->session; + return AR_EOK; +} + +/** + @brief De-allocates session memory for a given src_port + + @param[in] src_port Address/port of src module trying to de-register + + @detdesc + De-allocates a node in the linked list for a given src_port. + Make sure not to delet other nodes in the linked list. + This is how a local module registers to the GPR service. + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_deinit_session(uint32_t src_port, gpr_module_node_list_t *list_handle) +{ + if (NULL == list_handle) + { + return AR_EFAILED; + } + + gpr_heap_index_t heap_index = list_handle->heap_index; + gpr_module_node_t **chain = &list_handle->cb_list[0]; + + uint32_t MAX_CB_LIST_SIZE = list_handle->max_cb_list_size; + uint32_t hash_key = SESSION_HASH(MAX_CB_LIST_SIZE, src_port); + gpr_module_node_t *temp = chain[hash_key], *dealloc; + + ar_heap_info heap_info; + gpr_populate_ar_heap_info(heap_index, AR_HEAP_ALIGN_8_BYTES, &heap_info); + + if (temp != NULL) + { + if ((temp->my_module_port == src_port) & (temp->next == NULL)) // when there are no other nodes linked + { + dealloc = temp; + chain[hash_key] = NULL; + ar_heap_free(dealloc, &heap_info); + return AR_EOK; + } + else + { + if (temp->my_module_port == src_port) // If this is a first node and other nodes are linked to it + { + dealloc = temp->next; + ar_heap_free(temp, &heap_info); + chain[hash_key] = dealloc; + return AR_EOK; + } + else // not the first node and other nodes are linked to it.. + { + while (temp->next != NULL) + { + if (temp->next->my_module_port == src_port) // If this is a first node and other nodes are linked to it + { + dealloc = temp->next->next; + ar_heap_free(temp->next, &heap_info); + temp->next = dealloc; + return AR_EOK; + } + temp = temp->next; + } + } + } + } + + AR_MSG(DBG_HIGH_PRIO, "No such module port (%lu) found to deinit", src_port); + return AR_ENOTEXIST; // NOT exists +} diff --git a/gpr/core/src/hash_based/gpr_session_island.c b/gpr/core/src/hash_based/gpr_session_island.c new file mode 100644 index 0000000..ac67ef2 --- /dev/null +++ b/gpr/core/src/hash_based/gpr_session_island.c @@ -0,0 +1,58 @@ +/** + * \file gpr_session.c + * \brief + * This file contains GPR session implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ + +#include "gpr_session.h" + +/** + @brief Searches for callback function based on src port + + @param[in] my_port Address/port of module + @param[out] ret_entry Double pointer to the session found + + @detdesc + Searches the linked list until node matching + given src_port is found and returns pointer to the corresponding session + + @return + #AR_EOK when successful. +*/ +GPR_INTERNAL uint32_t gpr_get_session(uint32_t my_port, + gpr_module_entry_t **ret_entry, + gpr_module_node_list_t *list_handle) +{ + if (NULL == list_handle) + { + return AR_EFAILED; + } + gpr_module_node_t **chain = &list_handle->cb_list[0]; // Initialize current + uint32_t key = SESSION_HASH(list_handle->max_cb_list_size, my_port); + + gpr_module_node_t *temp = chain[key]; + + while (temp != NULL) + { + if (temp->my_module_port == my_port) // directly hashed slot finding + { + *ret_entry = &temp->session; + return AR_EOK; + } + temp = temp->next; // if it is open hashed slots + } + +#ifdef GPR_DEBUG_MSG + AR_MSG(DBG_ERROR_PRIO, "No such module port (%lu) found in linked list", my_port); +#endif + return AR_ENOTEXIST; +} \ No newline at end of file diff --git a/gpr/datalinks/gpr_lx/inc/gpr_lx.h b/gpr/datalinks/gpr_lx/inc/gpr_lx.h new file mode 100644 index 0000000..209a486 --- /dev/null +++ b/gpr/datalinks/gpr_lx/inc/gpr_lx.h @@ -0,0 +1,23 @@ +/* + * gpr_lx.h + * +:wq * This file has implementation platform wrapper for the GPR datalink layer + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gpr_comdef.h" +#include "ipc_dl_api.h" + +/****************************************************************************** + * Defines * + *****************************************************************************/ +/*IPC datalink init function called from gpr layer for glink*/ +GPR_INTERNAL uint32_t ipc_dl_lx_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl); + +/*IPC datalink de-init function called from gpr layer for glink*/ +GPR_INTERNAL uint32_t ipc_dl_lx_deinit (uint32_t src_domain_id, uint32_t dest_domain_id); diff --git a/gpr/datalinks/gpr_lx/inc/list.h b/gpr/datalinks/gpr_lx/inc/list.h new file mode 100644 index 0000000..4f6eaa6 --- /dev/null +++ b/gpr/datalinks/gpr_lx/inc/list.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008-2013 The Android Open Source Project + * + * 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. + + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause +*/ + +#ifndef _CUTILS_LIST_H_ +#define _CUTILS_LIST_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct listnode +{ + struct listnode *next; + struct listnode *prev; +}; + +#define node_to_item(node, container, member) \ + (container *) (((char*) (node)) - offsetof(container, member)) + +#define list_declare(name) \ + struct listnode name = { \ + .next = &name, \ + .prev = &name, \ + } + +#define list_for_each(node, list) \ + for (node = (list)->next; node != (list); node = node->next) + +#define list_for_each_reverse(node, list) \ + for (node = (list)->prev; node != (list); node = node->prev) + +#define list_for_each_safe(node, n, list) \ + for (node = (list)->next, n = node->next; \ + node != (list); \ + node = n, n = node->next) + +static inline void list_init(struct listnode *node) +{ + node->next = node; + node->prev = node; +} + +static inline void list_add_tail(struct listnode *head, struct listnode *item) +{ + item->next = head; + item->prev = head->prev; + head->prev->next = item; + head->prev = item; +} + +static inline void list_add_head(struct listnode *head, struct listnode *item) +{ + item->next = head->next; + item->prev = head; + head->next->prev = item; + head->next = item; +} + +static inline void list_remove(struct listnode *item) +{ + item->next->prev = item->prev; + item->prev->next = item->next; +} + +#define list_empty(list) ((list) == (list)->next) +#define list_head(list) ((list)->next) +#define list_tail(list) ((list)->prev) + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif diff --git a/gpr/datalinks/gpr_lx/src/gpr_lx.c b/gpr/datalinks/gpr_lx/src/gpr_lx.c new file mode 100644 index 0000000..44b4532 --- /dev/null +++ b/gpr/datalinks/gpr_lx/src/gpr_lx.c @@ -0,0 +1,480 @@ +/* + * gpr_lx.c + * + * This file has implementation platform wrapper for the GPR datalink layer + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#define LOG_TAG "gpr_dl_lx" + +#include +#include +#include +#include +#include +#include +#include "ar_osal_log.h" + +#ifdef GPR_USE_CUTILS +#include +#include +#else +#include "list.h" +#include "poll.h" +#endif + +#include +#include "gpr_comdef.h" +#include "ipc_dl_api.h" +#include "gpr_ids_domains.h" +#include "ar_osal_error.h" + +#define GPR_DL_LX_ADSP_DRV "/dev/aud_pasthru_adsp" +#define GPR_DL_LX_CC_DSP_DRV "/dev/gpr_channel" +#define GPR_DL_LX_MODEM_DRV "/dev/aud_pasthru_modem" +#define GPR_DL_LX_APPS_SPF_DRV "/dev/aud_pasthru_apps" +#define GPR_DL_LX_BUF_SIZE 4096 /*bytes*/ +#define GPR_DL_LX_NO_OF_BUFFERS 8 + +/** Data receive notification callback type*/ +typedef uint32_t (*gpr_dl_lx_receive_cb)(void *ptr, uint32_t length); + +/** Data send done notification callback type*/ +typedef uint32_t (*gpr_dl_lx_send_done_cb)(void *ptr, uint32_t length); + +typedef struct gpr_dl_lx_buf{ + struct listnode node; + void *buffer; +}gpr_dl_lx_buf_t; + +typedef struct gpr_dl_lx_port{ + uint32_t domain_id; + pthread_t receiver_thread; + bool thread_exit; + gpr_dl_lx_receive_cb rx_cb; + gpr_dl_lx_send_done_cb send_done; + int drv_fd; + int intpipe[2]; + struct listnode buff_list; + pthread_mutex_t buff_list_lock; + int buf_cnt; +} gpr_dl_lx_port_t; + +/*Array of structure pointers each member pointer corresponds to one domain*/ +gpr_dl_lx_port_t *gpr_dl_lx_ports[GPR_PL_NUM_TOTAL_DOMAINS_V]={NULL}; + +static uint32_t gpr_dl_lx_send(uint32_t domain_id, void *buf, uint32_t size); + +static uint32_t gpr_dl_lx_receive_done(uint32_t domain_id, void *buf); + +/*ipc datalink function table*/ +static ipc_to_gpr_vtbl_t gpr_dl_lx_vtbl = +{ + gpr_dl_lx_send, + gpr_dl_lx_receive_done, +}; + +void deallocate_buffers(gpr_dl_lx_port_t *dl_lx_port) +{ + gpr_dl_lx_buf_t *buffer_node = NULL; + struct listnode *item = NULL; + + pthread_mutex_lock(&dl_lx_port->buff_list_lock); + while (!list_empty(&dl_lx_port->buff_list)) { + item = list_head(&dl_lx_port->buff_list); + list_remove(item); + buffer_node = node_to_item(item, gpr_dl_lx_buf_t, node); + if (buffer_node->buffer) + free(buffer_node->buffer); + free(buffer_node); + buffer_node = NULL; + } + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); +} + +uint32_t allocate_buffers(gpr_dl_lx_port_t *dl_lx_port, + size_t buf_sz, size_t no_of_buffers) +{ + uint32_t status; + unsigned int i; + + pthread_mutex_lock(&dl_lx_port->buff_list_lock); + list_init(&dl_lx_port->buff_list); + + for (i = 0; i < no_of_buffers; i++) { + + gpr_dl_lx_buf_t *buffer_node = + (gpr_dl_lx_buf_t *)malloc(sizeof(gpr_dl_lx_buf_t)); + if (buffer_node == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d malloc failed", __func__, __LINE__); + status = AR_ENOMEMORY; + goto error; + } + + buffer_node->buffer = calloc(buf_sz, sizeof(int8_t)); + if (buffer_node->buffer == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d malloc for buf failed", __func__, __LINE__); + free (buffer_node); + status = AR_ENOMEMORY; + goto error; + } + list_add_tail(&dl_lx_port->buff_list, &buffer_node->node); + dl_lx_port->buf_cnt++; + } + AR_LOG_VERBOSE(LOG_TAG,"%s:%d buf_cnt = %d", __func__, __LINE__, dl_lx_port->buf_cnt); + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); + return AR_EOK; +error: + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); + deallocate_buffers(dl_lx_port); + return status; +} + +uint32_t get_buffer(gpr_dl_lx_port_t *dl_lx_port, void **buf) +{ + gpr_dl_lx_buf_t *buffer_node; + struct listnode *item; + pthread_mutex_lock(&dl_lx_port->buff_list_lock); + if (list_empty(&dl_lx_port->buff_list)) { + AR_LOG_ERR(LOG_TAG,"%s:%d No free buffers available", __func__, __LINE__); + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); + return AR_ENORESOURCE; + } + item = list_head(&dl_lx_port->buff_list); + if (item != NULL) { + list_remove(item); + buffer_node = node_to_item(item, gpr_dl_lx_buf_t, node); + if (buffer_node->buffer) { + *buf = buffer_node->buffer; + free(buffer_node); + } else { + AR_LOG_ERR(LOG_TAG,"%s:%d buffer node invalid", __func__, __LINE__); + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); + return AR_ENOTEXIST; + } + AR_LOG_VERBOSE(LOG_TAG,"%s:%d buf_cnt = %d", __func__, __LINE__, --dl_lx_port->buf_cnt); + } + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); + return AR_EOK; +} + +uint32_t put_buffer(gpr_dl_lx_port_t *dl_lx_port, void *buf) +{ + gpr_dl_lx_buf_t *buffer_node = NULL; + struct listnode *item = NULL; + struct listnode *temp_node = NULL; + + pthread_mutex_lock(&dl_lx_port->buff_list_lock); + list_for_each_safe(item, temp_node, &dl_lx_port->buff_list) { + buffer_node = node_to_item(item, gpr_dl_lx_buf_t, node); + if (buffer_node && buffer_node->buffer == buf) { + AR_LOG_ERR(LOG_TAG,"%s:%d buffer already put error case", __func__, __LINE__); + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); + return AR_EALREADY; + } + } + buffer_node = (gpr_dl_lx_buf_t *)malloc(sizeof(gpr_dl_lx_buf_t)); + if (buffer_node == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d malloc failed", __func__, __LINE__); + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); + return AR_ENOMEMORY; + } + buffer_node->buffer = buf; + list_add_tail(&dl_lx_port->buff_list, &buffer_node->node); + AR_LOG_VERBOSE(LOG_TAG,"%s:%d buf_cnt = %d", __func__, __LINE__, ++dl_lx_port->buf_cnt); + pthread_mutex_unlock(&dl_lx_port->buff_list_lock); + return AR_EOK; +} + +#define NUM_FDS 2 + +void *receiver_thread_loop(void *priv_data) +{ + uint32_t status; + int32_t receive_size; + void *buf; + uint32_t *temp; + gpr_dl_lx_port_t *dl_lx_port = (gpr_dl_lx_port_t *)priv_data; + struct pollfd *pfd; + if (dl_lx_port == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d invalid port instance", __func__, __LINE__); + return NULL; + } + pfd = (struct pollfd *)calloc(NUM_FDS, sizeof(struct pollfd)); + if (pfd == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d calloc failed for poll fd", __func__, __LINE__); + return NULL; + } + if (dl_lx_port->drv_fd) { + pfd[0].fd = dl_lx_port->drv_fd; + pfd[0].events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL; + pfd[1].fd = dl_lx_port->intpipe[0]; + pfd[1].events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL; + } else { + AR_LOG_ERR(LOG_TAG,"%s:%d invalid driver inst exit resp thread", __func__, __LINE__); + return NULL; + } + + while (1) { + if (dl_lx_port->thread_exit) { + AR_LOG_DEBUG(LOG_TAG,"%s:%d exiting receiver thread", __func__, __LINE__); + break; + } + + /*Implement poll related functionality here*/ + if (poll(pfd, NUM_FDS, -1) < 0) { + /*Poll errored out, treat it as a fatal error bail out*/ + int error = errno; + /** + * Continue polling if poll error is EINTR + */ + if (error == EINTR) { + AR_LOG_INFO(LOG_TAG,"%s:%d Poll interrupted due to EINTR", __func__, __LINE__); + continue; + } + + AR_LOG_ERR(LOG_TAG,"Poll failed error %s", strerror(error)); + break; + } + + AR_LOG_DEBUG(LOG_TAG,"Out of poll"); + if (pfd[0].revents & (POLLIN|POLLPRI)) { + /* + * Get a buffer from buffer queue, it is a finite queue + * So if the client holds the received buffers for long + * we would run out of buffers. + */ + status = get_buffer(dl_lx_port, &buf); + if (status != 0) { + AR_LOG_ERR(LOG_TAG,"%s:%d get_buffer failed", __func__, __LINE__); + /*Shall we break out or continue ?*/ + continue; + } + memset(buf, 0 , GPR_DL_LX_BUF_SIZE); + receive_size = read(dl_lx_port->drv_fd, buf, GPR_DL_LX_BUF_SIZE); + temp = (uint32_t *) buf; + AR_LOG_DEBUG(LOG_TAG,"recieved buffer %x %x %x %x size %d", temp[0], temp[1], temp[2], temp[3], receive_size); + if ((receive_size <= 0) || (receive_size > GPR_DL_LX_BUF_SIZE)) { + AR_LOG_ERR(LOG_TAG,"%s:%d read failed %d", __func__, __LINE__, errno); + put_buffer(dl_lx_port, buf); + } else { + if (dl_lx_port->rx_cb) { + status = dl_lx_port->rx_cb(buf, receive_size); + if (status != AR_EOK) { + AR_LOG_ERR(LOG_TAG,"%s:%d receive callback failed", __func__, __LINE__); + continue; + } + } + } + } else if (pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)) { + /* + *We should hit this case when we are trying to exit + *dl layer will close the driver, which inturn should + *unblock poll with an error mask; + */ + AR_LOG_INFO(LOG_TAG,"%s:%d Poll errored", __func__, __LINE__); + continue; + } else if (pfd[1].revents & (POLLIN|POLLPRI)) { + AR_LOG_ERR(LOG_TAG,"%s:%d unexpected poll!", __func__, __LINE__); + break; + } + } + return NULL; +} + + +static gpr_dl_lx_port_t * gpr_dl_lx_local_init(uint32_t src_domain_id, uint32_t dst_domain_id) +{ + gpr_dl_lx_port_t *dl_lx_port; + uint32_t status = 0; + char *drv_name = NULL; + pthread_attr_t tattr; + struct sched_param param = { .sched_priority = 3 }; + + if ((dst_domain_id < 0) || (dst_domain_id >= GPR_PL_NUM_TOTAL_DOMAINS_V) + || (src_domain_id < 0) || (src_domain_id >= GPR_PL_NUM_TOTAL_DOMAINS_V)) { + AR_LOG_ERR(LOG_TAG,"%s:%d invalid domain(src domain id %d, dst domain id %d)", + __func__, __LINE__, src_domain_id, dst_domain_id); + return NULL; + } + + AR_LOG_INFO(LOG_TAG,"%s:%d port setup for src domain id %d and dst domain id %d", + __func__, __LINE__, src_domain_id, dst_domain_id); + + if (gpr_dl_lx_ports[dst_domain_id] != NULL){ + AR_LOG_ERR(LOG_TAG,"%s:%d port already setup for domain id:%d", __func__, __LINE__, + dst_domain_id); + return gpr_dl_lx_ports[dst_domain_id]; + } + dl_lx_port = (gpr_dl_lx_port_t *)calloc(1, sizeof(gpr_dl_lx_port_t)); + if (dl_lx_port == NULL){ + AR_LOG_ERR(LOG_TAG,"%s:%d malloc failed", __func__, __LINE__); + return NULL; + } + dl_lx_port->domain_id = dst_domain_id; + dl_lx_port->thread_exit = false; + + if (dst_domain_id == GPR_IDS_DOMAIN_ID_ADSP_V) { + if (src_domain_id == GPR_IDS_DOMAIN_ID_APPS2_V) { + drv_name = GPR_DL_LX_APPS_SPF_DRV; + dl_lx_port->drv_fd = open(drv_name, O_RDWR); + AR_LOG_INFO(LOG_TAG,"%s:%d open drv_name:%s, drv_fd:%d", __func__, __LINE__, drv_name, dl_lx_port->drv_fd); + } else { + drv_name = GPR_DL_LX_ADSP_DRV; + dl_lx_port->drv_fd = open(drv_name, O_RDWR); + } + } else if (dst_domain_id == GPR_IDS_DOMAIN_ID_MODEM_V) { + drv_name = GPR_DL_LX_MODEM_DRV; + dl_lx_port->drv_fd = open(drv_name, O_RDWR); + } else if (dst_domain_id == GPR_IDS_DOMAIN_ID_CC_DSP_V) { + drv_name = GPR_DL_LX_CC_DSP_DRV; + dl_lx_port->drv_fd = open(drv_name, O_RDWR); + } else if (dst_domain_id == GPR_IDS_DOMAIN_ID_APPS2_V) { + drv_name = GPR_DL_LX_APPS_SPF_DRV; + dl_lx_port->drv_fd = open(drv_name, O_RDWR); + } else { + dl_lx_port->drv_fd = -1; + } + + if ((dl_lx_port->drv_fd < 0) || (pipe(dl_lx_port->intpipe) < 0) ) { + AR_LOG_ERR(LOG_TAG,"%s:%d driver open failed %d for %s", __func__, __LINE__, errno, drv_name); + free(dl_lx_port); + return NULL; + } + + pthread_mutex_init(&dl_lx_port->buff_list_lock, + (const pthread_mutexattr_t *) NULL); + + status = allocate_buffers(dl_lx_port, GPR_DL_LX_BUF_SIZE, + GPR_DL_LX_NO_OF_BUFFERS); + if (status) { + AR_LOG_ERR(LOG_TAG,"%s:%d buffer allocation failed", __func__, __LINE__); + free(dl_lx_port); + return NULL; + } + pthread_attr_init (&tattr); + pthread_attr_setschedparam (&tattr, ¶m); + pthread_attr_setschedpolicy(&tattr, SCHED_FIFO); + status = pthread_create(&dl_lx_port->receiver_thread, &tattr, + receiver_thread_loop, dl_lx_port); + if (status) { + AR_LOG_ERR(LOG_TAG,"%s:%d error:%d pthread_create fail", __func__, __LINE__, status); + free(dl_lx_port); + return NULL; + } + pthread_setname_np(dl_lx_port->receiver_thread, "gpr_receiver_thread"); + return dl_lx_port; +} + + +static uint32_t gpr_dl_lx_local_deinit(uint32_t src_domain_id, uint32_t dst_domain_id) +{ + uint32_t status = AR_EOK; + gpr_dl_lx_port_t *dl_lx_port; + + if (gpr_dl_lx_ports[dst_domain_id] == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d deinit already done", __func__, __LINE__); + return AR_EOK; + } + dl_lx_port = gpr_dl_lx_ports[dst_domain_id]; + gpr_dl_lx_ports[dst_domain_id] = NULL; + /* + * Set thread exit to true and then close the driver instance + * this should unblock the poll and then we do a pthread_join + * to ensure that the receiver_thread has exited. + */ + dl_lx_port->thread_exit = true; + status = write(dl_lx_port->intpipe[1], "Q", 1); + if(status < 0) { + /* proceed regardless with a error print */ + AR_LOG_ERR(LOG_TAG,"%s:%d write to driver failed %d", __func__, __LINE__, errno); + } + + status = pthread_join(dl_lx_port->receiver_thread, NULL); + if (status < 0){ + AR_LOG_ERR(LOG_TAG,"%s:%d pthread_join failed", __func__, __LINE__); + } + close(dl_lx_port->drv_fd); + dl_lx_port->drv_fd = 0; + free(dl_lx_port); + return status; +} + +uint32_t ipc_dl_lx_init(uint32_t src_domain_id, + uint32_t dest_domain_id, + const gpr_to_ipc_vtbl_t *p_gpr_to_ipc_vtbl, + ipc_to_gpr_vtbl_t ** pp_ipc_to_gpr_vtbl) +{ + gpr_dl_lx_port_t *dl_lx_port; + + if ((dest_domain_id < 0) || (dest_domain_id >= GPR_PL_NUM_TOTAL_DOMAINS_V) + || (src_domain_id < 0) || (src_domain_id >= GPR_PL_NUM_TOTAL_DOMAINS_V)) { + AR_LOG_ERR(LOG_TAG,"%s:%d invalid domain(src domain id %d, dst domain id %d)", + __func__, __LINE__, src_domain_id, dest_domain_id); + return AR_EBADPARAM; + } + + dl_lx_port = gpr_dl_lx_local_init(src_domain_id, dest_domain_id); + if (dl_lx_port == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d local_init failed", __func__, __LINE__); + return AR_EFAILED; + } + *pp_ipc_to_gpr_vtbl = &gpr_dl_lx_vtbl; + if (p_gpr_to_ipc_vtbl->receive && p_gpr_to_ipc_vtbl->send_done) { + dl_lx_port->rx_cb = p_gpr_to_ipc_vtbl->receive; + dl_lx_port->send_done = p_gpr_to_ipc_vtbl->send_done; + } else { + AR_LOG_ERR(LOG_TAG,"%s:%d no gpr cbs error out", __func__, __LINE__); + return AR_EBADPARAM; + } + gpr_dl_lx_ports[dest_domain_id] = dl_lx_port; + + return AR_EOK; +} + +uint32_t ipc_dl_lx_deinit(uint32_t src_domain_id, uint32_t dest_domain_id) +{ + uint32_t status = AR_EOK; + + status = gpr_dl_lx_local_deinit(src_domain_id, dest_domain_id); + return status; +} + +static uint32_t gpr_dl_lx_send(uint32_t domain_id, void *buf, uint32_t size) +{ + int32_t status; + gpr_dl_lx_port_t *dl_lx_port; + + if ((dl_lx_port = gpr_dl_lx_ports[domain_id]) == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d port domain %d not initialized", __func__, __LINE__, + domain_id); + return AR_ENOTEXIST; + } + AR_LOG_DEBUG(LOG_TAG,"%s:Sending buffer of size %d to driver",__func__, size); + status = write(dl_lx_port->drv_fd, buf, size); + if (status < 0) { + AR_LOG_ERR(LOG_TAG,"%s:%d write to driver failed %d", __func__, __LINE__, errno); + if (errno == ENETRESET) + return AR_ESUBSYSRESET; + else + return AR_EFAILED; + } + dl_lx_port->send_done(buf, size); + AR_LOG_DEBUG(LOG_TAG,"%s:Send done",__func__); + return AR_EOK; +} + +static uint32_t gpr_dl_lx_receive_done(uint32_t domain_id, void *buf) +{ + uint32_t status; + gpr_dl_lx_port_t *dl_lx_port; + + if ((dl_lx_port = gpr_dl_lx_ports[domain_id]) == NULL) { + AR_LOG_ERR(LOG_TAG,"%s:%d port domain %d not initialized", __func__, __LINE__, + domain_id); + return AR_ENOTEXIST; + } + status = put_buffer(dl_lx_port, buf); + return status; +} diff --git a/gpr/ext/dynamic_allocation/inc/gpr_dynamic_allocation.h b/gpr/ext/dynamic_allocation/inc/gpr_dynamic_allocation.h new file mode 100644 index 0000000..8e9f9f9 --- /dev/null +++ b/gpr/ext/dynamic_allocation/inc/gpr_dynamic_allocation.h @@ -0,0 +1,34 @@ +#ifndef __GPR_DYN_ALLOCATION_H__ +#define __GPR_DYN_ALLOCATION_H__ + +/** + * \file gpr_dynamic_allocation.h + * \brief + * This file contains APIs to allocate GPR packets dynamically. + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gpr_packet.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +GPR_INTERNAL uint32_t gpr_allocate_dynamic_packet(gpr_packet_t **packet, + uint32_t size); + +GPR_INTERNAL uint32_t gpr_check_and_free_dynamic_packet(gpr_packet_t *packet); + +GPR_INTERNAL uint32_t gpr_dynamic_packet_init(void); + +GPR_INTERNAL uint32_t gpr_dynamic_packet_deinit(void); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_DYN_ALLOCATION_H__ */ \ No newline at end of file diff --git a/gpr/ext/dynamic_allocation/src/gpr_dynamic_allocation.c b/gpr/ext/dynamic_allocation/src/gpr_dynamic_allocation.c new file mode 100644 index 0000000..3e4c7d5 --- /dev/null +++ b/gpr/ext/dynamic_allocation/src/gpr_dynamic_allocation.c @@ -0,0 +1,182 @@ +/** + * \file gpr_dynamic_allocation.c + * \brief + * This file contains implementation for dynamic packet allocation. + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "gpr_dynamic_allocation.h" +#include "gpr_list.h" +#include "ar_osal_mutex.h" +#include "ar_osal_error.h" +#include "ar_osal_heap.h" +#include "ar_osal_mem_op.h" + +/***************************************************************************** + * Structure definitions * + ****************************************************************************/ +typedef struct gpr_dynamic_packet +{ + gpr_list_node_t node; + gpr_packet_t * packet; +} gpr_dynamic_packet_t; + +gpr_list_t dynamic_packet_list; +ar_osal_mutex_t gpr_dyn_packet_list_lock; +static bool_t gpr_dynamic_packet_init_done = FALSE; + +/***************************************************************************** + * Helper functions * + ****************************************************************************/ +static void gpr_dyn_packet_lock_fn(void) +{ + (void)ar_osal_mutex_lock(gpr_dyn_packet_list_lock); +} + +static void gpr_dyn_packet_unlock_fn(void) +{ + (void)ar_osal_mutex_unlock(gpr_dyn_packet_list_lock); +} + +static void gpr_free_dynamic_packet_raw(gpr_dynamic_packet_t *dynamic_packet) +{ + ar_heap_info heap_info; + + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + heap_info.tag = AR_HEAP_TAG_DEFAULT; + heap_info.align_bytes = AR_HEAP_ALIGN_8_BYTES; + + ar_heap_free((void *)(dynamic_packet->packet), &heap_info); + dynamic_packet->packet = NULL; + ar_heap_free((void *)dynamic_packet, &heap_info); + dynamic_packet = NULL; + return; +} + +static void gpr_free_dynamic_packet_list(void) +{ + gpr_list_node_t * node = NULL; + + while (!gpr_list_raw_is_empty(&dynamic_packet_list)) + { + gpr_list_remove_head(&dynamic_packet_list, &node); + gpr_free_dynamic_packet_raw((gpr_dynamic_packet_t *)((void *)node)); + } +} + +static gpr_dynamic_packet_t *gpr_get_dynamic_packet(gpr_packet_t *packet) +{ + gpr_list_node_t * node = NULL; + gpr_list_node_t * head = NULL; + gpr_dynamic_packet_t *dynamic_packet = NULL; + + if ((gpr_list_raw_is_empty(&dynamic_packet_list))) + { + return dynamic_packet; + } + else + { + gpr_list_get_head(&dynamic_packet_list, &head); + node = head; + do + { + dynamic_packet = (gpr_dynamic_packet_t *)((void *)node); + if (dynamic_packet->packet == packet) + { + return dynamic_packet; + } + + node = node->next; + } while (node != head); + } + + dynamic_packet = NULL; + return dynamic_packet; +} + +GPR_INTERNAL uint32_t gpr_allocate_dynamic_packet(gpr_packet_t **packet, uint32_t size) +{ + gpr_dynamic_packet_t *dynamic_packet = NULL; + ar_heap_info heap_info; + + if (packet == NULL) { + AR_MSG(DBG_ERROR_PRIO, "alloc error, NULL packet found"); + return AR_EBADPARAM; + } + + ar_mem_set((void *)&heap_info, 0, sizeof(ar_heap_info)); + heap_info.tag = AR_HEAP_TAG_DEFAULT; + heap_info.align_bytes = AR_HEAP_ALIGN_8_BYTES; + + dynamic_packet = (gpr_dynamic_packet_t *)ar_heap_malloc(sizeof(gpr_dynamic_packet_t), &heap_info); + + if (!dynamic_packet) + { + AR_MSG(DBG_ERROR_PRIO, "failed to alloc memory %lu", size); + return AR_ENOMEMORY; + } + + *packet = (gpr_packet_t *)ar_heap_malloc(size, &heap_info); + if (*packet == NULL) + { + ar_heap_free((void *)dynamic_packet, &heap_info); + AR_MSG(DBG_ERROR_PRIO, "failed to alloc memory %lu", size); + return AR_ENOMEMORY; + } + + dynamic_packet->packet = *packet; + gpr_list_init_node((gpr_list_node_t *)dynamic_packet); + gpr_list_add_tail(&dynamic_packet_list, (gpr_list_node_t *)dynamic_packet); + return AR_EOK; +} + +GPR_INTERNAL uint32_t gpr_check_and_free_dynamic_packet(gpr_packet_t *packet) +{ + gpr_dynamic_packet_t *dynamic_packet = gpr_get_dynamic_packet(packet); + + if (dynamic_packet == NULL) + { + AR_MSG(DBG_ERROR_PRIO, "failed to free memory"); + return AR_EBADPARAM; + } + + gpr_list_delete(&dynamic_packet_list, (gpr_list_node_t *)((void *)dynamic_packet)); + gpr_free_dynamic_packet_raw(dynamic_packet); + return AR_EOK; +} + +GPR_INTERNAL uint32_t gpr_dynamic_packet_init(void) +{ + uint32_t result = AR_EOK; + + if (!gpr_dynamic_packet_init_done) + { + ar_osal_mutex_create(&gpr_dyn_packet_list_lock); + result = gpr_list_init(&dynamic_packet_list, gpr_dyn_packet_lock_fn, gpr_dyn_packet_unlock_fn); + if (AR_EOK == result) + { + gpr_dynamic_packet_init_done = TRUE; + } + } + + return result; +} + +GPR_INTERNAL uint32_t gpr_dynamic_packet_deinit(void) +{ + if (gpr_dynamic_packet_init_done) + { + gpr_free_dynamic_packet_list(); + ar_osal_mutex_destroy(gpr_dyn_packet_list_lock); + gpr_dynamic_packet_init_done = FALSE; + } + + return AR_EOK; +} diff --git a/gpr/ext/dynamic_allocation/stub_src/gpr_dynamic_allocation.c b/gpr/ext/dynamic_allocation/stub_src/gpr_dynamic_allocation.c new file mode 100644 index 0000000..e774c50 --- /dev/null +++ b/gpr/ext/dynamic_allocation/stub_src/gpr_dynamic_allocation.c @@ -0,0 +1,33 @@ +/** + * \file gpr_dynamic_allocation.c + * \brief + * This file contains stub implementation for dynamic packet allocation. + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gpr_dynamic_allocation.h" +#include "ar_osal_error.h" + +GPR_INTERNAL uint32_t gpr_allocate_dynamic_packet(gpr_packet_t **packet, uint32_t size) +{ + return AR_EFAILED; +} + +GPR_INTERNAL uint32_t gpr_check_and_free_dynamic_packet(gpr_packet_t *packet) +{ + return AR_EFAILED; +} + +GPR_INTERNAL uint32_t gpr_dynamic_packet_init(void) +{ + return AR_EOK; +} + +GPR_INTERNAL uint32_t gpr_dynamic_packet_deinit(void) +{ + return AR_EOK; +} diff --git a/gpr/ext/logging/inc/gpr_log.h b/gpr/ext/logging/inc/gpr_log.h new file mode 100644 index 0000000..eb76063 --- /dev/null +++ b/gpr/ext/logging/inc/gpr_log.h @@ -0,0 +1,46 @@ +#ifndef __GPR_LOG_H__ +#define __GPR_LOG_H__ + +/** + * \file gpr_log.h + * \brief + * This file contains GPR APIs for logging packets in case of a crash. + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gpr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +/** + * Initialize gpr logging + * \return AR_EOK (0) when successful. + * + */ +GPR_INTERNAL uint32_t gpr_log_init(void); + +/** + * De-initialize gpr logging, and clean up resources + * \return AR_EOK (0) when successful. + * + */ +GPR_INTERNAL uint32_t gpr_log_deinit(void); + +/** + * Log the given gpr packet to gpr_log_history_t + * \return AR_EOK (0) when successful. + * + */ +GPR_INTERNAL int32_t gpr_log_packet (gpr_packet_t* packet); +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_LOG_H__ */ \ No newline at end of file diff --git a/gpr/ext/logging/src/gpr_log_adsp.c b/gpr/ext/logging/src/gpr_log_adsp.c new file mode 100644 index 0000000..a042cdb --- /dev/null +++ b/gpr/ext/logging/src/gpr_log_adsp.c @@ -0,0 +1,194 @@ +/** + * \file gpr_log_adsp.c + * \brief + * This file contains logger implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "ar_osal_mem_op.h" +#include "ar_osal_mutex.h" +#include "ar_osal_heap.h" +#include "ar_osal_error.h" +#include "ar_osal_timer.h" +#include "ar_guids.h" +#include "ar_msg.h" +#include "gpr_api_i.h" +#include "gpr_log.h" +#include "gpr_msg_if.h" +#include "gpr_ids_domains.h" +#include "gpr_log_i.h" +#include "log.h" + +/***************************************************************************** + * Variables * + ****************************************************************************/ + +static ar_osal_mutex_t gpr_log_history_mutex; +static gpr_log_history_t gpr_log_history_modem; +static gpr_log_history_t gpr_log_history_generic; + +/***************************************************************************** + * Function Definitions * + ****************************************************************************/ + +GPR_INTERNAL uint32_t gpr_log_init(void) +{ + uint32_t result = AR_EOK; + + result = ar_osal_mutex_create(&gpr_log_history_mutex); + if (AR_EOK != result) + { + if (NULL != gpr_log_history_mutex) + { + (void)ar_osal_mutex_destroy(gpr_log_history_mutex); + gpr_log_history_mutex = NULL; + } + return AR_EFAILED; + } + + (void)ar_mem_cpy(gpr_log_history_modem.start_marker, sizeof(gpr_log_history_modem.start_marker), "GPRSTART", 8); + gpr_log_history_modem.size = GPR_LOG_HISTORY_BYTE_SIZE_V; + (void)ar_mem_set(gpr_log_history_modem.log, 0xFF, sizeof(gpr_log_history_modem.log)); + (void)ar_mem_cpy(gpr_log_history_modem.end_marker, sizeof(gpr_log_history_modem.end_marker), "GPR STOP", 8); + + gpr_log_history_modem.log_payloads = 0; + + (void)ar_mem_cpy(gpr_log_history_generic.start_marker, sizeof(gpr_log_history_generic.start_marker), "GPRSTART", 8); + gpr_log_history_generic.size = GPR_LOG_HISTORY_BYTE_SIZE_V; + (void)ar_mem_set(gpr_log_history_generic.log, 0xFF, sizeof(gpr_log_history_generic.log)); + (void)ar_mem_cpy(gpr_log_history_generic.end_marker, sizeof(gpr_log_history_generic.end_marker), "GPR STOP", 8); + + gpr_log_history_generic.log_payloads = 0; + +#ifdef GPR_LOG_PACKET_PAYLOAD + gpr_log_history_modem.log_payloads = 1; + gpr_log_history_generic.log_payloads = 1; +#endif + + return result; +} + +GPR_INTERNAL uint32_t gpr_log_deinit(void) +{ + AR_MSG(DBG_HIGH_PRIO, "GPR Log: Deinitializing gpr logger"); + if (NULL != gpr_log_history_mutex) + { + (void)ar_osal_mutex_destroy(gpr_log_history_mutex); + } + return AR_EOK; +} + +static void gpr_log_circ_write(uint8_t *const buf, + uint32_t const buf_size, + uint32_t *offset, + const uint8_t *const data, + uint32_t const data_size) +{ + uint32_t endpos; + uint32_t segment_size; + uint32_t remaining_size; + + remaining_size = ((data_size > buf_size) ? buf_size : data_size); + endpos = (*offset + remaining_size); + segment_size = (buf_size - *offset); + + /* Check whether buffer is full or not */ + if (endpos < buf_size) + { + (void)ar_mem_cpy(&buf[*offset], segment_size, data, remaining_size); + *offset = endpos; + } + else + { + if (endpos == buf_size) + { + /* Reset offset to 0 if end position and buffer size are equals */ + (void)ar_mem_cpy(&buf[*offset], segment_size, data, remaining_size); + *offset = 0; + } + else + { + /* Since current data cannot be fitted into the buffer, write only + * data which cab be fitted at he end of buffer and write rest of the data + * from begining of the buffer + */ + (void)ar_mem_cpy(&buf[*offset], segment_size, data, segment_size); + remaining_size -= segment_size; + *offset = remaining_size; + (void)ar_mem_cpy(buf, buf_size, &data[segment_size], remaining_size); + } + } +} + +GPR_INTERNAL int32_t gpr_log_packet(gpr_packet_t *packet) +{ + uint32_t packet_size; + uint32_t marker; + + uint16_t dst_domain_id; + uint16_t src_domain_id; + gpr_log_history_t *gpr_log_history; + + uint64_t time = ar_timer_get_time_in_us(); + + src_domain_id = packet->src_domain_id; + dst_domain_id = packet->dst_domain_id; + + if ((src_domain_id == GPR_IDS_DOMAIN_ID_MODEM_V) || (dst_domain_id == GPR_IDS_DOMAIN_ID_MODEM_V)) + { + gpr_log_history = &gpr_log_history_modem; + } + else + { + gpr_log_history = &gpr_log_history_generic; + } + + packet_size = GPR_PKT_GET_PACKET_BYTE_SIZE(packet->header); + + (void)ar_osal_mutex_lock(gpr_log_history_mutex); + + marker = GPR_LOG_SYNC_WORD; + + gpr_log_circ_write(gpr_log_history->log, + gpr_log_history->size, + &gpr_log_history->offset, + ((uint8_t *)&marker), + sizeof(marker)); + /* Write the sync word. */ + gpr_log_circ_write(gpr_log_history->log, + gpr_log_history->size, + &gpr_log_history->offset, + ((uint8_t *)&time), + sizeof(time)); + + /* Write the timestamp. */ +#ifdef GPR_LOG_PACKET_PAYLOAD + gpr_log_circ_write(gpr_log_history->log, + gpr_log_history->size, + &gpr_log_history->offset, + ((uint8_t *)packet), + packet_size); +#else + gpr_log_circ_write(gpr_log_history->log, + gpr_log_history->size, + &gpr_log_history->offset, + ((uint8_t *)packet), + sizeof(gpr_packet_t)); +#endif + + /* Write the packet. */ + gpr_log_history->offset = (((gpr_log_history->offset + 3) >> 2) << 2); + /* Align to 32-bits. */ + + (void)ar_osal_mutex_unlock(gpr_log_history_mutex); + gpr_log_diag_packet(packet, packet_size); + + return AR_EOK; +} diff --git a/gpr/ext/logging/src/gpr_log_diag.c b/gpr/ext/logging/src/gpr_log_diag.c new file mode 100644 index 0000000..33844ae --- /dev/null +++ b/gpr/ext/logging/src/gpr_log_diag.c @@ -0,0 +1,110 @@ +/** + * \file gpr_log_diag.c + * \brief + * This file contains helper functions to log gpr msgs in diag + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "ar_osal_mem_op.h" +#include "ar_osal_heap.h" +#include "ar_osal_error.h" +#include "ar_osal_timer.h" +#include "ar_guids.h" +#include "ar_msg.h" +#include "gpr_api_i.h" +#include "gpr_api_inline.h" +#include "gpr_log.h" +#include "gpr_msg_if.h" +#include "gpr_ids_domains.h" +#include "gpr_log_i.h" +#include "log.h" +#include "log_codes.h" + +#ifdef GPR_DIAG_LOG_CODES +// clang-format off + // If we are on sim the log codes are not defined in core + #ifndef SIM + #if defined GPR_UPD + #define GPR_ADSP_APPS_LOG_CODE LOG_GPR_ADSP_USERPD_APPS_C + #define GPR_ADSP_MODEM_LOG_CODE LOG_GPR_ADSP_USERPD_MODEM_C + #define GPR_MODEM_LOG_CODE LOG_GPR_MODEM_USERPD_C + #define GPR_SLPI_LOG_CODE LOG_GPR_SLPI_USERPD_C + #define GPR_CDSP_LOG_CODE LOG_GPR_CDSP_USERPD_C + #else + #define GPR_ADSP_APPS_LOG_CODE LOG_GPR_ADSP_APPS_C + #define GPR_ADSP_MODEM_LOG_CODE LOG_GPR_ADSP_MODEM_C + #define GPR_MODEM_LOG_CODE LOG_GPR_MODEM_C + #define GPR_SLPI_LOG_CODE LOG_GPR_SLPI_C + #define GPR_CDSP_LOG_CODE LOG_GPR_CDSP_C + #endif + #else + // Log codes are not defined on sim core label + #define GPR_ADSP_APPS_LOG_CODE 0x1D68 + #define GPR_ADSP_MODEM_LOG_CODE 0x1D6E + #endif + + // Figure out which generic log code to use based on target + #if defined modem_proc + #define GPR_LOG_CODE_GENERIC GPR_MODEM_LOG_CODE + #elif defined slpi_proc + #define GPR_LOG_CODE_GENERIC GPR_SLPI_LOG_CODE + #elif defined cdsp_proc + #define GPR_LOG_CODE_GENERIC GPR_CDSP_LOG_CODE + #else + #define GPR_LOG_CODE_GENERIC GPR_ADSP_APPS_LOG_CODE + #endif +// clang-format on +#endif + +typedef PACK(struct) +{ + log_hdr_type hdr; + uint32_t version; + gpr_packet_t gpr_pkt; +} +gpr_log_diag_log_pkt; + +static uint32_t gpr_log_get_diag_log_code(uint32_t src_domain_id, uint32_t dst_domain_id) +{ + uint32_t host_domain_id = 0; + __gpr_cmd_get_host_domain_id(&host_domain_id); + if (GPR_IDS_DOMAIN_ID_ADSP_V == host_domain_id) + { + if ((src_domain_id == GPR_IDS_DOMAIN_ID_MODEM_V) || (dst_domain_id == GPR_IDS_DOMAIN_ID_MODEM_V)) + { + return GPR_ADSP_MODEM_LOG_CODE; + } + else + { + return GPR_ADSP_APPS_LOG_CODE; + } + } + else + { + return GPR_LOG_CODE_GENERIC; + } +} + +void gpr_log_diag_packet(gpr_packet_t *packet, uint32_t packet_size) +{ + uint32_t src_domain_id = packet->src_domain_id; + uint32_t dst_domain_id = packet->dst_domain_id; + + uint32_t log_code = gpr_log_get_diag_log_code(src_domain_id, dst_domain_id); + + gpr_log_diag_log_pkt *diag_pkt_ptr = + log_alloc(log_code, sizeof(gpr_log_diag_log_pkt) + packet_size - sizeof(gpr_packet_t)); + if (NULL != diag_pkt_ptr) + { + ar_mem_cpy(((void *)&diag_pkt_ptr->gpr_pkt), sizeof(gpr_packet_t), packet, sizeof(gpr_packet_t)); + ar_mem_set(((void *)&diag_pkt_ptr->version), 0, sizeof(diag_pkt_ptr->version)); + log_commit(diag_pkt_ptr); + } +} diff --git a/gpr/ext/logging/src/gpr_log_generic.c b/gpr/ext/logging/src/gpr_log_generic.c new file mode 100644 index 0000000..6b2a6fb --- /dev/null +++ b/gpr/ext/logging/src/gpr_log_generic.c @@ -0,0 +1,166 @@ +/** + * \file gpr_log_generic.c + * \brief + * This file contains logger implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ +#include "ar_osal_mem_op.h" +#include "ar_osal_mutex.h" +#include "ar_osal_heap.h" +#include "ar_osal_error.h" +#include "ar_osal_timer.h" +#include "ar_guids.h" +#include "ar_msg.h" +#include "gpr_api_i.h" +#include "gpr_log.h" +#include "gpr_msg_if.h" +#include "gpr_log_i.h" + +/***************************************************************************** + * Variables * + ****************************************************************************/ + +static ar_osal_mutex_t gpr_log_history_mutex; +static gpr_log_history_t gpr_log_history_generic; + +/***************************************************************************** + * Function Definitions * + ****************************************************************************/ + +GPR_INTERNAL uint32_t gpr_log_init(void) +{ + uint32_t result = AR_EOK; + + result = ar_osal_mutex_create(&gpr_log_history_mutex); + if (AR_EOK != result) + { + if (NULL != gpr_log_history_mutex) + { + (void)ar_osal_mutex_destroy(gpr_log_history_mutex); + gpr_log_history_mutex = NULL; + } + return AR_EFAILED; + } + + (void)ar_mem_cpy(gpr_log_history_generic.start_marker, sizeof(gpr_log_history_generic.start_marker), "GPRSTART", 8); + gpr_log_history_generic.size = GPR_LOG_HISTORY_BYTE_SIZE_V; + (void)ar_mem_set(gpr_log_history_generic.log, 0xFF, sizeof(gpr_log_history_generic.log)); + (void)ar_mem_cpy(gpr_log_history_generic.end_marker, sizeof(gpr_log_history_generic.end_marker), "GPR STOP", 8); + + gpr_log_history_generic.log_payloads = 0; + +#ifdef GPR_LOG_PACKET_PAYLOAD + gpr_log_history_generic.log_payloads = 1; +#endif + + return result; +} + +GPR_INTERNAL uint32_t gpr_log_deinit(void) +{ + AR_MSG(DBG_HIGH_PRIO, "GPR Log: Deinitializing gpr logger "); + if (NULL != gpr_log_history_mutex) + { + (void)ar_osal_mutex_destroy(gpr_log_history_mutex); + } + return AR_EOK; +} + +static void gpr_log_circ_write(uint8_t *const buf, + uint32_t const buf_size, + uint32_t *offset, + const uint8_t *const data, + uint32_t const data_size) +{ + uint32_t endpos; + uint32_t segment_size; + uint32_t remaining_size; + + remaining_size = ((data_size > buf_size) ? buf_size : data_size); + endpos = (*offset + remaining_size); + segment_size = (buf_size - *offset); + + /* Check whether buffer is full or not */ + if (endpos < buf_size) + { + (void)ar_mem_cpy(&buf[*offset], segment_size, data, remaining_size); + *offset = endpos; + } + else + { + if (endpos == buf_size) + { + /* Reset offset to 0 if end position and buffer size are equals */ + (void)ar_mem_cpy(&buf[*offset], segment_size, data, remaining_size); + *offset = 0; + } + else + { + /* Since current data cannot be fitted into the buffer, write only + * data which cab be fitted at he end of buffer and write rest of the data + * from begining of the buffer + */ + (void)ar_mem_cpy(&buf[*offset], segment_size, data, segment_size); + remaining_size -= segment_size; + *offset = remaining_size; + (void)ar_mem_cpy(buf, buf_size, &data[segment_size], remaining_size); + } + } +} + +GPR_INTERNAL int32_t gpr_log_packet(gpr_packet_t *packet) +{ + uint32_t packet_size; + uint32_t marker; + + uint64_t time = ar_timer_get_time_in_us(); + + packet_size = GPR_PKT_GET_PACKET_BYTE_SIZE(packet->header); + + (void)ar_osal_mutex_lock(gpr_log_history_mutex); + + marker = GPR_LOG_SYNC_WORD; + + gpr_log_circ_write(gpr_log_history_generic.log, + gpr_log_history_generic.size, + &gpr_log_history_generic.offset, + ((uint8_t *)&marker), + sizeof(marker)); + /* Write the sync word. */ + gpr_log_circ_write(gpr_log_history_generic.log, + gpr_log_history_generic.size, + &gpr_log_history_generic.offset, + ((uint8_t *)&time), + sizeof(time)); + /* Write the timestamp. */ +#ifdef GPR_LOG_PACKET_PAYLOAD + gpr_log_circ_write(gpr_log_history_generic.log, + gpr_log_history_generic.size, + &gpr_log_history_generic.offset, + ((uint8_t *)packet), + packet_size); +#else + gpr_log_circ_write(gpr_log_history_generic.log, + gpr_log_history_generic.size, + &gpr_log_history_generic.offset, + ((uint8_t *)packet), + sizeof(gpr_packet_t)); +#endif + /* Write the packet. */ + gpr_log_history_generic.offset = (((gpr_log_history_generic.offset + 3) >> 2) << 2); + /* Align to 32-bits. */ + + (void)ar_osal_mutex_unlock(gpr_log_history_mutex); + + gpr_log_diag_packet(packet, packet_size); + + return AR_EOK; +} diff --git a/gpr/ext/logging/src/gpr_log_i.h b/gpr/ext/logging/src/gpr_log_i.h new file mode 100644 index 0000000..b48d743 --- /dev/null +++ b/gpr/ext/logging/src/gpr_log_i.h @@ -0,0 +1,55 @@ +#ifndef __GPR_LOG_I_H__ +#define __GPR_LOG_I_H__ + +/** + * \file gpr_log_i.h + * \brief + * This file contains internal structures for gpr logging + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/***************************************************************************** + * Defines * + ****************************************************************************/ + +#define GPR_LOG_HISTORY_BYTE_SIZE_V (4 * 1024) + +/** + * Indicates that the entire payload should be logged - not just the header + */ +#define GPR_LOG_PACKET_PAYLOAD 1 + +#define GPR_LOG_MAGIC_WORD_LEN 8 +// Used to indicate start of gpr packets in the cicrular buffer +#define GPR_LOG_SYNC_WORD 0xE91111E9 + +/***************************************************************************** + * Structure definitions * + ****************************************************************************/ + +typedef struct gpr_log_history_t gpr_log_history_t; +struct gpr_log_history_t +{ + uint8_t start_marker[GPR_LOG_MAGIC_WORD_LEN]; + uint32_t size; + uint32_t offset; + uint32_t log_payloads; + uint8_t log[GPR_LOG_HISTORY_BYTE_SIZE_V]; + uint8_t end_marker[GPR_LOG_MAGIC_WORD_LEN]; +}; + +void gpr_log_diag_packet(gpr_packet_t *packet, uint32_t packet_size); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* __GPR_LOG_I_H__ */ \ No newline at end of file diff --git a/gpr/ext/logging/stub_src/gpr_log_diag_stub.c b/gpr/ext/logging/stub_src/gpr_log_diag_stub.c new file mode 100644 index 0000000..c8ab8aa --- /dev/null +++ b/gpr/ext/logging/stub_src/gpr_log_diag_stub.c @@ -0,0 +1,29 @@ +/** + * \file gpr_log_diag_stub.c + * \brief + * This file contains stubs of the gpr diag logging files + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ + +#include "ar_osal_error.h" + +#include "gpr_api_i.h" +#include "gpr_log.h" + +uint32_t gpr_log_get_diag_log_code(uint32_t host_domain_id, uint32_t src_domain_id, uint32_t dest_domain_id) +{ + return 0; +} + +uint32_t gpr_log_diag_packet(uint32_t log_code, gpr_packet_t *packet, uint32_t packet_size) +{ + return AR_EOK; +} \ No newline at end of file diff --git a/gpr/ext/logging/stub_src/gpr_log_stub.c b/gpr/ext/logging/stub_src/gpr_log_stub.c new file mode 100644 index 0000000..914d433 --- /dev/null +++ b/gpr/ext/logging/stub_src/gpr_log_stub.c @@ -0,0 +1,50 @@ +/** + * \file gpr_log.c + * \brief + * This file contains logger implementation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/****************************************************************************** + * Includes * + *****************************************************************************/ + +#include "ar_osal_error.h" + +#include "gpr_api_i.h" +#include "gpr_log.h" + +/***************************************************************************** + * Defines * + ****************************************************************************/ + +/***************************************************************************** + * Structure definitions * + ****************************************************************************/ + +/***************************************************************************** + * Variables * + ****************************************************************************/ + +/***************************************************************************** + * Function Definitions * + ****************************************************************************/ + +GPR_INTERNAL uint32_t gpr_log_init(void) +{ + return AR_EOK; +} + +GPR_INTERNAL uint32_t gpr_log_deinit(void) +{ + return AR_EOK; +} + +GPR_INTERNAL int32_t gpr_log_packet(gpr_packet_t *packet) +{ + return AR_EOK; +} diff --git a/gpr/gpr.pc.in b/gpr/gpr.pc.in new file mode 100644 index 0000000..9b0ccd2 --- /dev/null +++ b/gpr/gpr.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: gpr +Description: gpr library +Version: @LT_VERSION@ +Libs: -L${libdir} -lar-gpr +Cflags: -I${includedir} diff --git a/gpr/platform/linux/gpr_init_lx_wrapper.c b/gpr/platform/linux/gpr_init_lx_wrapper.c new file mode 100644 index 0000000..5746ce6 --- /dev/null +++ b/gpr/platform/linux/gpr_init_lx_wrapper.c @@ -0,0 +1,193 @@ +/* + * gpr_init_lx_wrapper.c + * + * This file has implementation platform wrapper for the GPR datalink layer + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#define LOG_TAG "gpr_lx_wrapper" +#include +#include "gpr_api_i.h" +#include "gpr_lx.h" +#include + +#ifdef GPR_USE_CUTILS +#include +#else +#include +#ifndef ALOGD +#define ALOGD(fmt, arg...) syslog (LOG_NOTICE, fmt, ##arg) +#endif +#ifndef ALOGI +#define ALOGI(fmt, arg...) syslog (LOG_INFO, fmt, ##arg) +#endif +#ifndef ALOGE +#define ALOGE(fmt, arg...) syslog (LOG_ERR, fmt, ##arg) +#endif +#endif + +#define GPR_NUM_PACKETS_TYPE 3 + +#define GPR_NUM_PACKETS_1 ( 100 ) +#define GPR_DRV_BYTES_PER_PACKET_1 ( 512 ) +#define GPR_NUM_PACKETS_2 ( 4 ) +#define GPR_DRV_BYTES_PER_PACKET_2 ( 4096 ) +#define GPR_NUM_PACKETS_3 ( 0 ) +#define GPR_DRV_BYTES_PER_PACKET_3 ( 65536 ) + +#ifdef PLATFORM_SLATE +#undef GPR_NUM_PACKETS_2 +#define GPR_NUM_PACKETS_2 ( 8 ) + +#undef GPR_NUM_PACKETS_3 +#define GPR_NUM_PACKETS_3 ( 2 ) +#endif + +/***************************************************************************** + * Global variables * + ****************************************************************************/ +/* GPR IPC table containing init,deinit functions for datalink layers depending on +domains a given src domain wishes to establish a link with and the availability +of shared memory */ +struct ipc_dl_v2_t gpr_lx_ipc_dl_table[GPR_PL_NUM_TOTAL_DOMAINS_V]; + +struct gpr_packet_pool_info_v2_t gpr_lx_packet_pool_table[GPR_NUM_PACKETS_TYPE]={ + { GPR_HEAP_INDEX_DEFAULT, 0, 0, GPR_NUM_PACKETS_1, GPR_DRV_BYTES_PER_PACKET_1}, + { GPR_HEAP_INDEX_DEFAULT, 0, 0, GPR_NUM_PACKETS_2, GPR_DRV_BYTES_PER_PACKET_2}, + { GPR_HEAP_INDEX_DEFAULT, 1, 0, GPR_NUM_PACKETS_3, GPR_DRV_BYTES_PER_PACKET_3}, +}; + +uint32_t num_domains = 0; + +/***************************************************************************** + * Local function definitions * + ****************************************************************************/ + +GPR_INTERNAL void update_gpr_ipc_table(char *drv_path, uint16_t domain_id, + bool_t supp_shared_mem) +{ + int fd = 0; + + if (drv_path != NULL) { + fd = access(drv_path, F_OK); + if (fd == -1) { + ALOGI("%s:%d driver path does not exists, err %d for %s\n", __func__, __LINE__, errno, drv_path); + return; + } + } + + ALOGD("%s:%d num_dom %d %d\n", __func__, __LINE__, num_domains, domain_id); + + gpr_lx_ipc_dl_table[num_domains].domain_id = domain_id; + gpr_lx_ipc_dl_table[num_domains].init_fn = ipc_dl_lx_init; + gpr_lx_ipc_dl_table[num_domains].deinit_fn = ipc_dl_lx_deinit; + gpr_lx_ipc_dl_table[num_domains].supports_shared_mem = supp_shared_mem; + + num_domains++; +} + +GPR_INTERNAL uint32_t gpr_drv_init(void) +{ + ALOGD("GPR INIT START"); + uint32_t rc, domain_id; + uint32_t num_packet_pools = + sizeof(gpr_lx_packet_pool_table)/sizeof(gpr_packet_pool_info_v2_t); + + /* Reset to 0 to avoid wrong value when gpr_drv_init called multiple times due to failure */ + num_domains = 0; + memset(&gpr_lx_ipc_dl_table[0], 0, (sizeof(struct ipc_dl_v2_t) * GPR_PL_NUM_TOTAL_DOMAINS_V)); + + gpr_lx_ipc_dl_table[num_domains].domain_id = GPR_IDS_DOMAIN_ID_APPS_V; + gpr_lx_ipc_dl_table[num_domains].init_fn = ipc_dl_local_init; + gpr_lx_ipc_dl_table[num_domains].deinit_fn = ipc_dl_local_deinit; + gpr_lx_ipc_dl_table[num_domains].supports_shared_mem = TRUE; + + num_domains++; + +/* + * ToDo: Update gpr init proc domain for ARE on APPS support to + * GPR_IDS_DOMAIN_ID_APPS_V + * + * Modules and Containers in ACDB file does not support APPS PROC domain by + * default and would require updating definitions for each module in ACDB + * graph. Due to check in audioreach-engine (SPF) code that matches the + * container proc domain and GPR proc domain, and existing container domain + * being ADSP for container, initialize GPR with GPR_IDS_DOMAIN_ID_ADSP_V + * domain ID instead of GPR_IDS_DOMAIN_ID_APPS_V to support use-cases for + * ARE on APPS. + * Update gpr init domain ID back to GPR_IDS_DOMAIN_ID_APPS_V once APPS + * proc domain is supported for modules and container in ACDB data. + */ +#ifdef ARE_ON_APPS + gpr_lx_ipc_dl_table[num_domains].domain_id = GPR_IDS_DOMAIN_ID_ADSP_V; + gpr_lx_ipc_dl_table[num_domains].init_fn = ipc_dl_local_init; + gpr_lx_ipc_dl_table[num_domains].deinit_fn = ipc_dl_local_deinit; + gpr_lx_ipc_dl_table[num_domains].supports_shared_mem = TRUE; + + num_domains++; + domain_id = GPR_IDS_DOMAIN_ID_ADSP_V; +#else + update_gpr_ipc_table("/dev/aud_pasthru_adsp", + GPR_IDS_DOMAIN_ID_ADSP_V, + TRUE); + update_gpr_ipc_table("/dev/aud_pasthru_modem", + GPR_IDS_DOMAIN_ID_MODEM_V, + TRUE); + update_gpr_ipc_table("/dev/gpr_channel", + GPR_IDS_DOMAIN_ID_CC_DSP_V, + FALSE); + domain_id = GPR_IDS_DOMAIN_ID_APPS_V; +#endif + rc = gpr_drv_internal_init_v2(domain_id, + num_domains, + gpr_lx_ipc_dl_table, + num_packet_pools, + gpr_lx_packet_pool_table); + ALOGD("GPR INIT EXIT"); + return rc; +} + +GPR_INTERNAL uint32_t gpr_drv_init_domain(uint32_t domain_id) +{ + ALOGD("GPR INIT START, for domain id %d", domain_id); + uint32_t rc; + uint32_t num_packet_pools = + sizeof(gpr_lx_packet_pool_table)/sizeof(gpr_packet_pool_info_v2_t); + + memset(&gpr_lx_ipc_dl_table[0], 0, (sizeof(struct ipc_dl_v2_t) * GPR_PL_NUM_TOTAL_DOMAINS_V)); + + gpr_lx_ipc_dl_table[num_domains].domain_id = domain_id; + gpr_lx_ipc_dl_table[num_domains].init_fn = ipc_dl_local_init; + gpr_lx_ipc_dl_table[num_domains].deinit_fn = ipc_dl_local_deinit; + gpr_lx_ipc_dl_table[num_domains].supports_shared_mem = TRUE; + + num_domains++; + + if (domain_id == GPR_IDS_DOMAIN_ID_APPS_V) + { + update_gpr_ipc_table("/dev/aud_pasthru_adsp", + GPR_IDS_DOMAIN_ID_ADSP_V, + TRUE); + update_gpr_ipc_table("/dev/aud_pasthru_modem", + GPR_IDS_DOMAIN_ID_MODEM_V, + TRUE); + update_gpr_ipc_table("/dev/gpr_channel", + GPR_IDS_DOMAIN_ID_CC_DSP_V, + FALSE); + } + else if (domain_id == GPR_IDS_DOMAIN_ID_APPS2_V) + { + update_gpr_ipc_table("/dev/aud_pasthru_apps", + GPR_IDS_DOMAIN_ID_ADSP_V, + TRUE); + } + + rc = gpr_drv_internal_init_v2(domain_id, + num_domains, + gpr_lx_ipc_dl_table, + num_packet_pools, + gpr_lx_packet_pool_table); + ALOGD("GPR INIT EXIT"); + return rc; +} diff --git a/gsl/Android.mk b/gsl/Android.mk new file mode 100644 index 0000000..59b7d5d --- /dev/null +++ b/gsl/Android.mk @@ -0,0 +1,66 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := libar-gsl +LOCAL_MODULE_OWNER := qti +LOCAL_MODULE_TAGS := optional +LOCAL_VENDOR_MODULE := true + +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_CLIENT_SHM)),true) + LOCAL_CFLAGS += -DCLIENT_SHM_ENABLED +endif + +LOCAL_SRC_FILES := src/gsl_main.c \ + src/gsl_graph.c\ + src/gsl_shmem_mgr.c\ + src/gsl_subgraph.c\ + src/gsl_subgraph_pool.c\ + src/gsl_common.c\ + src/gsl_spf_ss_state.c\ + src/gsl_hw_rsc_mgr.c\ + src/gsl_rtc.c\ + src/gsl_rtc_main.c\ + src/gsl_dynamic_module_mgr.c\ + src/gsl_mdf_utils.c\ + src/gsl_spf_timeout.c\ + src/gsl_datapath.c\ + src/gsl_msg_builder.c\ + src/gsl_global_persist_cal.c\ + src/gsl_dls_client.c\ + src/gsl_cshm_mgr.c + +LOCAL_HEADER_LIBRARIES := libspf-headers +LOCAL_SHARED_LIBRARIES := \ + liblx-osal\ + libar-acdb\ + liblx-ar_util\ + libar-gpr + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/api\ + $(LOCAL_PATH)/inc\ + $(LOCAL_PATH)/rtc_api\ + $(LOCAL_PATH)/hw_rsc_api\ + $(LOCAL_PATH)/dls_client_api + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/api +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH)/rtc_api +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH)/hw_rsc_api +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH)/dls_client_api + +LOCAL_CFLAGS := -D_ANDROID_ +LOCAL_CFLAGS += -DGSL_DEBUG_ENABLE +LOCAL_CFLAGS += -DGSL_EXT_MEM_CACHE_DISABLE +LOCAL_CFLAGS += -DGSL_LOG_PKT_ENABLE +LOCAL_CFLAGS += -DGSL_PKT_LOG_PATH=\"/data/vendor/audio/gsl_log.bin\" +LOCAL_CFLAGS += -Wno-gnu-designator +LOCAL_CFLAGS += -Wno-shorten-64-to-32 +LOCAL_CFLAGS += -Wno-sign-compare +LOCAL_CFLAGS += -Wno-tautological-compare +LOCAL_CFLAGS += -Wno-typedef-redefinition +LOCAL_CFLAGS += -Wno-unused-function +LOCAL_CFLAGS += -Wno-unused-label +LOCAL_CFLAGS += -Wno-unused-local-typedef +LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-unused-variable + +include $(BUILD_SHARED_LIBRARY) diff --git a/gsl/Makefile.am b/gsl/Makefile.am new file mode 100644 index 0000000..d4dd1a9 --- /dev/null +++ b/gsl/Makefile.am @@ -0,0 +1,71 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gsl.pc +EXTRA_DIST = $(pkgconfig_DATA) + +AM_CFLAGS = -I$(srcdir)/inc +AM_CFLAGS += -I$(srcdir)/api +AM_CFLAGS += -I$(srcdir)/rtc_api +AM_CFLAGS += -I$(srcdir)/hw_rsc_api +AM_CFLAGS += -I$(srcdir)/dls_client_api + +AM_CFLAGS += -I$(top_srcdir)/ar_osal/api +AM_CFLAGS += -I$(top_srcdir)/ar_util/api +AM_CFLAGS += -I$(top_srcdir)/gpr/api +AM_CFLAGS += -I$(top_srcdir)/acdb/api +AM_CFLAGS += -I$(top_srcdir)/spf/api/ar_utils -I$(top_srcdir)/spf/api/apm -I$(top_srcdir)/spf/api/modules + +gsl_sources = ./inc/gsl_common.h \ + ./inc/gsl_graph.h \ + ./inc/gsl_main.h \ + ./inc/gsl_shmem_mgr.h \ + ./inc/gsl_subgraph.h \ + ./inc/gsl_subgraph_pool.h \ + ./inc/gsl_spf_ss_state.h \ + ./inc/gsl_rtc.h \ + ./inc/gsl_rtc_main.h \ + ./api/gsl_intf.h \ + ./inc/gsl_dynamic_module_mgr.h \ + ./rtc_api/gsl_rtc_intf.h \ + ./hw_rsc_api/gsl_hw_rsc_intf.h \ + ./inc/gsl_subgraph_driver_props_generic.h \ + ./api/gsl_subgraph_driver_props.h \ + ./inc/gsl_mdf_utils.h \ + ./inc/gsl_spf_timeout.h \ + ./inc/gsl_global_persist_cal.h \ + ./dls_client_api/gsl_dls_client_intf.h \ + ./inc/gsl_dls_client.h \ + ./inc/gsl_cshm_mgr.h + +gsl_c_sources = ./src/gsl_graph.c \ + ./src/gsl_main.c \ + ./src/gsl_mdf_utils.c \ + ./src/gsl_spf_timeout.c \ + ./src/gsl_shmem_mgr.c \ + ./src/gsl_subgraph.c \ + ./src/gsl_subgraph_pool.c \ + ./src/gsl_common.c \ + ./src/gsl_datapath.c \ + ./src/gsl_dynamic_module_mgr.c \ + ./src/gsl_spf_ss_state.c \ + ./src/gsl_rtc.c \ + ./src/gsl_rtc_main.c \ + ./src/gsl_hw_rsc_mgr.c \ + ./src/gsl_msg_builder.c \ + ./src/gsl_global_persist_cal.c \ + ./src/gsl_dls_client.c \ + ./src/gsl_cshm_mgr.c + +lib_includedir = $(includedir) +lib_include_HEADERS = $(gsl_sources) + +lib_LTLIBRARIES = libar-gsl.la +libar_gsl_la_CC = @CC@ +libar_gsl_la_LIBADD = $(top_builddir)/acdb/libar-acdb.la $(top_builddir)/ar_osal/libar-osal.la $(top_builddir)/ar_util/libar-util.la $(top_builddir)/spf/libar-spfhdrs.la $(top_builddir)/gpr/libar-gpr.la +libar_gsl_la_SOURCES = $(gsl_c_sources) +libar_gsl_la_CFLAGS = $(AM_CFLAGS) +libar_gsl_la_LDFLAGS = -shared -version-number @LT_VERSION_NUMBER@ + +if USES_ATS_DATA_LOGGING +libar_gsl_la_CFLAGS += -DATS_DATA_LOGGING +libar_gsl_la_CPPFLAGS = -DATS_DATA_LOGGING +endif diff --git a/gsl/api/gsl_intf.h b/gsl/api/gsl_intf.h new file mode 100644 index 0000000..d87b6d1 --- /dev/null +++ b/gsl/api/gsl_intf.h @@ -0,0 +1,1383 @@ +#ifndef GSL_INTF_H +#define GSL_INTF_H +/** + * \file gsl_intf.h + * + * \brief + * Defines public APIs for Graph Service Layer (GSL) + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define GSL_MAX_NUM_OF_ACDB_FILES 20 /**< maximum number of acdb files */ +#define GSL_MAX_LEN_OF_ACDB_FILENAME 256 /**< maxumum lengh of filename */ + +#define GSL_ATTRIBUTES_DATA_MODE_MASK 0x7 +/**< keep 3 bits for specifying the data mode */ +#define GSL_DATA_MODE_SHMEM 0x0 /**< shared memory mode */ +#define GSL_DATA_MODE_BLOCKING 0x1 /**< heap memory mode blocking */ +#define GSL_DATA_MODE_NON_BLOCKING 0x2 /**< heap memory mode non-blocking */ +#define GSL_DATA_MODE_PUSH_PULL 0x3 /**< push-pull mode */ +#define GSL_DATA_MODE_EXTERN_MEM 0x4 /**< external memory mode */ + +/**< 2 bits to control datapath set up */ +#define GSL_ATTRIBUTES_DATAPATH_SETUP_MASK 0x18 +/**< shift amount for datapath setup flags */ +#define GSL_ATTRIBUTES_DATAPATH_SETUP_SHIFT 3 +/**< + * use these flags when it is necessary to separate the allocation of memory + * buffers from sharing those buffers with DSP + * Example: opening graph with no GKV and push pull mode, the endpoint IID for + * the use case is not yet known, so cannot send shmem to DSP. + * + * default does allocation of buffers and shared mem setup together + * buffers must be allocated first before shmem can be set up + * Client is responsible for calling these in the correct order, + * i.e. shmem must be allocated before provisioning SPF + */ +/**< allocate buffers and set them up on SPF EP */ +#define GSL_DATAPATH_SETUP_DEFAULT 0x0 +/**< allocate buffers, do not set up shmem on SPF endpoint */ +#define GSL_DATAPATH_SETUP_ALLOC_SHMEM_ONLY 0x1 +/**< + * set up shmem on SPF endpoint only + * GSL ignores other params sent when this flag is used, since the datapath + * must be configured with ALLOC_SHMEM_ONLY before calling with this flag + * + * for packet-based modes, this operation is a no-op + */ +#define GSL_DATAPATH_SETUP_SPF_PROVISION_ONLY 0x2 + +/**< + * used to indicate a given buffer is the final buffer, client will get + * notified once the buffer has been rendered + */ +#define GSL_BUFF_FLAG_EOS 0x1 + +/**< true if buffer has a valid timestamp */ +#define GSL_BUFF_FLAG_TS_VALID 0x2 + +/**< used to indicate a buffer is the last in a frame */ +#define GSL_BUFF_FLAG_EOF 0x4 + +/**< + * used to indicate a buffer is media format, + * when this flag is set, buffer will contain the media format data only + */ +#define GSL_BUFF_FLAG_MEDIA_FORMAT 0x8 + +/** + * The source module_id for events originating from GSL and not from Spf + */ +#define GSL_EVENT_SRC_MODULE_ID_GSL 0x2001 /* DO NOT CHANGE */ + + +/** Commands that can be passed to gsl_ioctl */ +enum gsl_cmd_id { + /** Start a graph */ + GSL_CMD_START = 0x0, + /** + * Optional, can be called before GSL_CMD_START to start initializing + * modules in the DSP + */ + GSL_CMD_PREPARE = 0x1, + /** Flush a graph, causes graph to drop all unprocessed buffers */ + GSL_CMD_FLUSH = 0x3, + /** + * Stop graph, stop processing data and reset to initial state + * Optional Payload: struct gsl_cmd_properties + * GRAPH_STOP is issued only to those subgraphs with matching property_ID + * and property_values + */ + GSL_CMD_STOP = 0x4, + /** + * Add a new graph to an existing graph based on a new graph key vector. + * Payload: struct gsl_cmd_graph_select + */ + GSL_CMD_ADD_GRAPH = 0x5, + /** + * Remove existing graph based on a graph key vector + * Payload: struct gsl_cmd_remove_graph + */ + GSL_CMD_REMOVE_GRAPH = 0x6, + /** + * Modify existing graph based on a new graph key vector + * Payload: struct gsl_cmd_graph_select + */ + GSL_CMD_CHANGE_GRAPH = 0x7, + /** Get the path delay associated with a graph */ + GSL_CMD_QUERY_GRAPH_DELAY = 0x8, + /** + * Configure parameters used for write data exchange + * Payload: struct gsl_cmd_configure_read_write_params + */ + GSL_CMD_CONFIGURE_WRITE_PARAMS = 0xA, + /** + * Configure parameters used for read data exchange + * Payload: struct gsl_cmd_configure_read_write_params + */ + GSL_CMD_CONFIGURE_READ_PARAMS = 0xB, + /** + * Insert EOS marker in playback data stream, the EOS marker is inserted in + * the stream immediately after all the data successfully written to GSL. + * Once all the buffers before the EOS marker are played out, GSL generates + * an EOS event to client. + * Note: If a gsl_write operation is pending when this command is issued + * the buffer passed in the pending gsl_write is not gauranteed to be + * played out. + */ + GSL_CMD_EOS = 0xC, + /** + * Get buffer pointers and sizes for use in shared memory mode write + * operations + * Payload: struct gsl_cmd_get_shmem_buf_info will be sent from client + * and will get written to by GSL. + */ + GSL_CMD_GET_WRITE_BUFF_INFO = 0xD, + /** + * Get buffer pointers and sizes for use in shared memory mode read + * operations + * Payload: struct gsl_cmd_get_shmem_buf_info will be sent from client + * and will get written to by GSL. + */ + GSL_CMD_GET_READ_BUFF_INFO = 0xE, + /** + * Get pointer and size of position buffer used to synchronize writes in + * push/pull mode + * Payload: struct gsl_cmd_get_shmem_buf_info will be sent from client + * and will get written to by GSL. + */ + GSL_CMD_GET_WRITE_POS_BUFF_INFO = 0xF, + + /** + * Get pointer and size of position buffer used to synchronize reads in + * push/pull mode + * Payload: struct gsl_cmd_get_shmem_buf_info will be sent from client + * and will get written to by GSL. + */ + GSL_CMD_GET_READ_POS_BUFF_INFO = 0x10, + + /** + * Register a custom event with a spf module + * Payload: struct gsl_cmd_register_custom_event + */ + GSL_CMD_REGISTER_CUSTOM_EVENT = 0x11, + /** Free all read buffers for a graph */ + GSL_CMD_FREE_READ_BUFF = 0x12, + /** Free all write buffers for a graph */ + GSL_CMD_FREE_WRITE_BUFF = 0x13, + /** + * Suspend graph, stop processing data but does not reset to initial state + * If a subgraph is shared with multiple graphs then :- + * - The common subgraph remains in START + * if at least one graph is in START. + * - If none of the of graph is in START and one of the graph is in STOP + * then common subgraph goes to STOP state. + * - Common subgraph goes to SUSPEND state only when + * all the graphs issue SUSPEND. + */ + GSL_CMD_SUSPEND = 0x14, + /** + * Close subset of subgraphs in the graph based on properties + * Payload: struct gsl_cmd_properties + * GRAPH_STOP is issued only to those subgraphs with matching property_ID + * and property_values + */ + GSL_CMD_CLOSE_WITH_PROPS = 0x15, + GSL_CMD_MAX +}; + +/** Events that will be notified to client from GSL */ +enum gsl_event_id { + /** + * End of stream event, indicates that all data written to GSL prior to + * client calling GSL_CMD_EOS has been played out + * Payload: struct gsl_event_eos_payload + */ + GSL_EVENT_ID_EOS = 0x0, + /** + * Indicates buffer provided as part of read call has been filled + * Payload: struct gsl_event_read_write_done_payload + */ + GSL_EVENT_ID_READ_DONE = 0x1, + /** + * Indicates buffer provided as part of write has been consumed + * Payload: struct gsl_event_read_write_done_payload + */ + GSL_EVENT_ID_WRITE_DONE = 0x2, + /** + * Sent in non-blocking mode only, indicates that buffer has become + * available for client to write to + */ + GSL_EVENT_ID_BUFFER_AVAIL = 0x3, + GSL_EVENT_ID_MAX +}; + +/** + * Global events that can be raised through the global callback + */ +enum gsl_global_event_ids { + /** + * Indicates that an audio service is up, this can happen for example due + * to restart after SSR. + * payload: NULL + */ + GSL_GLOBAL_EVENT_AUDIO_SVC_UP, + /** + * Indicates that an audio service is down, this can happen for example due + * to SSR. + * payload: struct gsl_global_event_svc_dn_payload + */ + GSL_GLOBAL_EVENT_AUDIO_SVC_DN, + GSL_GLOBAL_EVENT_MAX +}; + + +/** + * Identifies data direction + */ +enum gsl_data_dir { + /** + * Indicates data is provided from gsl to client + */ + GSL_DATA_DIR_READ, + /** + * Indicates data is provided from client to gsl + */ + GSL_DATA_DIR_WRITE +}; + +typedef void *gsl_handle_t; /**< opaque handle that is returned to client */ + +/** opaque acdb handle that is returned to client */ +typedef void *gsl_acdb_handle_t; + +/** + * a single entry in a key vector + */ +struct gsl_key_value_pair { + uint32_t key; /**< key */ + uint32_t value; /**< value */ +}; + +/** + * a complete key vector + */ +struct gsl_key_vector { + uint32_t num_kvps; /**< number of key value pairs */ + struct gsl_key_value_pair *kvp; /**< vector of key value pairs */ +}; + +/** + * a key vector with a zero sized array. + */ +struct gsl_key_vector_array { + uint32_t num_keys; /**< number of keys */ + struct gsl_key_value_pair kvp[]; /**< array of key value pairs.*/ +}; + +/** + * a key vector list + */ +struct gsl_key_vector_list { + /**< number of key vectors in the key vector list */ + uint32_t num_key_vectors; + /**< size of the key vector list in bytes */ + uint32_t list_size; + /**< list of key vectors in the format of + * [#keys, kvPair+,..., #keys, kvPair+] + */ + struct gsl_key_vector_array *key_vector_list; +}; + +/** + * a tag key vector with a zero sized array + */ +struct gsl_tag_key_vector { + /**< the module tag identifier */ + uint32_t tag_id; + /**< number of keys */ + uint32_t num_keys; + /**< graph key value pair */ + struct gsl_key_value_pair kvp[]; +}; + +/** + * a tag key vector list + */ +struct gsl_tag_key_vector_list { + /**< number of key vectors in the key vector list */ + uint32_t num_key_vectors; + /**< size of the key vector list in bytes */ + uint32_t list_size; + /**< list of key vectors in the format of + *[#keys, kvPair+,..., #keys, kvPair+] + */ + struct gsl_tag_key_vector *key_vector_list; +}; + +/** + * Command payload for GSL_CMD_STOP ioctl. Properties used to match + * portions of the graph on which the command will be applied. + * This structure is used to match against the properties defined in + * gsl_subgraph_driver_props.h + */ +struct gsl_cmd_properties { + struct gsl_key_vector gkv; + /**< graph key vector to limit the scope of the operation **/ + uint32_t property_id; + /**< property ID of the subgraph(s) */ + uint32_t num_property_values; + /**< number of values for the subgraph property ID */ + uint32_t *property_values; + /**< + * Pointer to property values[num_property_values]. + * If subgraph's property value matches to any of the values in this + * set, the command will be carried out on that subgraph + */ +}; + +/** + * Cmd payload for GSL_CMD_CONFIGURE_WRITE_PARAMS and + * GSL_CMD_CONFIGURE_READ_PARAMS + */ +struct gsl_cmd_configure_read_write_params { + /** + * max number of bytes in a single buffer. Read/Write operations shall take + * buffers such that the size is a multiple of buff_size. + */ + uint32_t buff_size; + /** number of buffers GSL will use for data exchange */ + uint32_t num_buffs; + /** + * In case of write, wait till number of bytes received from client goes + * ABOVE this value before issuing START to SPF + * In case of read, wait till client has read this many bytes before + * issuing START to SPF + * Set to 0 for immediate start + */ + uint32_t start_threshold; + /** + * TBD, currently not supported + */ + uint32_t stop_threshold; + /** + * Bitfield used to indicate attributes for data transfers, below are the + * defined fields: + * data_mode(Bits 0,1,2): One of GSL_DATA_MODE_SHMEM, + * GSL_DATA_MODE_BLOCKING, GSL_DATA_MODE_NON_BLOCKING, + * GSL_DATA_MODE_PUSH_PULL, GSL_DATA_MODE_EXTERN_MEM + * datapath_setup(Bits 3,4): one of GSL_DATAPATH_SETUP_DEFAULT, + * GSL_DATAPATH_SETUP_ALLOC_SHMEM_ONLY, + * GSL_DATAPATH_SETUP_SPF_PROVISION_ONLY + */ + uint32_t attributes; + /** + * Optional tag used to queue read buffers before first gsl_graph_read + * When set to 0, buffers are not queued until first gsl_graph_read call + */ + uint32_t shmem_ep_tag; + /** + * Optional field for passing platform specific data to GSL, this can be + * used for example to communicate some heap properties to osal layer. + * Must be set to 0 for clients that dont have any specific platform data. + */ + uint32_t platform_info; + /* maximum possible size of metadata for use case */ + uint32_t max_metadata_size; +}; + +/** Cmd payload for GSL_CMD_ADD_GRAPH and GSL_CMD_CHANGE_GRAPH */ +struct gsl_cmd_graph_select { + /** + * Used to lookup the new graph. In the case of GSL_CMD_CHANGE_GRAPH the + * old graph will be torn down and the new graph will be setup. In the + * case of GSL_CMD_ADD_GRAPH the new graph is setup without tearing down + * the old graph + */ + struct gsl_key_vector graph_key_vector; + /** + * Used to lookup the calibration data that will be set on the new graph + */ + struct gsl_key_vector cal_key_vect; +}; + +/** Cmd payload for GSL_CMD_REMOVE_GRAPH*/ +struct gsl_cmd_remove_graph { + /** + * Used to lookup the graph that will be removed + */ + struct gsl_key_vector graph_key_vector; +}; + +/** + * Cmd payload for GSL_CMD_GET_WRITE_BUFF_INFO and GSL_CMD_GET_READ_BUFF_INFO. + * GSL writes to the payload created by the caller. Caller is responsible to + * provide the appropriate amount of memory to hold addresses for all buffers. + */ +struct gsl_shmem_buf { + /** buffer address */ + uint8_t *addr; + /** per buffer metadata */ + uint64_t metadata; +}; + +struct gsl_cmd_get_shmem_buf_info { + /** buffer size, all buffers have the same size */ + uint32_t size; + /** number of buffers */ + uint32_t num_buffs; + /** list of buffs, containts num_buffs entries */ + struct gsl_shmem_buf *buffs; +}; + +/** + * Cmd payload for GSL_CMD_REGISTER_CUSTOM_EVENT + */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4200) +#endif /* _MSC_VER */ +struct gsl_cmd_register_custom_event { + /** Valid instance ID of module */ + uint32_t module_instance_id; + + /** Valid event ID of the module */ + uint32_t event_id; + + /** + * Size of the event config data based upon the module_instance_id/event_id + * combination. @values > 0 bytes, in multiples of 4 bytes atleast + */ + uint32_t event_config_payload_size; + + /** + * 1 - to register the event + * 0 - to de-register the event + */ + uint32_t is_register; + + /** + * module specifc event registration payload + */ + uint8_t event_config_payload[]; +}; +#ifdef _MSC_VER +#pragma warning(pop) +#endif /* _MSC_VER */ + +/** + * Holds the path of single acdb file, this struct should be bitwise matching + * against what ACDB APIs expect + */ +struct gsl_acdb_file { + /** Full file path name length */ + uint32_t fileNameLen; + /** + * Array that holds the ACDB file path and name, which cannot exceed 256 + * characters, including the NULL-termiated character + */ + char fileName[GSL_MAX_LEN_OF_ACDB_FILENAME]; +}; + +/** + * Holds list of ACDB files, this struct should be bitwise matching + * against what ACDB APIs expect + */ +struct gsl_acdb_data_files { + /** Number of ACDB files */ + uint32_t num_files; + /** Array of ACDB file full paths */ + struct gsl_acdb_file acdbFiles[GSL_MAX_NUM_OF_ACDB_FILES]; +}; + +/** + * \brief callback used to notify global events to client. + * + * Global events are events that are not bound to a specific gsl graph handle. + * + * \param[in] event_id indicates the global event id + * \param[in] event_payload event id specific payload + * \param[in] event_payload_sz size of the event id specific payload + * \param[in] client_data opaque client data + */ +typedef uint32_t (*gsl_global_cb_func_ptr)(enum gsl_global_event_ids event_id, + void *event_payload, size_t event_payload_sz, void *client_data); + +/** Argument for gsl_init */ +struct gsl_init_data { + /** + * acdb files to pass to acdb, setting this NULL means acdb_addr will be + * used to acces the data + */ + struct gsl_acdb_data_files *acdb_files; + + /** path of acdb delta file */ + struct gsl_acdb_file *acdb_delta_file; + + /** acdb image address*/ + const void *acdb_addr; + + /** + * indicates number of times GSL should check that spf is + * ready, gsl_init call is blocked until spf is ready. Spf readiness + * check is skipped in-case this field is set to 0 + */ + uint32_t max_num_ready_checks; + + /** + * Amount of time in ms that GSL waits before re-attempting to check Spf + * readiness + */ + uint32_t ready_check_interval_ms; +}; + +/* Convenience structure for external mem mode buffers */ +struct gsl_extern_alloc_buff_info { + /** unique handle identifying external mem allocation */ + uint64_t alloc_handle; + /** size in bytes of the allocation */ + uint32_t alloc_size; + /** offset of data buffer within the allocation in bytes */ + uint32_t offset; +}; + +/** + * Struct for passing buffer info to gsl_read and gsl_write, also used as a + * return payload for GSL_EVENT_ID_READ_DONE and GSL_EVENT_ID_WRITE_DONE + */ +struct gsl_buff { + uint64_t timestamp; /**< timestamp in micro-secs */ + uint32_t flags; /**< bitmasked flags for e.g. GSL_BUFF_FLAG_EOS */ + uint32_t size; /**< size of buffer in bytes */ + uint8_t *addr; /**< data buffer. Not used in extern mem mode */ + uint32_t metadata_size; /**< size of metadata buffer in bytes */ + uint8_t *metadata; /**< metadata buffer. Can contain multiple metadata */ + struct gsl_extern_alloc_buff_info alloc_info; /**< extern mem mode info */ +}; + +/** + * Maps the modules instance id to module id for a single module + */ +struct gsl_module_id_info_entry { + uint32_t module_id; /**< module id */ + uint32_t module_iid; /**< globally unique module instance id */ +}; + +/** + * Used to return the module info data to client + */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4200) +#endif /* _MSC_VER */ +struct gsl_module_id_info { + uint32_t num_modules; /**< number entries in module list below */ + struct gsl_module_id_info_entry module_entry[]; /**< module list */ +}; + +/** + * Structure mapping the tag_id to module info (mid and miid) + */ +struct gsl_tag_module_info_entry { + uint32_t tag_id; /**< tag id of the module */ + uint32_t num_modules; /**< number of modules matching the tag_id */ + struct gsl_module_id_info_entry module_entry[]; /**< module list */ +}; + +/** + * Used to return tags and module info data to client given a graph key vector + */ +struct gsl_tag_module_info { + uint32_t num_tags; /**< number of tags */ + uint8_t tag_module_entry[]; + /**< variable payload of type struct gsl_tag_module_info_entry */ +}; +#ifdef _MSC_VER +#pragma warning(pop) +#endif /* _MSC_VER */ + +/** + * Event payload passed to client with GSL_EVENT_ID_READ_DONE and + * GSL_EVENT_ID_WRITE_DONE events + */ +struct gsl_event_read_write_done_payload { + uint32_t tag; /**< tag that was used to read/write this buffer */ + uint32_t status; /**< data buffer status as defined in ar_osal_error.h */ + uint32_t md_status; /**< meta-data status as defined in ar_osal_error.h */ + struct gsl_buff buff; /**< buffer that was passed to gsl_read/gsl_write */ +}; + +/** + * EOS rendered status returned from Spf + */ +enum gsl_eos_render_status_t { + GSL_EOS_RENDERED, + GSL_EOS_DROPPED +}; + +/** + * Event payload passed to client with GSL_EVENT_ID_EOS + */ +struct gsl_event_eos_payload { + /** + * module instance id from which the EOS event was raised, Invalid (0) + * when dropped. + */ + uint32_t module_instance_id; + + /** + * Indicates whether the final sample was rendered or dropped + */ + enum gsl_eos_render_status_t render_status; +}; + +/** + * Event payload passed to client with GSL_GLOBAL_EVENT_AUDIO_SVC_DN + */ +struct gsl_global_event_svc_dn_payload { + /** + * Number of graph handles + */ + uint32_t num_handles; + + /** + * List of graph handles impacted by the audio svc going down, client is + * responsible to close these and re-open them once it receives the audio + * svc up notification + */ + gsl_handle_t *handle_list; +}; + +/** + * \brief Returns the GSL version + * + * \param[out] major: the major version is incremented whenever the current + * version is NOT backwards compatible with previous version + * \param[out] minor: the minor version is incremented whenever the current + * version has additional features to the previous version but is backwards + * compatible with it + */ +void gsl_get_version(uint32_t *major, uint32_t *minor); + +/** + * \brief Initialize GSL, must be called before any other GSL calls + * + * \param[in] init_data: data used during initialization + */ +int32_t gsl_init(struct gsl_init_data *init_data); + +/** + * \brief Initialize GSL cshm, must be called before any other cshm calls + * + * \param[in] num_client: number of clients to be intialized with. + * If 0, then default value of CSHM_DEFAULT_INIT_CLIENT_NUM will be used. + */ +int32_t gsl_cshm_init(uint32_t num_client); + +/** + * \brief De-Initialize GSL cshm, must be called after gsl_deinit() + */ +int32_t gsl_cshm_deinit(void); + +/** + * De-initialize GSL, no GSL APIs should be called after this + */ +void gsl_deinit(void); + +/** + * \brief Register a global callback function for GSL + * \param[in] global_cb callback function pointer used to notify global events + * such as SSR + * \param[in] client_data opaque client data that will be passed back to client + * whenever the callback is invoked + */ +int32_t gsl_register_global_event_cb(gsl_global_cb_func_ptr global_cb, + void *client_data); + +/** + * \brief Load a graph that is specified using graph_key_vector to the DSP. + * Does not reload graphs which are already loaded. + * + * \param[in] graph_key_vect: used to identify the graph. + * \param[in] cal_key_vect: OPTIONAL used to identify calibration data to be + * sent to the graph, setting to NULL means dont send any + * calibration + * \param[out] graph_handle: graph handle on success, null otherwise + * + * \return GSL_EOK on success, error code otherwise + */ + +int32_t gsl_open(const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect, gsl_handle_t *graph_handle); + +/** + * \brief Close a graph that was specified using the graph_handle + * + * \param[in] graph_handle: Handle of the graph to close + * + * \return GSL_EOK on success, error code otherwise + */ +int32_t gsl_close(gsl_handle_t graph_handle); + + +/** + * \brief Push calibration data for a given graph to DSP, Must be called before + * a graph is started. This API need not be called in the case of + * GSL_CMD_CHANGE_GRAPH as the calibration will be set during the graph change + * operation itself + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] graph_key_vect: OPTIONAL identifies the portion of the graph + * to which this calibration needs to be applied to. For SSMD scenarios, + * graph_handle can contain more than one graph key vector. In such cases, + * clients can provide specific graph key vector to which this calibration + * needs to be set. The graph_key_vector input should match to one of the + * GKVs that the graph_handle has. If this parameter is NULL, then GSL sets + * the prior_ckv to the one that was given during gsl_open(). + * \param[in] cal_key_vect: used to identify the cal data. + * + * \return EOK on success, error code otherwise + */ +int32_t gsl_set_cal(gsl_handle_t graph_handle, + const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect); + +/** + * \brief Set a configuration payload on a specified graph, the payload is + * stored in acdb + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] graph_key_vect: OPTIONAL identifies the portion of the graph + * to which this config needs to be applied. For SSMD scenarios, + * graph_handle can contain more than one graph key vector. In such cases, + * clients can provide specific graph key vector to which this calibration + * needs to be set. The graph_key_vector input should match to one of the + * GKVs that the graph_handle has. + * \param[in] tag: identifies a capability in acdb + * \param[in] tag_key_vect: identifies a payload in the database + * + * \return EOK on success, error code otherwise + */ +int32_t gsl_set_config(gsl_handle_t graph_handle, + const struct gsl_key_vector *graph_key_vect, uint32_t tag, + const struct gsl_key_vector *tag_key_vect); + +/** + * \brief Set a custom configuration parameter on a specified graph, the + * payload is provided from the caller. + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] payload: custom caller defined payload that will get sent to the + * module, payload structure shall be always according to OOB sturcutre format + * defined by SPF + * \param[in] payload_size: the size of the payload buffer + * + * \return EOK on success, error code otherwise + */ +int32_t gsl_set_custom_config(gsl_handle_t graph_handle, + const uint8_t *payload, const uint32_t payload_size); + +/** + * \brief Set a custom configuration parameter on a specified graph, the + * payload is provided from the caller. Caller also provides tag ID so gsl + * can look up ACDB for the module IID to which this payload needs to be + * sent to. + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] tag: identifies a module instance matching the tag ID + * \param[in] payload: custom caller defined payload that gets sent to the + * module, payload structure shall be always according to format + * defined by SPF {MIID, PID, Size, Error Code, Variable payload} + * \param[in] payload_size: the size of the payload buffer + * + * \return EOK on success, error code otherwise + */ +int32_t gsl_set_tagged_custom_config(gsl_handle_t graph_handle, uint32_t tag, + const uint8_t *payload, const size_t payload_size); + +/** + * \brief Persistent set a custom configuration parameter on a specified graph, + * the payload is provided from the caller. Caller also provides tag ID so gsl + * can look up ACDB for the module IID to which this payload needs to be + * sent to. + * LIMITATION: The payload can contain only a single PID that is destined to a + * single MID. + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] tag: identifies a module instance matching the tag ID + * \param[in] payload: custom caller defined payload that gets sent to the + * module, payload structure shall be always according to format + * defined by SPF {MIID, PID, Size, Error Code, Variable payload} + * \param[in] payload_size: the size of the payload buffer + * + * \return EOK on success, error code otherwise + */ +int32_t gsl_set_tagged_custom_config_persist(gsl_handle_t graph_handle, + uint32_t tag, const uint8_t *payload, const uint32_t payload_size); + +/** + * \brief Get the configuration parameter for a specified graph, caller + * provides a payload + * + * \param[in] graph_handle: returned from gsl_open + * \param[in,out] payload: Buffer that contains the module ids and + * param ids along with empty areas that will be filled with parameter + * data + * \param[in,out] size: holds the size of the client buffer passed in for + * payload. On return will hold actual bytes written. + * + * \return EOK on success, error code otherwise. Note that EOK does not mean we + * got valid data, it is possible that the buffer did not contain enough space + * for a given parameter. The client should check the error codes inside the + * buffer before reading the data. + */ +int32_t gsl_get_custom_config(gsl_handle_t graph_handle, uint8_t *payload, + uint32_t size); + +/** + * \brief Get the configuration parameter for a specified graph from the module + * that is specified by a tag, caller provides a payload with the PIDs + * populated. GSL will populate the MIDS into the payload. + * LIMITATION: Only a single parameter on a single module can be looked up at a + * time + * + * \param[in] graph_handle: returned from gsl_open + * \param[in] tag: tag used by GSL to lookup the MIDs + * \param[in,out] payload: Buffer that contains param ids along with empty + * areas that will be filled with parameter data + * \param[in,out] size: holds the size of the client buffer passed in for + * payload. On return will hold actual bytes written. + * + * \return EOK on success, error code otherwise. Note that EOK does not mean we + * got valid data, it is possible that the buffer did not contain enough space + * for a given parameter. The client should check the error codes inside the + * buffer before reading the data. + */ +int32_t gsl_get_tagged_custom_config(gsl_handle_t graph_handle, uint32_t tag, + uint8_t *payload, uint32_t *size); + + +/** + * \brief Send commands to GSL for controlling Graphs in Spf. + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] cmd_id: identifies the command + * \param[in,out] cmd_payload: command specific parameters + * \param[in] cmd_payload_sz: size of cmd_payload + * + * \return EOK on success, error code otherwise + */ +int32_t gsl_ioctl(gsl_handle_t graph_handle, + enum gsl_cmd_id cmd_id, void *cmd_payload, size_t cmd_payload_sz); + +/** + * \brief Receive data buffers from Spf. + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] tag: used to identify the module in Spf to read buffers from + * \param[in,out] buff: buffer where data will be copied to + * \param[out] filled_size: actual number of bytes filled into the buffer by + * GSL + * + * \return EOK on success, + * AR_EABORTED when buffer is not queued to spf because of graph + * close, stop, or flush (non-fatal error), + * error code otherwise + */ +int32_t gsl_read(gsl_handle_t graph_handle, uint32_t tag, + struct gsl_buff *buff, uint32_t *filled_size); + +/** + * \brief Write data buffers to Spf. + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] tag: used to identify the module in Spf to write buffers to + * \param[in] buff: buffer containing data that will be written + * \param[out] consumed_size: actual number of bytes consumed by GSL + * + * \return EOK on success, + * AR_EABORTED when buffer is not queued to spf because of graph + * close, stop, or flush (non-fatal error), + * error code otherwise + */ +int32_t gsl_write(gsl_handle_t graph_handle, uint32_t tag, + struct gsl_buff *buff, uint32_t *consumed_size); + +/** data that will be passed to client in the event callback */ +struct gsl_event_cb_params { + uint32_t source_module_id; + /**< identifies the module which generated event */ + uint32_t event_id; + /**< identifies the event, in case of GSL internal events it will hold a + * value from enum gsl_event_id + */ + uint32_t event_payload_size; /**< size of payload below */ + void *event_payload; /**< payload associated with the event if any */ +}; + +/** + * \brief Callback function signature for events to client + * + * \param[in] event_params: holds all event related info + * \param[in] client_data: client data that was provided during cb registration + */ +typedef void (*gsl_cb_func_ptr)(struct gsl_event_cb_params *event_params, + void *client_data); + +/** + * \brief Register an event callback function with Spf + * + * \param[in] graph_handle: graph handle returned from gsl_open + * \param[in] cb: pointer to callback function + * \param[in] client_data: opaque data that will be passed to client in the + * callback + * + * \return EOK on success, error code otherwise + */ +int32_t gsl_register_event_cb(gsl_handle_t graph_handle, + gsl_cb_func_ptr cb, void *client_data); + +/** + * \brief Query database for data associated with a given tag and tkv. + * This API is used to get spf module data in the form {IID, PID, Size, + * ErrorCode, variable length payload} + * + * \param[in] graph_key_vect: graph key vector + * \param[in] tag: used to identify a certain capability + * \param[in] tag_key_vect: tag key vector used to identify a specific payload + * in acdb + * \param[in,out] payload: pointer to a buffer where the payload will be + * copied to + * \param[in,out] payload_size: holds the size of the client buffer passed in + * for payload and on return will hold the size of the actual data written to + * the buffer. + * + * \return EOK on success, error code otherwise. In-case the provided + * payload_size is not big enough to hold output data the error code + * AR_ENEEDMORE will be returned and payload_size will be set to + * expected size. + */ +int32_t gsl_get_tagged_data( + const struct gsl_key_vector *graph_key_vect, uint32_t tag, + struct gsl_key_vector *tag_key_vect, uint8_t *payload, + size_t *payload_size); + +/** + * \brief Query database for module_iid to module_id mapping data + * + * \param[in] graph_key_vect: graph key vector + * \param[in] tag: identifies a set of modules in ACDB that were tagged with + * with this tag by system designer + * \param[out] module_info: module info will be copied here. GSL dynamically + * allocates memory to hold module_info for the num_modules matching the tag. + * Client is responsible to free the memory after use. + * \param[out] module_info_size: holds the size of the data written + * to the module_info buffer + * + * \return EOK on success, error code otherwise. + */ +int32_t gsl_get_tagged_module_info( + const struct gsl_key_vector *graph_key_vect, uint32_t tag, + struct gsl_module_id_info **module_info, uint32_t *module_info_size); + +/** + * \brief Query database for all tags and corresponding module_iid and + * module_id mapping given a graph key vector + * \param[in] graph_key_vect: graph key vector + * \param[in,out] tag_module_info: tag module info will be copied here. + * GSL clients would call this API twice, first call tag_module_info is + * set to NULL and GSL fills only the size - *tag_module_info_size. + * GSL clients then allocate memory set it to tag_module_info and call + * the API again for the second time and the tag module info gets copied + * into that memory. The payload is in the format "struct gsl_tag_module_info" + * \param[in,out] tag_module_info_size: used to provide the size (in bytes) + * of tag_module_info from client and output the expected size from + * gsl in-case size passed from client was too small + * + * \return EOK on success, error code otherwise. + */ +int32_t gsl_get_tags_with_module_info( + const struct gsl_key_vector *graph_key_vect, void *tag_module_info, + size_t *tag_module_info_size); + +/** + * \brief enable persistence for cals set to ACDB + * \param[in] enable_flag: 1 means enable, 0 is disable + * \return EOK on success, error code otherwise + */ +int32_t gsl_enable_acdb_persistence(uint8_t enable_flag); + +/** + * \brief Store custom calibration to ACDB + * + * \param[in] graph_key_vect: graph key vector + * \param[in] cal_key_vect: tag key vector used to identify an entry in acdb + * \param[in] payload: pointer to a buffer containing custom calibration + * \param[in] payload_size: holds the size of the client buffer passed in for + * payload + * + * \return EOK on success, error code otherwise + * + * see ACDB_CMD_SET_CAL_DATA in acdb.h for more documentation + */ +int32_t gsl_set_cal_data_to_acdb( + const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect, uint8_t *payload, + uint32_t payload_size); + +/** + * \brief Retrieve custom calibration from ACDB + * + * \param[in] graph_key_vect: graph key vector + * \param[in] cal_key_vect: tag key vector used to identify an entry in acdb + * \param[in] num_modules: The number of module instances in the param_list + * \param[in] param_list: List of module instances plus their parameters to get + * data for + * \param[out] payload: pointer to a buffer of returned payload_size to hold + * returned calibration + * \param[in,out] payload_size: holds the size of the client buffer passed in + * for payload. Client will call this API twice, once to fill this payload + * size and the second time to fill payload, with memory of returned + * payload_size allocated for payload + * + * \return EOK on success, error code otherwise + * + * see ACDB_CMD_GET_CAL_DATA in acdb.h for more documentation + */ +int32_t gsl_get_cal_data_from_acdb( + const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect, uint32_t num_modules, + uint8_t *param_list, void *payload, uint32_t *payload_size); + +/** + * \brief Store custom tag to ACDB + * + * \param[in] graph_key_vect: graph key vector + * \param[in] tag_id: tag ID to be set + * \param[in] tag_key_vect: tag key vector used to identify an entry in acdb + * \param[in] payload: pointer to a buffer containing custom tag data + * \param[in] payload_size: holds the size of the client buffer passed in for + * payload + * + * \return EOK on success, error code otherwise + * + * see ACDB_CMD_SET_TAG_DATA in acdb.h for more documentation + */ +int32_t gsl_set_tag_data_to_acdb( + const struct gsl_key_vector *graph_key_vect, uint32_t tag_id, + const struct gsl_key_vector *tag_key_vect, uint8_t *payload, + uint32_t payload_size); + +/** + * \brief Retrieve custom tag from ACDB + * + * \param[in] graph_key_vect: graph key vector + * \param[in] tag_id: tag ID for data to retrieve + * \param[in] tag_key_vect: tag key vector used to identify an entry in acdb + * \param[in] num_modules: The number of module instances in the param_list + * \param[in] param_list: List of module instances plus their parameters to get + * data for + * \param[out] payload: pointer to a buffer of returned payload_size to hold + * returned tag data + * \param[in,out] payload_size: holds the size of the client buffer passed in + * for payload. Client will call this API twice, once to fill this payload + * size and the second time to fill payload, with memory of returned + * payload_size allocated for payload + * + * \return EOK on success, error code otherwise + * + * see ACDB_CMD_GET_TAG_DATA in acdb.h for more documentation + */ +int32_t gsl_get_tag_data_from_acdb( + const struct gsl_key_vector *graph_key_vect, uint32_t tag_id, + const struct gsl_key_vector *tag_key_vect, uint32_t num_modules, + uint8_t *param_list, void *payload, uint32_t *payload_size); + +/** + * \brief Updates the read/write temporary path that AML uses for the + * reinit/delta persistence functionality. + * + * \param[in] cmd_id: Command ID is ACDB_CMD_SET_TEMP_PATH. + * \param[in] cmd: a null terminated char array of under 255 chars + * + * \return - AR_EOK -- Command executed successfully. + * - AR_EBADPARAM -- Invalid input parameters were provided. + * - AR_EFAILED -- Command execution failed. + */ +int32_t gsl_set_temp_path_to_acdb(uint32_t path_length, const char *temp_path); + +/** + * \brief Get an ever increasing count of data buffers processed by GSL + * + * For playback case returns the number of buffers acked by Spf. For capture + * case returns the number of buffers received from Spf. + * + * \param[in] graph_handle: graph handle + * \param[in] dir: indicates whether to return the write or read buffer counts + * \param[out] cnt: An ever increasing count of buffers, the number wraps back + * to zero once it reaches SIZE_MAX + * + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_get_processed_buff_cnt(gsl_handle_t graph_handle, + enum gsl_data_dir dir, uint32_t *cnt); + +/** + * \brief Get the size of available buffer (in bytes) ready to be written (playback) / read + * (capture) + * + * For playback case, returns the size of empty buffer (in bytes) for GSL clients to write. + * For capture case, returns the size of buffer (in bytes) that GSL clients can queue to SPF + * for read. + * + * \param[in] graph_handle: graph handle + * \param[in] dir: indicates whether to return write or read available buffer size + * \param[out] bytes: buffer size (in bytes) ready to be written (playback) / read (capture) + * + * \return AR_EOK in success, error code otherwise. + */ +int32_t gsl_get_avail_buffer_size(gsl_handle_t graph_handle, enum gsl_data_dir dir, + uint32_t *bytes); + +/** + * \brief Get driver data + * + * This API is to be called by GSL clients for querying any driver specific + * data that they stored in ACDB + * + * \param[in] module_id: client defined module_id against which data is stored + * in acdb + * \param[in] key_vect: OPTIONAL key vector used to look up data + * \param[in] data_payload: buffer where data will be returned, client is + * responsible to allocate memory for this buffer. If this is set to NULL + * the size of the output data will be returned in data_payload_size + * \param[in,out] data_payload_size: on input it containes the size of + * data_payload, on output will have the size actually written + * + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_get_driver_data(const uint32_t module_id, + const struct gsl_key_vector *key_vect, void *data_payload, + uint32_t *data_payload_size); + +/** + * \brief Get all tag/TKV variations + * + * Retrieves all tag and tag key vector variations which are defined for a + * given graph key vector in ACDB + * + * \param[in] graph_key_vect: GKV to find tag & TKV pairs in ACDB for + * \param[in,out] data_payload: buffer where data will be returned, client is + * responsible to allocate memory for this buffer. + * If data_payload->key_vector_list is set to NULL, + * the size of the output data will be returned in data_payload->list_size. + * + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_get_graph_tkvs(const struct gsl_key_vector *graph_key_vect, + struct gsl_tag_key_vector_list *data_payload); + +/** + * \brief Get all CKVs for given GKV + * + * Queries for all SPF module calibration key vectors under a given graph + * key vector. + * + * \param[in] graph_key_vect: GKV to find CKVs in ACDB for + * \param[in,out] data_payload: buffer where data will be returned, client is + * responsible to allocate memory for this buffer. + * If data_payload->key_vector_list is set to NULL, + * the size of the output data will be returned in data_payload->list_size. + * + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_get_graph_ckvs(const struct gsl_key_vector *graph_key_vect, + struct gsl_key_vector_list *data_payload); + +/** + * \brief Get KVs used by driver module + * + * Queries ACDB for all driver key vectors used by a particular driver module + * + * \param[in] driver_id: uint32_t identifying the driver module + * \param[in,out] data_payload: buffer where data will be returned, client is + * responsible to allocate memory for this buffer. + * If data_payload->key_vector_list is set to NULL, + * the size of the output data will be returned in data_payload->list_size. + * + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_get_driver_module_kvs(uint32_t driver_id, + struct gsl_key_vector_list *data_payload); + +/** + * \brief Get all GKVs that contain the provided key IDs as a subset + * + * Queries ACDB for all graph key vectors that contain the provided key ids as + * a subset. A graph key vector supports certain capabiliies if it matches + * the key id subset. If the subset contains zero keys, this api will return + * all the graph key vectors defined in ACDB. + * + * \param[in] key_ids: pointer to the set of key IDs to query. Client-managed + * \param[in] num_key_ids: number of entries in key_ids + * \param[in,out] data_payload: buffer where data will be returned, client is + * responsible to allocate memory for this buffer. + * If data_payload->key_vector_list is set to NULL, + * the size of the output data will be returned in data_payload->list_size. + * + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_get_supported_gkvs(uint32_t *key_ids, + const uint32_t num_key_ids, struct gsl_key_vector_list *data_payload); + +/** + * \brief get human-readable alias for a GKV + * + * Retrieves an alias of the graph key vector for readability. The alias + * includes the the usecase ID followed by a human readable graph key + * vector with names for keys and values. The string length is limited to + * 255 bytes. + * + * API is to be called twice: once to get the size, and once to get the string. + * + * \param[in] graph_key_vect: GKV to find alias for + * \param[in, out] alias: string containing the alias. Client is + * responsible to allocate memory for this buffer. If this is set to NULL + * the size of the output data will be returned in alias_len. + * \param[in, out] alias_len: The length of the string including the null + * terminating character. on input it containes the allocated size of alias, + * on output will have the size actually written + * + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_get_graph_alias(const struct gsl_key_vector *graph_key_vect, + char *alias, uint32_t *alias_len); + +/** + * \brief add acdb database + * + * Extends the database by adding database files (*.acdb and *.qwsp) at runtime. + * + * \param[in] acdb_data_files: A list of database file paths + * containing *.acdb and *.qwsp + * \param[in] writable_file_path: The delta data file path and temp files + * \param[in/out] acdb_handle: A handle to the database provided + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_add_database(struct gsl_acdb_data_files *acdb_data_files, + struct gsl_acdb_file *writable_file_path, + gsl_acdb_handle_t *acdb_handle); + +/** + * \brief remove acdb database + * + * Shrinks the database by removing all data associated with the given + * database handle at runtime. + * This includes database files (*.qwsp and .acdb) and heap data + * + * \param[in] acdb_handle: A handle to the database to remove + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_remove_database(gsl_acdb_handle_t acdb_handle); + +typedef uint32_t gsl_mem_id_t; + +typedef enum gsl_cshm_cache_type { + /** 0 cached.*/ + GSL_CSHM_CACHED = 1, + /** 1 uncached.*/ + GSL_CSHM_UNCACHED, +} gsl_cshm_cache_type_t; + +typedef enum gsl_subsystem { + /** Invalid sub system.*/ + GSL_SS_INVALID = 0, + /** Used for MODEM DSP sub system.*/ + GSL_SS_MODEM_DSP = 1, + /** Used for APPS sub system.*/ + GSL_SS_APPS = 2, + /** Used for SENSOR DSP sub system.*/ + GSL_SS_SENSOR_DSP = 3, + /** Used for COMPUTE DSP sub system.*/ + GSL_SS_COMPUTE_DSP = 4, + /** Used for Companion chip DSP (CC_DSP) sub system.*/ + GSL_SS_CC_DSP = 5, + /** Used for ADSP sub system.*/ + GSL_SS_ADSP = 6, +} gsl_subsystem_t; + +typedef struct gsl_cshm_info { + /** Cached or uncached memory type.*/ + gsl_cshm_cache_type_t type; + /** Allows rouing shared memory access across multiple DSPs.*/ + gsl_subsystem_t subsystem_mask; + /** Flags for shared memory allocation.*/ + int32_t flag; + /** File descriptor for mapped memory region.*/ + uint64_t fd; + /** Unique GSL memory identifier.*/ + gsl_mem_id_t mem_id; +} gsl_cshm_info_t; + +/** + * \brief Allocates shared memory for external clients. Send + * APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS commands to SPF to map allocated + * memory. + * + * \param[in] size: number of bytes to be allocated + * \param[in/out] info: properties of shared memory to be allocated. + * fd and mem_id of allocated memory + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_cshm_alloc(uint32_t size, gsl_cshm_info_t *info); + +/** + * \brief Deallocates shared memory for external clients. Send + * APM_CMD_GLOBAL_SHARED_MEM_UNMAP_REGIONS commands to SPF to unmap + * memory to be deallocated. + * + * \param[in] mem_id: identifier to shared memory to be deallocated + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_cshm_dealloc(gsl_mem_id_t mem_id); + +/** + * \brief Send notification to module running in SPF w.r.t particular + * operation on shared memory block. Operation is opaque to gsl. + *AR_SPF_MSG_GLOBAL_SH_MEM commands to SPF to forwards it to custom module. + * + * \param[in] mem_id: identifier to shared memory to be deallocated + * \param[in] offset: Offset (in bytes) from where the chunk of memory starts. + * This is relative to the beginning of the total shared memory + * allocated + * \param[in] length: Size of the chunk of memory. + * \param[in] miid: Module Instance ID of the module to which this call is intended for. + * In case of invalid/inactive miid, error is returned. + * \param[in] prop_flag: Flags to provide additional information for this call + * Bit 0 – Release memory + Bit used to convey if client wants the module to release/stop + using a chunk of previously informed memory. + 0 – Default. Not a release message. + 1 – Here, if length is zero, module is asked to release + entire memory mapped to it with mem_id. + If length is non-zero, the module is asked to release this + chunck only. + + * \return AR_EOK in success, error code otherwise + */ +int32_t gsl_cshm_msg(gsl_mem_id_t mem_id, uint32_t offset, uint32_t length, uint32_t miid, + uint32_t prop_flag); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* GSL_INTF_H */ diff --git a/gsl/api/gsl_subgraph_driver_props.h b/gsl/api/gsl_subgraph_driver_props.h new file mode 100644 index 0000000..b7c25e3 --- /dev/null +++ b/gsl/api/gsl_subgraph_driver_props.h @@ -0,0 +1,47 @@ +#ifndef GSL_SUBGRAPH_DRIVER_PROPS_H +#define GSL_SUBGRAPH_DRIVER_PROPS_H + +/** + * \file gsl_subgraph_driver_props.h + * + * \brief + * Represents GSL subgraph driver properties + * + + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @h2xml_title_date {08/01/2018} + */ + +#include "ar_osal_types.h" + +#define SUB_GRAPH_PROP_ID_SG_TYPE 0x08000010 +#define SUB_GRAPH_TYPE_STREAM 0x1 +#define SUB_GRAPH_TYPE_DEVICE 0x2 +#define SUB_GRAPH_TYPE_STREAM_DEVICE 0x3 +#define SUB_GRAPH_TYPE_STREAM_PP 0x4 +#define SUB_GRAPH_TYPE_DEVCICE_PP 0x5 + +typedef struct sg_type_t sg_type_t; + +/** + * @h2xmlp_property {"SUB_GRAPH_TYPE", SUB_GRAPH_PROP_ID_SG_TYPE} + * @h2xmlp_description {} + */ +struct sg_type_t { + uint32_t sg_type; + /**< + * @h2xmle_rangeList {"SUB_GRAPH_TYPE_STREAM"=1; + * "SUB_GRAPH_TYPE_DEVCICE"=2; + * "SUB_GRAPH_TYPE_STREAM_DEVICE"=3; + * "SUB_GRAPH_TYPE_STREAM_PP"=4; + * "SUB_GRAPH_TYPE_DEVCICE_PP"=5} + * @h2xmle_default {1} + * @h2xmle_description {} + */ +}; + +#endif diff --git a/gsl/api/gsl_subgraph_driver_props.xml b/gsl/api/gsl_subgraph_driver_props.xml new file mode 100644 index 0000000..56851ca --- /dev/null +++ b/gsl/api/gsl_subgraph_driver_props.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/gsl/api/gsl_subgraph_platform_driver_props.xml b/gsl/api/gsl_subgraph_platform_driver_props.xml new file mode 100644 index 0000000..0d05338 --- /dev/null +++ b/gsl/api/gsl_subgraph_platform_driver_props.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/gsl/dls_client_api/gsl_dls_client_intf.h b/gsl/dls_client_api/gsl_dls_client_intf.h new file mode 100644 index 0000000..53ba41e --- /dev/null +++ b/gsl/dls_client_api/gsl_dls_client_intf.h @@ -0,0 +1,149 @@ +#ifndef GSL_DLS_CLIENT_INTF_H +#define GSL_DLS_CLIENT_INTF_H +/** + * \file gsl_dls_client_intf.h + * + * \brief + * Defines a set of APIs that the realtime tuning client can use to + * register log codes and recieve log packet data from the gsl dls + * client + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +#include "ar_osal_types.h" + + /* The minimum number of DLS buffers allowed*/ +#define GSL_DLS_CLIENT_MIN_BUFFER_COUNT 10 + +/* The maximum number of DLS buffers allowed*/ +#define GSL_DLS_CLIENT_MAX_BUFFER_COUNT 256 + +struct gsl_dls_ready_buffer_index_list_t +{ + /* + * The number of buffers that are ready to read from + */ + uint16_t buffer_count; + /* + * List of dls log buffer indexes + */ + uint16_t buffer_index_list[GSL_DLS_CLIENT_MAX_BUFFER_COUNT]; +}; + +struct gsl_dls_buffer_pool_config_t +{ + /* The size of a single binary log packet buffer */ + uint32_t buffer_size; + /* The number of binary log buffers */ + uint32_t buffer_count; +}; + +struct gls_dls_buffer_t +{ + /* The size of the buffer */ + uint32_t size; + /* A pointer to the buffer */ + uint8_t* buffer; +}; + +/** + * \brief callback function that is called when SPF notifies the DLS client + * about buffers that are ready to read. + * + * \return AR_EOK on success, error otherwise + */ +typedef int32_t(*GSL_DLS_CLIENT_BUFFER_READY_CALLBACK)(void); + +/** + * \brief Checks if the DLS feature is enabled in GSL + * \detdesc + * feature needs to be enabled by defining ATS_DATA_LOGGING in your build configuration + * \return AR_EOK on success, AR_EUNSUPPORTED otherwise + */ +int32_t gsl_dls_client_is_feature_supported(); + +/** + * \brief Initializes the DLS Client + * + * \param[in] buffer_pool_config: configuration used to setup the dls buffer pool size. + * \param[in] callback: callback function that is called when SPF notifies the DLS client about buffers that are ready to read. + * + * \return AR_EOK on success, error otherwise + */ +int32_t gsl_dls_client_init(struct gsl_dls_buffer_pool_config_t* buffer_pool_config, GSL_DLS_CLIENT_BUFFER_READY_CALLBACK callback); + +/** + * \brief Cleans up resources aquired during gsl_dls_client_init(...) + * + * \return AR_EOK on success, error otherwise + */ +int32_t gsl_dls_client_deinit(); + +/** + * \brief Allocates and configures shared memory for storing log buffers and registers + * for log buffer commit notifications from DLS on SPF + * + * \param[in] buffer_pool_config: contains the number of DLS Log Buffers and the size of each buffer + * + * \return AR_EOK on success, error otherwise + */ +int32_t gsl_dls_client_create_buffer_pool(struct gsl_dls_buffer_pool_config_t* buffer_pool_config); + +/** + * \brief Retrieves a list of buffers index for dls buffers that are ready to read from + * + * \param[in] buffer_ready_list: + * + * \return AR_EOK on success, error otherwise + */ +void gsl_dls_client_get_ready_dls_buffer_list(struct gsl_dls_ready_buffer_index_list_t* buffer_ready_list); + +/** + * \brief Gets a log buffer from the dls buffer pool + * + * \param[in] buffer_index_read: the index of the buffer to read from the dls buffer pool + * \param[out] dls_log_buffer: contains the size of the log buffer and a pointer to the buffer in the shared memory buffer pool + * + * \return AR_EOK on success, error otherwise + */ +int32_t gsl_dls_client_get_log_buffer(uint32_t log_buffer_index, struct gls_dls_buffer_t* dls_log_buffer); + +/** + * \brief Stores used log buffers in gsl dsl client context + * + * \param[in] buffer_index_list: list of buffers to be stored + */ +void gsl_dls_client_set_used_buffers(struct gsl_dls_ready_buffer_index_list_t *buffer_index_list); + +/** + * \brief Returns used DLS buffers back to SPF + * + * \param[out] buffer_index_list: the list of buffers to return to DLS on SPF + * + * \return AR_EOK on success, error otherwise + */ +int32_t gsl_dls_client_return_used_buffers(struct gsl_dls_ready_buffer_index_list_t* buffer_index_list); + +/** + * \brief Registers or deregisters a log code. Registered log codes will start to accumulate binary buffers in SPFs DLS + * + * \param[in] log_code: The log code to register/de-register + * \param[in] is_log_code_enabled:true for registering a log code and false for de-registering + * + * \return AR_EOK on success, error otherwise + */ +int32_t gsl_dls_client_register_deregister_log_code(uint32_t log_code, bool_t is_log_code_enabled); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*GSL_DLS_CLIENT_INTF_H*/ diff --git a/gsl/gsl.pc.in b/gsl/gsl.pc.in new file mode 100644 index 0000000..b6313b8 --- /dev/null +++ b/gsl/gsl.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: gsl +Description: gsl library +Version: @LT_VERSION@ +Libs: -L${libdir} -lar-gsl +Cflags: -I${includedir} diff --git a/gsl/hw_rsc_api/gsl_hw_rsc_intf.h b/gsl/hw_rsc_api/gsl_hw_rsc_intf.h new file mode 100644 index 0000000..0a97514 --- /dev/null +++ b/gsl/hw_rsc_api/gsl_hw_rsc_intf.h @@ -0,0 +1,113 @@ +#ifndef GSL_HW_RSC_INTF_H +#define GSL_HW_RSC_INTF_H +/** + * \file gsl_hw_rsc_intf.h + * + * \brief + * GSL Hardware Resource API layer + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "ar_osal_types.h" +#include "gsl_intf.h" + +enum gsl_hw_rsc_command_rsp { + GSL_HW_RSC_REQUEST_RSP, + GSL_HW_RSC_RELEASE_RSP, +}; + +/** + * \brief Request for HW resource configuration. + * Look up into ACDB to retrieve the configuration + * and send request command to SPF PRM module + * + * \param[in] miid: Module instance ID against which HW resource configuration + * is stored in ACDB + * \param[in] key_vect: Key vector used to look up data base for HW resource + * configuration + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_request_hw_rsc_config(uint32_t miid, + const struct gsl_key_vector *key_vect); + +/** + * \brief Release HW resource configuration. + * Look up into ACDB to retrieve the configuration + * and send release command to SPF PRM module + * + * \param[in] miid: Module instance ID against which HW resource configuration + * is stored in ACDB + * \param[in] key_vect: Key vector used to look up data base for HW resource + * configuration + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_release_hw_rsc_config(uint32_t miid, + const struct gsl_key_vector *key_vect); + +/** + * \brief Request for HW resource configuration. + * Clients provide the configuration that needs to + * be sent to SPF PRM module + * + * \param[in] payload: Pointer to HW resource configuration + * payload should be in the form {MIID, PID, size, error_code} followed by + * variable payload. Client is expected to send only one PID at a time + * using this API. + * \param[in] payload_size: Size of the HW resource configuration + * \param[in,out] buff: OPTIONAL buffer to receive the response payload from + * Spf. Will be filled if present. + * \param[in,out] buff_size: OPTIONAL size of memory allocated for buff. + * If buff is written to, contains the number of bytes written. + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_request_hw_rsc_custom_config(const uint8_t *payload, + size_t payload_size, void *buff, uint32_t *buff_size); + +/** + * \brief Release HW resource configuration. + * Clients provide the configuration that needs to + * be sent to SPF PRM module + * + * \param[in] payload: Pointer to HW resource configuration + * payload should be in the form {MIID, PID, size, error_code} followed by + * variable payload. Client is expected to send only one PID at a time + * using this API. + * \param[in] payload_size: Size of the HW resource configuration + * \param[in,out] buff: OPTIONAL buffer to receive the response payload from + * Spf. Will be filled if present. + * \param[in,out] buff_size: OPTIONAL size of memory allocated for buff. + * If buff is written to, contains the number of bytes written. + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_release_hw_rsc_custom_config(const uint8_t *payload, + size_t payload_size, void *buff, uint32_t *buff_size); + +/** + * \brief Initialize GSL HW resource manager layer. + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_hw_rsc_init(void); + +/** + * \brief De-Initialize GSL HW resource manager layer. + * + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_hw_rsc_deinit(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif //GSL_HW_RSC_INTF_H diff --git a/gsl/inc/gsl_common.h b/gsl/inc/gsl_common.h new file mode 100644 index 0000000..5846fe4 --- /dev/null +++ b/gsl/inc/gsl_common.h @@ -0,0 +1,343 @@ +#ifndef GSL_COMMON_H +#define GSL_COMMON_H +/** + * \file gsl_common.h + * + * \brief + * Common header file used by GSL modules. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" +#include "ar_osal_log.h" +#include "ar_osal_file_io.h" +#include "ar_osal_mutex.h" +#include "ar_osal_signal.h" +#include "ar_osal_heap.h" +#include "ar_osal_mem_op.h" +#include "ar_osal_servreg.h" +#include "gpr_ids_domains.h" +#include "gpr_packet.h" +#include "gsl_spf_timeout.h" +#include +#include +#include + +#define GSL_TIMEOUT_NS(x) ((x) * (1000LL) * (1000LL)) +#define GSL_TIMEOUT_US(x) ((x) * (1000LL)) +#define GSL_ALIGN_8BYTE(x) (((x) + 7) & (~7)) +#define GSL_PADDING_8BYTE_ALIGN(x) ((((x) + 7) & 7) ^ 7) +#define GSL_GPR_SRC_DOMAIN_ID GPR_IDS_DOMAIN_ID_APPS_V +#ifdef MDSP_PROC +#define GSL_GPR_DST_DOMAIN_ID GPR_IDS_DOMAIN_ID_MODEM_V +#else +#define GSL_GPR_DST_DOMAIN_ID GPR_IDS_DOMAIN_ID_ADSP_V +#endif +#define GSL_EXT_MEM_HDL_NOT_ALLOCD 0 + +#define DEBUG_TOKEN_MASK 0xFFFFF000 +#define DEBUG_TOKEN_SHIFT 12 +#define INSERT_DEBUG_TOKEN(x, value) (x) = (x) | ((value) << DEBUG_TOKEN_SHIFT) +#define GET_DEBUG_TOKEN(x, value) (value) = ((x) & DEBUG_TOKEN_MASK) \ + >> DEBUG_TOKEN_SHIFT +#define REMOVE_DEBUG_TOKEN(x) (x) = ((x) & ~DEBUG_TOKEN_MASK) + +#define GSL_GET_SPF_SS_MASK(OSAL_SYS_ID) (1<<(OSAL_SYS_ID - 1)) +#define GSL_TEST_SPF_SS_BIT(SPF_SS_MASK, OSAL_SYS_ID) \ +((OSAL_SYS_ID) && ((SPF_SS_MASK) \ +& GSL_GET_SPF_SS_MASK(OSAL_SYS_ID))>>(OSAL_SYS_ID - 1)) + +#define GSL_LOG_TAG "gsl" +#define GSL_ERR(...) AR_LOG_ERR(GSL_LOG_TAG, __VA_ARGS__) + +#if defined(GSL_LOG_PKT_ENABLE) || defined(GSL_LOG_DATA_ENABLE) +// packet & data logging general +/* for now both data and control are logged to same file */ + +extern ar_fhandle pkt_log_fd; +extern char *gsl_str; +extern ar_osal_mutex_t log_mutex; +static uint32_t log_file_ref_count; + +#ifndef GSL_PKT_LOG_PATH +#define GSL_PKT_LOG_PATH "gsl_log.bin" +#endif + +#define GSL_PKT_LOG_INIT() \ +do {\ +log_file_ref_count = 0; \ +ar_osal_mutex_create(&log_mutex); \ +} while (0) + +#define GSL_PKT_LOG_OPEN(FILE_ACCESS) \ +do {\ +GSL_MUTEX_LOCK(log_mutex); \ +log_file_ref_count++; \ +if (pkt_log_fd == NULL && log_file_ref_count == 1) {\ +ar_fopen(&pkt_log_fd, GSL_PKT_LOG_PATH, FILE_ACCESS);\ +} \ +GSL_MUTEX_UNLOCK(log_mutex); \ +} while (0) + + +#define GSL_PKT_LOG_CLOSE() \ +do {\ +GSL_MUTEX_LOCK(log_mutex); \ +if (log_file_ref_count > 0) \ +log_file_ref_count--; \ +if (pkt_log_fd != NULL && log_file_ref_count == 0) {\ +ar_fclose(pkt_log_fd); \ +pkt_log_fd = NULL; \ +} \ +GSL_MUTEX_UNLOCK(log_mutex); \ +} while (0) + +/* + * @param DST_FD File descriptor where logs will be logged to + * @param ID_STR MUST be exactly 8 chars, string that will be placed in the log + * before BUFF to help in parsing + * @param META_DATA 4-byte meta-data field that caller can set to anything + * @param DATA_BUFF pointer to buffer that will be written to log + * @param DATA_SIZE size of the buffer above + * @param OOB_BUFF optional out-of-band or second buffer to also write to log + * @param OOB_SIZE size of the second buffer above + */ +#define GSL_PKT_LOG_TO_FILE(DST_FD, ID_STR, META_DATA, DATA_BUFF, DATA_SIZE, \ +OOB_BUFF, OOB_SIZE)\ +do {\ +GSL_MUTEX_LOCK(log_mutex); \ +if (pkt_log_fd != NULL) {\ +size_t bytes_written; \ +char *id_str = ID_STR; \ +uint32_t metadata = META_DATA; \ +uint32_t metadata_size = sizeof(metadata); \ +uint32_t packet_size = DATA_SIZE + OOB_SIZE + metadata_size \ ++ sizeof(metadata_size); \ +ar_fwrite(DST_FD, gsl_str, strlen(gsl_str), &bytes_written); \ +ar_fwrite(DST_FD, id_str, strlen(id_str), &bytes_written); \ +ar_fwrite(DST_FD, &packet_size, sizeof(packet_size), &bytes_written); \ +ar_fwrite(DST_FD, &metadata_size, sizeof(metadata_size), &bytes_written); \ +ar_fwrite(DST_FD, &metadata, metadata_size, &bytes_written); \ +if (0 != DATA_SIZE) \ +ar_fwrite(DST_FD, DATA_BUFF, DATA_SIZE, &bytes_written); \ +if (0 != OOB_SIZE) \ +ar_fwrite(DST_FD, OOB_BUFF, OOB_SIZE, &bytes_written); \ +} \ +GSL_MUTEX_UNLOCK(log_mutex); \ +} while (0) + +#define GSL_PKT_LOG_DEINIT() \ +do { \ +if (pkt_log_fd != NULL) {\ +ar_fclose(pkt_log_fd); \ +pkt_log_fd = NULL; \ +} \ +ar_osal_mutex_destroy(log_mutex); \ +} while (0) +#else +#define GSL_PKT_LOG_INIT() +#define GSL_PKT_LOG_DEINIT() +#define GSL_PKT_LOG_OPEN(FILE_ACCESS) +#define GSL_PKT_LOG_CLOSE() +#endif + +#ifdef GSL_LOG_PKT_ENABLE +#define GSL_LOG_PKT(ID_STR, META_DATA, PKT_BUFF, PKT_SIZE, \ +OOB_BUFF, OOB_SIZE) \ +GSL_PKT_LOG_TO_FILE(pkt_log_fd, ID_STR, META_DATA, PKT_BUFF, PKT_SIZE, \ +OOB_BUFF, OOB_SIZE) +#else +#define GSL_LOG_PKT(ID_STR, META_DATA, PKT_BUFF, PKT_SIZE, OOB_BUFF, OOB_SIZE) +#endif //GSL_LOG_PKT_ENABLE + +#ifdef GSL_LOG_DATA_ENABLE +#define GSL_PKT_LOG_DATA(ID_STR, META_DATA, BUFF, SIZE) \ +GSL_PKT_LOG_TO_FILE(pkt_log_fd, ID_STR, META_DATA, BUFF, SIZE, NULL, 0) +#else +#define GSL_PKT_LOG_DATA(ID_STR, META_DATA, BUFF, SIZE) +#endif // GSL_LOG_DATA_ENABLE + +#ifdef GSL_DEBUG_ENABLE +#define GSL_DBG(...) AR_LOG_DEBUG(GSL_LOG_TAG, __VA_ARGS__) +#define GSL_INFO(...) AR_LOG_INFO(GSL_LOG_TAG, __VA_ARGS__) +#define GSL_VERBOSE(...) AR_LOG_VERBOSE(GSL_LOG_TAG, __VA_ARGS__) + +static inline void gsl_print_sg_conn_info(uint32_t *sg_conn_info, + uint32_t num_sgs) +{ + uint32_t i = 0, num_children = 0; + uint32_t *p = sg_conn_info; + + GSL_DBG("num_sg_conn = %d", num_sgs); + for (i = 0; i < num_sgs; ++i) { + GSL_DBG("sg %x has %d children:", *(p), num_children = *(p + 1)); + p += 2; + while (num_children) { + GSL_DBG("%x, ", *(p++)); + --num_children; + } + } +} + +#else +#define GSL_LOG_TAG "gsl" +#define GSL_DBG(...) +#define GSL_INFO(...) +#define GSL_VERBOSE(...) +#define GSL_PRINT_SG_CONN_INFO(SG_CONN_INFO_PTR) +static inline void gsl_print_sg_conn_info(uint32_t *sg_conn_info, + uint32_t num_sgs) +{ (void) sg_conn_info; (void) num_sgs; /* keep compiler happy */ } +#endif /* GSL_DEBUG_ENABLE */ + + /** get container base address given a member from the same structure */ +#define get_container_base(p, type, member) ((type *)( \ + (int8_t *)(p)- \ + (uintptr_t)(&((type *)0)->member))) + + +#define test_bit(var, bit_pos) ((var) & (1 << (bit_pos))) +#define set_bit(var, bit_pos) (var = (var) | (1 << (bit_pos))) +#define clear_bit(var, bit_pos) (var = (var) & (~(1 << (bit_pos)))) +#define get_bit(var, bit_pos) (((var) & (1 << (bit_pos)))>>(bit_pos)) + +#define GSL_MUTEX_LOCK(lock) \ + do { \ + if (lock) \ + if (ar_osal_mutex_lock(lock)) \ + GSL_ERR("failed to acquire mutex"); \ + } while (0) + +#define GSL_MUTEX_UNLOCK(lock) \ + do { \ + if (lock) \ + if (ar_osal_mutex_unlock(lock)) \ + GSL_ERR("failed to release mutex"); \ + } while (0) + +/* used to decode basic responses from Spf */ +struct spf_cmd_basic_rsp { + uint32_t opcode; + int32_t status; +}; + + /** Graph signal object structure */ +struct gsl_signal { + /** signal object */ + ar_osal_signal_t sig; + /** + * mutex used to synchronize access to below data + */ + ar_osal_mutex_t *lock; + /** + * bitmask that indicates which events caused the signal to get set + * GSL_GRAPH_SIG_FLAG_SPF_RSP --> response was received from spf + * GSL_GRAPH_SIG_FLAG_CLOSE --> close was triggered from client + */ + uint32_t flags; + /** signal status */ + int32_t status; + /** gpr packet pointer */ + void *gpr_packet; + /** gpr expected packet token */ + uint32_t expected_packet_token; +}; + +enum gsl_graph_sig_event_mask { + GSL_SIG_EVENT_MASK_SPF_RSP = 0x1, + GSL_SIG_EVENT_MASK_CLOSE = 0x2, + GSL_SIG_EVENT_MASK_RTGM_DONE = 0x4, + GSL_SIG_EVENT_CLIENT_OP_DONE = 0x8, + GSL_SIG_EVENT_MASK_SSR = 0x10 +}; + +struct gsl_servreg_handle_list { + uint32_t num_handles; + ar_osal_servreg_t handles[]; +}; + +/** signal functions */ +uint32_t gsl_signal_create(struct gsl_signal *sig_p, ar_osal_mutex_t *lock); +uint32_t gsl_signal_destroy(struct gsl_signal *sig_p); +uint32_t gsl_signal_timedwait(struct gsl_signal *sig_p, uint32_t timeout_ms, + uint32_t *ev_flags, uint32_t *status, gpr_packet_t **gpr_pkt); +uint32_t gsl_signal_set(struct gsl_signal *sig_p, uint32_t ev_flags, + int32_t status, void *gpr_pkt); +uint32_t gsl_signal_clear(struct gsl_signal *sig_p, uint32_t ev_flags); +int32_t gsl_allocate_gpr_packet(uint32_t opcode, uint32_t src_port, + uint32_t dst_port, uint32_t payload_size, uint32_t token, + uint32_t dest_domain, struct gpr_packet_t **alloc_packet); +int32_t gsl_send_spf_cmd(struct gpr_packet_t **packet, + struct gsl_signal *sig_p, gpr_packet_t **rsp_pkt); +int32_t gsl_send_spf_cmd_wait_for_basic_rsp(gpr_packet_t **packet, + struct gsl_signal *sig_p); +int32_t gsl_send_spf_satellite_info(uint32_t proc_id, + uint32_t supported_ss_mask, uint32_t src_port, struct gsl_signal *sig_p); + +/** memory allocation helper functions */ +static inline void *gsl_mem_zalloc(size_t size) +{ + void *p; + + static ar_heap_info heap_info = { + .align_bytes = AR_HEAP_ALIGN_DEFAULT, + .pool_type = AR_HEAP_POOL_DEFAULT, + .heap_id = AR_HEAP_ID_DEFAULT, + .tag = AR_HEAP_TAG_DEFAULT + }; + + /* allocate and initialize with 0 */ + p = ar_heap_calloc(size, &heap_info); + + return p; +} + +static inline void gsl_mem_free(void *p) +{ + static ar_heap_info heap_info = { + .align_bytes = AR_HEAP_ALIGN_DEFAULT, + .pool_type = AR_HEAP_POOL_DEFAULT, + .heap_id = AR_HEAP_ID_DEFAULT, + .tag = AR_HEAP_TAG_DEFAULT + }; + + ar_heap_free(p, &heap_info); +} + +static inline int32_t gsl_memset(void *p, int32_t val, size_t size) +{ + return ar_mem_set(p, val, size); +} + +static inline int32_t gsl_memcpy(void *dst, size_t dst_size, const void *src, + size_t size) +{ + return ar_mem_cpy(dst, dst_size, src, size); +} + +static inline void *gsl_mem_realloc(void *p, size_t old_sz, size_t new_sz) +{ + void *new_p = NULL; + static ar_heap_info heap_info = { + .align_bytes = AR_HEAP_ALIGN_DEFAULT, + .pool_type = AR_HEAP_POOL_DEFAULT, + .heap_id = AR_HEAP_ID_DEFAULT, + .tag = AR_HEAP_TAG_DEFAULT + }; + + new_p = ar_heap_malloc(new_sz, &heap_info); + if (!new_p) { + GSL_ERR("ar_heap_malloc alloc mem failed!"); + } else { + gsl_memset(new_p, 0, new_sz); + gsl_memcpy(new_p, new_sz, p, old_sz); + ar_heap_free(p, &heap_info); + } + + return new_p; +} + +#endif diff --git a/gsl/inc/gsl_cshm_mgr.h b/gsl/inc/gsl_cshm_mgr.h new file mode 100644 index 0000000..6cd218f --- /dev/null +++ b/gsl/inc/gsl_cshm_mgr.h @@ -0,0 +1,86 @@ +#ifndef GSL_CSHM_MGR_H +#define GSL_CSHM_MGR_H +/** + * \file gsl_cshm_mgr.h + * + * \brief + * Manages client shared memory allocations in the system + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ +#include +#include "ar_osal_shmem.h" +#include "ar_util_list.h" +#include "ar_osal_mutex.h" +#include "ar_osal_signal.h" +#include "ar_osal_error.h" +#include "ar_osal_sys_id.h" +#include "gsl_spf_ss_state.h" + +/** Default number of clients supported during initilization.*/ +#define CSHM_DEFAULT_INIT_CLIENT_NUM 50 +/** Page size used by cshm manager.*/ +#define GSL_CSHM_MGR_PAGE_SZ 4096 +/** Returns true if shmem buffer uses offset mode.*/ +#define GSL_SHMEM_IS_OFFSET_MODE(type) \ +(((ar_shmem_buffer_index_type_t)(type)) == AR_SHMEM_BUFFER_OFFSET) +/** Source port identifier for client shmem communication.*/ +#define GSL_CSHMEM_SRC_PORT 0x2009 +/** Magic word to validate shmem region.GSL*/ +#define GSL_CSHM_MAGIC_WORD 0x47534D +/** Mask for validating magic word.*/ +#define GSL_MAGIC_WORD_MASK 0xFFFFFF +/** Bit shift used for cshm index encoding.*/ +#define GSL_CSHM_IDX_SHIFT 24 + +struct cshm_info { + /** unique identifier assigned to the shared memory region.*/ + uint32_t mem_id; + /** metadata for shmem allocation from AR.*/ + ar_shmem_info *mem_info; + /** Bitmask of subsystems. */ + uint32_t spf_ss_mask; + /** Indicates if memory contens needs sync.*/ + bool dirty; +}; + +typedef struct cshm_info cshm_info_t; + +static inline gsl_mem_id_t to_gsl_mem_id(uint8_t index) +{ + return (gsl_mem_id_t)((uintptr_t)(GSL_CSHM_MAGIC_WORD | + (index << GSL_CSHM_IDX_SHIFT))); +} + +static inline uint8_t to_gsl_cshm_indx(gsl_mem_id_t mem_id) +{ + return ((uintptr_t)mem_id >> GSL_CSHM_IDX_SHIFT) & 0xff; +} + +static inline bool_t is_valid_gsl_mem_id(gsl_mem_id_t mem_id) +{ + if (((uintptr_t)mem_id & GSL_MAGIC_WORD_MASK) != GSL_CSHM_MAGIC_WORD) { + return false; + } + + return true; +} + +static inline bool is_mem_id_dirty(cshm_info_t * info) +{ + return info->dirty; +} + +static inline void set_mem_id_dirty(cshm_info_t * info, bool val) +{ + info->dirty = val; +} +bool gsl_check_mem_id_present(uint32_t mem_id); +static int32_t gsl_cshm_handle_rsp(gpr_packet_t *rsp, uint32_t expected_opcode); +int32_t gsl_cshm_unmap_to_spf(ar_shmem_info *mem_info, uint32_t mem_id); +int32_t gsl_cshm_map_to_spf(ar_shmem_info *mem_info, uint32_t mem_id); +int32_t gsl_send_glb_msg_to_spf(uint32_t mem_id, uint32_t offset, uint32_t length, + uint32_t miid, ar_shmem_info *mem_info, uint32_t prop_flag); +void gsl_cshm_handle_ssr(enum spf_ss_state_t state, uint32_t spf_ss_mask); +#endif \ No newline at end of file diff --git a/gsl/inc/gsl_datapath.h b/gsl/inc/gsl_datapath.h new file mode 100644 index 0000000..0f92573 --- /dev/null +++ b/gsl/inc/gsl_datapath.h @@ -0,0 +1,362 @@ +#ifndef GSL_DATAPATH_H +#define GSL_DATAPATH_H + +/** + * \file gsl_datapath.h + * + * \brief + * Implement data path handling for Graph Service Layer (GSL) + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include "ar_osal_types.h" +#include "ar_osal_mutex.h" +#include "ar_osal_signal.h" +#include "ar_util_list.h" +#include "ar_osal_error.h" +#include "gsl_intf.h" +#include "gsl_common.h" +#include "gsl_msg_builder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GSL_MAX_NUM_DATA_BUFFERS 16 /* client can at most use this many buffs*/ +#define GSL_DP_DATA_MODE(dp) ((dp)->config.attributes \ +&GSL_ATTRIBUTES_DATA_MODE_MASK) + +#define GSL_DATAPATH_SETUP_MODE(cfg) \ +(((cfg)->attributes & GSL_ATTRIBUTES_DATAPATH_SETUP_MASK) \ +>> GSL_ATTRIBUTES_DATAPATH_SETUP_SHIFT) + +/** + * represents one buffer in GSL + */ +struct gsl_buff_internal { + /** + * memory allocation for this buffer + */ + gsl_msg_t gsl_msg; + + /** + * Used in read scenario only, holds the size of data received from spf. + * for this buffer + */ + uint32_t size_from_spf; + + /** + * Used in read scenario only, holds the time-stamp/flags of the + * buffer received from Spf. + */ + uint64_t spf_timestamp; + uint32_t spf_flags; +}; + +struct gsl_metadata_buff_internal { + /** + * memory allocation for this buffer + */ + gsl_msg_t gsl_msg; + + /* + * metadata buffer passed from clients in read/write + */ + uint8_t *client_md_ptr; + /** + * size of metadata buffer above + */ + uint32_t size; + + /** + * Used in read scenario only, holds the size of metadata received from spf. + * for this buffer + */ + uint32_t md_size_from_spf; + + uint32_t md_status_from_spf; +}; + + +/* this is the context for this module */ +struct gsl_data_path_info { + /** + * client provided configuration for this set of data buffers + */ + struct gsl_cmd_configure_read_write_params config; + + /** + * array of gsl internal buffers, actual number of buffers is stored in + * config.num_buffs + */ + struct gsl_buff_internal *buff_list; + + /** + * array of metadata buffers + */ + struct gsl_metadata_buff_internal *md_buff_list; + + struct gsl_signal dp_signal; + + /** + * buffer avail bitmask - each bit when set indicates corresponding buffer + * is used (not with GSL), when clear indicates buffer is available + * (with GSL) + * + * bit pos 0: indicates buffer number 0 is used or available + * bit pos 1: indicates buffer number 1 is used or available + * . . . + * bit pos num_buffs - 1: buffer number (num_buffs - 1) is used or avail + */ + int32_t buff_used_status; + + /** Buffer available to be queued to spf [0,...,config.num_buffs) */ + int32_t curr_buff_index; + + /** + * next metadata buffer available + * [0,...,GSL_MAX_NUM_DATA_BUFFERS) + * + */ + uint32_t md_buff_list_head; + + /** + * oldest metadata buffer that is already used + * [0,...,GSL_MAX_NUM_DATA_BUFFERS) + */ + uint32_t md_buff_list_tail; + + /** + * oldest metadata buffer that has not yet been acked by spf + * [0,...,GSL_MAX_NUM_DATA_BUFFERS) + */ + uint32_t md_buff_list_acked; + + /* + * number of md buffers = GSL_METADATA_TO_DATA_FACTOR * + * number_of_data_buffers + */ + uint32_t md_buff_list_size; + + /** Lock used to mark buffers as available or used */ + ar_osal_mutex_t lock; + + /** + * Used to cache the module iid and tag from previous read/write, if they + * are the same then skip acdb look-up + */ + uint32_t miid; + uint32_t cached_tag; + + /** + * Keeps count of number of buffers sent to or received from spf + * Incremented by 1 everytime we get a read or write done from spf + */ + uint32_t processed_buf_cnt; + + uint32_t src_port; + + bool_t oob_metadata_flag; + + uint32_t master_proc_id; + + bool_t is_shmem_supported; +}; + +/** + * \brief instantiate global refcount lock + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_dp_create_cache_refcount_lock(void); + +/** + * \brief destroy global refcount lock + */ +void gsl_dp_destroy_cache_refcount_lock(void); + +/** + * \brief initialise a new data path for a graph + * + * \param[in] dp_info: pointer to datapath to init + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_data_path_init(struct gsl_data_path_info *dp_info); + +/** + * \brief tear down a data path for a graph + * + * \param[in] dp_info: pointer to datapath to deinit + */ +void gsl_data_path_deinit(struct gsl_data_path_info *dp_info); + +/** + * \brief Configure a data path + * + * \param[in] dp_info: pointer to data path + * \param[in] cfg: configuration params from client + * + * These 3 params are for push pull setup: + * \param[in] src_port: source port of the parent graph + * \param[in] cfg_signal: signal used for sending CFG on parent graph (GRP_2) + * \param[in] dir: whether graph is read or write + * + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \param[in] proc_id: master proc id corresponding to the usecase. + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_dp_config_data_path(struct gsl_data_path_info *dp_info, + struct gsl_cmd_configure_read_write_params *cfg, uint32_t src_port, + struct gsl_signal *cfg_signal, enum gsl_data_dir dir, + ar_osal_mutex_t lock, uint32_t proc_id); + +/** + * \brief Read data from a datapath + * + * \param[in] dp_info: pointer to data path + * \param[in] buff: holds the buffer info for data being read + * \param[out] filled_size: used to return number of bytes actually read + * + * \return AR_EOK on success, + * AR_EABORTED when buffer is not queued to spf because of graph + * close, stop, or flush (non-fatal error), + * error code otherwise + */ +int32_t gsl_dp_read(struct gsl_data_path_info *dp_info, struct gsl_buff *buff, + uint32_t *filled_size); + +/** + * \brief Write data to a datapath + * + * \param[in] dp_info: pointer to data path + * \param[in] buff: holds the buffer info for data being written + * \param[out] consumed_size: used to return number of bytes actually written + * + * \return AR_EOK on success, + * AR_EABORTED when buffer is not queued to spf because of graph + * close, stop, or flush (non-fatal error), + * error code otherwise + */ +int32_t gsl_dp_write(struct gsl_data_path_info *dp_info, struct gsl_buff *buff, + uint32_t *consumed_size); + +/** + * \brief Issue an EOS data path command to Spf + * + * \param[in] dp_info: pointer to a datapath + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_dp_write_send_eos(struct gsl_data_path_info *dp_info); + +/** + * \brief handle buf done on a read datapath + * + * \param[in] dp_info: pointer to data path + * \param[in] packet: GPR packet received in callback + * \param[in] cb: client callback registered with GSL + * \param[in] client_data: pointer to payload for client callback + * + * \return AR_EOK on success, + * error code otherwise + */ + +int32_t gsl_handle_read_buff_done(struct gsl_data_path_info *dp_info, + gpr_packet_t *packet, gsl_cb_func_ptr cb, void *client_data); + +/** + * \brief handle buf done for media format buffer + * on a write datapath + * + * \param[in] dp_info: pointer to data path + * \param[in] packet: GPR packet received in callback + * + * \return AR_EOK on success + */ +int32_t gsl_handle_media_format_buff_done(struct gsl_data_path_info *dp_info, + gpr_packet_t *packet); + +/** + * \brief handle buf done on a write datapath + * + * \param[in] dp_info: pointer to data path + * \param[in] packet: GPR packet received in callback + * \param[in] cb: client callback registered with GSL + * \param[in] client_data: pointer to payload for client callback + * + * \return AR_EOK on success, + * error code otherwise + */ +int32_t gsl_handle_write_buff_done(struct gsl_data_path_info *dp_info, + gpr_packet_t *packet, gsl_cb_func_ptr cb, void *client_data); + +/** + * \brief Get data buffer pointers and other info for this datapath + * + * \param[in] dp_info: pointer to a datapath + * \param[in,out] cfg: used to return information regarding the buffers + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_dp_get_buff_info(struct gsl_data_path_info *dp_info, + struct gsl_cmd_get_shmem_buf_info *cfg); + +/** + * \brief Get pos buffer pointers and other info for this datapath + * + * \param[in] dp_info: pointer to a datapath + * \param[in,out] cfg: used to return information regarding the buffers + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_dp_get_pos_buff_info(struct gsl_data_path_info *dp_info, + struct gsl_cmd_get_shmem_buf_info *cfg); + +/** + * \brief get processed buffer count for a graph + * + * \param[in] dp_info: pointer to a datapath + * + * \return the number of processed buffers + */ +uint32_t gsl_dp_get_processed_buff_cnt(struct gsl_data_path_info *dp_info); + +/** + * \brief get available buffer size for a graph path + * + * \param[in] dp_info: pointer to a datapath + * + * \return the size of available buffer (in bytes) + */ +uint32_t gsl_dp_get_avail_buffer_size(struct gsl_data_path_info *dp_info); + +/** + * \brief wait for all buffers to come back on a datapath + * + * \param[in] dp_info: pointer to a datapath + * + * \return AR_EOK on success, error code otherwise + */ + +int32_t gsl_wait_for_all_buffs_to_be_avail(struct gsl_data_path_info *dp_info); + +/** + * \brief queue all buffs on a read datapath to SPF + * + * \param[in] dp_info: pointer to a datapath + * + * \return AR_EOK on success, error code otherwise + */ + +int32_t gsl_dp_queue_read_buffers_to_spf(struct gsl_data_path_info *dp_info); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* GSL_DATAPATH_H */ diff --git a/gsl/inc/gsl_dls_client.h b/gsl/inc/gsl_dls_client.h new file mode 100644 index 0000000..7079987 --- /dev/null +++ b/gsl/inc/gsl_dls_client.h @@ -0,0 +1,80 @@ +#ifndef GSL_DLS_CLIENT_H +#define GSL_DLS_CLIENT_H +/** + * \file gsl_dls_client.h + * \brief + * Contains definitions used by the Data Logging Service (DLS) client + * + * This module is responsible for delivering binary log + * packet data to the gsl realtime tunning client. GSL subscribes + * subscription to dls event notifications from SPF. The gsl + * realtime tuning client registers the log codes it wants to + * recieve data for. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +#include "apm_api.h" +#include "dls_api.h" +#include "gsl_shmem_mgr.h" +#include "gsl_common.h" +#include "gsl_dls_client_intf.h" + +#define GSL_DLS_CLIENT_GPR_SRC_PORT 0x3003 +#define GSL_DLS_CLIENT_SHMEM_MAX_BUFFER_SZ_SHIFT 13 /* page size = 8192 B*/ +#define GSL_DLS_CLIENT_SHMEM_MAX_BUFFER_SZ (1 << GSL_DLS_CLIENT_SHMEM_MAX_BUFFER_SZ_SHIFT) + +#define GSL_DLS_CLIENT_SHMEM_MIN_BUFFER_SZ_SHIFT 11 /* page size = 2048 B*/ +#define GSL_DLS_CLIENT_SHMEM_MIN_BUFFER_SZ (1 << GSL_DLS_CLIENT_SHMEM_MIN_BUFFER_SZ_SHIFT) + +enum gsl_dls_commit_log_buffer_register_enum_t +{ + GLS_DLS_EVENT_FLAG_DEREGISTER_COMMIT_LOG_BUFFER = 0, + GLS_DLS_EVENT_FLAG_REGISTER_COMMIT_LOG_BUFFER = 1, +}; + +struct gsl_dls_client_ctxt +{ + GSL_DLS_CLIENT_BUFFER_READY_CALLBACK buffer_ready_callback; + /** + * 1 Indicates dls is configured with default configuration + * 0 Otherwise + */ + int32_t is_dls_buffer_configured; + /** + * The configuration for the buffer pool used throught the session + */ + struct gsl_dls_buffer_pool_config_t buffer_pool_config; + /** + * Shared memory for storing DLS binary log packets used for realtime monitoring + */ + struct gsl_shmem_alloc_data dls_shmem; + /** + * Signal used to wait for responses from spf + */ + struct gsl_signal sig; + /** + * lock used in conjuction with above signal + */ + ar_osal_mutex_t sig_lock; + /** + * for signaling when to return used buffers to spf + */ + struct gsl_signal ready_buffer_sig; + /** + * List of used buffers to send to spf + */ + struct gsl_dls_ready_buffer_index_list_t used_buffers; +}; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*GSL_DLS_CLIENT_H*/ diff --git a/gsl/inc/gsl_dynamic_module_mgr.h b/gsl/inc/gsl_dynamic_module_mgr.h new file mode 100644 index 0000000..ba6d363 --- /dev/null +++ b/gsl/inc/gsl_dynamic_module_mgr.h @@ -0,0 +1,58 @@ +#ifndef GSL_SPF_DYN_MODULE_MGR_H +#define GSL_SPF_DYN_MODULE_MGR_H +/** + * \file gsl_dynamic_module_mgr.h + * + * \brief + * Manages the loading and unloading of Spf dynamic modules + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ar_osal_types.h" +#include "gsl_common.h" +#include "gsl_intf.h" + + +/* + * \brief initialise dynamic module mgr + * + * \param[in] num_master_procs: Number of SPF masters + * \param[in] master_procs: Array of SPF master proc ids + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_dynamic_module_mgr_init(uint32_t num_master_procs, + uint32_t *master_procs); + + +/* + * \brief deinitialise dynamic module mgr + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_dynamic_module_mgr_deinit(void); + +/* + * \brief Load or reload bootup dynamic modules to spf + * + * \param[in] master_proc: SPF master proc id + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_do_load_bootup_dyn_modules(uint32_t master_proc, + gsl_acdb_handle_t handle); + +/* + * \brief Unload bootup dynamic modules to spf + * + * \param[in] master_proc: SPF master proc id + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_do_unload_bootup_dyn_modules(uint32_t master_proc, + gsl_acdb_handle_t handle); + + +#endif //GSL_SPF_DYN_MODULE_MGR_H diff --git a/gsl/inc/gsl_global_persist_cal.h b/gsl/inc/gsl_global_persist_cal.h new file mode 100644 index 0000000..23d1c64 --- /dev/null +++ b/gsl/inc/gsl_global_persist_cal.h @@ -0,0 +1,77 @@ +#ifndef GSL_GLOBAL_PERSIST_CAL_H +#define GSL_GLOBAL_PERSIST_CAL_H +/** + * \file gsl_global_persist_cal.h + * + * \brief + * Manages global persist cal for subgraphs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gsl_shmem_mgr.h" +#include "acdb.h" +#include "ar_util_list.h" + +#define GSL_MAX_IIDS_PER_GP_CAL 10 + +struct gsl_glbl_persist_cal { + struct ar_list_node_t node; + uint32_t cal_id; + uint32_t ref_cnt; + struct gsl_shmem_alloc_data cal_data; + uint32_t cal_data_size; +}; + +struct gsl_glbl_persist_cal_iid_list { + /* assumed that there is a maximum number of IIDs per cal for ease of + * allocating space + */ + uint32_t iids[GSL_MAX_IIDS_PER_GP_CAL]; + uint8_t num_iids; + struct gsl_glbl_persist_cal *gpcal; +}; + +/* ********************************** */ +/* GLOBAL PERSIST CAL POOL MANAGEMENT */ +/* ********************************** */ + + /** + * \brief initialize the data structure used for the pool + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_global_persist_cal_pool_init(void); + +/** + * \brief Deinitialize the data structure used for the pool + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_global_persist_cal_pool_deinit(void); + +/** + * \brief Add a cal to the pool + * + * \param[in] cal_id: identifier of global persist cal to add to/find in pool + * \param[in] cal_data_size: size of ACDB data associated with this cal_id + * \param[in] master_proc: SPF master proc id + * \param[out] cal_data: Set to NULL when we already have ACDB data for this + * cal_id in the pool. Otherwise holds pointer to shmem + * object into which to fill the data for this cal_id + * + * \return pointer to global persist cal object which was added to pool + */ +struct gsl_glbl_persist_cal *gsl_global_persist_cal_pool_add(uint32_t cal_id, + uint32_t cal_data_size, struct gsl_shmem_alloc_data **cal_data, + uint32_t master_proc); + +/** + * \brief Remove a cal from pool + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_global_persist_cal_pool_remove(struct gsl_glbl_persist_cal *gpc); + +#endif /* GSL_GLOBAL_PERSIST_CAL */ diff --git a/gsl/inc/gsl_graph.h b/gsl/inc/gsl_graph.h new file mode 100644 index 0000000..88c8d4b --- /dev/null +++ b/gsl/inc/gsl_graph.h @@ -0,0 +1,718 @@ +#ifndef GSL_GRAPH_H +#define GSL_GRAPH_H +/** + * \file gsl_graph.h + * + * \brief + * Graph management layer header for Graph Service Layer (GSL). + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" +#include "ar_osal_mutex.h" +#include "ar_osal_signal.h" +#include "ar_util_list.h" +#include "ar_osal_error.h" +#include "gsl_intf.h" +#include "gsl_subgraph.h" +#include "gsl_common.h" +#include "gsl_datapath.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GSL_MAX_NUM_DATA_BUFFERS 16 /* client can at most use this many buffs*/ + +/** Graph states enumeration */ +enum gsl_graph_states { + /** Graph initialized */ + GRAPH_IDLE, + /** Graph successfully opened on SPF */ + GRAPH_OPENED, + /** Graph started on SPF */ + GRAPH_STARTED, + /** Graph stoped on SPF */ + GRAPH_STOPPED, + /** Graph closed on SPF, but not deinited */ + GRAPH_CLOSED, + /** + * Graph is an error state but clean-up operations (such as close) on SPF + * are allowed + */ + GRAPH_ERROR_ALLOW_CLEANUP, + /** + * Graph is in an unrecoverable error state no spf operations are allowed + */ + GRAPH_ERROR, +}; + +/** Graph signals enumeration */ +enum gsl_graph_sig { + GRAPH_CTRL_GRP1_CMD_SIG, + /**< + * Signal used to wait for response from group 1 SPF control requests, + * it is assumed that requests within this group are serialized by the + * client. Group 1 includes: OPEN, PREPARE, START and STOP, + * CONFIGURE_READ_BUFFERS, CONFIGURE_WRITE_BUFFERS + */ + GRAPH_CTRL_GRP2_CMD_SIG, + /**< + * Signal used to wait for response from group 2 SPF control requests, + * it is assumed that these requests are serialized by the client. Group 2 + * includes: SET_CFG, REGISTER_CFG, FLUSH and REGSITER_MODULE_EVENTS + */ + GRAPH_CTRL_GRP3_CMD_SIG, + /**< + * Signal used to wait for response from group 3 SPF control requests, + * it is assumed that these requests are serialized by the client. + * Group 3 includes: CLOSE + * Group 3 should also not conflict with group 1, but is separated here to + * prevent improper behaviour when a command of group 1 interferes with a + * command of group 3 by e.g. timing out then returning before + * ex: start times out, GSL decides to close malfunctioning graph and sends + * close, then SPF returns response for start before close + */ + GRAPH_CMD_SIG_MAX, /**< Max signals */ +}; + +/** Subgraph connection data structure */ +struct gsl_graph_sg_conn_data { + uint32_t num_sgs; /**< number of subgraphs in the connection data */ + size_t size; /**< size of the subgraph connection data */ + AcdbSubgraph *subgraphs; /**< subgraph connection data structure */ +}; + +struct gsl_transient_state_info { + /** flags to indicate when certain transient operations are in progress */ + bool_t flush_in_prog; + bool_t read_in_prog; + bool_t write_in_prog; + bool_t stop_in_prog; + + /** + * signal to tell flush and stop when it is safe to proceed + * Note that it is not under a lock, so do not use the flags or status + */ + struct gsl_signal trans_state_change_sig; +}; + +/* used to cache some RTC related data for this graph */ +struct gsl_graph_rtc_cache { + /* + * these are used as a temporary cache to store the sgids and connections + * that will need to be opened at the end of RTGM sequence + */ + struct gsl_graph_sg_conn_data pruned_plus_reopen_sg_conn; + /* + * These cache the param data on what was modified only. We need to + * decrement and then re-increment the open refcounts so that they close + * properly in RTCs which close an SG/conn shared by multiple graphs. + */ + struct gsl_sgid_list preserved_sgids; + struct gsl_graph_sg_conn_data preserved_sg_conn; +}; + +/** GKV node structure */ +struct gsl_graph_gkv_node { + ar_list_node_t node; + /** pointer to GKV */ + struct gsl_key_vector gkv; + /** pointer to CKV */ + struct gsl_key_vector ckv; + /** Number of subgraphs in gkv */ + uint32_t num_of_subgraphs; + /** Array of size num_of_subgraphs to hold subgraph memory pointers */ + struct gsl_subgraph **sg_array; + /** Number of cals in global persist cal list */ + uint32_t num_of_gp_cals; + /** + * Array of size num_of_gp_cals. Holds references to global persist cals + * and all IIDs associated with that cal. + */ + struct gsl_glbl_persist_cal_iid_list *glbl_persist_cal_list; + /** subgraph connection data */ + struct gsl_graph_sg_conn_data sg_conn_data; + + /** + * Cannot have more than 32 subgraphs in a GKV + * Each bit indicate whether that particular subgraph + * is stopped or not from this gkv_node + */ + uint32_t sg_stop_mask; + + /** + * Cannot have more than 32 subgraphs in a GKV + * Each bit indicate whether that particular subgraph + * is started or not from this gkv_node + */ + uint32_t sg_start_mask; + /** + * bit mask: each bit indicates whether the SGs in this GKV require a + * specific spf subsystem (e.g. ADSP, CDSP..etc). Use the macros defined + * in gsl_spf_ss_state.h in-conjunction with the sys-ids in + * ar_osal_sys_id.h to get/set these bits + */ + uint32_t spf_ss_mask; + /* + * used to cache data during real-time calibration operations such as graph + * change. Not used outside of real-time calibration + */ + struct gsl_graph_rtc_cache rtc_cache; +}; + +/** Graph data structure */ +struct gsl_graph { + /** current state of the graph */ + enum gsl_graph_states graph_state; + /** lock object to serialize graph operations */ + ar_osal_mutex_t graph_lock; + /** lock object to serialize get/set config opreations */ + ar_osal_mutex_t get_set_cfg_lock; + /** Array of graph signal objects for control and data commands */ + struct gsl_signal graph_signal[GRAPH_CMD_SIG_MAX]; + /** control information for flush and RTGM */ + struct gsl_transient_state_info transient_state_info; + /** control flag for dumping tag cfg to qact */ + bool_t rtc_conn_active; + /** graph source port to send GPR commands */ + uint32_t src_port; + /** graph routing id to send GPR commands */ + uint32_t proc_id; + /** holds information for read data path */ + struct gsl_data_path_info read_info; + /** holds information for write data path */ + struct gsl_data_path_info write_info; + /** clients cb function ptr */ + gsl_cb_func_ptr cb; + /** client data sent as part of cb */ + void *client_data; + /** number of gkv nodes */ + uint32_t num_gkvs; + /** List of gkv nodes */ + struct ar_list_t gkv_list; + /** lock object to serialize gkv_list iterations */ + ar_osal_mutex_t gkv_list_lock; + /** + * bitmask represents the Spf subsystems this graph depends on the + * values for this bitmask are provided in gsl_spf_ss_state.h + */ + uint32_t ss_mask; +}; + +struct gsl_prepare_change_graph_single_gkv_params { + /* gkv that is being prepared for change graph */ + struct gsl_key_vector old_gkv; + /* num_sgs in sgs */ + uint32_t num_sgs; + /* list of all the subgraphs that will be present in the new gkv */ + uint32_t *sgs; + /* sg connection info that represent all sg conncetions in the new gkv */ + struct gsl_graph_sg_conn_data sg_conn_info; + /* + * number of subraphs that must be force closed/reopened even if they exist + * in both old and new gkvs, this is used in RTGM scenarios when user + * modifies subgraphs + */ + uint32_t num_sgs_to_reopen; + /* + * list of all subraphs that must be force closed/reopened + */ + uint32_t *sgs_to_reopen; + /* + * list of all subraph connections that must be force closed/reopened + */ + struct gsl_graph_sg_conn_data sg_conn_info_to_reopen; +}; + +struct gsl_change_graph_single_gkv_params { + struct gsl_key_vector old_gkv; + struct gsl_key_vector new_gkv; + struct gsl_key_vector new_ckv; +}; + +/** + * \brief initialize a graph's internals + * Initialize graph instance and register to GPR to + * receive/send commands/events/data from spf + * Update state under graph_hdl_lock when calling this + * + * \param[in] graph: pointer to graph's memory + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_init(struct gsl_graph *graph); + +/** + * \brief deinitialize a graph's internals + * call under the graph_hdl_lock to sync with SSR + * + * \param[in] graph: pointer to graph's memory + * + * \return AR_EOK + */ +int32_t gsl_graph_deinit(struct gsl_graph *graph); + +/** + * \brief Fetch a graph's information from ACDB + * + * \param[in] gkv: graph key vector to identify the graph + * + * \param[out] sg_id_list: stores the graph's sgs + * \param[out] sg_conn_info: stores conn info for sgs in graph + * + * This function allocates memory that must be freed in *sg_id_list and in + * sg_conn_info->subgraphs + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_acdb_get_graph(const struct gsl_key_vector *gkv, + uint32_t **sg_id_list, AcdbGetGraphRsp *sg_conn_info); + +/** + * \brief Load a graph specified by gkv on to SPF. Calibration is also sent + * if ckv also is specified. + * + * \param[in] graph: pointer to graph's memory + * \param[in] gkv: graph key vector to identify the graph + * \param[in] ckv: OPTIONAL used to retrieve calibration for graph + * \param[in] lock: OPTIONAL operations occur with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_open(struct gsl_graph *graph, + const struct gsl_key_vector *gkv, + const struct gsl_key_vector *ckv, + ar_osal_mutex_t lock); + +/** + * \brief Close the graph on SPF. Releases all resources that belong to + * the graph. + * + * \param[in] graph: pointer to graph's memory + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_close(struct gsl_graph *graph, + ar_osal_mutex_t lock); + +/** + * \brief Set graph calibration on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in] ckv: pointer to calibration key vector + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_set_cal(struct gsl_graph *graph, + const struct gsl_key_vector *gkv, + const struct gsl_key_vector *ckv, + ar_osal_mutex_t lock); + +/** + * \brief Set graph configuration on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in] gkv: OPTIONAL specific graph key vector to apply config to for + * SSMD scenarios which have more than 1 GKV in the graph + * \param[in] tag: tag ID + * \param[in] tkv: Tag key vector + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_set_config(struct gsl_graph *graph, + const struct gsl_key_vector *gkv, uint32_t tag, + const struct gsl_key_vector *tkv, ar_osal_mutex_t lock); + +/** + * \brief Set custom graph configuration on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in,out] payload: pointer to config payload + * \param[in] payload_size: payload size + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_set_custom_config(struct gsl_graph *graph, + const uint8_t *payload, const uint32_t payload_size, + ar_osal_mutex_t lock); + +/** + * \brief Get custom graph configuration from SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in,out] payload: pointer to config payload + * \param[in] payload_size: payload size + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_get_custom_config(struct gsl_graph *graph, + uint8_t *payload, uint32_t payload_size, ar_osal_mutex_t lock); + +/** + * \brief Get tagged custom graph configuration from SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in,out] payload: pointer to config payload + * \param[in,out] payload_size: payload size + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_get_tagged_custom_config(struct gsl_graph *graph, + uint32_t tag, uint8_t *payload, uint32_t *payload_size, + ar_osal_mutex_t lock); + +/** + * \brief Set custom graph configuration on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in] tag: tag ID + * \param[in] payload: pointer to config payload + * \param[in] payload_size: payload size + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_set_tagged_custom_config(struct gsl_graph *graph, + uint32_t tag, const uint8_t *payload, const size_t payload_size, + ar_osal_mutex_t lock); + +/** + * \brief Set persistent custom graph configuration on SPF + * + * \param[in] graph: pointer to graph's memory + * \param[in] tag: tag ID + * \param[in] payload: pointer to config payload + * \param[in] payload_size: payload size + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_set_tagged_custom_config_persist(struct gsl_graph *graph, + uint32_t tag, const uint8_t *payload, const uint32_t payload_size, + ar_osal_mutex_t lock); + +/** + * \brief Set graph prepare command on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_prepare(struct gsl_graph *graph, + ar_osal_mutex_t lock); + +/** + * \brief Configure the data path for this graph + * + * \param[in] graph: pointer to graph's meory + * \param[in] read_write_flag: indicates which path is being configured, 1 + * means READ path, 0 means WRITE path + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_config_data_path(struct gsl_graph *graph, + enum gsl_data_dir dir, struct gsl_cmd_configure_read_write_params *cfg); + +/** + * \brief Set graph start command on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_start(struct gsl_graph *graph, + ar_osal_mutex_t lock); + +/** + * \brief Set graph suspend command on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_suspend(struct gsl_graph *graph, + ar_osal_mutex_t lock); + +/** + * \brief Set graph stop command on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_stop(struct gsl_graph *graph, + ar_osal_mutex_t lock); + +/** + * \brief Write data to a graph + * + * \param[in] graph: pointer to graph's meory + * \param[in] tag: tag used to indentify the module in spf that will receive + * the data + * \param[in] buff: holds the buffer info for data being written + * \param[out] consumed_size: used to return number of bytes actually written + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, + * AR_EABORTED when buffer is not queued to spf because of graph + * close, stop, or flush (non-fatal error), + * error code otherwise + */ +int32_t gsl_graph_write(struct gsl_graph *graph, uint32_t tag, + struct gsl_buff *buff, uint32_t *consumed_size); + +/** + * \brief Read data from a graph + * + * \param[in] graph: pointer to graph + * \param[in] tag: tag used to identify the module in spf that will provide + * the data + * \param[in] buff: holds the buffer info for data being read + * \param[out] filled_size: used to return number of bytes actually read + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, + * AR_EABORTED when buffer is not queued to spf because of graph + * close, stop, or flush (non-fatal error), + * error code otherwise + */ +int32_t gsl_graph_read(struct gsl_graph *graph, uint32_t tag, + struct gsl_buff *buff, uint32_t *filled_size); + +/** + * \brief Get tagged module info + * + * \param[in] graph_key_vect: pointer to graph key vector + * \param[in] tag: tag used to indentify the module + * \param[out] module_info: holds {MID, MIID} info + * \param[out] module_info_size: size of the module info buffer + * allocated by GSL + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_get_module_tag_info(const struct gsl_key_vector *gkv, + uint32_t tag, struct gsl_module_id_info **module_info, + uint32_t *module_info_size); + +/** + * \brief Issue custom event registration command to Spf + * + * \param[in] graph: pointer to graph + * \param[in] reg_ev: event registration payload + */ +int32_t gsl_graph_register_custom_event(struct gsl_graph *graph, + struct gsl_cmd_register_custom_event *reg_ev); + +/** + * \brief Set graph flush command on SPF. + * + * \param[in] graph: pointer to graph's memory + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_graph_flush(struct gsl_graph *graph, + ar_osal_mutex_t lock); + +/** + * \brief Add a new graph to an existing graph on SPF. + * + * \param[in] graph: pointer to graph + * \param[in] new_graph: pointer to GKV and CKV structure + * \param[in] lock: optional mutex lock + */ +int32_t gsl_graph_add_new(struct gsl_graph *graph, + struct gsl_cmd_graph_select *new_graph, ar_osal_mutex_t lock); + +/** + * \brief Change to a new graph from an existing graph on SPF. + * + * \param[in] graph: pointer to graph + * \param[in] new_graph: pointer to new GKV and CKV structure + * \param[in] lock: optional mutex lock + * + * \return AR_EOK for success or error code for failure + */ +int32_t gsl_graph_change(struct gsl_graph *graph, + struct gsl_cmd_graph_select *new_graph, ar_osal_mutex_t lock); + +/** + * \brief Prepare to change a single graph. This function will add a new + * gkv_node to the graph corresponding to the new gkv and close the old gkv_node + * that corresponds to the old gkv. It caches the subgraphs that need to be + * opened on spf without actually opening them. Caller can later + * call gsl_graph_change_single_gkv to open them on Spf. This separation is + * needed for RTGM support. + * + * \param[in] graph: pointer to graph + * \param[in] params: Holds parameters related to the new graph + * \param[in] lock: optional mutex lock + * + * \return AR_EOK for success or error code for failure + */ +int32_t gsl_graph_prepare_to_change_single_gkv(struct gsl_graph *graph, + struct gsl_prepare_change_graph_single_gkv_params *params, + ar_osal_mutex_t lock); + +/** + * \brief Change only graph corresponding to a single GKV on SPF, must be + * called only after gsl_graph_prepare_to_change_single_gkv + * + * \param[in] graph: pointer to graph + * \param[in] new_gkv: GKV that will be opened on Spf + * \param[in] new_ckv: CKV that will be applied to the graph on Spf + * \param[in] lock: optional mutex lock + * + * \return AR_EOK for success or error code for failure + */ +int32_t gsl_graph_change_single_gkv(struct gsl_graph *graph, + struct gsl_change_graph_single_gkv_params *params, + ar_osal_mutex_t lock); + +/** + * \brief helper method to set config passed by QACT on changed graphs, + * must be called between gsl_graph_change_single_gkv and gsl_graph_start + * Builds and sends a set cfg packet with the given payload. + * + * \param[in] graph: pointer to graph + * \param[in] tag_data_size: size of tag data blob + * \param[in] tag_data: data blob comprising a valid payload for + * APM_CMD_SET_CFG. Will be sent as-is. + * + * \return AR_EOK for success or error code for failure + */ +int32_t gsl_graph_change_set_config_helper(struct gsl_graph *graph, + uint32_t tag_data_size, uint8_t *tag_data); + +/** + * \brief removes an old graph from an existing graph on SPF. + * + * \param[in] graph: pointer to graph + * \param[in] old_graph: pointer to GKV to be removed + * \param[in] oc_lock: optional mutex lock used for closing graph + * \param[in] ss_lock: optional mutex lock used for stoping graph + */ +int32_t gsl_graph_remove_old(struct gsl_graph *graph, + struct gsl_cmd_remove_graph *old_graph, ar_osal_mutex_t oc_lock, + ar_osal_mutex_t ss_lock); + +/** + * \brief Get the current state of the graph + * + * \param[in] graph: pointer to graph's memory + * + * \return the current state + */ + +/* + * \brief Get the current state of the graph + * + * \param[in] graph: pointer to graph's memory + * + * \return the current state + */ +enum gsl_graph_states gsl_graph_get_state(struct gsl_graph *graph); + +/** + * \brief Update the graphs state + * + * \param[in] graph: graph object + * \param[in] new_state: New state to set on the graph + * + * \return state after it has been updated + */ +enum gsl_graph_states gsl_graph_update_state(struct gsl_graph *graph, + enum gsl_graph_states new_state); + +/** + * \brief Dispatch an event to the graph on all signals + * + * \param[in] graph: graph obj + * \param[in] ev_mask: indicates what is the event to be raised on the graph + * + * \return AR_EOK on success, error code otherwise + */ +void gsl_graph_signal_event_all(struct gsl_graph *graph, + enum gsl_graph_sig_event_mask ev_mask); + +/** + * \brief Query database for all tags and corresponding module_iid/module_id + * mapping given a graph key vector + * \param[in] graph_key_vect: graph key vector + * \param[in,out] tag_module_info: client buffer where tag module info + * gets copied to + * \param[in,out] tag_module_info_size: size of the tag module info + * + * \return EOK on success, error code otherwise. + */ +int32_t gsl_graph_get_tags_with_module_info( + const struct gsl_key_vector *graph_key_vect, + struct gsl_tag_module_info *tag_module_info, + size_t *tag_module_info_size); + +/** + * \brief Query database for tagged data + * \param[in] graph_key_vect: graph key vector + * \param[in,out] tag_module_info: client buffer where tag module info + * gets copied to + * \param[in,out] tag_module_info_size: size of the tag module info + * + * \return EOK on success, error code otherwise. + */ +int32_t gsl_graph_get_tagged_data( + const struct gsl_key_vector *graph_key_vect, uint32_t tag, + struct gsl_key_vector *tag_key_vect, + uint8_t *payload, size_t *payload_size); + +/** + * \brief Issue graph stop for the subgraphs with matching properties + * + * \param[in] graph: graph object + * \param[in] stop_props: subgraph properties + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return EOK on success, error code otherwise. + */ +int32_t gsl_graph_stop_with_properties(struct gsl_graph *graph, + struct gsl_cmd_properties *stop_props, ar_osal_mutex_t lock); + +/** + * \brief Issue graph close for the subgraphs with matching properties + * + * \param[in] graph: graph object + * \param[in] props: subgraph properties + * \param[in] lock: OPTIONAL all operations happen with this lock acquired + * + * \return EOK on success, error code otherwise. + */ +int32_t gsl_graph_close_with_properties(struct gsl_graph *graph, + struct gsl_cmd_properties *props, ar_osal_mutex_t lock); + +/** + * \brief Set RTGM state for the current graph + * + * \param[in] graph: graph object + * \param[in] rtgm_in_prog: true indicates RTGM in prog + * + * \return EOK on success, error code otherwise. + */ +void gsl_graph_set_rtgm_state(struct gsl_graph *graph, bool_t rtgm_in_prog); +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* GSL_GRAPH_H */ + diff --git a/gsl/inc/gsl_main.h b/gsl/inc/gsl_main.h new file mode 100644 index 0000000..ffee361 --- /dev/null +++ b/gsl/inc/gsl_main.h @@ -0,0 +1,13 @@ +#ifndef GSL_MAIN_H +#define GSL_MAIN_H +/** + * \file gsl_main.h + * + * \brief + * Main entry point for Graph Service Layer (GSL) + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + #endif //GSL_MAIN_H diff --git a/gsl/inc/gsl_mdf_utils.h b/gsl/inc/gsl_mdf_utils.h new file mode 100644 index 0000000..d307332 --- /dev/null +++ b/gsl/inc/gsl_mdf_utils.h @@ -0,0 +1,253 @@ +#ifndef GSL_MDF_UTILS_H +#define GSL_MDF_UTILS_H +/** + * \file gsl_mdf_utils.h + * + * \brief + * Multi-DSP framework utilities library + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + + /** + * @h2xml_title_date {08/01/2018} + */ + #include "ar_osal_types.h" + #include "gsl_common.h" + +#define GSL_MULTI_DSP_FWK_DATA_MID 0x2005 + + /** + * @h2xmlm_module {"GSL_MULTI_DSP_FWK_DATA_MID", GSL_MULTI_DSP_FWK_DATA_MID} + * @h2xmlm_displayName {"GSL_MULTI_DSP_FWK_DATA_MID"} + * @h2xmlm_description {Processor group shared memory information \n} + * + * - This module supports the following parameter IDs: \n + * - #PARAM_ID_PROC_GROUP_INFO_PARAMS \n + * - #PARAM_ID_PROC_DOMAIN_INFO \n + * + * @{ <-- Start of the Module --> + */ +#define PARAM_ID_PROC_GROUP_INFO_PARAMS 0x0001 +#define PARAM_ID_PROC_DOMAIN_INFO 0x0002 + +/** @h2xmle_description {Shared memory info of each group} + * @h2xmlp_subStruct + */ +struct per_group_shmem_info_t { + /** @h2xmle_description {Size of the shared memory} + * @h2xmle_default {1024} + */ + uint32_t shmem_size; + + /** @h2xmle_description {Number of satellite procs in this group} + * @h2xmle_default {1} + */ + uint32_t num_satellite_procs; + + /** @h2xmle_description {Master proc in this group} + * @h2xmle_default {1} + */ + uint32_t master_proc; + + /** @h2xmle_description {Satellite processor IDs.} + * @h2xmle_variableArraySize {num_satellite_procs} + */ + uint32_t satellite_proc_ids[]; + +}; + +/* Shared memory information for each processor group. */ +typedef struct per_group_shmem_info_t per_group_shmem_info_t; + + +/** + * @h2xmlp_parameter {"PARAM_ID_PROC_GROUP_INFO_PARAMS", + * PARAM_ID_PROC_GROUP_INFO_PARAMS} + * @h2xmlp_description {Used to configure processor group info} + */ +struct proc_group_info_params_t { + /** @h2xmle_description {Number of processor group.} + * @h2xmle_default {1} + */ + uint32_t num_proc_groups; + +#ifdef __H2XML__ + /** + * @h2xmle_variableArraySize {num_proc_groups} + */ + per_group_shmem_info_t shmem_info[]; +#endif +}; + +typedef struct proc_group_info_params_t proc_group_info_params_t; + +/** @h2xmle_description {Processor domain type for each processor} + * @h2xmlp_subStruct + */ +struct proc_domain_type { + /** @h2xmle_description {Processor id} + * @h2xmle_default {2} + */ + uint32_t proc_id; + /** @h2xmle_description {Proc domain type, 1: static 2: dynamic} + * @h2xmle_default {1} + */ + uint32_t proc_type; +}; + +typedef struct proc_domain_type proc_domain_type_t; + +/** + * @h2xmlp_parameter {"PARAM_ID_PROC_DOMAIN_INFO", + * PARAM_ID_PROC_DOMAIN_INFO} + * @h2xmlp_description {Used to identify processor domain type} + */ +struct proc_domain_info { + /** @h2xmle_description {Number of processors} + * @h2xmle_default {1} + */ + uint32_t num_procs; + /** + * @h2xmle_variableArraySize {num_procs} + */ + proc_domain_type_t domain_type[]; +}; +/** + * @} + */ + +/* + * \brief Returns all proc domain ids + * Returns number of SPF processors and fills proc_domain_type + * array with SPF proc domain id and type + * + * \param[out] proc_domains: SPF processors domain info. + * \param[out] num_procs: number of SPF processors. + */ +int32_t gsl_mdf_utils_get_proc_domain_info( + proc_domain_type_t **proc_domains, uint32_t *num_procs); + +/* + * \brief Returns all master proc ids + * Returns number of SPF masters if master_proc_ids is NULL + * Else, fills master_proc_ids array with SPF master proc ids + * + * \param[out] num_master_procs: number of SPF masters. + * \param[out] master_proc_ids: Array of SPF master proc ids + */ +int32_t gsl_mdf_utils_get_master_proc_ids(uint32_t *num_master_procs, + uint32_t master_proc_ids[]); + +/* + * \brief Returns the susbsytem mask of master proc and it's satellites + * + * \param[in] master_proc: SPF master proc id + * \param[out] supported_ss_mask: Subsystem mask including master proc mask + * + */ +int32_t gsl_mdf_utils_get_supported_ss_info_from_master_proc( + uint32_t master_proc, + uint32_t *supported_ss_mask); + +/* + * \brief Returns if the subsystem mask is of a master proc + * + * \param[in] supported_ss_mask: Subsystem mask + * + */ +bool_t gsl_mdf_utils_is_master_proc(uint32_t spf_ss_mask); + +/* + * \brief Returns the master proc corresponding to the mask. + * Returns 0 if it doesn't exist in proc group of any master proc. + * + * \param[in] supported_ss_mask: Subsystem mask + * + */ +uint32_t gsl_mdf_utils_get_master_proc_id(uint32_t spf_ss_mask); + +/* + * \brief Looks up the spf susbsytem ids from ACDB + * + * \param[in] sg_list: subgraph id list comprising a graph + * \param[in] num_sg: number of subgraphs in sg list + * \param[out] ss_mask: mask comprising this subsystems this graph requires, + * use macros from gsl_spf_ss_state.h to test if a subsystem is present + * \return AR_EOK on success, error code otherwise + */ +uint32_t gsl_mdf_utils_query_graph_ss_mask(uint32_t *sg_id_list, + uint32_t num_sgs, uint32_t *ss_mask); + +/* + * \brief allocate the loaned MDF shmem for a given ss_mask if not already + * done so + * + * \param[in] ss_mask: mask representing the set of subsystems for which to + * allocate the shared loaned memory + * \param[in] master_proc: SPF master proc id + * + */ +int32_t gsl_mdf_utils_shmem_alloc(uint32_t ss_mask, uint32_t master_proc); + +/* + * \brief notify mdf utils that some ss have been restarted. This is to remap + * the loaned memory to those ss. + * + * \param[in] restarted_ss_mask: mask representing the set of subsystems which + * have been restarted + */ +void gsl_mdf_utils_notify_ss_restarted(uint32_t restarted_ss_mask); + +/* + * \brief frees or unmap the mdf shmem for all ss groups. + * + * \param[in] ss_mask: mask representing the set of subsystems for which to + * de-allocate or un map the shared loaned memory + */ +int32_t gsl_mdf_utils_shmem_free(uint32_t ss_mask); + +/* + * \brief Creates dynamic PD and allocates shared memory for given + * subsystems + * + * \param[in] ss_mask: mask representing the subsystems + * \param[in] master_proc_id: Master proc id + */ +int32_t gsl_mdf_utils_register_dynamic_pd(uint32_t ss_mask, + uint32_t master_proc_id, uint32_t src_port, + struct gsl_signal *sig, uint32_t *dyn_ss_mask); + +/* + * \brief Releases dynamic PD and deallocates shared memory for given + * subsystems + * \param[in] ss_mask: mask representing the subsystems + * \param[in] master_proc_id: Master proc id + */ +int32_t gsl_mdf_utils_deregister_dynamic_pd(uint32_t ss_mask, + uint32_t master_proc_id); + +/* + * \brief Check if the given subsystem is of dynamic PD type + * \param[in] sys_id: proc id + * \return TRUE if dynamic PD, FALSE otherwise. + */ +bool_t gsl_mdf_utils_is_dynamic_pd(uint32_t proc_id); + +/* + * \brief Check if dynamic PD is active for a given subsystem + * \param[in] sys_id: proc id + * \return TRUE if pending, FALSE otherwise. + */ +bool_t gsl_mdf_utils_get_dynamic_pd_state(uint32_t proc_id); + +/* + * \brief initialize MDF utils, internally queries ACDB to get supported SS info + * + */ +int32_t gsl_mdf_utils_init(void); + +int32_t gsl_mdf_utils_deinit(void); +#endif diff --git a/gsl/inc/gsl_mdf_utils.xml b/gsl/inc/gsl_mdf_utils.xml new file mode 100644 index 0000000..053a6e8 --- /dev/null +++ b/gsl/inc/gsl_mdf_utils.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gsl/inc/gsl_msg_builder.h b/gsl/inc/gsl_msg_builder.h new file mode 100644 index 0000000..59742dc --- /dev/null +++ b/gsl/inc/gsl_msg_builder.h @@ -0,0 +1,67 @@ +#ifndef GSL_MSG_BUILDER_H +#define GSL_MSG_BUILDER_H +/** + * \file gsl_mem_mgr.h + * + * \brief + * Constructs message that is to be sent to Spf. + * Allocates shared memory or does non shared memory operations + * depending on the availability of shared memory b/n GSL & SPF domain. + * + * GSL sessions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "gsl_shmem_mgr.h" +#include "ar_osal_error.h" +#include "ar_osal_types.h" +#include "gpr_packet.h" + +typedef struct gsl_msg { + gpr_packet_t *gpr_packet; + struct gsl_shmem_alloc_data shmem; + uint8_t *payload; + uint32_t proc_id; +} gsl_msg_t; + +int32_t gsl_msg_builder_init(uint32_t num_master_procs, uint32_t *master_procs); + +int32_t gsl_msg_builder_deinit(void); + +/* In scenarios, where shared memory availability is mandatory (Ex: persist cal) + * Use APIs provided by gsl_shmem_mgr. + * + * Allocate shared memory & GPR packet + */ +int32_t gsl_msg_alloc(uint32_t opcode, uint32_t src_port, + uint32_t dst_port, uint32_t gpr_payload_size, + uint32_t token, uint32_t dest_domain, + uint32_t oob_payload_size, bool_t force_inband, + gsl_msg_t *msg); + +/* In scenarios, where shared memory availability is mandatory (Ex: persist cal) + * Use APIs provided by gsl_shmem_mgr. + * + * Allocate GPR packet & shared memory using extra flags + */ +int32_t gsl_msg_alloc_ext(uint32_t opcode, uint32_t src_port, + uint32_t dst_port, uint32_t gpr_payload_size, + uint32_t token, uint32_t dest_domain, + uint32_t oob_payload_size, bool_t force_inband, + uint32_t spf_ss_mask, uint32_t flags, + uint32_t platform_info, gsl_msg_t *msg); + +/* Free gsl msg */ +int32_t gsl_msg_free(gsl_msg_t *msg); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/gsl/inc/gsl_rtc.h b/gsl/inc/gsl_rtc.h new file mode 100644 index 0000000..1cdf94c --- /dev/null +++ b/gsl/inc/gsl_rtc.h @@ -0,0 +1,147 @@ +#ifndef GSL_RTC_H +#define GSL_RTC_H +/** + * \file gsl_rtc.h + * + * \brief + * Include file for gsl rtc graph functionality + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" +#include "gsl_graph.h" +#include "gsl_rtc_intf.h" + + + /* + * Initialize signals in GSL RTC layer + * + * \return AR_EOK for success, error otherwise + */ +int32_t gsl_rtc_internal_init(void); + +/* + * De-initialize signals in GSL RTC layer + * + * \return AR_EOK for success, error otherwise + */ +int32_t gsl_rtc_internal_deinit(void); + +/** + * \brief Get total size in bytes of all the graph key vectors + * and calibration key vectors in a single graph + * + * \param[in] graph: graph obj + * + * \return size of graph and calibration key vectors in the graph + */ +uint32_t gsl_rtc_graph_get_gkv_ckv_size(struct gsl_graph *graph); + +/** + * \brief Copy CKVs (in-band) from a single graph in the form - + * {{CKV1}, {CKV2}, ... }, where each CKVn is in the form- + * {num_kvps, {kvp1}, {kvp2}, ... } + * + * \param[in] graph: graph obj + * \param[in] payload: buffer to copy the ckv data + * \param[out] num_ckvs: number of ckvs in the graph + * + * \return size in bytes of all the cal key vectors in a graph + */ +uint32_t gsl_rtc_graph_copy_ckvs(struct gsl_graph *graph, uint8_t *payload, + uint32_t *num_ckvs); + +/** + * \brief Copy GKVs (in-band) from a single graph in the form - + * {{GKV1}, {GKV2}, ... }, where each GKVn is in the form- + * {num_kvps, {kvp1}, {kvp2}, ... } + * + * \param[in] graph: graph obj + * \param[in] payload: buffer to copy the gkv data + * \param[out] num_gkvs: number of gkvs in the graph + * + * \return size in bytes of all the cal key vectors in a graph + */ +uint32_t gsl_rtc_graph_copy_gkvs(struct gsl_graph *graph, uint8_t *payload, + uint32_t *num_gkvs); + +/** + * \brief Get persist data for the given subgraph in the graph + * + * \param[in] graph: graph obj + * \param[in] sgid: subgraph ID + * \param[in] proc_id: processor ID + * \param[in/out] total_size: total size of the persist data + * \param[out] sg_cal_data: Pointer to buffer containing the persistent data + * for this subgraph + * + * \return AR_EOK for success, error otherwise + */ +int32_t gsl_rtc_graph_get_persist_data(struct gsl_graph *graph, uint32_t sgid, + uint32_t proc_id, uint32_t *total_size, uint8_t **sg_cal_data); + +/** + * \brief Get non-persist data for the given subgraph in the graph + * + * \param[in] graph: graph obj + * \param[in] total_size: total size of the non-persist data + * \param[in/out] sg_cal_data: Pointer to store non-persist data + * + * \return AR_EOK for success, error otherwise + */ +int32_t gsl_rtc_graph_get_non_persist_data(struct gsl_graph *graph, + uint32_t total_size, uint8_t *sg_cal_data); + +/** + * \brief Set non-persist data for the given subgraph in the graph + * + * \param[in] graph: graph obj + * \param[in] total_size: total size of the non-persist data + * \param[in] sg_cal_data: Pointer to non-persist data to be set + * + * \return AR_EOK for success, error otherwise + */ +int32_t gsl_rtc_graph_set_non_persist_data(struct gsl_graph *graph, + uint32_t total_size, uint8_t *sg_cal_data); + +/** + * \brief Set persist data for the given subgraph in the graph + * + * \param[in] graph: graph obj + * \param[in] params: structure containing all the parameters needed to set + * persistent data + * + * \return AR_EOK for success, error otherwise + */ +int32_t gsl_rtc_graph_set_persist_data(struct gsl_graph *graph, + struct gsl_rtc_persist_param *params); + +/** + * \brief Prepare for RTGM graph change operation. This function will do the + * RTGM related steps that must be done prior to updating the ACDB data + * + * \param[in] graph: graph obj + * \param[in] rtc_params: parameters relating to the graph change + * \param[in] lock: OPTIONAL lock + * + * \return AR_EOK for success, error otherwise + */ +int32_t gsl_rtc_internal_prepare_change_graph(struct gsl_graph *graph, + struct gsl_rtc_prepare_change_graph_info *rtc_params, + ar_osal_mutex_t lock); + +/** + * \brief Perform an RTGM graph change operation. This function will do the + * RTGM related steps that must be done after updating the ACDB data + * + * \param[in] graph: graph obj + * \param[in] rtc_params: parameters relating to the graph change + * \param[in] lock: OPTIONAL lock + * + * \return AR_EOK for success, error otherwise + */ +int32_t gsl_rtc_internal_change_graph(struct gsl_graph *graph, + struct gsl_rtc_change_graph_info *rtc_params, ar_osal_mutex_t lock); +#endif /* GSL_RTC_H */ diff --git a/gsl/inc/gsl_rtc_main.h b/gsl/inc/gsl_rtc_main.h new file mode 100644 index 0000000..e1cca97 --- /dev/null +++ b/gsl/inc/gsl_rtc_main.h @@ -0,0 +1,41 @@ +#ifndef GSL_RTC_MAIN_H +#define GSL_RTC_MAIN_H +/** + * \file gsl_rtc_main.h + * + * \brief + * GSL RTC internal header + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ar_osal_types.h" + +enum gsl_rtc_request_type { + GSL_RTC_GET_UC_INFO, + GSL_RTC_GET_PERSIST_DATA, + GSL_RTC_GET_NON_PERSIST_DATA, + GSL_RTC_SET_PERSIST_DATA, + GSL_RTC_SET_NON_PERSIST_DATA, + GSL_RTC_PREPARE_CHANGE_GRAPH, + GSL_RTC_CHANGE_GRAPH, + GSL_RTC_CONN_INFO_CHANGE, +}; + +typedef int32_t(*gsl_rtc_cb_t)(enum gsl_rtc_request_type req, void *cb_data); + +/* + * Initialize GSL RTC layer + * \param[in] cb callback into gsl_main to get graph information (gkv, ckv) + */ + +int32_t gsl_rtc_init(gsl_rtc_cb_t cb); + +/* + * De-initialize GSL RTC layer + * \param[in] cb callback into gsl_main to get graph information (gkv, ckv) + */ + +int32_t gsl_rtc_deinit(void); + +#endif /* GSL_RTC_MAIN_H */ diff --git a/gsl/inc/gsl_shmem_mgr.h b/gsl/inc/gsl_shmem_mgr.h new file mode 100644 index 0000000..a44410a --- /dev/null +++ b/gsl/inc/gsl_shmem_mgr.h @@ -0,0 +1,103 @@ +#ifndef GSL_SHMEM_MGR_H +#define GSL_SHMEM_MGR_H +/** + * \file gsl_shmem_mgr.h + * + * \brief + * Manages shared memory that is mapped to Spf, tries to reuse existing + * unused memory blocks that are already mapped with Spf across multiple + * GSL sessions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "ar_osal_error.h" +#include "ar_osal_types.h" + +#define GSL_SHMEM_MGR_FRAME_SZ_SHIFT 10 /* frame size = 1024 */ +#define GSL_SHMEM_MGR_FRAME_SZ (1 << GSL_SHMEM_MGR_FRAME_SZ_SHIFT) + +/* flags that can get or'ed and passed to alloc functions */ +#define GSL_SHMEM_LOANED 0x1 +#define GSL_SHMEM_DEDICATED_PAGE 0x2 +#define GSL_SHMEM_MAP_UNCACHED 0x4 +#define GSL_SHMEM_CMA 0x8 + +/* used to tell SPF we're doing something with CMA */ +#define GSL_GPR_CMA_FLAG_BIT 0x2 + +typedef struct gsl_shmem_page *gsl_shmem_handle_t; + +struct gsl_shmem_alloc_data { + gsl_shmem_handle_t handle; /*< shmem mgr handle */ + void *v_addr; /*< address to be used by client for accessing buffer */ + uint32_t spf_mmap_handle; /*< handle to be passed to Spf */ + uint64_t spf_addr; /*< spf addr populated from ipa */ + uint64_t metadata; /*< metadata returned from OSAL */ +}; + +struct gsl_shmem_alloc_data_per_proc { + uint32_t proc_id; + struct gsl_shmem_alloc_data persist_cal_data; + uint32_t persist_cal_data_size; +}; + +/* + * master_proc id values can vary from AR_SUB_SYS_ID_FIRST - AR_SUB_SYS_ID_LAST + * proc_ids as defined in ar_osal_sys_id.h + */ +int32_t gsl_shmem_init(uint32_t num_master_procs, uint32_t *master_procs); + +int32_t gsl_shmem_deinit(void); + +int32_t gsl_shmem_alloc(uint32_t size_bytes, uint32_t master_proc_id, + struct gsl_shmem_alloc_data *alloc_data); + +int32_t gsl_shmem_alloc_ext(uint32_t size_bytes, uint32_t spf_ss_mask, + uint32_t flags, uint32_t platform_info, uint32_t master_proc_id, + struct gsl_shmem_alloc_data *alloc_data); + +int32_t gsl_shmem_map_extern_mem(uint64_t ext_mem_hdl, uint32_t size_bytes, + uint32_t master_proc_id, struct gsl_shmem_alloc_data *alloc_data); + +int32_t gsl_shmem_unmap_extern_mem(struct gsl_shmem_alloc_data alloc_data); + +uint64_t gsl_shmem_get_metadata( + const struct gsl_shmem_alloc_data *alloc_data); + +int32_t gsl_shmem_get_mapped_ss_mask( + const struct gsl_shmem_alloc_data *alloc_data); + +int32_t gsl_shmem_free(struct gsl_shmem_alloc_data *alloc_data); + +void gsl_shmem_signal_ssr(uint32_t master_proc_id); +void gsl_shmem_clear_ssr(uint32_t master_proc_id); +void gsl_shmem_remap_pre_alloc(uint32_t master_proc_id); +int32_t gsl_shmem_map_allocation(const struct gsl_shmem_alloc_data *alloc_data, + uint32_t flags, uint32_t ss_mask_to_map_to, uint32_t master_proc_id); +int32_t gsl_shmem_map_allocation_to_spf( + const struct gsl_shmem_alloc_data *alloc_data, + uint32_t flags, uint32_t ss_mask_to_map_to, + uint32_t master_proc_id); +int32_t gsl_shmem_unmap_allocation(struct gsl_shmem_alloc_data *alloc_data, + uint32_t ss_mask_to_unmap_to); +int32_t gsl_shmem_map_dynamic_pd(struct gsl_shmem_alloc_data *alloc_data, + uint32_t flags, uint32_t ss_mask, uint32_t master_proc_id); +int32_t gsl_shmem_unmap_dynamic_pd(struct gsl_shmem_alloc_data *alloc_data, + uint32_t ss_mask, uint32_t master_proc_id); +void gsl_shmem_cache_pending_memmap_packets(uint32_t master_proc_id, void *gpr_packet); +uint32_t gsl_shmem_check_and_unmap_cache_pending_packets(uint32_t master_proc_id); + +int32_t gsl_shmem_hyp_assign(gsl_shmem_handle_t alloc_handle, + uint64_t dest_sys, uint64_t src_sys); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/gsl/inc/gsl_spf_ss_state.h b/gsl/inc/gsl_spf_ss_state.h new file mode 100644 index 0000000..3999d2d --- /dev/null +++ b/gsl/inc/gsl_spf_ss_state.h @@ -0,0 +1,67 @@ +#ifndef GSL_SPF_SS_STATE_H +#define GSL_SPF_SS_STATE_H +/** + * \file gsl_spf_ss_state.h + * + * \brief + * Maintains the state of all the audio proc_ids such as ADSP, CDSP, MDSP + * etc. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ar_osal_types.h" +#include "ar_osal_sys_id.h" + +enum spf_ss_state_t { + GSL_SPF_SS_STATE_DN = 0, + GSL_SPF_SS_STATE_UP = 1 +}; + +typedef void (*gsl_spf_ss_cb_t)(enum spf_ss_state_t state, + uint32_t ss_mask); + +/* + * Initialize the global spf subsystem state + * \param[in] master_proc: SPF master proc id + * \param[in] supported_ss_mask: bitmask which represents which subsystems are + * supported, a 1 in bit N means the subsystem with id N is supported. + * \param[in] cb callback to notify other modules within GSL of state changes + */ +int32_t gsl_spf_ss_state_init(uint32_t master_proc, uint32_t supported_ss_mask, + gsl_spf_ss_cb_t cb); + +/* + * Deinitialize the global spf subsystem state + * \param[in] master_proc: SPF master proc id + */ +void gsl_spf_ss_state_deinit(uint32_t master_proc); + +/* + * update the state of one or more spf subsystems, returns the new state + * after it has been updated + * \param[in] master_proc: SPF master proc id + * \param[in] ss_mask bitmask indicating which subsystems state to change + * \param[in] the new state for the subsystems indicated in ss_mask + */ +uint32_t gsl_spf_ss_state_set(uint32_t master_proc, uint32_t ss_mask, + enum spf_ss_state_t state); + +/* + * Retrieve the current state of the spf subsystems + * \return ss_state_mask bitmask indicating the state of each subsystem a + * 1 in this field means the corresponding subsystem is both supported and up + * \param[in] master_proc: SPF master proc id + */ +uint32_t gsl_spf_ss_state_get(uint32_t master_proc); + +/* + * Checks if a proc_id is supported for a particular master_proc on + * this platform. + * \param[in] master_proc: SPF master proc id + * \param[in] proc_id proc_ids as defined in ar_osal_sys_id.h + */ +bool_t gsl_spf_ss_state_is_ss_supported(uint32_t master_proc, uint32_t proc_id); + +#endif /* GSL_SPF_SS_STATE_H */ + diff --git a/gsl/inc/gsl_spf_timeout.h b/gsl/inc/gsl_spf_timeout.h new file mode 100644 index 0000000..2ae2243 --- /dev/null +++ b/gsl/inc/gsl_spf_timeout.h @@ -0,0 +1,122 @@ +#ifndef GSL_SPF_TIMEOUTS_H +#define GSL_SPF_TIMEOUTS_H +/** + * \file gsl_spf_timeouts.h + * + * \brief + * Represents GSL SPF timeouts + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + + /** + * @h2xml_title_date {09/25/2025} + */ + #include "ar_osal_types.h" + +#define GSL_SPF_TIMEOUTS 0x2006 + + /** + * @h2xmlm_module {"GSL_SPF_TIMEOUTS", GSL_SPF_TIMEOUTS} + * @h2xmlm_displayName {"GSL_SPF_TIMEOUTS"} + * @h2xmlm_description {Timeout configuration groups associated with the Graph \n} + * + * - This module supports the following parameter IDs: \n + * - #SPF_TIMEOUTS_INFO \n + * + * @{ <-- Start of the Module --> + */ +#define PARAM_ID_SPF_TIMEOUTS 0x0001 + +/** @h2xmle_description {Timeout configuration groups} + * @h2xmlp_subStruct + */ + +extern uint32_t GSL_SPF_TIMEOUT_MS; +extern uint32_t GSL_GRAPH_OPEN_TIMEOUT_MS; +extern uint32_t GSL_GRAPH_PREPARE_TIMEOUT_MS; +extern uint32_t GSL_GRAPH_START_STOP_TIMEOUT_MS; +extern uint32_t GSL_SPF_READ_WRITE_TIMEOUT_MS; + +#if !defined(__GSL_GPR_STUB__) && (defined(_WIN32) || defined(_WIN64)) \ + && !defined(_KERNEL_MODE) && defined(ARSPF_WIN_PORTING) + /** WIN32/64 - SPF PORTING Timeout can be less than COSIM mode */ +#define GSL_SPF_TIMEOUT_MS_DEFAULT ((3)*(1000)) +#define GSL_GRAPH_OPEN_TIMEOUT_MS_DEFAULT ((3)*(1000)) +#define GSL_GRAPH_PREPARE_TIMEOUT_MS_DEFAULT (0) +#define GSL_GRAPH_START_STOP_TIMEOUT_MS_DEFAULT (0) +#define GSL_SPF_READ_WRITE_TIMEOUT_MS_DEFAULT ((3)*(1000)) +#elif !defined(__GSL_GPR_STUB__) && (defined(_WIN32) || defined(_WIN64)) \ + && !defined(_KERNEL_MODE) +/** WIN32/64 COSIM Mode requires longer delays(30 min) */ +#define GSL_SPF_TIMEOUT_MS_DEFAULT ((1800)*(1000)) +#define GSL_GRAPH_OPEN_TIMEOUT_MS_DEFAULT ((1800)*(1000)) +#define GSL_GRAPH_PREPARE_TIMEOUT_MS_DEFAULT (0) +#define GSL_GRAPH_START_STOP_TIMEOUT_MS_DEFAULT (0) +#define GSL_SPF_READ_WRITE_TIMEOUT_MS_DEFAULT ((3600)*(1000)) +#elif defined(__GSL_GPR_STUB__) +/** + * unit-testing with GPR stub we increase the timeout due to APM sim globally + * serializeng all SPF commands which causes more delays in multi-session tests + */ +#define GSL_SPF_TIMEOUT_MS_DEFAULT (2000) +#define GSL_GRAPH_OPEN_TIMEOUT_MS_DEFAULT (2000) +#define GSL_GRAPH_PREPARE_TIMEOUT_MS_DEFAULT (2000) +#define GSL_GRAPH_START_STOP_TIMEOUT_MS_DEFAULT (5500) +#define GSL_SPF_READ_WRITE_TIMEOUT_MS_DEFAULT (60000LL) /* 1 min */ +#else +#define GSL_SPF_TIMEOUT_MS_DEFAULT (1000) +#define GSL_GRAPH_OPEN_TIMEOUT_MS_DEFAULT (4000) +#define GSL_GRAPH_PREPARE_TIMEOUT_MS_DEFAULT (2000) +#define GSL_GRAPH_START_STOP_TIMEOUT_MS_DEFAULT (5500) +#define GSL_SPF_READ_WRITE_TIMEOUT_MS_DEFAULT (1000) +#endif + +/** + * @h2xmlp_parameter {"PARAM_ID_SPF_TIMEOUTS", + * PARAM_ID_SPF_TIMEOUTS} + * @h2xmlp_description {Contains timeouts used for setting max wait + * times for responses or operations between GSL and SPF} + */ +struct spf_timeouts_value { + /** @h2xmle_description {Max wait time for SPF response, excluding the graph open command} + * @h2xmle_default {0x3e8} + */ + uint32_t spf_timeout; + /** @h2xmle_description {Max wait time for SPF response to the graph open command} + * @h2xmle_default {0xfa0} + */ + uint32_t graph_open_timeout; + /** @h2xmle_description {Max wait time for SPF response to the graph prepare command} + * @h2xmle_default {0x7d0} + */ + uint32_t graph_prepare_timeout; + /** @h2xmle_description {Max wait time for start/stop operation completion} + * @h2xmle_default {0x157c} + */ + uint32_t graph_start_stop_timeout; + /** @h2xmle_description {Max wait time for read/write operation completion} + * @h2xmle_default {0x3e8} + */ + uint32_t spf_read_write_timeout; +}; + +/** + * @} + */ + +/* + * \brief get spf timeouts from acdb + * + */ +int32_t gsl_spf_timeouts_get_timeouts_from_acdb(void); + +/* + * \brief initialize SPF timeouts, internally queries ACDB to get supported info + * + */ +int32_t gsl_spf_timeouts_init(void); + +#endif diff --git a/gsl/inc/gsl_spf_timeout.xml b/gsl/inc/gsl_spf_timeout.xml new file mode 100644 index 0000000..0e210ec --- /dev/null +++ b/gsl/inc/gsl_spf_timeout.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/gsl/inc/gsl_subgraph.h b/gsl/inc/gsl_subgraph.h new file mode 100644 index 0000000..6b060bc --- /dev/null +++ b/gsl/inc/gsl_subgraph.h @@ -0,0 +1,149 @@ +#ifndef GSL_SUBGRAPH_H +#define GSL_SUBGRAPH_H +/** + * \file gsl_subgraph.h + * + * \brief + * Represents a single sub-graph + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ar_util_list.h" +#include "gsl_intf.h" +#include "gsl_shmem_mgr.h" +#include "gsl_subgraph_driver_props.h" +#include "gsl_subgraph_driver_props_generic.h" +#include "acdb.h" +#include "ar_osal_sys_id.h" + +struct gsl_child_sg { + struct ar_list_node_t node; /**< list node for subgraph children */ + uint32_t ref_cnt; + uint32_t sg_id; + struct gsl_subgraph *sg_obj; +}; + +struct gsl_subgraph { + struct ar_list_node_t node; + uint32_t sg_id; + uint32_t open_ref_cnt; + uint32_t start_ref_cnt; + uint32_t stop_ref_cnt; + uint32_t num_proc_ids; + /* below shmem pointer points to data of type AcdbSgIdPersistData */ + struct gsl_shmem_alloc_data_per_proc persist_cal_data_per_proc[AR_SUB_SYS_ID_LAST]; + /* below shmem pointer points to data of type AcdbSgIdPersistData */ + struct gsl_shmem_alloc_data user_persist_cfg_data; + uint32_t user_persist_cfg_data_size; + /* below shmem pointer points to data of type AcdbSgIdPersistData */ + struct gsl_shmem_alloc_data cma_persist_cfg_data; + uint32_t cma_cal_data_size; + struct sg_generic_t drv_prop_data; + struct sg_type_t sg_type_data; + struct ar_list_t children; +}; + +struct gsl_sgid_list { + uint32_t len; + uint32_t *sg_ids; +}; + +struct gsl_sgobj_list { + uint32_t len; + struct gsl_subgraph **sg_objs; +}; + +/** + * \brief initialize a subgraph object + * + * \param[in] sg: subgraph object to be initialized + * calibration + * \param[in] sg_id: subgraph id to be used for this object + * + * \return GSL_EOK on success, error code otherwise + */ +uint32_t gsl_subgraph_init(struct gsl_subgraph *sg, uint32_t sg_id); + +/** + * \brief Add child subgraphs to a given subgraph object + * + * \param[in] sg: the subgraph to add children to + * \param[in] child_sgids: contains information about the child subgraphs + * to add. + * \param[out] pruned_child_sgids: OPTIONAL if not NULL will be set to + * a list of child subgraphs with corresponding refcnt of 1. These will + * be edges that need to be opened on Spf. + * \param[out] existing_child_sgids: OPTIONAL if not NULL will be set to + * the subgraphs NOT in pruned_child_sgids, i.e. the ones which do not + * need to be opened on SPF + * + * \return GSL_EOK on success, error code otherwise + */ +uint32_t gsl_subgraph_add_children(struct gsl_subgraph *sg, + AcdbSubgraph *child_sgids, AcdbSubgraph *pruned_child_sgids, + AcdbSubgraph *existing_child_sgids); + +/** + * \brief Remove child subgraphs from a given subgraph object + * + * \param[in] sg: the subgraph to remove children from + * \param[in] child_sgids: contains information about the child subgraphs + * to remove. + * \param[in] props: SG properties. If not NULL only remove a child if it + * matches the properties. In case the parent matches the properties then + * remove all of its children. + * \param[out] pruned_child_sgids: OPTIONAL if not NULL will be set to + * a list of child subgraphs whose refrence count became 0 and got deleted + * from the subgraph. These will be edges that need to be closed on Spf. + * + * \return GSL_EOK on success, error code otherwise + */ +uint32_t gsl_subgraph_remove_children(struct gsl_subgraph *sg, + AcdbSubgraph *child_sgids, struct gsl_cmd_properties *props, + AcdbSubgraph *pruned_child_sgids); + +/** + * \brief Read persistent cal pertaining to this subgraph from ACDB and + * store inside the subgraph object + * + * \param[in] sg: the subgraph whose persistent cal data we want to read + * \param[in] ckv: new ckv that is being set. we do not use delta ckv here + * \param[in] mem_type: what type of memory (cma/normal) to query ACDB for + * \param[in] master_proc: SPF master proc id + * + * \return GSL_EOK on success, error code otherwise + */ +int32_t gsl_subgraph_query_persist_cal_by_mem(struct gsl_subgraph *sg_obj, + const struct gsl_key_vector *ckv, const AcdbHwAccelMemType mem_type, + uint32_t master_proc, uint32_t persist_cal_idx); + +/** + * \brief Copy perstent data provided by caller into this subgraphs shared + * memory buffer + * + * \param[in] sg: the subgraph whose persistent cal data we want to read + * \param[in] persistent_cal: pointer to blob of persistent cal data + * \param[in] persistent_cal_sz: size of persistent_cal in bytes + * \param[in] master_proc: SPF master proc id + * + * \return GSL_EOK on success, error code otherwise + */ +int32_t gsl_subgraph_set_persist_cal(struct gsl_subgraph *sg, + uint8_t *persistent_cal, uint32_t persistent_cal_sz, + uint32_t master_proc, uint32_t persist_cal_idx); + +/** + * \brief Checks if the given subgraph matches at least one of the property + * values in the given set + * + * \param[in] sg: subgraph object + * \param[in] props: containts a property id and a set of values to match + * against + * + * \return TRUE if sg contains the same property_id with a value that matches + * one of the values in the set of values in props. FALSE otherwise. + */ +bool_t is_matching_sg_property(struct gsl_subgraph *sg, + struct gsl_cmd_properties *props); +#endif /* GSL_SUBGRAPH */ diff --git a/gsl/inc/gsl_subgraph_driver_props_generic.h b/gsl/inc/gsl_subgraph_driver_props_generic.h new file mode 100644 index 0000000..8252186 --- /dev/null +++ b/gsl/inc/gsl_subgraph_driver_props_generic.h @@ -0,0 +1,51 @@ +#ifndef GSL_SUBGRAPH_DRIVER_PROPS_GENERIC_H +#define GSL_SUBGRAPH_DRIVER_PROPS_GENERIC_H + +/** + * \file gsl_subgraph_driver_props.h + * + * \brief + * Represents GSL subgraph driver properties - generic + + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @h2xml_title_date {08/01/2018} + */ + +#include "ar_osal_types.h" + +#define SUB_GRAPH_PROP_ID_GENERIC 0x08000001 +#define ROUTING_ID_MDSP 0x1 +#define ROUTING_ID_ADSP 0x2 +#define ROUTING_ID_APPS 0x3 +#define ROUTING_ID_SDSP 0x4 +#define ROUTING_ID_CDSP 0x5 +#define FLUSHABLE_FALSE 0x0 +#define FLUSHABLE_TRUE 0x1 + +typedef struct sg_generic_t sg_generic_t; + +/** + * @h2xmlp_property {"SUB_GRAPH_PROP", SUB_GRAPH_PROP_ID_GENERIC} + * @h2xmlp_description {} + */ +struct sg_generic_t { + uint32_t routing_id; + /**< + * @h2xmle_rangeList {"ROUTING_ID_MDSP"=1; "ROUTING_ID_ADSP"=2; + * "ROUTING_ID_APPS"=3; "ROUTING_ID_SDSP"=4; "ROUTING_ID_CDSP"=5} + * @h2xmle_default {2} + * @h2xmle_description {} + */ + uint32_t is_flushable; + /**< + * @h2xmle_rangeList {"FLUSHABLE_FALSE"=0; "FLUSHABLE_TRUE"=1} + * @h2xmle_default {1} + * @h2xmle_description {} + */ +}; + +#endif diff --git a/gsl/inc/gsl_subgraph_pool.h b/gsl/inc/gsl_subgraph_pool.h new file mode 100644 index 0000000..84a1732 --- /dev/null +++ b/gsl/inc/gsl_subgraph_pool.h @@ -0,0 +1,75 @@ +#ifndef GSL_SUBGRAPH_POOL_H +#define GSL_SUBGRAPH_POOL_H +/** + * \file gsl_subgraph_pool.h + * + * \brief + * Implements a store for all subgraphs active in Spf, note this is a + * singleton. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_subgraph.h" + +/** + * \brief initialize the data structure used for the pool + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_sg_pool_init(void); + +/** + * \brief Deinitialize the data structure used for the pool + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_sg_pool_deinit(void); + +/** + * \brief Find a subgraph by SGID in the pool + * + * \param[in] sgid: the subgraph ID find + * + * \return pointer to the SG object + */ +struct gsl_subgraph *gsl_sg_pool_find(uint32_t sgid); + +/** + * \brief Add a subgraph to the pool + * + * \return AR_EOK on success, error code otherwise + */ +struct gsl_subgraph *gsl_sg_pool_add(uint32_t sg_id, bool_t preload_only); + +/** + * \brief Remove a subgraph from pool + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_sg_pool_remove(struct gsl_subgraph *sg, bool_t unload_only); + +/** + * \brief Determine which subgraphs out of the provided list have a refrence + * count of 1 and return the corresponding subgraph ids + * + * \param[in] subgraphs: the set of subgraphs to prune from + * \param[in] num_sgs: number of subgraphs in sg_objs + * \param[in] props: OPTIONAL subgrah properties, all subgraphs that do not + * match the properties will be pruned out + * \param[out] pruned_sgids: subgraph ids of the subgraph objs that have a + * refcnt of 1 + * + * \return GSL_EOK on success, error code otherwise + */ +uint32_t gsl_sg_pool_prune_sg_list(struct gsl_subgraph **subgraphs, + uint32_t num_sgs, struct gsl_cmd_properties *props, + struct gsl_sgid_list *pruned_sgids, struct gsl_sgid_list *existing_sgids); + +/** + * \brief Scan through the child subgraphs of each entry in the pool and set + * its obj_ref to gsl_subgraph entry in the pool if it is not already set + */ +void gsl_sg_pool_update_child_refs(void); +#endif //GSL_SUBGRAPH_POOL_H diff --git a/gsl/rtc_api/gsl_rtc_intf.h b/gsl/rtc_api/gsl_rtc_intf.h new file mode 100644 index 0000000..c46aa72 --- /dev/null +++ b/gsl/rtc_api/gsl_rtc_intf.h @@ -0,0 +1,292 @@ +#ifndef GSL_RTC_INTF_H +#define GSL_RTC_INTF_H +/** + * \file gsl_rtc_intf.h + * + * \brief + * Interface definition for GSL RTC functionality + + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "ar_osal_types.h" +#include "gsl_intf.h" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4200) +#endif +struct gsl_rtc_key_vector { + uint32_t num_kvps; /**< number of key-value pairs */ + struct gsl_key_value_pair kvp[]; /**< key-value pairs */ +}; + +struct gsl_rtc_uc_data { + uint32_t graph_handle; /**< graph handle id for the active use-case */ + uint32_t num_gkvs; /**< number of gkvs in the graph */ + uint32_t num_ckvs; /**< number of ckvs in the graph */ + uint8_t payload[]; + /**< + * GKV vectors followed by CKV vectors. Each GKV or CKV vector + * is in the form - struct gsl_rtc_key_vector + */ +}; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +struct gsl_rtc_active_uc_info { + uint32_t num_usecases; /**< total number of active use-cases */ + uint32_t total_size; /**< total size for gsl_rtc_active_uc_data */ + struct gsl_rtc_uc_data *uc_data; + /**< memory pointing to active use-case data */ +}; + +struct gsl_rtc_param { + /** GSL graph handle */ + uint32_t graph_handle; + /** sgid of the non-persist cal data */ + uint32_t sgid; + /** total size of the non-persist cal data */ + uint32_t total_size; + /** + * Pointer to non-persist cal data. + * The data in this buffer can contain one or more parameters + * in the form - {MIID, PID, Size, ErrorCode, VariablePayload} + */ + uint8_t *sg_cal_data; +}; + +struct gsl_rtc_persist_param { + /** GSL graph handle */ + uint32_t graph_handle; + /** sgid of the persist cal data */ + uint32_t sgid; + /** processor id of the persist cal data within the sgid */ + uint32_t proc_id; + /** + * Total size of the perist cal data. + * It is both input and output. GSL updates it + * with the actual data that is copied into the buffer + */ + uint32_t *total_size; + /** + * Pointer to persist cal data. + * The data in this buffer can contain one or more parameters + * in the form - {MIID, PID, Size, ErrorCode, VariablePayload} + * + * In the case where this structure is passed in as part of + * set this pointer will be set by the caller. In + * the case of get it will be set by gsl. + * + * Setting the pointer to NULL results in GSL to query the data from ACDB + * using the CKV below + */ + uint8_t *sg_cal_data; + /** pointer to CKV used to query acdb in-case above pointer is NULL */ + struct gsl_rtc_key_vector *ckv; +}; + +struct gsl_rtc_prepare_change_graph_info { + /* GSL graph handle */ + uint32_t graph_handle; + /** + * GKV corresponding to active use-case + */ + struct gsl_rtc_key_vector *old_gkv; + /* + * Number of subgraphs in sg_conn_info + */ + uint32_t num_sgs; + /* + * size of sg_conn_info structure below in bytes + */ + uint32_t size_of_sg_conn_info; + /* + * sg connection info for sg connections that are in the graph after + * RTGM modification + * + * the data is structured as follows: + * sg_id_1, num_children, child0, child1... + * sg_id_2, num_children, child0, child1... + * ... + */ + uint32_t *sg_conn_info; + /* + * number of existing subgraphs that have module level modifications and + * therefore should be closed and reopened + */ + uint32_t num_modified_sgs; + /* + * list of existing subgraphs that have module level modifications and + * therefore should be closed and reopened + */ + uint32_t *modified_sgs; + /* + * number of entires in modified_sg_conn_info + */ + uint32_t num_modified_sg_connections; + /* + * size of the modified sg_conn_info strucutre below in bytes + */ + uint32_t size_of_modified_sg_conn_info; + /* + * sg connection info for sg connections that are either + * a. input to or output from modified sgs + * or + * b. modified by user (source or sink modules changed) + * + * the data should be structured as follows: + * sg_id_1, num_children, child0, child1... + * sg_id_2, num_children, child0, child1... + * ... + */ + uint32_t *modified_sg_conn_info; +}; + +struct gsl_rtc_change_graph_info { + /* GSL graph handle */ + uint32_t graph_handle; + /** + * GKV corresponding to active use-case + */ + struct gsl_rtc_key_vector *old_gkv; + /** + * GKV used to replace the old_gkv, this typically only changes if there + * is a subgraph add or delete, it is allowed to be same as old_gkv + */ + struct gsl_rtc_key_vector *new_gkv; + /** + * CKV used to identy calibration data for the new graph + */ + struct gsl_rtc_key_vector *new_ckv; + /** + * Size of tag data blob. Set to 0 to indicate none included + */ + uint32_t tag_data_size; + /** + * Tag data blob pointer + */ + uint8_t *tag_data; +}; + +typedef enum gsl_rtc_conn_state { + /** + * The rtc connection 'start' state. The RTC client will issue this + * command when it establishes a connection with ATS + */ + GSL_RTC_CONNECTION_STATE_START, + /** + * The rtc connection 'stop' state. The RTC client will issue this + * command when it disconnects from ATS + */ + GSL_RTC_CONNECTION_STATE_STOP, +} gsl_rtc_conn_state; + +struct gsl_rtc_conn_info { + /** + * The state of an RTC session. + */ + gsl_rtc_conn_state state; +}; + +/** + * \brief Get active use-case info + * + * \param[in/out] rsp: rsp pointer + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_rtc_get_active_usecase_info(struct gsl_rtc_active_uc_info *info); + +/** + * \brief get persist calibration data + * + * \param[in/out] rtc_param: pointer to struct gsl_rtc_persist_param + * RTC client is responsible to allocate/free the memory + * for gsl_rtc_persist_param + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_rtc_get_persist_data(struct gsl_rtc_persist_param *rtc_param); + +/** + * \brief get non-persist calibration data + * RTC client is responsible to allocate/free the memory + * for gsl_rtc_param + * + * \param[in/out] rtc_param: pointer to struct gsl_rtc_param + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_rtc_get_non_persist_data(struct gsl_rtc_param *rtc_param); + +/** + * \brief set persist calibration data + * RTC client is responsible to allocate/free the memory + * for gsl_rtc_persist_param + * + * \param[in/out] rtc_param: pointer to struct gsl_rtc_persist_param + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_rtc_set_persist_data(struct gsl_rtc_persist_param *rtc_param); + + +/** + * \brief set non-persist calibration data + * + * \param[in/out] rtc_param: pointer to struct gsl_rtc_param + * RTC client is responsible to allocate/free the memory + * for gsl_rtc_param + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_rtc_set_non_persist_data(struct gsl_rtc_param *rtc_param); + +/** + * \brief Prepare for graph change operation, this will update GSL state and + * close subgraphs and connections that are no longer needed but will not open + * anything on Spf. This must be called before the ACDB data is updated. + * + * \param[in] rtc_param: pointer to struct gsl_rtc_prepare_change_graph, + * carries information about the RTGM operation to be performed + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_rtc_prepare_change_graph( + struct gsl_rtc_prepare_change_graph_info *rtc_param); + +/** + * \brief Complete the graph change operation that is already prepared. Note + * calling gsl_rtc_prepare_change_graph is mandatory before calling this API + * also the ACDB data on the device must be updated before calling this API. + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_rtc_change_graph(struct gsl_rtc_change_graph_info *rtc_param); + +/** + * \brief Notifies GSL about client connectivity. + * \sa gsl_rtc_prepare_change_graph + * gsl_rtc_change_graph + * gsl_rtc_rtgm_session_state + * + * \param[in]: rtgm_session_info: info about RTC session to store internally + * + * \return AR_EOK on success, error code otherwise + */ +int32_t gsl_rtc_notify_conn_state(struct gsl_rtc_conn_info *rtgm_session_info); + +#define GSL_RTC_GKV_SIZE_BYTES(num_kvps) (sizeof(struct gsl_rtc_key_vector) +\ + ((num_kvps) * sizeof(struct gsl_key_value_pair))) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* GSL_RTC_INTF_H */ diff --git a/gsl/src/gsl_common.c b/gsl/src/gsl_common.c new file mode 100644 index 0000000..711980e --- /dev/null +++ b/gsl/src/gsl_common.c @@ -0,0 +1,366 @@ +/** + * \file gsl_common.c + * + * \brief + * Common utilities used by various modules within GSL, this is the + * lowest level module within GSL + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_common.h" +#include "ar_osal_error.h" +#include "ar_osal_mutex.h" +#include "ar_osal_sys_id.h" +#include "gpr_api_inline.h" +#include "apm_api.h" +#include "ar_util_err_detection.h" +#include "ar_osal_servreg.h" + +uint32_t gsl_signal_create(struct gsl_signal *sig_p, ar_osal_mutex_t *lock) +{ + if (!sig_p) + return AR_EBADPARAM; + + sig_p->flags = 0; + sig_p->status = 0; + sig_p->gpr_packet = NULL; + sig_p->lock = lock; + sig_p->expected_packet_token = 0; + + return ar_osal_signal_create(&sig_p->sig); +} + +uint32_t gsl_signal_destroy(struct gsl_signal *sig_p) +{ + uint32_t rc = AR_EOK; + + if (!sig_p) + return AR_EBADPARAM; + + if (sig_p->lock) + GSL_MUTEX_LOCK(*sig_p->lock); + + /* if there was a pending gpr packet that never got consumed free it */ + if (sig_p->gpr_packet) + __gpr_cmd_free(sig_p->gpr_packet); + sig_p->gpr_packet = NULL; + sig_p->expected_packet_token = 0; + + rc = ar_osal_signal_destroy(sig_p->sig); + sig_p->sig = NULL; + if (sig_p->lock) + GSL_MUTEX_UNLOCK(*sig_p->lock); + + sig_p->lock = NULL; + + return rc; +} + +uint32_t gsl_signal_timedwait(struct gsl_signal *sig_p, uint32_t timeout_ms, + uint32_t *ev_flags, uint32_t *status, gpr_packet_t **gpr_packet) +{ + uint32_t rc = AR_EOK; + + if (!sig_p) + return AR_EBADPARAM; + + rc = ar_osal_signal_timedwait(sig_p->sig, GSL_TIMEOUT_NS(timeout_ms)); + if (!rc) { + if (sig_p->lock) + GSL_MUTEX_LOCK(*sig_p->lock); + ar_osal_signal_clear(sig_p->sig); + *ev_flags = sig_p->flags; + if (status) + *status = sig_p->status; + if (gpr_packet) + *gpr_packet = (gpr_packet_t *) sig_p->gpr_packet; + sig_p->gpr_packet = NULL; + sig_p->flags = 0; /* clear */ + sig_p->status = 0; + if (sig_p->lock) + GSL_MUTEX_UNLOCK(*sig_p->lock); + } + // clear gpr packet token + sig_p->expected_packet_token = 0; + return rc; +} + +uint32_t gsl_signal_set(struct gsl_signal *sig_p, uint32_t ev_flags, + int32_t status, void *gpr_packet) +{ + uint32_t rc = AR_EOK; + + if (!sig_p) + return AR_EBADPARAM; + + if (sig_p->lock) + GSL_MUTEX_LOCK(*sig_p->lock); + sig_p->flags |= ev_flags; + sig_p->status = status; + /* if there was a pending gpr packet that never got consumed free it */ + if (sig_p->gpr_packet) + __gpr_cmd_free(sig_p->gpr_packet); + if (gpr_packet && sig_p->expected_packet_token != ((gpr_packet_t *)gpr_packet)->token) { + // there is a delay packet received, just ignore it. + GSL_ERR("received a delay packet, opcode[0x%x], token 0x%08x, ignore it.", + ((gpr_packet_t *)gpr_packet)->opcode, ((gpr_packet_t *)gpr_packet)->token); + rc = AR_EUNEXPECTED; + goto exit; + } + sig_p->gpr_packet = gpr_packet; + rc = ar_osal_signal_set(sig_p->sig); + +exit: + if (sig_p->lock) + GSL_MUTEX_UNLOCK(*sig_p->lock); + + return rc; +} + +uint32_t gsl_signal_clear(struct gsl_signal *sig_p, uint32_t ev_flags) +{ + uint32_t rc = AR_EOK; + + if (!sig_p) + return AR_EBADPARAM; + if (sig_p->lock) + GSL_MUTEX_LOCK(*sig_p->lock); + sig_p->flags &= ~ev_flags; + rc = ar_osal_signal_clear(sig_p->sig); + if (sig_p->lock) + GSL_MUTEX_UNLOCK(*sig_p->lock); + + return rc; +} + +int32_t gsl_allocate_gpr_packet(uint32_t opcode, uint32_t src_port, + uint32_t dst_port, uint32_t payload_size, uint32_t token, + uint32_t dest_domain, struct gpr_packet_t **alloc_packet) +{ + int32_t rc = AR_EOK; + gpr_cmd_alloc_ext_t alloc_params; + + alloc_params.src_domain_id = GSL_GPR_SRC_DOMAIN_ID; + alloc_params.dst_domain_id = (uint8_t) dest_domain; + alloc_params.client_data = 0; + + alloc_params.src_port = src_port; + alloc_params.dst_port = dst_port; + alloc_params.token = token; + alloc_params.opcode = opcode; + alloc_params.payload_size = payload_size; + alloc_params.ret_packet = alloc_packet; + + rc = __gpr_cmd_alloc_ext(&alloc_params); + return rc; +} + +/* Payload must be 8B aligned for spf */ +int32_t gsl_send_spf_cmd(gpr_packet_t **packet, struct gsl_signal *sig_p, + gpr_packet_t **rsp_pkt) +{ + int32_t rc = AR_EOK; + uint32_t ev_flags = 0, spf_status = 0, i = 0; + uint32_t opcode = (*packet)->opcode; + struct gsl_servreg_handle_list *restart_handle_list; + bool_t do_restart = false; + static uint32_t debug_token = 0; /* token is echoed in SPF log */ + + #ifdef GSL_DEBUG_ENABLE + /* Cache debug variables for later + * Needed as there is no guarantee of packet surviving beyond async_send + */ + uint32_t src_port = (*packet)->src_port, + dst_port = (*packet)->dst_port; + #endif + if(opcode != APM_CMD_REGISTER_MODULE_EVENTS) { + if ((debug_token << DEBUG_TOKEN_SHIFT) == 0) + ++debug_token; + INSERT_DEBUG_TOKEN((*packet)->token, debug_token); + ++debug_token; + if(sig_p == NULL) + GSL_VERBOSE("sending pkt opcode 0x%x token 0x%08x", opcode, (*packet)->token); + } + if (sig_p != NULL) + sig_p->expected_packet_token = (*packet)->token; + + rc = __gpr_cmd_async_send(*packet); + if (rc) { + __gpr_cmd_free(*packet); + goto exit; + } + + if (sig_p != NULL) { + GSL_DBG("Wait for Rsp opcode[0x%x] src_port[0x%x] dst_port[0x%x] token 0x%08x", + opcode, src_port, dst_port, (*packet)->token); + /* + * once osal signal is set it remains set till cleared, so if we + * got a set before wait is called the below wait will immediately + * return + */ + if (opcode == APM_CMD_GRAPH_OPEN) { + rc = gsl_signal_timedwait(sig_p, GSL_GRAPH_OPEN_TIMEOUT_MS, + &ev_flags, &spf_status, rsp_pkt); + } else if (opcode == APM_CMD_GRAPH_START || opcode == APM_CMD_GRAPH_STOP) { + rc = gsl_signal_timedwait(sig_p, GSL_GRAPH_START_STOP_TIMEOUT_MS, + &ev_flags, &spf_status, rsp_pkt); + } else if (opcode == APM_CMD_GRAPH_PREPARE) { + rc = gsl_signal_timedwait(sig_p, GSL_GRAPH_PREPARE_TIMEOUT_MS, &ev_flags, + &spf_status, rsp_pkt); + } else { + rc = gsl_signal_timedwait(sig_p, GSL_SPF_TIMEOUT_MS, &ev_flags, + &spf_status, rsp_pkt); + } + + if (opcode != APM_CMD_REGISTER_MODULE_EVENTS) { + GSL_DBG("rcvd pkt token : 0x%x", (*packet)->token); + REMOVE_DEBUG_TOKEN((*packet)->token); + } + GSL_DBG("Wait done rc[0x%x] opcd[0x%x] src_prt[0x%x] dst_prt[0x%x]", + rc, opcode, src_port, dst_port); + GSL_DBG("flags[0x%x] spf_status[0x%x]", ev_flags, spf_status); + + if (rc) { + rc = AR_ETIMEOUT; + spf_status = AR_ETIMEOUT; + } else if (ev_flags & GSL_SIG_EVENT_MASK_CLOSE) + rc = AR_EABORTED; + else if (ev_flags & GSL_SIG_EVENT_MASK_SSR) + rc = AR_ESUBSYSRESET; + else if ((ev_flags & GSL_SIG_EVENT_MASK_SPF_RSP)) { + rc = spf_status; + if (rsp_pkt && *rsp_pkt) { + GSL_LOG_PKT("recv_pkt", ((gpr_packet_t *)(*rsp_pkt))->src_port, + (gpr_packet_t *)(*rsp_pkt), + GPR_PKT_GET_HEADER_BYTE_SIZE( + ((gpr_packet_t *)(*rsp_pkt))->header) + + GPR_PKT_GET_PAYLOAD_BYTE_SIZE( + ((gpr_packet_t *)(*rsp_pkt))->header), NULL, 0); + } + } + + if (spf_status) { + /* error detection */ + rc = ar_err_det_detect_spf_error((*packet)->dst_domain_id, + spf_status, opcode, &do_restart, (void *)&restart_handle_list); + + if (rc) { + GSL_ERR("Error detection failed. Not restarting"); + } else if (do_restart) { + /* we get an array of the handles to restart back + * first entry is number of array entries following + */ + for (i = 0; i < restart_handle_list->num_handles; ++i) { + ar_osal_servreg_restart_service( + restart_handle_list->handles[i]); + } + } + rc = spf_status; + } + } + +exit: + /* mark packet null to indicate it has been sent */ + *packet = NULL; + return rc; +} + +int32_t gsl_send_spf_cmd_wait_for_basic_rsp(gpr_packet_t **packet, + struct gsl_signal *sig_p) +{ + int32_t rc = AR_EOK; + gpr_packet_t *rsp = NULL; + struct spf_cmd_basic_rsp *basic_rsp = NULL; + uint32_t cached_opcode = (*packet)->opcode; + /* cache opcode since packet is freed when sent */ + + rc = gsl_send_spf_cmd(packet, sig_p, &rsp); + if (!rc && rsp && rsp->opcode == GPR_IBASIC_RSP_RESULT) { + basic_rsp = GPR_PKT_GET_PAYLOAD(struct spf_cmd_basic_rsp, rsp); + if (cached_opcode != basic_rsp->opcode) { + GSL_ERR("Recieved unexpected rsp opcode %x, expected %x", + basic_rsp->opcode, cached_opcode); + rc = AR_EUNEXPECTED; + } + } + + if (rsp) + __gpr_cmd_free(rsp); + + return rc; +} + +int32_t gsl_send_spf_satellite_info(uint32_t proc_id, + uint32_t supported_ss_mask, uint32_t src_port, struct gsl_signal *sig_p) +{ + uint32_t i = 0, j = 0; + gpr_cmd_alloc_ext_t gpr_args; + int32_t rc = AR_EOK; + gpr_packet_t *send_pkt = NULL; + apm_cmd_header_t *apm_hdr; + apm_param_id_satellite_pd_info_t *sat_pd_info; + apm_module_param_data_t *param_hdr; + + if (supported_ss_mask == (uint32_t) GSL_GET_SPF_SS_MASK(proc_id)) + return AR_EOK; + + gpr_args.src_domain_id = GPR_IDS_DOMAIN_ID_APPS_V; + gpr_args.dst_domain_id = (uint8_t) proc_id; + gpr_args.src_port = src_port; + gpr_args.dst_port = APM_MODULE_INSTANCE_ID; + gpr_args.opcode = APM_CMD_SET_CFG; + gpr_args.token = 0; + gpr_args.client_data = 0; + gpr_args.ret_packet = &send_pkt; + /* below allocate for worst case since payload size is small enough */ + gpr_args.payload_size = sizeof(apm_cmd_header_t) + + sizeof(apm_module_param_data_t) + + sizeof(apm_param_id_satellite_pd_info_t) + + ((AR_SUB_SYS_ID_LAST + 1) * sizeof(uint32_t)); + + rc = __gpr_cmd_alloc_ext(&gpr_args); + if (rc) { + GSL_ERR("Failed to allocate gpr pkt %d", rc); + goto exit; + } + + apm_hdr = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + apm_hdr->mem_map_handle = 0; + apm_hdr->payload_address_lsw = 0; + apm_hdr->payload_address_msw = 0; + apm_hdr->payload_size = sizeof(apm_module_param_data_t) + + sizeof(apm_param_id_satellite_pd_info_t) + + ((AR_SUB_SYS_ID_LAST + 1) * sizeof(uint32_t)); + + param_hdr = (apm_module_param_data_t *)(apm_hdr + 1); + param_hdr->module_instance_id = APM_MODULE_INSTANCE_ID; + param_hdr->param_id = APM_PARAM_ID_SATELLITE_PD_INFO; + param_hdr->param_size = sizeof(apm_param_id_satellite_pd_info_t) + + ((AR_SUB_SYS_ID_LAST + 1) * sizeof(uint32_t)); + param_hdr->error_code = 0; + + sat_pd_info = (apm_param_id_satellite_pd_info_t *)(param_hdr + 1); + + /* + * disable ADSP from the bitmask for now as we assume master is on + * ADSP. This can be revisited in the future once we add support for + * multiple masters + */ + supported_ss_mask &= ~proc_id; + for (i = AR_SUB_SYS_ID_FIRST; i <= AR_SUB_SYS_ID_LAST; ++i) { + if (GSL_TEST_SPF_SS_BIT(supported_ss_mask, i)) + sat_pd_info->proc_domain_id_list[j++] = i; + } + + sat_pd_info->num_proc_domain_ids = j; + if (sat_pd_info->num_proc_domain_ids > 0) { + GSL_LOG_PKT("send_pkt", src_port, send_pkt, sizeof(*send_pkt) + + gpr_args.payload_size, NULL, 0); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, sig_p); + if (rc) + GSL_ERR("failed to send spf satellite info rc %d", rc); + } +exit: + return rc; +} diff --git a/gsl/src/gsl_cshm_mgr.c b/gsl/src/gsl_cshm_mgr.c new file mode 100644 index 0000000..720ce14 --- /dev/null +++ b/gsl/src/gsl_cshm_mgr.c @@ -0,0 +1,681 @@ +/** + * \file gsl_cshm_mgr.c + * + * \brief + * Manages client shared memory allocations in the system + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +#include "gsl_intf.h" +#include "gsl_shmem_mgr.h" +#include "gsl_common.h" +#include "gsl_cshm_mgr.h" +#include "apm_memmap_api.h" +#include "apm_api.h" +#include "gpr_ids_domains.h" +#include "gpr_api_inline.h" +#include "ar_spf_cmd_api.h" + +#ifdef CLIENT_SHM_ENABLED + +typedef struct { + /* Indicates cshm init done + */ + bool is_init_done; + /* Protects cshm info lock + */ + ar_osal_mutex_t cshm_list_lock; + /* Max number of cshm allocation can be done at init time. If this limit crosses + * gsl init num_max_cshm_list * 2 number of info. + */ + uint32_t num_max_cshm_list; + /* Array of client memory info + */ + cshm_info_t** cshm_info_list; + /* Signal used to wait for responses from spf. Only one event can be sent at a time. + */ + struct gsl_signal sig; + /* Lock used in conjuction with above signal + */ + ar_osal_mutex_t sig_lock; +} cshm_ctx_t; + +static cshm_ctx_t cshm_ctx_glb; + +struct gsl_apm_mem_map_global { + struct apm_cmd_global_shared_mem_map_regions_t mmap_header; + struct apm_shared_map_region_payload_t mmap_payload; +}; + + + +gsl_mem_id_t gsl_get_mem_id(cshm_info_t *cmem_info) { + + gsl_mem_id_t mem_id = 0; + int index = 0; + + GSL_MUTEX_LOCK(cshm_ctx_glb.cshm_list_lock); + for(index = 0; index < cshm_ctx_glb.num_max_cshm_list; index++) { + if (!cshm_ctx_glb.cshm_info_list[index]){ + break; + } + } + + if (index == cshm_ctx_glb.num_max_cshm_list) { + cshm_ctx_glb.num_max_cshm_list = cshm_ctx_glb.num_max_cshm_list * 2; + GSL_INFO("max client list limit reached. Expanding max client list to %d",cshm_ctx_glb.num_max_cshm_list) + cshm_info_t * mem_info_list = gsl_mem_zalloc(sizeof(cshm_info_t*) * + cshm_ctx_glb.num_max_cshm_list); + if (mem_info_list == NULL ) { + GSL_ERR("Failed to allocate global context"); + cshm_ctx_glb.num_max_cshm_list = cshm_ctx_glb.num_max_cshm_list / 2; + goto exit; + } + gsl_memcpy(mem_info_list, (sizeof(cshm_info_t*) * cshm_ctx_glb.num_max_cshm_list), + cshm_ctx_glb.cshm_info_list, sizeof(cshm_info_t*) * + cshm_ctx_glb.num_max_cshm_list); + gsl_mem_free(cshm_ctx_glb.cshm_info_list); + cshm_ctx_glb.cshm_info_list = mem_info_list; + } + mem_id = to_gsl_mem_id(index); + cshm_ctx_glb.cshm_info_list[index] = cmem_info; + +exit: + GSL_MUTEX_UNLOCK(cshm_ctx_glb.cshm_list_lock); + return mem_id; +} + + +static uint32_t gsl_cshm_gpr_callback(gpr_packet_t *packet, void *cb_data) +{ + uint32_t rc = AR_EOK; + uint32_t master_proc = packet->src_domain_id; + + cb_data; /* Referencing to keep compiler happy */ + rc = gsl_signal_set(&cshm_ctx_glb.sig, GSL_SIG_EVENT_MASK_SPF_RSP, + AR_EOK, packet); + if (rc) + __gpr_cmd_free(packet); + + /* do not free packet, it will be freed by waiter */ + return 0; +} + +int32_t gsl_cshm_init(uint32_t num_client) +{ + int32_t rc = AR_EOK; + + if (cshm_ctx_glb.is_init_done == true) { + GSL_INFO("init already done"); + rc = AR_EOK; + goto exit; + } + if (num_client == 0) + num_client = CSHM_DEFAULT_INIT_CLIENT_NUM; + cshm_ctx_glb.num_max_cshm_list = num_client; + cshm_ctx_glb.cshm_info_list = gsl_mem_zalloc(sizeof(cshm_info_t*) *cshm_ctx_glb.num_max_cshm_list); + + if (cshm_ctx_glb.cshm_info_list == NULL ) { + GSL_ERR("Failed to allocate global context %d", rc); + goto exit; + } + + rc = ar_osal_mutex_create(&cshm_ctx_glb.cshm_list_lock); + if (rc) { + GSL_ERR("ar mutex create failed %d", rc); + goto free_ctxt; + } + rc = ar_osal_mutex_create(&cshm_ctx_glb.sig_lock); + if (rc) { + GSL_ERR("ar mutex create failed %d", rc); + goto cleanup_cshm_lock; + } + rc = gsl_signal_create(&cshm_ctx_glb.sig, + &cshm_ctx_glb.sig_lock); + if (rc) { + GSL_ERR("ar signal create failed %d", rc); + goto cleanup_sig_lock; + } + + rc = __gpr_cmd_register(GSL_CSHMEM_SRC_PORT, gsl_cshm_gpr_callback, &cshm_ctx_glb); + if (rc) { + GSL_ERR("gpr cmd register failed %d", rc); + goto cleanup_sig_lock; + } + cshm_ctx_glb.is_init_done = true; + goto exit; + +cleanup_sig_lock: + ar_osal_mutex_destroy(cshm_ctx_glb.sig_lock); +cleanup_cshm_lock: + ar_osal_mutex_destroy(cshm_ctx_glb.cshm_list_lock); +free_ctxt: + if (cshm_ctx_glb.cshm_info_list != NULL ) { + gsl_mem_free(cshm_ctx_glb.cshm_info_list); + cshm_ctx_glb.cshm_info_list = NULL ; + } +exit: + return rc; +} + +int32_t gsl_cshm_deinit(void) { + int32_t rc = AR_EOK; + + if (cshm_ctx_glb.is_init_done == false) { + GSL_INFO("cshm not initilaized"); + rc = AR_EUNSUPPORTED; + } + + __gpr_cmd_deregister(GSL_CSHMEM_SRC_PORT); + + if(cshm_ctx_glb.sig_lock) { + ar_osal_mutex_destroy(cshm_ctx_glb.sig_lock); + cshm_ctx_glb.sig_lock = NULL; + } + + if(cshm_ctx_glb.cshm_list_lock) { + ar_osal_mutex_destroy(cshm_ctx_glb.cshm_list_lock); + cshm_ctx_glb.cshm_list_lock = NULL; + } + + if(cshm_ctx_glb.cshm_info_list) { + gsl_mem_free(cshm_ctx_glb.cshm_info_list); + cshm_ctx_glb.cshm_info_list = NULL; + } + cshm_ctx_glb.num_max_cshm_list = 0; + cshm_ctx_glb.is_init_done = false; + return rc; +} + +void gsl_cshm_handle_ssr(enum spf_ss_state_t state, uint32_t spf_ss_mask) +{ + if (!(GSL_GET_SPF_SS_MASK(AR_AUDIO_DSP) & spf_ss_mask)) { + return; // SSR handling only for ADSP now + } + if (state == GSL_SPF_SS_STATE_DN) { + gsl_signal_set(&cshm_ctx_glb.sig, GSL_SIG_EVENT_MASK_SSR, 0, NULL); + /* mark all mem_id dirty*/ + for(int i = 0; i < cshm_ctx_glb.num_max_cshm_list; i++) { + if (cshm_ctx_glb.cshm_info_list[i] != NULL) { + set_mem_id_dirty(cshm_ctx_glb.cshm_info_list[i], true); + GSL_DBG("marking dirty %d", cshm_ctx_glb.cshm_info_list[i]->mem_id); + } + } + } else { + gsl_signal_clear(&cshm_ctx_glb.sig, GSL_SIG_EVENT_MASK_SSR); + } +} +bool gsl_check_mem_id_present(uint32_t mem_id) +{ + bool found = false; + + for(int i = 0; i < cshm_ctx_glb.num_max_cshm_list; i++) { + if (cshm_ctx_glb.cshm_info_list[i] != NULL && + cshm_ctx_glb.cshm_info_list[i]->mem_id == mem_id) { + found = true; + break; + } + } + return found; +} +int32_t gsl_add_mem_info(cshm_info_t *mem_info) +{ + int32_t rc = AR_EFAILED; + int32_t index_found = cshm_ctx_glb.num_max_cshm_list; + + GSL_MUTEX_LOCK(cshm_ctx_glb.cshm_list_lock); + for(int i = 0; i < cshm_ctx_glb.num_max_cshm_list; i++) { + if (cshm_ctx_glb.cshm_info_list[i] == NULL) { + index_found = i; + cshm_ctx_glb.cshm_info_list[i] = mem_info; + rc = AR_EOK; + break; + } + } + if ( index_found == cshm_ctx_glb.num_max_cshm_list) { + /** this case is not ever possible ever possible. New entry will be added already + * while gsl_get_mem_id. Even if it'sreaching just return failure, can't do anything. + */ + } + GSL_MUTEX_UNLOCK(cshm_ctx_glb.cshm_list_lock); + +exit: + return rc; +} + +cshm_info_t* gsl_get_mem_info(uint32_t index) +{ + if ( index >= 0 && index < cshm_ctx_glb.num_max_cshm_list) { + return cshm_ctx_glb.cshm_info_list[index]; + } + return NULL; +} + +int32_t gsl_rem_mem_info(uint32_t index) +{ + int32_t rc = AR_EFAILED; + + if ( index >= 0 && index < cshm_ctx_glb.num_max_cshm_list && + cshm_ctx_glb.cshm_info_list[index] != NULL) { + gsl_mem_free(cshm_ctx_glb.cshm_info_list[index]); + cshm_ctx_glb.cshm_info_list[index] = NULL; + rc = AR_EOK; + } + return rc; +} + +static int32_t gsl_cshm_handle_rsp(gpr_packet_t *rsp, uint32_t expected_opcode) +{ + + struct spf_cmd_basic_rsp *basic_rsp; + int32_t rc = AR_EOK; + + switch (rsp->opcode) { + case GPR_IBASIC_RSP_RESULT: + basic_rsp = GPR_PKT_GET_PAYLOAD(struct spf_cmd_basic_rsp, rsp); + switch (basic_rsp->opcode) { + case APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS: + case APM_CMD_GLOBAL_SHARED_MEM_UNMAP_REGIONS : + case AR_SPF_MSG_GLOBAL_SH_MEM: + if (basic_rsp->status) { + GSL_ERR("received failure %x from spf", basic_rsp->status); + rc = AR_EFAILED; + } + break; + default: + GSL_ERR("unsupported opcode %d encountered in GPR SHMEM response", + basic_rsp->opcode); + rc = AR_EFAILED; + break; + }; + break; + }; + + if (expected_opcode != rsp->opcode) { + GSL_ERR("Recieved unexpected rsp opcode %x, expected %x", + rsp->opcode, expected_opcode); + rc = AR_EUNEXPECTED; + } + __gpr_cmd_free(rsp); + return rc; +} + +int32_t gsl_cshm_map_to_spf(ar_shmem_info *mem_info, uint32_t mem_id) +{ + struct gsl_apm_mem_map_global *mmap; + apm_shared_map_region_payload_t *region; + int32_t rc = AR_EOK; + uint32_t tmp_spf_ss_mask; + uint32_t sys_id = AR_MODEM_DSP; + gpr_packet_t *send_pkt, *rsp_pkt = NULL ; + uint8_t cma_client_data = 0; + uint32_t master_proc_id = AR_AUDIO_DSP; + + /* if this is a CMA page we need to set client data on all gpr packets */ + if ((mem_info->flags & (AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG + << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) != 0) + cma_client_data = GSL_GPR_CMA_FLAG_BIT; + + for ( int i =0 ; i < mem_info->num_sys_id; i++) { + if (!gsl_spf_ss_state_get(mem_info->sys_id[i].proc_id)) + continue; + rc = gsl_allocate_gpr_packet(APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS, GSL_CSHMEM_SRC_PORT, + APM_MODULE_INSTANCE_ID, sizeof(*mmap) + sizeof(*region), 0, master_proc_id, + &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate shmem map pkt %d", rc); + goto exit; + } + /* + * Set client_data based on is_offset flag, this tells gpr in kernel to + * replace the MSW/LSW fields in the MMAP with actual physical address + * instead of the handle that got returned from osal, this is a hack to + * get around linux limitation where PA cannot be returned to + * user-space from kernel + */ + + mmap = GPR_PKT_GET_PAYLOAD(struct gsl_apm_mem_map_global, send_pkt); + + mmap->mmap_header.shmem_id = mem_id; + mmap->mmap_header.mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL; + mmap->mmap_header.num_regions = 1; + mmap->mmap_header.property_flag = 0; + if (mem_info->cache_type == AR_SHMEM_UNCACHED) + mmap->mmap_header.property_flag |= + APM_MEMORY_MAP_BIT_MASK_IS_UNCACHED; + mmap->mmap_header.property_flag |= mem_info->index_type << + APM_MEMORY_MAP_SHIFT_IS_OFFSET_MODE; + mmap->mmap_header.property_flag |= mem_info->mem_type << + APM_MEMORY_MAP_SHIFT_IS_VIRTUAL; + /*TODO: kernal mapping*/ + mmap->mmap_payload.shm_addr_lsw = mem_info->ipa_lsw; + mmap->mmap_payload.shm_addr_msw = mem_info->ipa_msw; + mmap->mmap_payload.mem_size_bytes = mem_info->buf_size; + + send_pkt->client_data |= cma_client_data; + + GSL_LOG_PKT("send_pkt", GSL_CSHMEM_SRC_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*mmap), NULL , 0); + rc = gsl_send_spf_cmd(&send_pkt, &cshm_ctx_glb.sig, &rsp_pkt); + if (rc) { + GSL_ERR("send spf cmd failed with err %d", rc); + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + goto exit; + } + if (!rsp_pkt) { + GSL_ERR("Received NULL response packet"); + rc = AR_EUNEXPECTED; + goto exit; + } + + rc = gsl_cshm_handle_rsp(rsp_pkt, GPR_IBASIC_RSP_RESULT); + if (rc) { + GSL_ERR("handle shmem response failed %d", rc); + goto exit; + } + } + +exit: + return rc; +} + +int32_t gsl_cshm_unmap_to_spf(ar_shmem_info *mem_info, uint32_t mem_id) +{ + struct apm_cmd_global_shared_mem_unmap_regions_t *payload; + int32_t rc = AR_EOK; + gpr_packet_t *send_pkt, *rsp_pkt = NULL ; + uint8_t cma_client_data = 0; + + /* if this is a CMA page we need to set client data on all gpr packets */ + if ((mem_info->flags & (AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG + << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) != 0) + cma_client_data = GSL_GPR_CMA_FLAG_BIT; + + for ( int i =0 ; i < mem_info->num_sys_id; i++) { + /* if the DSP is down silently skip unmap */ + if (!gsl_spf_ss_state_get(mem_info->sys_id[i].proc_id)) + continue; + + rc = gsl_allocate_gpr_packet(APM_CMD_GLOBAL_SHARED_MEM_UNMAP_REGIONS, + GSL_CSHMEM_SRC_PORT, APM_MODULE_INSTANCE_ID, sizeof(*payload), 0, + mem_info->sys_id[i].proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + payload = GPR_PKT_GET_PAYLOAD( + struct apm_cmd_global_shared_mem_unmap_regions_t, send_pkt); + payload->shmem_id = mem_id; + + send_pkt->client_data |= cma_client_data; + + GSL_LOG_PKT("send_pkt", GSL_CSHMEM_SRC_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*payload), NULL , 0); + rc = gsl_send_spf_cmd(&send_pkt, &cshm_ctx_glb.sig, &rsp_pkt); + if (rc || !rsp_pkt) { + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + goto exit; + } + rc = gsl_cshm_handle_rsp(rsp_pkt, GPR_IBASIC_RSP_RESULT); + if (rc) { + GSL_ERR("handle shmem response failed %d", rc); + goto exit; + } + } +exit: + return rc; +} + +int32_t gsl_send_glb_msg_to_spf(uint32_t mem_id, uint32_t offset, uint32_t length, + uint32_t miid, ar_shmem_info *mem_info, uint32_t prop_flag) +{ + int32_t rc = AR_EOK; + ar_spf_msg_global_sh_mem_t *payload; + gpr_packet_t *send_pkt, *rsp_pkt = NULL; + uint8_t cma_client_data = 0; + + for ( int i =0 ; i < mem_info->num_sys_id; i++) { + /* if the DSP is down silently skip MSG */ + if (!gsl_spf_ss_state_get(mem_info->sys_id[i].proc_id)) { + continue; + } + rc = gsl_allocate_gpr_packet(AR_SPF_MSG_GLOBAL_SH_MEM, + GSL_CSHMEM_SRC_PORT, miid, sizeof(*payload), 0, + mem_info->sys_id[i].proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + payload = GPR_PKT_GET_PAYLOAD( + struct ar_spf_msg_global_sh_mem_t, send_pkt); + payload->shmem_id = mem_id; + payload->property_flag = prop_flag; + payload->shmem_addr_lsw = offset; + payload->shmem_addr_msw = 0; + payload->shmem_size = length; + + send_pkt->client_data |= cma_client_data; + + GSL_LOG_PKT("send_pkt", GSL_CSHMEM_SRC_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*payload), NULL , 0); + rc = gsl_send_spf_cmd(&send_pkt, &cshm_ctx_glb.sig, &rsp_pkt); + if (rc || !rsp_pkt) { + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + goto exit; + } + rc = gsl_cshm_handle_rsp(rsp_pkt, GPR_IBASIC_RSP_RESULT); + if (rc) { + GSL_ERR("handle shmem response failed %d", rc); + goto exit; + } + } + +exit: + return rc; +} + +int32_t gsl_cshm_alloc(uint32_t size, gsl_cshm_info_t *info) +{ + int32_t rc = AR_EOK; + int32_t rc1 = AR_EOK; + cshm_info_t *client_shm_info = NULL; + ar_shmem_info *shmem_info = NULL; + uint8_t sys_id = AR_SUB_SYS_ID_FIRST; + uint32_t tmp_spf_ss_mask, spf_ss_mask; + uint8_t sys_ids[AR_SUB_SYS_ID_LAST]; + + GSL_INFO("Enter: Alloc with size: 0x%x", size); + /* spf_ss_mask should come from use case, currently defaulting to ADSP */ + spf_ss_mask = GSL_GET_SPF_SS_MASK(AR_AUDIO_DSP); + client_shm_info = gsl_mem_zalloc(sizeof(cshm_info_t)); + if (client_shm_info == NULL) { + GSL_ERR("client shm info alloc failed with error %d", rc); + goto exit; + } + client_shm_info->mem_id =(uint32_t)gsl_get_mem_id(client_shm_info); + if (client_shm_info->mem_id == 0) { + GSL_ERR("No mem_id available"); + goto free_client_shm_info; + } + + client_shm_info->mem_info = gsl_mem_zalloc(sizeof(ar_shmem_info)); + if (client_shm_info->mem_info == NULL) { + rc = -AR_ENORESOURCE; + goto free_mem_id; + } + shmem_info = client_shm_info->mem_info; + shmem_info->buf_size = (size + GSL_CSHM_MGR_PAGE_SZ - 1) & + (~(GSL_CSHM_MGR_PAGE_SZ - 1)); + shmem_info->cache_type = (info->type == GSL_CSHM_CACHED) ? AR_SHMEM_CACHED : AR_SHMEM_UNCACHED; + + shmem_info->num_sys_id = 0; + shmem_info->sys_id = gsl_mem_zalloc(sizeof(uint8_t) *AR_SUB_SYS_ID_LAST); + if (shmem_info->sys_id == NULL) { + rc = -AR_ENORESOURCE; + goto free_shm_info; + } + /* populate ss_id_list based on spf_ss_mask */ + tmp_spf_ss_mask = spf_ss_mask; + while (tmp_spf_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(spf_ss_mask, sys_id)) { + shmem_info->sys_id[shmem_info->num_sys_id++].proc_id = sys_id; + } + ++sys_id; + tmp_spf_ss_mask >>= 1; + } + /* set special flag for CMA allocations */ + if (info->flag & GSL_SHMEM_CMA) + shmem_info->flags = + AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG + << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG; + client_shm_info->spf_ss_mask = spf_ss_mask; + rc = ar_shmem_alloc(shmem_info); + if (rc) { + GSL_ERR("ar_shmem_alloc failed with error %d", rc); + goto free_sys_id; + } + + rc = gsl_cshm_map_to_spf(shmem_info, client_shm_info->mem_id); + if (rc) { + GSL_ERR("Failed to map page with spf error %d", rc); + goto free_shm_mem; + } + rc = gsl_add_mem_info(client_shm_info); + if (rc) { + GSL_ERR("adding client info failed %d", rc); + goto unmap_with_spf; + } + info->mem_id = client_shm_info->mem_id; + info->fd = shmem_info->ipa_lsw; + goto exit; + + +unmap_with_spf: + if (shmem_info != NULL) { + rc1 = gsl_cshm_unmap_to_spf(shmem_info, client_shm_info->mem_id); + if (rc1) { + GSL_ERR("unmapping shared memory with mem_id %d failed %d", client_shm_info->mem_id, rc1); + } + } +free_shm_mem: + if (shmem_info != NULL) + ar_shmem_free(shmem_info); +free_sys_id: + if (shmem_info->sys_id != NULL) + gsl_mem_free(shmem_info->sys_id); +free_shm_info: + if (client_shm_info->mem_info != NULL) + gsl_mem_free(client_shm_info->mem_info); +free_mem_id: + rc1 = gsl_rem_mem_info(to_gsl_cshm_indx(client_shm_info->mem_id)); + if (rc1) { + GSL_ERR("removing client info with mem_id %d failed %d", client_shm_info->mem_id, rc1); + goto exit; + } + client_shm_info = NULL; +free_client_shm_info: + if (client_shm_info != NULL) + gsl_mem_free(client_shm_info); + +exit: + return rc; +} + +int32_t gsl_cshm_dealloc(gsl_mem_id_t mem_id) +{ + int32_t rc = AR_EOK; + cshm_info_t *client_shm_info = NULL; + + GSL_INFO("Enter: mem_id 0x%x", mem_id); + if (!is_valid_gsl_mem_id(mem_id) || + (client_shm_info = gsl_get_mem_info(to_gsl_cshm_indx(mem_id))) == NULL) { + GSL_ERR("invalid mem_id %d", mem_id); + rc = AR_EBADPARAM; + goto exit; + } + if (is_mem_id_dirty(client_shm_info)) { + GSL_DBG("releasing a dirty shared memory with mem_id %d", mem_id); + goto release_mem; + } + rc = gsl_cshm_unmap_to_spf(client_shm_info->mem_info, (uint32_t)mem_id); + if (rc) { + GSL_ERR("unmapping shared memory with mem_id %d failed %d", mem_id, rc); + goto exit; + } +release_mem: + ar_shmem_free(client_shm_info->mem_info); + gsl_mem_free(client_shm_info->mem_info->sys_id); + gsl_mem_free(client_shm_info->mem_info); + rc = gsl_rem_mem_info(to_gsl_cshm_indx(mem_id)); + if (rc) { + GSL_ERR("removing client info with mem_id %d failed %d", mem_id, rc); + goto exit; + } + +exit: + return rc; +} + +int32_t gsl_cshm_msg(gsl_mem_id_t mem_id, uint32_t offset, uint32_t length, uint32_t miid, + uint32_t prop_flag) +{ + int32_t rc = AR_EOK; + cshm_info_t *client_shm_info = NULL; + + if (!is_valid_gsl_mem_id(mem_id) || + (client_shm_info = gsl_get_mem_info(to_gsl_cshm_indx(mem_id))) == NULL) { + GSL_ERR("invalid mem_id 0x%x", mem_id); + rc = AR_EBADPARAM; + goto exit; + } + if (is_mem_id_dirty(client_shm_info)) { + rc = gsl_cshm_map_to_spf(client_shm_info->mem_info, client_shm_info->mem_id); + if (rc) { + GSL_ERR("Failed to map page with spf error %d", rc); + goto exit; + } + GSL_DBG("dirty mem_id %d mapping is success", mem_id); + set_mem_id_dirty(client_shm_info, false); + } + rc = gsl_send_glb_msg_to_spf((uint32_t)mem_id, offset, length, miid,client_shm_info->mem_info, + prop_flag); + if (rc) { + GSL_ERR("unmapping shared memory with mem_id %d failed %d", mem_id, rc); + goto exit; + } +exit: + return rc; +} + +#else +int32_t gsl_cshm_alloc(uint32_t size, gsl_cshm_info_t *info) +{ + GSL_ERR("Client shared memory feature is disabled"); + return AR_EUNSUPPORTED; +} +int32_t gsl_cshm_dealloc(gsl_mem_id_t mem_id) +{ + GSL_ERR("Client shared memory feature is disabled"); + return AR_EUNSUPPORTED; +} +int32_t gsl_cshm_msg(gsl_mem_id_t mem_id, uint32_t offset, uint32_t length, uint32_t miid, + uint32_t prop_flag) +{ + GSL_ERR("Client shared memory feature is disabled"); + return AR_EUNSUPPORTED; +} +int32_t gsl_cshm_init(uint32_t num_client) +{ + GSL_ERR("Client shared memory feature is disabled"); + return AR_EUNSUPPORTED; +} +void gsl_cshm_handle_ssr(enum spf_ss_state_t state, uint32_t spf_ss_mask) +{ + return; +} +#endif \ No newline at end of file diff --git a/gsl/src/gsl_datapath.c b/gsl/src/gsl_datapath.c new file mode 100644 index 0000000..8d55867 --- /dev/null +++ b/gsl/src/gsl_datapath.c @@ -0,0 +1,2528 @@ +/** + * \file gsl_datapath.c + * + * \brief + * Implement data path handling for Graph Service Layer (GSL) + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_error.h" +#include "ar_osal_sys_id.h" +#include "apm_api.h" +#include "rd_sh_mem_ep_api.h" +#include "wr_sh_mem_ep_api.h" +#include "sh_mem_pull_push_mode_api.h" + +#include "gsl_datapath.h" +#include "gsl_common.h" +#include "gpr_api_inline.h" + +#define GSL_MAX_RETRIES 3 +#define GSL_MAX_CACHE_UNMAP_RETRIES 3 +#define GSL_MAX_CACHE_SIZE 32 + +#define GSL_METADATA_TO_DATA_FACTOR 2 + +#define GSL_EXT_MEM_HANDLE_CHANGING UINT64_MAX + +#define GSL_TO_64_BIT(MSW_32_BIT, LSW_32_BIT)\ +(((uint64_t)(MSW_32_BIT) << 32) + (LSW_32_BIT)) + +struct gsl_ext_mem_cache_entry { + uint64_t alloc_handle; + uint32_t alloc_size; + uint32_t num_bufs_in_flight; + uint64_t last_used; // used when finding LRU eviction candidate + // todo: state + struct gsl_shmem_alloc_data shmem_data; + ar_osal_mutex_t lock; // protects alloc_handle and num_bufs_in_flight +}; + +/* Global cache object for external memory */ +static struct gsl_external_mem_cache { + struct gsl_ext_mem_cache_entry *entries; // array of [GSL_MAX_CACHE_SIZE]; + uint64_t age_counter; // for updating last used + uint32_t num_extern_mem_datapaths; // refcount, essentially + ar_osal_mutex_t num_dps_lock; // lock for refcount + ar_osal_mutex_t global_cache_lock; // lock to serialise maps & evicts +} ext_mem_cache; + +static void ext_mem_cache_init(void) +{ + uint32_t i; + + /* hold lock through init process so that next thread has an inited cache */ + GSL_MUTEX_LOCK(ext_mem_cache.num_dps_lock); + /* check then post-increment */ + if (ext_mem_cache.num_extern_mem_datapaths++ == 0) { + GSL_DBG("Init ext mem cache"); + + /* if first UC, instantiate the cache array and locks.*/ + ext_mem_cache.entries = gsl_mem_zalloc( + sizeof(struct gsl_ext_mem_cache_entry) * GSL_MAX_CACHE_SIZE); + ext_mem_cache.age_counter = 0; + ar_osal_mutex_create(&ext_mem_cache.global_cache_lock); + + for (i = 0; i < GSL_MAX_CACHE_SIZE; ++i) + ar_osal_mutex_create(&ext_mem_cache.entries[i].lock); + } + GSL_MUTEX_UNLOCK(ext_mem_cache.num_dps_lock); +} + +static void ext_mem_cache_deinit(void) +{ + uint32_t i; + + /* hold lock through deinit process */ + GSL_MUTEX_LOCK(ext_mem_cache.num_dps_lock); + /* decrement then check whether to tear down the cache */ + if (--ext_mem_cache.num_extern_mem_datapaths == 0) { + GSL_DBG("Deinit ext mem cache"); + + /* unmap all entries */ + for (i = 0; i < GSL_MAX_CACHE_SIZE; ++i) { + //state... + if (ext_mem_cache.entries[i].alloc_handle + != GSL_EXT_MEM_HDL_NOT_ALLOCD) + gsl_shmem_unmap_extern_mem(ext_mem_cache.entries[i].shmem_data); + ar_osal_mutex_destroy(ext_mem_cache.entries[i].lock); + } + ar_osal_mutex_destroy(ext_mem_cache.global_cache_lock); + gsl_mem_free(ext_mem_cache.entries); + ext_mem_cache.entries = NULL; + } + GSL_MUTEX_UNLOCK(ext_mem_cache.num_dps_lock); +} + +/* + * note this does not increment bufs in flight + * -- that's done in get_entry for concurrency reasons + */ +static void ext_mem_cache_update_entry_last_used(uint32_t index) +{ + uint32_t i; + uint64_t least_recently_used = UINT64_MAX; + + /* + * Not protecting this: + * it does not matter if age counter is same for 2 buffers + */ + ext_mem_cache.entries[index].last_used = ext_mem_cache.age_counter++; + + /* int rollover handling for age counter */ + if (ext_mem_cache.age_counter == UINT64_MAX) { + for (i = 0; i < GSL_MAX_CACHE_SIZE; ++i) { + if (ext_mem_cache.entries[i].last_used < least_recently_used) + least_recently_used = ext_mem_cache.entries[i].last_used; + } + for (i = 0; i < GSL_MAX_CACHE_SIZE; ++i) + ext_mem_cache.entries[i].last_used -= least_recently_used; + + ext_mem_cache.age_counter = 0; + } +} + +/* + * This only copies required fields out: alloc_handle, alloc_size, spf_addr + * If you need more, you need to add the copy. + * input: index is the token set on the buffer we sent to DSP + */ +static void ext_mem_cache_buf_done(uint32_t index, + struct gsl_ext_mem_cache_entry *cache_entry_data) +{ + /* + * copy required data out before we decrement buffs in flight. + * Once we decrement, cache entry could go away + */ + cache_entry_data->alloc_handle = ext_mem_cache.entries[index].alloc_handle; + cache_entry_data->alloc_size = ext_mem_cache.entries[index].alloc_size; + cache_entry_data->shmem_data.spf_addr + = ext_mem_cache.entries[index].shmem_data.spf_addr; + + GSL_MUTEX_LOCK(ext_mem_cache.entries[index].lock); + --ext_mem_cache.entries[index].num_bufs_in_flight; + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[index].lock); +} + +static int32_t ext_mem_cache_evict_entry(uint32_t *evicted_idx, + struct gsl_shmem_alloc_data *to_unmap) +{ + uint32_t i, lru_idx = UINT32_MAX, num_tries = 0; + uint64_t least_recently_used = UINT64_MAX; + bool_t entry_locked = FALSE; + + while (!entry_locked) { + /* + * bail if our candidate LRU gets repeatedly re-used from under us + * This means all buffers are being used frequently (cache too small) + */ + if (num_tries++ == GSL_MAX_CACHE_UNMAP_RETRIES) + goto cache_full; + + for (i = 0; i < GSL_MAX_CACHE_SIZE; ++i) { + /* this is the eviction strategy */ + if (ext_mem_cache.entries[i].num_bufs_in_flight == 0 && + ext_mem_cache.entries[i].last_used < least_recently_used) { + lru_idx = i; + least_recently_used = ext_mem_cache.entries[i].last_used; + } + } + + if (lru_idx == UINT32_MAX) { + /* bail with failure -- all bufs in use */ + goto cache_full; + } + + /* + * get lock and invalidate the alloc handle so other threads + * can't grab it from under this one, and make sure no thread sent a buf + * in the mean-time (i.e. dodge check-then-use issues) + */ + GSL_MUTEX_LOCK(ext_mem_cache.entries[lru_idx].lock); + if (ext_mem_cache.entries[lru_idx].num_bufs_in_flight == 0) { + /* if bufs in flight non-zero, our candidate got used */ + ext_mem_cache.entries[lru_idx].alloc_handle + = GSL_EXT_MEM_HDL_NOT_ALLOCD; + + entry_locked = TRUE; /* exit this loop */ + } + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[lru_idx].lock); + } + + /* the unmap is sent outside the global mapping lock */ + gsl_memcpy(to_unmap, sizeof(struct gsl_shmem_alloc_data), + &ext_mem_cache.entries[lru_idx].shmem_data, + sizeof(struct gsl_shmem_alloc_data)); + + ext_mem_cache.entries[lru_idx].alloc_size = 0; + ext_mem_cache.entries[lru_idx].last_used = UINT64_MAX; + gsl_memset(&ext_mem_cache.entries[lru_idx].shmem_data, 0, + sizeof(struct gsl_shmem_alloc_data)); + + *evicted_idx = lru_idx; + + return AR_EOK; + +cache_full: + GSL_ERR("Cache all in use. Increase your cache size"); + /* todo: map one-time use buffer for this case */ + return AR_ENORESOURCE; +} + +/* + * output: alloc_data is constructed as a copy, idx is the index into the array + * Use idx as the token to send to gecko + * This function increments num_bufs_in_flight for synchronization reasons. + */ +static uint32_t ext_mem_cache_get_entry(uint32_t proc_id, + struct gsl_extern_alloc_buff_info ext_mem_data, + struct gsl_shmem_alloc_data *alloc_data, uint32_t *idx) +{ + int32_t rc = AR_EOK; + uint32_t i, first_unused = UINT32_MAX; + struct gsl_shmem_alloc_data to_unmap = { 0 }; + + /* + * locking here only for cache disabled, to prevent double unmap + * Should be moved back to where it is commented out when cache enabled. + * Could make disable flow more efficient (no other locks) with this, + * but effort is better spent on enabling the cache as designed... + */ + GSL_MUTEX_LOCK(ext_mem_cache.global_cache_lock); + + /* + * Checking if item is in the cache already + * Not locking every check as this is costly. We will re-check under lock. + */ + for (i = 0; i < GSL_MAX_CACHE_SIZE; ++i) { + +#ifdef GSL_EXT_MEM_CACHE_DISABLE + if (ext_mem_cache.entries[i].num_bufs_in_flight == 0 && + ext_mem_cache.entries[i].alloc_handle + != GSL_EXT_MEM_HDL_NOT_ALLOCD) { + + GSL_MUTEX_LOCK(ext_mem_cache.entries[i].lock); + /* + * check again that handle is valid -- other thread may + * have unmapped already + */ + if (ext_mem_cache.entries[i].num_bufs_in_flight == 0 && + ext_mem_cache.entries[i].alloc_handle + != GSL_EXT_MEM_HDL_NOT_ALLOCD) { + GSL_DBG("Unmapping entry %d, handle 0x%x", + i, ext_mem_cache.entries[i].alloc_handle); + + ext_mem_cache.entries[i].alloc_handle + = GSL_EXT_MEM_HDL_NOT_ALLOCD; + + //unmapping within lock... not efficient + rc = gsl_shmem_unmap_extern_mem( + ext_mem_cache.entries[i].shmem_data); + if (rc != AR_EOK) + GSL_DBG("unmap extern mem failed rc=%d", rc); + } + + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[i].lock); + + } + /* we will never hit the next check in cache disabled path. */ +#endif // GSL_EXT_MEM_CACHE_DISABLE + + if (ext_mem_cache.entries[i].alloc_handle + == ext_mem_data.alloc_handle) { + + /* found cache entry. mark it in use safely */ + GSL_MUTEX_LOCK(ext_mem_cache.entries[i].lock); + if (ext_mem_cache.entries[i].alloc_handle + == ext_mem_data.alloc_handle) { + ++ext_mem_cache.entries[i].num_bufs_in_flight; + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[i].lock); + + goto exit_success; + } + + /* implied else */ + /* Our entry got sniped by an eviction. Log and map later */ + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[i].lock); + GSL_DBG("gsl extmem cache entry got sniped. increase cache size?"); + } + } + + /* We did not find our buffer in the cache. We need to map it */ + /* see note at top of function re lock */ + //GSL_MUTEX_LOCK(ext_mem_cache.global_cache_lock); + /* all mappings are serialised to avoid double-mapping the same alloc */ + + /* + * Check if our handle got added to the cache while we were waiting for + * the global lock + */ + for (i = 0; i < GSL_MAX_CACHE_SIZE; ++i) { + if (ext_mem_cache.entries[i].alloc_handle + == ext_mem_data.alloc_handle) { + /* our buffer got mapped by another thread. We can stop. */ + GSL_MUTEX_LOCK(ext_mem_cache.entries[i].lock); + ++ext_mem_cache.entries[i].num_bufs_in_flight; + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[i].lock); + + /* see note at top of function re lock */ + //GSL_MUTEX_UNLOCK(ext_mem_cache.global_cache_lock); + goto exit_success; + } + + /* + * continue even if we see an unused buff, since desired buffer could be + * after first unused once we add aging out + */ + if (first_unused == UINT32_MAX + && ext_mem_cache.entries[i].alloc_handle + == GSL_EXT_MEM_HDL_NOT_ALLOCD) { + first_unused = i; + } + } + + /* + * Buffer is not already in cache. If we saw empty space, take it + * if no empty space, find a buffer to evict. + */ + if (first_unused != UINT32_MAX) { + i = first_unused; + } else { + /* there was no unused buffer. We need to evict an entry */ + rc = ext_mem_cache_evict_entry(&i, &to_unmap); + if (rc != AR_EOK) { + GSL_ERR("Unable to evict: cache all in use right now. rc=%d", rc); + goto exit_error; + } + } + + /* we evicted entry i and it's available, or we saw i was unused */ + GSL_MUTEX_LOCK(ext_mem_cache.entries[i].lock); + ext_mem_cache.entries[i].num_bufs_in_flight = 1; + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[i].lock); + + GSL_DBG("mapping entry %d, handle 0x%x", i, ext_mem_data.alloc_handle); + + /* map inside the global lock in case 2 graphs call on the same handle */ + rc = gsl_shmem_map_extern_mem(ext_mem_data.alloc_handle, + ext_mem_data.alloc_size, proc_id, &ext_mem_cache.entries[i].shmem_data); + if (rc != AR_EOK) { + GSL_ERR("map extern mem failed rc=%d", rc); + GSL_MUTEX_LOCK(ext_mem_cache.entries[i].lock); + ext_mem_cache.entries[i].num_bufs_in_flight = 0; + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[i].lock); + goto exit_error; + } + + GSL_MUTEX_LOCK(ext_mem_cache.entries[i].lock); + ext_mem_cache.entries[i].alloc_size = ext_mem_data.alloc_size; + ext_mem_cache.entries[i].last_used = ext_mem_cache.age_counter; + ext_mem_cache.entries[i].alloc_handle = ext_mem_data.alloc_handle; + GSL_MUTEX_UNLOCK(ext_mem_cache.entries[i].lock); + + /* see note at top of function re lock */ + //GSL_MUTEX_UNLOCK(ext_mem_cache.global_cache_lock); + + /* + * Unmapping from outside the global lock. + * This is to allow shmem mgr in future to not be serialised. + */ + if (to_unmap.handle) { + GSL_DBG("Unmapping because evicted, handle 0x%x", + ext_mem_cache.entries[i].alloc_handle); + rc = gsl_shmem_unmap_extern_mem(to_unmap); + if (rc != AR_EOK) { + /* ignore this, we have torn down the entry anyway */ + GSL_DBG("unmap extern mem failed rc=%d", rc); + } + } + +exit_success: + gsl_memcpy(alloc_data, sizeof(struct gsl_shmem_alloc_data), + &ext_mem_cache.entries[i].shmem_data, + sizeof(struct gsl_shmem_alloc_data)); + *idx = i; + + /* + * see note at top of function re lock + * for now with disable just use the unlock here + */ + //return rc; + +exit_error: + GSL_MUTEX_UNLOCK(ext_mem_cache.global_cache_lock); + return rc; +} + +static struct gsl_buff_internal *gsl_dp_find_buff_from_va( + struct gsl_data_path_info *dp_info, uint8_t *vaddr, uintptr_t *offset, + uint32_t *idx) +{ + uint32_t i = 0; + struct gsl_buff_internal *buff; + + /* + * find the corresponding allocation, this also serves as a sanity check + * on the vaddr passed from client + */ + for (i = 0; i < dp_info->config.num_buffs; ++i) { + buff = &dp_info->buff_list[i]; + if (vaddr >= (uint8_t *)buff->gsl_msg.shmem.v_addr) { + *offset = vaddr - (uint8_t *)buff->gsl_msg.shmem.v_addr; + *idx = i; + if (*offset < dp_info->config.buff_size) + return buff; + } + } + + return NULL; +} + +/* + * Marks a buffer as available, available here means the buffer is with GSL and + * not with Spf. So GSL can only read/write buffers that are available. + */ +static void gsl_mark_buffer_as_avail(struct gsl_data_path_info *dp_info, + uint32_t buf_index) +{ + GSL_MUTEX_LOCK(dp_info->lock); + + if (buf_index <= dp_info->config.num_buffs) + clear_bit(dp_info->buff_used_status, buf_index); + + GSL_MUTEX_UNLOCK(dp_info->lock); +} + +/* reset the internal metadata buff queue to empty state */ +static void gsl_clear_internal_md_buff(struct gsl_data_path_info *dp_info) +{ + GSL_MUTEX_LOCK(dp_info->lock); + dp_info->md_buff_list_head = 0; + dp_info->md_buff_list_tail = 0; + dp_info->md_buff_list_acked = 0; + GSL_MUTEX_UNLOCK(dp_info->lock); +} + +static struct gsl_metadata_buff_internal *gsl_enqueue_internal_md_buff( + struct gsl_data_path_info *dp_info) +{ + struct gsl_metadata_buff_internal *gsl_md_buff = NULL; + uint32_t tmp_head; + int32_t rc; + + GSL_MUTEX_LOCK(dp_info->lock); + + /* + * note this logic depends on the fact that similiar to data buffers, + * metadata buffers come in the order of FIFO + */ + tmp_head = (dp_info->md_buff_list_head + 1) % dp_info->md_buff_list_size; + + if (tmp_head == dp_info->md_buff_list_tail) { + /* queue full */ + GSL_MUTEX_UNLOCK(dp_info->lock); + GSL_ERR("internal md buff queue full"); + gsl_md_buff = NULL; + goto exit; + } + + gsl_md_buff = &dp_info->md_buff_list[dp_info->md_buff_list_head]; + dp_info->md_buff_list_head = tmp_head; + GSL_MUTEX_UNLOCK(dp_info->lock); + + /* + * alloc shared memroy if needed, only allocate md memory if not already + * done, we free this in gsl_data_path_deinit once we are done with the + * usecase + */ + if (dp_info->oob_metadata_flag && !gsl_md_buff->gsl_msg.shmem.handle) { + rc = gsl_shmem_alloc(dp_info->config.max_metadata_size, + dp_info->master_proc_id, &gsl_md_buff->gsl_msg.shmem); + if (rc) { + GSL_ERR("failed to allocate shmem for metadata err %d", rc); + goto exit; + } + } +exit: + return gsl_md_buff; +} + +/* + * dequeues and frees the oldest internal metadata buffer. Copies to client + * memory if requested by caller and returns the client buffer + * note: this function does not free shared memory so that the allocations can + * be reused, they get freed in gsl_data_path_deinit + */ +static struct gsl_metadata_buff_internal *gsl_dequeue_internal_md_buff( + struct gsl_data_path_info *dp_info) +{ + struct gsl_metadata_buff_internal *gsl_md_buff = NULL; + + GSL_MUTEX_LOCK(dp_info->lock); + + /* + * note this logic depends on the fact that metadata buffers come in the + * order of FIFO + */ + if (dp_info->md_buff_list_tail == dp_info->md_buff_list_head) { + /* empty condition */ + GSL_ERR("internal md buff queue empty"); + goto exit; + } + + gsl_md_buff = &dp_info->md_buff_list[dp_info->md_buff_list_tail]; + + dp_info->md_buff_list_tail = (dp_info->md_buff_list_tail + 1) % + dp_info->md_buff_list_size; +exit: + GSL_MUTEX_UNLOCK(dp_info->lock); + + return gsl_md_buff; +} + +/* + * update the spf returned metadata status and size to tail entry in the + * internal metadata buff list + */ +static void gsl_store_md_status_from_spf(struct gsl_data_path_info *dp_info, + uint32_t size_from_spf, uint32_t status_from_spf) +{ + struct gsl_metadata_buff_internal *gsl_md_buff = NULL; + + GSL_MUTEX_LOCK(dp_info->lock); + + gsl_md_buff = &dp_info->md_buff_list[dp_info->md_buff_list_acked]; + gsl_md_buff->md_size_from_spf = size_from_spf; + gsl_md_buff->md_status_from_spf = status_from_spf; + dp_info->md_buff_list_acked = (dp_info->md_buff_list_acked + 1) % + dp_info->md_buff_list_size; + GSL_MUTEX_UNLOCK(dp_info->lock); +} + +static void gsl_handle_buff_done_shmem(struct gsl_data_path_info *dp_info, + gsl_cb_func_ptr cb, + struct gsl_event_read_write_done_payload *rw_done_payload, + uint32_t buff_idx, uint64_t pa, uint32_t status, + struct gsl_buff_internal *gsl_buff, uint32_t ev_id, void *client_data, + struct gsl_metadata_buff_internal *gsl_md_buff, uint32_t md_status) +{ + /* used to pass to client in callback */ + uint64_t offset; + struct gsl_event_cb_params ev; + struct gsl_ext_mem_cache_entry cache_entry = { 0 }; + + ev.event_id = ev_id; + ev.source_module_id = GSL_EVENT_SRC_MODULE_ID_GSL; + rw_done_payload->tag = dp_info->cached_tag; + + switch (GSL_DP_DATA_MODE(dp_info)) { + case GSL_DATA_MODE_BLOCKING: + gsl_mark_buffer_as_avail(dp_info, buff_idx); + gsl_signal_set(&dp_info->dp_signal, GSL_SIG_EVENT_MASK_SPF_RSP, + status, NULL); + break; + case GSL_DATA_MODE_NON_BLOCKING: + gsl_mark_buffer_as_avail(dp_info, buff_idx); + ev.event_payload = NULL; + ev.event_payload_size = 0; + if (cb) + cb(&ev, client_data); + + /* + * below signal set is needed during close as gsl_graph_close waits for + * all buffers to come back from Spf + */ + gsl_signal_set(&dp_info->dp_signal, + GSL_SIG_EVENT_MASK_SPF_RSP, status, NULL); + break; + case GSL_DATA_MODE_SHMEM: + offset = pa - gsl_buff->gsl_msg.shmem.spf_addr; + rw_done_payload->buff.addr = + (uint8_t *)(gsl_buff->gsl_msg.shmem.v_addr) + offset; + rw_done_payload->buff.size = gsl_buff->size_from_spf; + rw_done_payload->status = status; + + if (gsl_md_buff) { + rw_done_payload->buff.metadata = gsl_md_buff->client_md_ptr; + rw_done_payload->buff.metadata_size = gsl_md_buff->md_size_from_spf; + rw_done_payload->md_status = gsl_md_buff->md_status_from_spf; + } else { + rw_done_payload->buff.metadata = NULL; + rw_done_payload->buff.metadata_size = 0; + rw_done_payload->md_status = md_status; + } + if (ev_id == GSL_EVENT_ID_READ_DONE) { + GSL_PKT_LOG_DATA("rd__data", dp_info->src_port, + rw_done_payload.buff.addr, rw_done_payload.buff.size); + } + + /* issue the callback to client */ + /* note client must copy in cb context */ + ev.event_payload = rw_done_payload; + ev.event_payload_size = + sizeof(struct gsl_event_read_write_done_payload); + if (cb) + cb(&ev, client_data); + break; + case GSL_DATA_MODE_EXTERN_MEM: + + /* + * This only copies required fields: alloc_handle, alloc_size, spf_addr + * If you need more, you need to add the copy to the function + */ + ext_mem_cache_buf_done(buff_idx, &cache_entry); + + offset = pa - cache_entry.shmem_data.spf_addr; + rw_done_payload->buff.size = gsl_buff->size_from_spf; + + rw_done_payload->buff.alloc_info.alloc_size = cache_entry.alloc_size; + rw_done_payload->buff.alloc_info.alloc_handle + = cache_entry.alloc_handle; + rw_done_payload->buff.alloc_info.offset = (uint32_t)offset; + // this can technically lose data... if the offset is > 4 Gigs... + + ev.event_payload = rw_done_payload; + ev.event_payload_size = + sizeof(struct gsl_event_read_write_done_payload); + + rw_done_payload->status = status; + + if (gsl_md_buff) { + rw_done_payload->buff.metadata = gsl_md_buff->client_md_ptr; + rw_done_payload->buff.metadata_size = gsl_md_buff->md_size_from_spf; + rw_done_payload->md_status = gsl_md_buff->md_status_from_spf; + } else { + rw_done_payload->buff.metadata = NULL; + rw_done_payload->buff.metadata_size = 0; + rw_done_payload->md_status = md_status; + } + + if (cb) + cb(&ev, client_data); + + break; + default: + GSL_ERR("got handle buff done for unknown data mode %d", + GSL_DP_DATA_MODE(dp_info)); + } +} + +static int32_t gsl_handle_buff_done_nonshmem(struct gsl_data_path_info *dp_info, + gpr_packet_t *gpr_packet, uint32_t ev_id, gsl_cb_func_ptr cb, + void *client_data, uint32_t status, uint32_t index) +{ + struct gsl_buff_internal *buff = &dp_info->buff_list[index]; + struct gsl_event_cb_params ev; + + ev.event_id = ev_id; + ev.source_module_id = GSL_EVENT_SRC_MODULE_ID_GSL; + ev.event_payload = NULL; + ev.event_payload_size = 0; + if (!buff) { + GSL_ERR("No buff available"); + return AR_EBADPARAM; + } + buff->gsl_msg.payload = (uint8_t *)gpr_packet; + gsl_mark_buffer_as_avail(dp_info, index); + + if (cb) + cb(&ev, client_data); + + /* + * below signal set is needed during close as gsl_graph_close waits for + * all buffers to come back from Spf + */ + gsl_signal_set(&dp_info->dp_signal, + GSL_SIG_EVENT_MASK_SPF_RSP, status, NULL); + + return AR_EOK; +} + +static struct gsl_buff_internal *gsl_find_next_avail_buffer( + struct gsl_data_path_info *dp_info, uint32_t *buf_idx) +{ + struct gsl_buff_internal *gsl_buff = NULL; + + GSL_MUTEX_LOCK(dp_info->lock); + + if (dp_info->config.num_buffs == 0) + goto exit; + + if (test_bit(dp_info->buff_used_status, dp_info->curr_buff_index)) + goto exit; + + gsl_buff = &dp_info->buff_list[dp_info->curr_buff_index]; + *buf_idx = dp_info->curr_buff_index; + set_bit(dp_info->buff_used_status, dp_info->curr_buff_index); + dp_info->curr_buff_index = (dp_info->curr_buff_index + 1) % + dp_info->config.num_buffs; + +exit: + GSL_MUTEX_UNLOCK(dp_info->lock); + + return gsl_buff; +} + +/* + * used to send push pull bufs to shared mem EP + */ +static int32_t gsl_dp_configure_pull_push_on_spf( + struct gsl_data_path_info *dp_info, struct gsl_signal *signal) +{ + int32_t rc = AR_EOK; + struct apm_cmd_header_t *apm_hdr = NULL; + struct apm_module_param_data_t *param_hdr = NULL; + struct sh_mem_pull_push_mode_cfg_t *pull_push_cfg = NULL; + uint8_t *spf_cmd; + uint32_t spf_cmd_sz = 0; + gpr_packet_t *send_pkt = NULL; + + /* configure pull_push mode buffers on spf */ + spf_cmd_sz = GSL_ALIGN_8BYTE(sizeof(*apm_hdr) + sizeof(*param_hdr) + + sizeof(*pull_push_cfg)); + + rc = gsl_allocate_gpr_packet(APM_CMD_SET_CFG, dp_info->src_port, + dp_info->miid, spf_cmd_sz, 0, dp_info->master_proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + spf_cmd = GPR_PKT_GET_PAYLOAD(uint8_t, send_pkt); + gsl_memset(spf_cmd, 0, spf_cmd_sz); + + apm_hdr = (struct apm_cmd_header_t *)spf_cmd; + param_hdr = (struct apm_module_param_data_t *) + (spf_cmd + sizeof(*apm_hdr)); + pull_push_cfg = (struct sh_mem_pull_push_mode_cfg_t *)(spf_cmd + + sizeof(*apm_hdr) + sizeof(*param_hdr)); + + apm_hdr->payload_size = spf_cmd_sz - sizeof(*apm_hdr); + param_hdr->module_instance_id = dp_info->miid; + param_hdr->param_id = PARAM_ID_SH_MEM_PULL_PUSH_MODE_CFG; + param_hdr->param_size = sizeof(*pull_push_cfg); + + pull_push_cfg->circ_buf_mem_map_handle = + dp_info->buff_list[0].gsl_msg.shmem.spf_mmap_handle; + pull_push_cfg->shared_circ_buf_addr_lsw = + (uint32_t)dp_info->buff_list[0].gsl_msg.shmem.spf_addr; + pull_push_cfg->shared_circ_buf_addr_msw = + (uint32_t)(dp_info->buff_list[0].gsl_msg.shmem.spf_addr >> 32); + pull_push_cfg->shared_circ_buf_size = dp_info->config.buff_size; + + pull_push_cfg->pos_buf_mem_map_handle = + dp_info->buff_list[1].gsl_msg.shmem.spf_mmap_handle; + pull_push_cfg->shared_pos_buf_addr_lsw = + (uint32_t)dp_info->buff_list[1].gsl_msg.shmem.spf_addr; + pull_push_cfg->shared_pos_buf_addr_msw = + (uint32_t)(dp_info->buff_list[1].gsl_msg.shmem.spf_addr >> 32); + + GSL_LOG_PKT("send_pkt", dp_info->src_port, send_pkt, sizeof(*send_pkt) + + spf_cmd_sz, NULL, 0); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, signal); + if (rc) + GSL_ERR("set config inband failed rc %d", rc); + +exit: + return rc; +} + +/* + * allocate the buffers for push pull mode, but don't send them to spf yet + */ +static int32_t gsl_dp_allocate_push_pull_buffers( + struct gsl_data_path_info *dp_info, enum gsl_data_dir dir) +{ + int32_t rc = AR_EOK; + uint32_t flags = 0; + struct gsl_cmd_configure_read_write_params *cfg = &dp_info->config; + + /* + * in push_pull mode we allocate two dedicated buffers one for data + * requested by client and another for the position buffer + */ + if (cfg->num_buffs > 2 || cfg->num_buffs < 1) { + GSL_ERR("num buffs %d in push_pull mode exceeds 2 or less than 1", + cfg->num_buffs); + return AR_EBADPARAM; + } + dp_info->config.num_buffs = 2; + + /* allocate memory for internal buffers */ + dp_info->buff_list = gsl_mem_zalloc( + dp_info->config.num_buffs * sizeof(struct gsl_buff_internal)); + if (!dp_info->buff_list) { + rc = AR_ENOMEMORY; + goto exit; + } + + if (dir == GSL_DATA_DIR_READ) + flags = GSL_SHMEM_DEDICATED_PAGE | GSL_SHMEM_MAP_UNCACHED; + else + flags = GSL_SHMEM_DEDICATED_PAGE; + + rc = gsl_shmem_alloc_ext(cfg->buff_size, + GSL_GET_SPF_SS_MASK(dp_info->master_proc_id), flags, + cfg->platform_info, dp_info->master_proc_id, + &dp_info->buff_list[0].gsl_msg.shmem); + if (rc) { + GSL_ERR("shmem alloc failed rc %d", rc); + goto free_buff_list; + } + + /* allocate position buffer as a dedicated page */ + rc = gsl_shmem_alloc_ext( + sizeof(struct sh_mem_pull_push_mode_position_buffer_t), + GSL_GET_SPF_SS_MASK(dp_info->master_proc_id), + GSL_SHMEM_DEDICATED_PAGE | GSL_SHMEM_MAP_UNCACHED, + cfg->platform_info, dp_info->master_proc_id, + &dp_info->buff_list[1].gsl_msg.shmem); + if (rc) { + GSL_ERR("shmem alloc failed rc %d", rc); + goto cleanup; + } + + return rc; + +cleanup: + gsl_shmem_free(&dp_info->buff_list[0].gsl_msg.shmem); +free_buff_list: + gsl_mem_free(dp_info->buff_list); + dp_info->buff_list = NULL; +exit: + return rc; +} + +static int32_t reconfigure_buffers(struct gsl_data_path_info *dp_info, + struct gsl_cmd_configure_read_write_params *cfg) +{ + int32_t rc = AR_EOK; + uint32_t i; + /* handle the scenario where buffers were already configured */ + if (cfg->attributes == dp_info->config.attributes && + cfg->buff_size == dp_info->config.buff_size && + cfg->num_buffs == dp_info->config.num_buffs) { + /* client requested same configuration no-op */ + return AR_EALREADY; + } + + /* free current buffers */ + for (i = 0; i < dp_info->config.num_buffs; ++i) { + rc = gsl_msg_free(&dp_info->buff_list[i].gsl_msg); + if (rc != AR_EOK) { + GSL_ERR("Failed to free gsl msg %d", rc); + return rc; + } + } + + /* free internal buffer object */ + if (dp_info->buff_list) { + gsl_mem_free(dp_info->buff_list); + dp_info->buff_list = NULL; + } + if (dp_info->md_buff_list) { + gsl_mem_free(dp_info->md_buff_list); + dp_info->md_buff_list = NULL; + } + + if (GSL_DP_DATA_MODE(dp_info) == GSL_DATA_MODE_EXTERN_MEM + && (cfg->attributes & GSL_ATTRIBUTES_DATA_MODE_MASK) + != GSL_DATA_MODE_EXTERN_MEM) { + /* if reconfiguring out of extern mem mode, tell the extmem cache */ + ext_mem_cache_deinit(); + } + + return rc; +} + +static int32_t gsl_dp_config_nonshmem(struct gsl_data_path_info *dp_info, + struct gsl_cmd_configure_read_write_params *cfg) +{ + int rc = AR_EOK; + + if (cfg->num_buffs > GSL_MAX_NUM_DATA_BUFFERS) { + GSL_ERR("num_buffs greater than %d", GSL_MAX_NUM_DATA_BUFFERS); + rc = AR_EBADPARAM; + goto exit; + } + + /* allocate memory for internal buffers and md buffers */ + dp_info->buff_list = gsl_mem_zalloc(cfg->num_buffs * sizeof(struct + gsl_buff_internal)); + if (!dp_info->buff_list) { + rc = AR_ENOMEMORY; + goto exit; + } + + if (cfg->max_metadata_size > 0) { + dp_info->md_buff_list_size = GSL_METADATA_TO_DATA_FACTOR * + cfg->num_buffs; + dp_info->md_buff_list = gsl_mem_zalloc(dp_info->md_buff_list_size * + sizeof(struct gsl_metadata_buff_internal)); + if (!dp_info->md_buff_list) { + rc = AR_ENOMEMORY; + goto free_internal_buffs; + } + } + + dp_info->config = *cfg; /* copy the cfg sent by client */ + goto exit; + +free_internal_buffs: + gsl_mem_free(dp_info->buff_list); +exit: + return rc; +} + +/* specific push pull configuration */ +static int32_t gsl_dp_config_push_pull_mode(struct gsl_data_path_info *dp_info, + struct gsl_cmd_configure_read_write_params *cfg, + struct gsl_signal *signal, enum gsl_data_dir dir) +{ + int32_t rc = AR_EOK; + uint32_t i; + + if (GSL_DATAPATH_SETUP_MODE(cfg) == GSL_DATAPATH_SETUP_ALLOC_SHMEM_ONLY + || GSL_DATAPATH_SETUP_MODE(cfg) == GSL_DATAPATH_SETUP_DEFAULT) { + + if (cfg->num_buffs > GSL_MAX_NUM_DATA_BUFFERS) { + GSL_ERR("num_buffs greater than %d", GSL_MAX_NUM_DATA_BUFFERS); + rc = AR_EBADPARAM; + goto exit; + } + + if (dp_info->config.num_buffs > 0) { + rc = reconfigure_buffers(dp_info, cfg); + if (rc == AR_EALREADY) + return AR_EOK; + else if (rc) + return rc; + } + + dp_info->config = *cfg; /* copy the cfg sent by client */ + + rc = gsl_dp_allocate_push_pull_buffers(dp_info, dir); + if (rc) { + GSL_ERR("failed to allocate push pull buffers %d", rc); + goto clean_cfg; + } + /* if we didn't bail, we successfully allocated 2 buffs */ + } + + if (GSL_DATAPATH_SETUP_MODE(cfg) == GSL_DATAPATH_SETUP_SPF_PROVISION_ONLY + || GSL_DATAPATH_SETUP_MODE(cfg) == GSL_DATAPATH_SETUP_DEFAULT) { + /** + * send now-allocated push pull buffers + */ + rc = gsl_dp_configure_pull_push_on_spf(dp_info, signal); + if (rc) { + GSL_ERR("failed to send push pull buffers to spf %d", rc); + goto free_buffers; + } + } + + return rc; + +free_buffers: + if (GSL_DATAPATH_SETUP_MODE(cfg) == GSL_DATAPATH_SETUP_DEFAULT) + for (i = 0; i < 2; ++i) + gsl_shmem_free(&dp_info->buff_list[i].gsl_msg.shmem); +clean_cfg: + if (GSL_DATAPATH_SETUP_MODE(cfg) != GSL_DATAPATH_SETUP_SPF_PROVISION_ONLY) + gsl_memset(&dp_info->config, 0, sizeof(dp_info->config)); +exit: + return rc; +} + +static int32_t gsl_dp_config_extern_mem_mode( + struct gsl_data_path_info *dp_info, + struct gsl_cmd_configure_read_write_params *cfg) +{ + int32_t rc = AR_EOK; + + /* + * for extern mem mode, we don't get _any_ buffer info from cfg + * we also don't need to do much + */ + + /* Handle case where DP was in a different mode: deallocate buffers */ + if (dp_info->config.num_buffs > 0) { + rc = reconfigure_buffers(dp_info, cfg); + if (rc == AR_EALREADY) { + rc = AR_EOK; + goto exit; + } else if (rc) { + goto exit; + } + } + + /* allocate internal md buffers */ + if (cfg->max_metadata_size > 0) { + dp_info->md_buff_list_size = GSL_METADATA_TO_DATA_FACTOR * + GSL_MAX_NUM_DATA_BUFFERS; + dp_info->md_buff_list = gsl_mem_zalloc(dp_info->md_buff_list_size * + sizeof(struct gsl_metadata_buff_internal)); + if (!dp_info->md_buff_list) { + rc = AR_ENOMEMORY; + goto exit; + } + } + + if (GSL_DP_DATA_MODE(dp_info) != GSL_DATA_MODE_EXTERN_MEM) { + /* tell cache if this DP was not previously in extern mem mode */ + ext_mem_cache_init(); + } + + dp_info->config = *cfg; /* copy the cfg sent by client */ + + /* sanity: ensure non-existent DP buffers are never accessed later */ + dp_info->config.num_buffs = 0; + dp_info->config.buff_size = 0; + +exit: + return rc; +} + +static int32_t gsl_dp_config_common_modes(struct gsl_data_path_info *dp_info, + struct gsl_cmd_configure_read_write_params *cfg) +{ + int32_t rc = AR_EOK; + uint32_t i = 0, j = 0; + uint32_t flags = 0; + + /* + * if dp was already configured, either free the existing buffs or + * return early if configuration is the same. + */ + if (dp_info->config.num_buffs > 0) { + rc = reconfigure_buffers(dp_info, cfg); + if (rc == AR_EALREADY) + return AR_EOK; + else if (rc) + goto exit; + } + + if (cfg->num_buffs > GSL_MAX_NUM_DATA_BUFFERS) { + GSL_ERR("num_buffs greater than %d", GSL_MAX_NUM_DATA_BUFFERS); + rc = AR_EBADPARAM; + goto exit; + } + + dp_info->config = *cfg; /* copy the cfg sent by client */ + + /* allocate memory for internal buffers and md buffers */ + dp_info->buff_list = gsl_mem_zalloc(cfg->num_buffs * sizeof(struct + gsl_buff_internal)); + if (!dp_info->buff_list) { + rc = AR_ENOMEMORY; + goto exit; + } + if (cfg->max_metadata_size > 0) { + dp_info->md_buff_list_size = GSL_METADATA_TO_DATA_FACTOR * + cfg->num_buffs; + dp_info->md_buff_list = gsl_mem_zalloc(dp_info->md_buff_list_size * + sizeof(struct gsl_metadata_buff_internal)); + if (!dp_info->md_buff_list) { + rc = AR_ENOMEMORY; + goto free_internal_buffs; + } + } + /* + * if client passed any sort of platform info then use a dedicated + * page for shmem + */ + if (cfg->platform_info != 0) + flags = GSL_SHMEM_DEDICATED_PAGE; + + for (i = 0; i < cfg->num_buffs; ++i) { + rc = gsl_shmem_alloc_ext(cfg->buff_size, + GSL_GET_SPF_SS_MASK(dp_info->master_proc_id), + flags, cfg->platform_info, dp_info->master_proc_id, + &dp_info->buff_list[i].gsl_msg.shmem); + if (rc) { + GSL_ERR("shmem alloc failed rc %d", rc); + goto cleanup; + } + } + + return rc; + +cleanup: + for (j = 0; j < i; ++j) + gsl_shmem_free(&dp_info->buff_list[j].gsl_msg.shmem); + + gsl_memset(&dp_info->config, 0, sizeof(dp_info->config)); +free_internal_buffs: + gsl_mem_free(dp_info->buff_list); + dp_info->buff_list = NULL; + if (dp_info->md_buff_list) { + gsl_mem_free(dp_info->md_buff_list); + dp_info->md_buff_list = NULL; + dp_info->md_buff_list_size = 0; + } +exit: + return rc; +} + +static int32_t gsl_dp_write_shmem(struct gsl_data_path_info *dp_info, + struct gsl_buff_internal *buff, struct gsl_metadata_buff_internal *md_buff, + uintptr_t offset, uint32_t buff_idx, uint32_t size, + struct gsl_buff *client_buff) +{ + data_cmd_wr_sh_mem_ep_data_buffer_v2_t *write_cmd; + media_format_t *media_fmt; + int32_t rc; + uint64_t tmp; + gpr_packet_t *send_pkt = NULL; + uint32_t gpr_pld_size; + uint32_t opcode = DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2; + + GSL_VERBOSE("Send WRITE flag %d", client_buff->flags); + + if (client_buff->flags & GSL_BUFF_FLAG_MEDIA_FORMAT) { + opcode = DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT; + gpr_pld_size = client_buff->size; + } else if (!dp_info->oob_metadata_flag) { + gpr_pld_size = sizeof(*write_cmd) + client_buff->metadata_size; + } else { + gpr_pld_size = sizeof(*write_cmd); + } + + rc = gsl_allocate_gpr_packet(opcode, dp_info->src_port, dp_info->miid, + gpr_pld_size, buff_idx, dp_info->master_proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + + if (client_buff->flags & GSL_BUFF_FLAG_MEDIA_FORMAT) { + media_fmt = GPR_PKT_GET_PAYLOAD(media_format_t, send_pkt); + gsl_memcpy(media_fmt, client_buff->size, client_buff->addr, + client_buff->size); + GSL_PKT_LOG_DATA("wr__data", dp_info->src_port, client_buff->addr, + client_buff->size); + GSL_VERBOSE("Send WRITE buffer addr 0x%llX, size %u", + client_buff->addr, client_buff->size); + } else { + write_cmd = + GPR_PKT_GET_PAYLOAD(data_cmd_wr_sh_mem_ep_data_buffer_v2_t, + send_pkt); + + tmp = buff->gsl_msg.shmem.spf_addr + offset; + write_cmd->data_buf_addr_lsw = (uint32_t)tmp; + write_cmd->data_buf_addr_msw = (uint32_t)(tmp >> 32); + write_cmd->data_buf_size = size; + write_cmd->data_mem_map_handle = buff->gsl_msg.shmem.spf_mmap_handle; + write_cmd->flags = 0; + if (client_buff->flags & GSL_BUFF_FLAG_TS_VALID) { + write_cmd->flags |= RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG; + write_cmd->timestamp_lsw = (uint32_t)client_buff->timestamp; + write_cmd->timestamp_msw = client_buff->timestamp >> 32; + } else { + write_cmd->timestamp_lsw = 0; + write_cmd->timestamp_msw = 0; + } + + if (client_buff->flags & GSL_BUFF_FLAG_EOF) + write_cmd->flags |= WR_SH_MEM_EP_BIT_MASK_EOF_FLAG; + write_cmd->md_buf_size = 0; + write_cmd->md_buf_addr_lsw = 0; + write_cmd->md_buf_addr_msw = 0; + write_cmd->md_mem_map_handle = 0; + + if (dp_info->oob_metadata_flag && md_buff) { + /* updata address of oob metadata to gpr packet */ + tmp = md_buff->gsl_msg.shmem.spf_addr; + write_cmd->md_buf_addr_lsw = (uint32_t)tmp; + write_cmd->md_buf_addr_msw = (uint32_t)(tmp >> 32); + write_cmd->md_mem_map_handle = + md_buff->gsl_msg.shmem.spf_mmap_handle; + } else if (client_buff->metadata_size) { + /* copy in-band metadata directly to gpr packet */ + tmp = sizeof(gpr_packet_t) + sizeof(*write_cmd); + gsl_memcpy((uint8_t *)send_pkt + tmp, + dp_info->config.max_metadata_size, client_buff->metadata, + client_buff->metadata_size); + } + write_cmd->md_buf_size = client_buff->metadata_size; + GSL_PKT_LOG_DATA("wr__data", dp_info->src_port, buff->addr, + buff->size); + + GSL_VERBOSE("Send WRITE to Spf p_addr 0x%llX, size %u", + tmp, write_cmd->data_buf_size); + } + + GSL_LOG_PKT("send_pkt", dp_info->src_port, send_pkt, sizeof(*send_pkt) + + gpr_pld_size, NULL, 0); + + rc = gsl_send_spf_cmd(&send_pkt, NULL, NULL); + if (rc) + GSL_ERR("wite shmem failed with %d", rc); + +exit: + return rc; +} + +static int32_t gsl_dp_read_shmem(struct gsl_data_path_info *dp_info, + struct gsl_buff_internal *internal_buf, + struct gsl_metadata_buff_internal *md_buff, uintptr_t offset, + uint32_t read_sz, uint32_t buff_idx) +{ + data_cmd_rd_sh_mem_ep_data_buffer_v2_t *read_cmd; + int32_t rc; + uint64_t tmp; + gpr_packet_t *send_pkt = NULL; + + rc = gsl_allocate_gpr_packet(DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2, + dp_info->src_port, dp_info->miid, + sizeof(*read_cmd), buff_idx, dp_info->master_proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + read_cmd = + GPR_PKT_GET_PAYLOAD(data_cmd_rd_sh_mem_ep_data_buffer_v2_t, send_pkt); + + tmp = internal_buf->gsl_msg.shmem.spf_addr + offset; + read_cmd->data_buf_addr_lsw = (uint32_t)tmp; + read_cmd->data_buf_addr_msw = (uint32_t)(tmp >> 32); + read_cmd->data_buf_size = read_sz; + read_cmd->data_mem_map_handle = internal_buf->gsl_msg.shmem.spf_mmap_handle; + read_cmd->md_buf_addr_lsw = 0; + read_cmd->md_buf_addr_msw = 0; + read_cmd->md_mem_map_handle = 0; + read_cmd->md_buf_size = 0; + if (dp_info->oob_metadata_flag && md_buff) { + /* updata address of oob metadata to gpr packet */ + tmp = md_buff->gsl_msg.shmem.spf_addr; + read_cmd->md_buf_addr_lsw = (uint32_t)tmp; + read_cmd->md_buf_addr_msw = (uint32_t)(tmp >> 32); + read_cmd->md_mem_map_handle = md_buff->gsl_msg.shmem.spf_mmap_handle; + read_cmd->md_buf_size = md_buff->size; + } + + GSL_VERBOSE("Send READ to Spf p_addr 0x%llX, size %u", + tmp, read_cmd->data_buf_size); + + GSL_LOG_PKT("send_pkt", dp_info->src_port, send_pkt, sizeof(*send_pkt) + + sizeof(*read_cmd), NULL, 0); + + rc = gsl_send_spf_cmd(&send_pkt, NULL, NULL); + if (rc) + GSL_ERR("failed send spf cmd %d", rc); + +exit: + return rc; +} + +static int32_t gsl_dp_read_nonshmem(struct gsl_data_path_info *dp_info, + uint32_t md_buff_size, uint32_t read_sz, uint32_t buff_idx) +{ + data_cmd_rd_sh_mem_ep_data_buffer_v2_t *read_cmd; + int32_t rc; + gsl_msg_t gsl_msg; + + rc = gsl_msg_alloc(DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2, + dp_info->src_port, dp_info->miid, + sizeof(*read_cmd), buff_idx, dp_info->master_proc_id, + 0, true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate GSL msg %d", rc); + goto exit; + } + + read_cmd = + GPR_PKT_GET_PAYLOAD(data_cmd_rd_sh_mem_ep_data_buffer_v2_t, + gsl_msg.gpr_packet); + + read_cmd->data_buf_size = read_sz; + read_cmd->md_buf_size = md_buff_size; + read_cmd->data_mem_map_handle = 0; + read_cmd->md_mem_map_handle = 0; + + GSL_VERBOSE("Send READ of size %u", read_cmd->data_buf_size); + + GSL_LOG_PKT("send_pkt", dp_info->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*read_cmd), NULL, 0); + + rc = gsl_send_spf_cmd(&gsl_msg.gpr_packet, NULL, NULL); + if (rc) + GSL_ERR("failed send spf cmd %d", rc); + +exit: + return rc; +} + +static int32_t gsl_dp_write_nonshmem(struct gsl_data_path_info *dp_info, + struct gsl_buff *buff, uint32_t *consumed_size) +{ + int32_t rc = AR_EOK, retries = 0; + uint32_t buff_size, write_buff_size, buf_idx, ev_flags = 0; + uint8_t *buff_addr; + data_cmd_wr_sh_mem_ep_data_buffer_v2_t *write_cmd; + uint32_t gpr_pld_size; + struct gsl_buff_internal *internal_buf = NULL; + struct gsl_signal *sig_p = &dp_info->dp_signal; + + *consumed_size = 0; + buff_size = buff->size; + buff_addr = buff->addr; + + while (buff_size > 0) { + retries = 0; + do { + internal_buf = gsl_find_next_avail_buffer(dp_info, + &buf_idx); + if (!internal_buf) { + if (GSL_DP_DATA_MODE(dp_info) == + GSL_DATA_MODE_NON_BLOCKING) { + /* NON-BLOCKING mode */ + GSL_VERBOSE("No buff available"); + return AR_ENORESOURCE; + } + + /* BLOCKING mode */ + GSL_VERBOSE("Waiting for buff done"); + + rc = gsl_signal_timedwait(sig_p, + GSL_SPF_READ_WRITE_TIMEOUT_MS, &ev_flags, NULL, NULL); + if (rc) { + GSL_VERBOSE("Came out of wait with err %d", rc); + return rc; + } + GSL_VERBOSE("Came out of wait flags[0x%x]", ev_flags); + if (ev_flags & GSL_SIG_EVENT_MASK_CLOSE) { + rc = AR_EIODATA; + goto exit; + } else if (ev_flags & GSL_SIG_EVENT_MASK_SSR) { + rc = AR_ESUBSYSRESET; + goto exit; + } + } + } while ((internal_buf == NULL) && (retries++ < GSL_MAX_RETRIES)); + + if (!internal_buf) { + rc = AR_ENOMEMORY; + goto exit; + } + + gpr_pld_size = sizeof(*write_cmd); + + if (buff_size > dp_info->config.buff_size) + write_buff_size = dp_info->config.buff_size; + else + write_buff_size = buff_size; + + rc = gsl_msg_alloc(DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2, + dp_info->src_port, dp_info->miid, + gpr_pld_size, buf_idx, dp_info->master_proc_id, + write_buff_size + buff->metadata_size, true, + &internal_buf->gsl_msg); + + gsl_memcpy(internal_buf->gsl_msg.payload, buff_size, buff_addr, + write_buff_size); + + if (buff->metadata_size) + gsl_memcpy((uint8_t *)internal_buf->gsl_msg.payload + + write_buff_size, + dp_info->config.max_metadata_size, + buff->metadata, buff->metadata_size); + + write_cmd = + GPR_PKT_GET_PAYLOAD(data_cmd_wr_sh_mem_ep_data_buffer_v2_t, + internal_buf->gsl_msg.gpr_packet); + write_cmd->data_buf_size = write_buff_size; + write_cmd->md_buf_size = buff->metadata_size; + write_cmd->data_mem_map_handle = 0; + write_cmd->md_mem_map_handle = 0; + write_cmd->flags = 0; + + if (buff->flags & GSL_BUFF_FLAG_TS_VALID) { + write_cmd->flags |= RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG; + write_cmd->timestamp_lsw = (uint32_t)buff->timestamp; + write_cmd->timestamp_msw = buff->timestamp >> 32; + } else { + write_cmd->timestamp_lsw = 0; + write_cmd->timestamp_msw = 0; + } + + rc = gsl_send_spf_cmd(&internal_buf->gsl_msg.gpr_packet, NULL, NULL); + if (rc != AR_EOK) { + GSL_VERBOSE("%s fail rc = %d", __func__, rc); + goto exit; + } + + *consumed_size += write_buff_size; + buff_addr += write_buff_size; + buff_size -= write_buff_size; + } + + /* send eos if it was marked in the buff */ + if (buff->flags & GSL_BUFF_FLAG_EOS) + gsl_dp_write_send_eos(dp_info); + +exit: + return rc; +} + +static int32_t gsl_dp_write_heap(struct gsl_data_path_info *dp_info, + struct gsl_buff *buff, uint32_t *consumed_size) +{ + struct gsl_buff_internal *internal_buf = NULL; + struct gsl_metadata_buff_internal *internal_md_buf = NULL; + int32_t rc = AR_EOK, retries = 0; + uint32_t buff_size, write_buff_size, buf_idx, ev_flags = 0; + uint8_t *buff_addr; + struct gsl_signal *sig_p = &dp_info->dp_signal; + + *consumed_size = 0; + buff_size = buff->size; + buff_addr = buff->addr; + while (buff_size > 0) { + retries = 0; + do { + internal_buf = gsl_find_next_avail_buffer(dp_info, + &buf_idx); + if (!internal_buf) { + if (GSL_DP_DATA_MODE(dp_info) == + GSL_DATA_MODE_NON_BLOCKING) { + /* NON-BLOCKING mode */ + GSL_ERR("No buff available"); + return AR_ENORESOURCE; + } + + /* BLOCKING mode */ + GSL_VERBOSE("Waiting for buff done"); + + rc = gsl_signal_timedwait(sig_p, + GSL_SPF_READ_WRITE_TIMEOUT_MS, &ev_flags, NULL, NULL); + if (rc) { + GSL_ERR("Came out of wait with err %d", rc); + return rc; + } + GSL_VERBOSE("Came out of wait flags[0x%x]", ev_flags); + if (ev_flags & GSL_SIG_EVENT_MASK_CLOSE) { + rc = AR_EIODATA; + goto exit; + } else if (ev_flags & GSL_SIG_EVENT_MASK_SSR) { + rc = AR_ESUBSYSRESET; + goto exit; + } + } + } while ((internal_buf == NULL) && (retries++ < GSL_MAX_RETRIES)); + + if (!internal_buf) { + rc = AR_ENOMEMORY; + goto exit; + } + + if (buff_size > dp_info->config.buff_size) + write_buff_size = dp_info->config.buff_size; + else + write_buff_size = buff_size; + + GSL_VERBOSE("Write buf idx %d, bytes: %d", buf_idx, write_buff_size); + + gsl_memcpy(internal_buf->gsl_msg.shmem.v_addr, buff_size, buff_addr, + write_buff_size); + + /* + * Copy the metadata to shared memory, note that for blocking and + * non-blocking modes GSL always uses out-of-band metadata. This to + * avoid copying the metadata from gpr packet to a temporary storage on + * read_done handling + */ + if (dp_info->config.max_metadata_size > 0 && buff->metadata) { + gsl_dequeue_internal_md_buff(dp_info); + /* enqueue a new metadata buffer to go with the next shmem write */ + internal_md_buf = gsl_enqueue_internal_md_buff(dp_info); + if (!internal_md_buf) { + GSL_ERR("failed to enqueue internal md buff"); + rc = AR_ENORESOURCE; + goto exit; + } + } + + rc = gsl_dp_write_shmem(dp_info, internal_buf, internal_md_buf, 0, + buf_idx, write_buff_size, buff); + if (rc != AR_EOK) { + GSL_VERBOSE("gsl_dp_write_shmem fail rc=%d", rc); + goto exit; + } + + *consumed_size += write_buff_size; + buff_addr += write_buff_size; + buff_size -= write_buff_size; + } + + /* send eos if it was marked in the buff */ + if (buff->flags & GSL_BUFF_FLAG_EOS) + gsl_dp_write_send_eos(dp_info); + +exit: + return rc; +} + +/* + * data_buff_addr: this points to a location within the client passed + * buff that we copy the data into. Needed to sequentially write into + * client buffer as this function can be called multiple times per + * client buffer. + * client_buff: this is client created object that we copy metadata + * and flags into. + */ +static void gsl_dp_fill_client_buff(struct gsl_data_path_info *dp_info, + struct gsl_buff_internal *internal_buf, + struct gsl_metadata_buff_internal *md_buf, + uint8_t *data_buff_addr, uint32_t *buff_size, + bool_t *captured_timestamp, struct gsl_buff *client_buff) +{ + gpr_packet_t *packet = NULL; + uint8_t *payload = NULL; + + if (!dp_info->is_shmem_supported) { + data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t *rd_done; + + packet = (gpr_packet_t *)internal_buf->gsl_msg.payload; + rd_done = (data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t *) + GPR_PKT_GET_PAYLOAD( + data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t, + packet); + payload = (uint8_t *)rd_done + + sizeof(data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t); + *buff_size = rd_done->data_size; + gsl_memcpy(data_buff_addr, *buff_size, payload, *buff_size); + + if (rd_done->md_size != 0) { + client_buff->metadata_size = rd_done->md_size; + gsl_memcpy(client_buff->metadata, + client_buff->metadata_size, + payload + rd_done->data_size, + client_buff->metadata_size); + } + + internal_buf->spf_timestamp = + ((uint64_t)rd_done->timestamp_msw << 32) | + rd_done->timestamp_lsw; + internal_buf->spf_flags = rd_done->flags; + __gpr_cmd_free(packet); + } else { + /* + * @TODO: Assumption that spf always returns buffer of size <= + * requested size by client. Check if that's correct + */ + *buff_size = internal_buf->size_from_spf; + + gsl_memcpy(data_buff_addr, *buff_size, + internal_buf->gsl_msg.shmem.v_addr, *buff_size); + + if (md_buf != NULL) { + gsl_memcpy(client_buff->metadata, client_buff->metadata_size, + md_buf->gsl_msg.shmem.v_addr, + md_buf->md_size_from_spf); + client_buff->metadata_size = md_buf->md_size_from_spf; + } + } + + /* + * update time-stamp to client, in-case we have already put a timestamp + * in clients shmem_buff we dont update it again as we want to keep the + * timestamp of very first buffer returned from spf. + */ + if (!(*captured_timestamp)) { + client_buff->flags = 0; + if (internal_buf->spf_flags & + RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG) { + client_buff->flags |= GSL_BUFF_FLAG_TS_VALID; + client_buff->timestamp = internal_buf->spf_timestamp; + } + *captured_timestamp = true; + } +} + +static int32_t gsl_dp_read_heap(struct gsl_data_path_info *dp_info, + struct gsl_buff *buff, uint32_t *filled_size) +{ + struct gsl_buff_internal *internal_buf = NULL; + struct gsl_metadata_buff_internal *internal_md_buf = NULL; + int32_t rc = AR_EOK, retries = 0; + uint32_t buff_size, read_buff_size, buf_idx, ev_flags = 0; + uint8_t *buff_addr; + struct gsl_signal *sig_p = + &dp_info->dp_signal; + bool_t captured_timestamp = false; + + *filled_size = 0; + buff_size = buff->size; + buff_addr = buff->addr; + /* + * below while is to handle the case where client tries to read more than + * one buffer size + */ + while (buff_size >= dp_info->config.buff_size) { + retries = 0; + do { + /* + * in the context of read, buffer avail means the buffer is filled + * with data + */ + internal_buf = gsl_find_next_avail_buffer(dp_info, + &buf_idx); + if (!internal_buf) { + if (GSL_DP_DATA_MODE(dp_info) == GSL_DATA_MODE_NON_BLOCKING) { + /* NON-BLOCKING mode */ + GSL_VERBOSE("No buff available"); + return AR_ENORESOURCE; + } + + /** BLOCKING mode */ + GSL_VERBOSE("Waiting for buff done"); + rc = gsl_signal_timedwait(sig_p, + GSL_SPF_READ_WRITE_TIMEOUT_MS, &ev_flags, NULL, NULL); + if (rc) { + GSL_VERBOSE("Came out of wait with err %d", rc); + return rc; + } + GSL_VERBOSE("Came out of wait flags[0x%x]", ev_flags); + if (ev_flags & GSL_SIG_EVENT_MASK_CLOSE) { + rc = AR_EIODATA; + goto exit; + } else if (ev_flags & GSL_SIG_EVENT_MASK_SSR) { + rc = AR_ESUBSYSRESET; + goto exit; + } + } + } while ((internal_buf == NULL) && (retries++ < GSL_MAX_RETRIES)); + + if (!internal_buf) { + rc = AR_ENOMEMORY; + goto exit; + } + + if (dp_info->config.max_metadata_size > 0 && buff->metadata) { + internal_md_buf = gsl_dequeue_internal_md_buff(dp_info); + if (!internal_md_buf) { + GSL_ERR("failed to dequeue internal md buff"); + rc = AR_ENORESOURCE; + } + } + + gsl_dp_fill_client_buff(dp_info, internal_buf, internal_md_buf, + buff_addr, &read_buff_size, + &captured_timestamp, buff); + + GSL_PKT_LOG_DATA("rd__data", dp_info->src_port, + buff_addr, read_buff_size); + + /* queue the buffer back to spf */ + if (!dp_info->is_shmem_supported) { + rc = gsl_dp_read_nonshmem(dp_info, buff->metadata_size, + dp_info->config.buff_size, buf_idx); + if (rc != AR_EOK) + goto exit; + } else { + if (dp_info->config.max_metadata_size > 0 && + buff->metadata) { + if (buff->metadata_size == 0) { + GSL_ERR("got 0 md size from spf"); + rc = AR_EFAILED; + } + + /* enqueue a new metadata buffer to go with the next + * shmem read + */ + internal_md_buf = gsl_enqueue_internal_md_buff(dp_info); + if (!internal_md_buf) { + GSL_ERR("failed to enqueue internal md buff"); + rc = AR_ENORESOURCE; + } else { + internal_md_buf->size = buff->metadata_size; + } + } + + /* queue the shmem buffer back to spf */ + rc = gsl_dp_read_shmem(dp_info, internal_buf, internal_md_buf, 0, + dp_info->config.buff_size, buf_idx); + if (rc != AR_EOK) + goto exit; + } + + *filled_size += read_buff_size; + buff_addr += read_buff_size; + buff_size -= read_buff_size; + } +exit: + return rc; +} + +static int32_t gsl_dp_write_extern_mem(struct gsl_data_path_info *dp_info, + struct gsl_buff *buff) +{ + struct gsl_buff_internal internal_buf = { 0, }; + struct gsl_metadata_buff_internal *internal_md_buf = NULL; + + int32_t rc = AR_EOK; + uint32_t cache_idx = 0; + + /* This will find or map buffer in cache. Fails when cache full */ + rc = ext_mem_cache_get_entry(dp_info->master_proc_id, buff->alloc_info, + &internal_buf.gsl_msg.shmem, &cache_idx); + if (rc != AR_EOK) + return rc; + + ext_mem_cache_update_entry_last_used(cache_idx); + + if (dp_info->config.max_metadata_size > 0) { + /* enqueue a new metadata buffer */ + internal_md_buf = gsl_enqueue_internal_md_buff(dp_info); + if (!internal_md_buf) { + GSL_ERR("failed to enqueue internal md buff"); + rc = AR_ENORESOURCE; + goto exit; + } + + if (dp_info->oob_metadata_flag) { + internal_md_buf->size = buff->metadata_size; + gsl_memcpy(internal_md_buf->gsl_msg.shmem.v_addr, + internal_md_buf->size, buff->metadata, buff->metadata_size); + } + } + + rc = gsl_dp_write_shmem(dp_info, &internal_buf, internal_md_buf, + buff->alloc_info.offset, cache_idx, buff->size, buff); + if (rc != AR_EOK) { + GSL_VERBOSE("gsl_dp_write_shmem fail rc=%d", rc); + goto exit; + } + + /* send eos if it was marked in the buff */ + if (buff->flags & GSL_BUFF_FLAG_EOS) + gsl_dp_write_send_eos(dp_info); +exit: + return rc; +} + +static int32_t gsl_dp_read_extern_mem(struct gsl_data_path_info *dp_info, + struct gsl_buff *buff) +{ + struct gsl_buff_internal internal_buf = { 0, }; + struct gsl_metadata_buff_internal *internal_md_buf = NULL; + + int32_t rc = AR_EOK; + uint32_t cache_idx; + + /* This will find or map buffer in cache. Fails when cache full */ + rc = ext_mem_cache_get_entry(dp_info->master_proc_id, buff->alloc_info, + &internal_buf.gsl_msg.shmem, &cache_idx); + if (rc != AR_EOK) + return rc; + + ext_mem_cache_update_entry_last_used(cache_idx); + if (dp_info->config.max_metadata_size > 0) { + /* enqueue a new metadata buffer */ + internal_md_buf = gsl_enqueue_internal_md_buff(dp_info); + if (!internal_md_buf) { + GSL_ERR("failed to enqueue internal md buff"); + rc = AR_ENORESOURCE; + goto exit; + } + + internal_md_buf->size = buff->metadata_size; + internal_md_buf->client_md_ptr = buff->metadata; + } + + rc = gsl_dp_read_shmem(dp_info, &internal_buf, internal_md_buf, + buff->alloc_info.offset, buff->size, cache_idx); + if (rc != AR_EOK) { + GSL_VERBOSE("gsl_dp_read_shmem fail rc=%d", rc); + goto exit; + } + +exit: + return rc; +} + +/* we need to create the refcount lock at GSL init time*/ +int32_t gsl_dp_create_cache_refcount_lock(void) +{ + int32_t rc = AR_EOK; + + rc = ar_osal_mutex_create(&ext_mem_cache.num_dps_lock); + if (rc) + GSL_ERR("failed to create mutex: %d", rc); + + return rc; +} + +/* similarly, can only be destroyed at GSL deinit time*/ +void gsl_dp_destroy_cache_refcount_lock(void) +{ + ar_osal_mutex_destroy(ext_mem_cache.num_dps_lock); +} + +/* This should be called only once. Check if lock exists. */ +int32_t gsl_data_path_init(struct gsl_data_path_info *dp_info) +{ + int32_t rc = AR_EOK; + + rc = ar_osal_mutex_create(&dp_info->lock); + if (rc) { + GSL_ERR("failed to create mutex: %d", rc); + goto exit; + } + /* + * use dp lock for this signal + * Could split to more locks later if necessary + */ + rc = gsl_signal_create(&dp_info->dp_signal, &dp_info->lock); + if (rc) { + GSL_ERR("failed to create mutex: %d", rc); + goto cleanup; + } + + return rc; + +cleanup: + ar_osal_mutex_destroy(dp_info->lock); +exit: + return rc; +} + +void gsl_data_path_deinit(struct gsl_data_path_info *dp_info) +{ + uint32_t i = 0; + struct gsl_metadata_buff_internal *internal_md_buff; + + /* decrement refcount in cache if extern mem */ + if (GSL_DP_DATA_MODE(dp_info) == GSL_DATA_MODE_EXTERN_MEM) + ext_mem_cache_deinit(); + + /* free data buffers, num_buffs will be 0 if data path not configured */ + for (i = 0; i < dp_info->config.num_buffs; ++i) + gsl_msg_free(&dp_info->buff_list[i].gsl_msg); + + /* free all oob metadata buffers */ + if (dp_info->config.max_metadata_size > 0) { + for (i = 0; i < dp_info->md_buff_list_size; ++i) { + internal_md_buff = &dp_info->md_buff_list[i]; + if (internal_md_buff->gsl_msg.shmem.v_addr) + gsl_shmem_free(&internal_md_buff->gsl_msg.shmem); + } + } + + if (dp_info->buff_list) { + gsl_mem_free(dp_info->buff_list); + dp_info->buff_list = NULL; + } + if (dp_info->md_buff_list) { + gsl_mem_free(dp_info->md_buff_list); + dp_info->md_buff_list_size = 0; + dp_info->md_buff_list = NULL; + } + + gsl_signal_destroy(&dp_info->dp_signal); + ar_osal_mutex_destroy(dp_info->lock); +} + +int32_t gsl_dp_config_data_path(struct gsl_data_path_info *dp_info, + struct gsl_cmd_configure_read_write_params *cfg, uint32_t src_port, + struct gsl_signal *push_pull_cfg_signal, enum gsl_data_dir dir, + ar_osal_mutex_t lock, uint32_t proc_id) +{ + /* + * Push pull config requires us to send a SET_CFG to SPF. This is + * done with the GRP_2 signal from graph. We pass this in here specifically + * for use configuring push pull mode. + * + * Similarly, dir is only used when configuring push pull mode, to set + * flags on allocated shmem buffers differently in read/write mode. + */ + + int32_t rc = AR_EOK; + struct gpr_cmd_gpr_packet_pool_info_t gpr_pkt_info; + uint32_t max_rw_cmd_sz; + + if (!dp_info || !cfg) + return AR_EBADPARAM; + + /* Need to no-op in provision only with non-push pull mode, alrdy set up*/ + if (GSL_DATAPATH_SETUP_MODE(cfg) == GSL_DATAPATH_SETUP_SPF_PROVISION_ONLY + && GSL_DP_DATA_MODE(dp_info) != GSL_DATA_MODE_PUSH_PULL) + return AR_EOK; + + /* this will no-op if already inited */ + if (!dp_info->lock) { + rc = gsl_data_path_init(dp_info); + if (rc) + return rc; + } + + dp_info->src_port = src_port; //needed for sending packets + dp_info->master_proc_id = proc_id; + + GSL_MUTEX_LOCK(lock); + dp_info->src_port = src_port; + + /* + * Used to determine whether or not metadata will be in-band or out-of-band + */ + gsl_memset(&gpr_pkt_info, 0, sizeof(gpr_pkt_info)); + rc = __gpr_cmd_get_gpr_packet_info(&gpr_pkt_info); + max_rw_cmd_sz = sizeof(gpr_packet_t) + + sizeof(data_cmd_rd_sh_mem_ep_data_buffer_v2_t) + cfg->max_metadata_size; + if (rc) { + GSL_ERR("failed to get gpr packet info rc = %d", rc); + goto exit; + } + + dp_info->oob_metadata_flag = false; + + /* Check if proc supports shared memory */ + __gpr_cmd_is_shared_mem_supported(dp_info->master_proc_id, + &dp_info->is_shmem_supported); + + switch (cfg->attributes & GSL_ATTRIBUTES_DATA_MODE_MASK) { + case GSL_DATA_MODE_PUSH_PULL: + if (!dp_info->is_shmem_supported) { + rc = AR_EUNSUPPORTED; + goto exit; + } + + rc = gsl_dp_config_push_pull_mode(dp_info, cfg, + push_pull_cfg_signal, dir); + if (rc) + goto exit; + /* nothing more to set up if provision only */ + if (GSL_DATAPATH_SETUP_MODE(cfg) + == GSL_DATAPATH_SETUP_SPF_PROVISION_ONLY) + goto exit; + /* push/pull mode doesnt support meta data */ + break; + case GSL_DATA_MODE_EXTERN_MEM: + if (!dp_info->is_shmem_supported) { + rc = AR_EUNSUPPORTED; + goto exit; + } + + rc = gsl_dp_config_extern_mem_mode(dp_info, cfg); + if (rc) + goto exit; + if (max_rw_cmd_sz > gpr_pkt_info.bytes_per_min_size_packet) + dp_info->oob_metadata_flag = true; + break; + case GSL_DATA_MODE_BLOCKING: + case GSL_DATA_MODE_NON_BLOCKING: + if (!dp_info->is_shmem_supported) { + rc = gsl_dp_config_nonshmem(dp_info, cfg); + if (rc) + goto exit; + dp_info->oob_metadata_flag = false; + break; + } + + /* for blocking/non-blocking modes always use oob metadata */ + if (cfg->max_metadata_size > 0) + dp_info->oob_metadata_flag = true; + case GSL_DATA_MODE_SHMEM: + if (!dp_info->is_shmem_supported) { + rc = AR_EUNSUPPORTED; + goto exit; + } + + rc = gsl_dp_config_common_modes(dp_info, cfg); + if (rc) + goto exit; + if (max_rw_cmd_sz > gpr_pkt_info.bytes_per_min_size_packet) + dp_info->oob_metadata_flag = true; + break; + + default: + GSL_ERR("invalid data mode %d", GSL_DP_DATA_MODE(dp_info)); + rc = AR_EBADPARAM; + goto exit; + } + + /** mark all buffers available for use */ + dp_info->buff_used_status = 0; + dp_info->curr_buff_index = 0; /**< start with buf 0 */ + dp_info->processed_buf_cnt = 0; + dp_info->md_buff_list_head = 0; + dp_info->md_buff_list_tail = 0; + + GSL_MUTEX_UNLOCK(lock); + + return rc; + +exit: + GSL_MUTEX_UNLOCK(lock); + return rc; +} + +int32_t gsl_dp_read(struct gsl_data_path_info *dp_info, struct gsl_buff *buff, + uint32_t *filled_size) +{ + uint32_t rc = AR_EOK, buff_idx; + struct gsl_buff_internal *internal_buff; + struct gsl_metadata_buff_internal *internal_md_buff = NULL; + uintptr_t offset; + + switch (GSL_DP_DATA_MODE(dp_info)) { + case GSL_DATA_MODE_SHMEM: + if (!dp_info->is_shmem_supported) { + rc = AR_EUNSUPPORTED; + goto exit; + } + + internal_buff = gsl_dp_find_buff_from_va(dp_info, buff->addr, &offset, + &buff_idx); + if (internal_buff == NULL) { + rc = AR_EHANDLE; + goto exit; + } + if (dp_info->config.max_metadata_size > 0) { + internal_md_buff = gsl_enqueue_internal_md_buff(dp_info); + if (!internal_md_buff) { + GSL_ERR("failed to create shmem for metadata"); + rc = AR_ENORESOURCE; + goto exit; + } + internal_md_buff->client_md_ptr = buff->metadata; + internal_md_buff->size = buff->metadata_size; + } + rc = gsl_dp_read_shmem(dp_info, internal_buff, internal_md_buff, + offset, buff->size, buff_idx); + /* + * in shared memory mode the read is returned immediately and no data + * is filled till we get buff done + */ + *filled_size = 0; + break; + case GSL_DATA_MODE_EXTERN_MEM: + if (!dp_info->is_shmem_supported) { + rc = AR_EUNSUPPORTED; + goto exit; + } + + rc = gsl_dp_read_extern_mem(dp_info, buff); + break; + case GSL_DATA_MODE_BLOCKING: + case GSL_DATA_MODE_NON_BLOCKING: + rc = gsl_dp_read_heap(dp_info, buff, filled_size); + break; + default: + GSL_ERR("unsupported read mode 0x%X", + GSL_DP_DATA_MODE(dp_info)); + rc = AR_EUNSUPPORTED; + } + +exit: + return rc; +} + +int32_t gsl_dp_write(struct gsl_data_path_info *dp_info, struct gsl_buff *buff, + uint32_t *consumed_size) +{ + uint32_t rc = AR_EOK, buff_idx; + struct gsl_buff_internal *internal_buff; + struct gsl_metadata_buff_internal *internal_md_buff = NULL; + uintptr_t offset; + + switch (GSL_DP_DATA_MODE(dp_info)) { + case GSL_DATA_MODE_SHMEM: + if (!dp_info->is_shmem_supported) { + rc = AR_EUNSUPPORTED; + goto exit; + } + + internal_buff = gsl_dp_find_buff_from_va(dp_info, + buff->addr, &offset, &buff_idx); + if (internal_buff == NULL) { + rc = AR_EHANDLE; + goto exit; + } + if (dp_info->config.max_metadata_size > 0) { + internal_md_buff = gsl_enqueue_internal_md_buff(dp_info); + if (!internal_md_buff) { + GSL_ERR("failed to enqueue metadata"); + rc = AR_ENORESOURCE; + goto exit; + } + + if (internal_md_buff && dp_info->oob_metadata_flag) { + gsl_memcpy(internal_md_buff->gsl_msg.shmem.v_addr, + buff->metadata_size, buff->metadata, buff->metadata_size); + } + } + rc = gsl_dp_write_shmem(dp_info, internal_buff, internal_md_buff, + offset, buff_idx, buff->size, buff); + *consumed_size = buff->size; + + if (buff->flags & GSL_BUFF_FLAG_EOS) + gsl_dp_write_send_eos(dp_info); + + break; + case GSL_DATA_MODE_EXTERN_MEM: + if (!dp_info->is_shmem_supported) { + rc = AR_EUNSUPPORTED; + goto exit; + } + + rc = gsl_dp_write_extern_mem(dp_info, buff); + *consumed_size = buff->size; + + break; + case GSL_DATA_MODE_BLOCKING: + case GSL_DATA_MODE_NON_BLOCKING: + if (!dp_info->is_shmem_supported) { + rc = gsl_dp_write_nonshmem(dp_info, buff, + consumed_size); + } else { + rc = gsl_dp_write_heap(dp_info, buff, consumed_size); + } + break; + default: + GSL_ERR("unsupported write mode 0x%X", + GSL_DP_DATA_MODE(dp_info)); + rc = AR_EUNSUPPORTED; + } + +exit: + return rc; +} + +int32_t gsl_dp_write_send_eos(struct gsl_data_path_info *dp_info) +{ + data_cmd_wr_sh_mem_ep_eos_t *eos_cmd; + int32_t rc; + gsl_msg_t gsl_msg; + + rc = gsl_msg_alloc(DATA_CMD_WR_SH_MEM_EP_EOS, dp_info->src_port, + dp_info->miid, sizeof(*eos_cmd), 0, + dp_info->master_proc_id, 0, true, &gsl_msg); + + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + eos_cmd = + GPR_PKT_GET_PAYLOAD(struct data_cmd_wr_sh_mem_ep_eos_t, + gsl_msg.gpr_packet); + eos_cmd->policy = WR_SH_MEM_EP_EOS_POLICY_LAST; + + GSL_VERBOSE("Send EOS to Spf dst miid=%d", dp_info->miid); + + GSL_LOG_PKT("send_pkt", dp_info->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*eos_cmd), NULL, 0); + rc = gsl_send_spf_cmd(&gsl_msg.gpr_packet, NULL, NULL); + if (rc) + GSL_ERR("failed to send EOS err %d", rc); + +exit: + return rc; +} + +int32_t gsl_handle_read_buff_done(struct gsl_data_path_info *dp_info, + gpr_packet_t *packet, gsl_cb_func_ptr cb, void *client_data) +{ + data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t *rd_done; + uint32_t buff_idx; + struct gsl_buff_internal *gsl_buff = NULL; + struct gsl_buff_internal tmp = { 0 }; + int32_t status; + struct gsl_metadata_buff_internal *gsl_md_buff; + /* used to pass to client in callback */ + struct gsl_event_read_write_done_payload rw_done_payload = { 0 }; + uint64_t pa; + uint8_t *spf_metadata = NULL; + int32_t rc = AR_EOK; + + REMOVE_DEBUG_TOKEN(packet->token); + buff_idx = packet->token; + + /* token is used differently for external mem */ + if (GSL_DP_DATA_MODE(dp_info) != GSL_DATA_MODE_EXTERN_MEM) { + if (buff_idx > GSL_MAX_NUM_DATA_BUFFERS) { + GSL_VERBOSE("Buff_idx %d returned as token is invalid", buff_idx); + rc = AR_EBADPARAM; + goto free_pkt; + } + + if (dp_info->is_shmem_supported) + gsl_buff = &dp_info->buff_list[buff_idx]; + } else { + /* hacky. Allocate on stack since ext mem mode has no buff list */ + gsl_buff = &tmp; + } + + rd_done = GPR_PKT_GET_PAYLOAD( + data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t, packet); + status = rd_done->data_status; + pa = GSL_TO_64_BIT(rd_done->data_buf_addr_msw, rd_done->data_buf_addr_lsw); + + /* + * In cases of non shmem usecase, gsl_handle_buff_done_nonshmem + * frees gpr packet after copying the data to client buffer. + */ + if (!dp_info->is_shmem_supported) { + /* packet is freed in nonshmem after fill_client_buff */ + rc = gsl_handle_buff_done_nonshmem(dp_info, + packet, GSL_EVENT_ID_READ_DONE, cb, client_data, status, buff_idx); + goto exit; + } else { + gsl_buff->size_from_spf = rd_done->data_size; + gsl_buff->spf_timestamp = + ((uint64_t)rd_done->timestamp_msw << 32) | rd_done->timestamp_lsw; + gsl_buff->spf_flags = rd_done->flags; + + /* below needed to pass data back to client in shmem mode */ + rw_done_payload.buff.flags = 0; + rw_done_payload.buff.timestamp = 0; + if (gsl_buff->spf_flags & RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG) { + rw_done_payload.buff.timestamp = gsl_buff->spf_timestamp; + rw_done_payload.buff.flags |= GSL_BUFF_FLAG_TS_VALID; + } + GSL_VERBOSE("Read_Done buf idx %d, size_from_spf %d", packet->token, + gsl_buff->size_from_spf); + + if ((GSL_DP_DATA_MODE(dp_info) == GSL_DATA_MODE_SHMEM || + GSL_DP_DATA_MODE(dp_info) == GSL_DATA_MODE_EXTERN_MEM) && + dp_info->config.max_metadata_size > 0) { + + gsl_md_buff = gsl_dequeue_internal_md_buff(dp_info); + if (gsl_md_buff) { + if (dp_info->oob_metadata_flag) + spf_metadata = gsl_md_buff->gsl_msg.shmem.v_addr; + else + spf_metadata = (uint8_t *)rd_done + + sizeof(data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t); + if (gsl_memcpy(gsl_md_buff->client_md_ptr, gsl_md_buff->size, + spf_metadata, rd_done->md_size)) { + /* if copy failed return ENEEDMORE to client */ + gsl_md_buff->md_size_from_spf = rd_done->md_size; + gsl_md_buff->md_status_from_spf = AR_ENEEDMORE; + } else { + gsl_md_buff->md_size_from_spf = rd_done->md_size; + gsl_md_buff->md_status_from_spf = rd_done->md_status; + } + } else { + GSL_ERR("failed to dequeue internal md buff. No md returned"); + } + + gsl_handle_buff_done_shmem(dp_info, cb, &rw_done_payload, buff_idx, + pa, status, gsl_buff, GSL_EVENT_ID_READ_DONE, client_data, + gsl_md_buff, 0); + + } else { + if (dp_info->config.max_metadata_size > 0) + gsl_store_md_status_from_spf(dp_info, rd_done->md_size, + rd_done->md_status); + gsl_handle_buff_done_shmem(dp_info, cb, &rw_done_payload, buff_idx, + pa, status, gsl_buff, GSL_EVENT_ID_READ_DONE, client_data, + NULL, 0); + } + + } +free_pkt: + __gpr_cmd_free(packet); +exit: + return rc; +} + +int32_t gsl_handle_media_format_buff_done(struct gsl_data_path_info *dp_info, + gpr_packet_t *packet) +{ + uint32_t buff_idx; + int32_t status = AR_EOK; + + REMOVE_DEBUG_TOKEN(packet->token); + buff_idx = packet->token; + gsl_mark_buffer_as_avail(dp_info, buff_idx); + gsl_signal_set(&dp_info->dp_signal, GSL_SIG_EVENT_MASK_SPF_RSP, status, + NULL); + GSL_VERBOSE("Media_format_buff Write_Done buf idx %d", packet->token); + __gpr_cmd_free(packet); + return AR_EOK; +} + +int32_t gsl_handle_write_buff_done(struct gsl_data_path_info *dp_info, + gpr_packet_t *packet, gsl_cb_func_ptr cb, void *client_data) +{ + data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2_t *wr_done; + uint32_t buff_idx; + struct gsl_buff_internal *gsl_buff = NULL; + struct gsl_buff_internal tmp = { 0 }; + int32_t status; + /* used to pass to client in callback */ + struct gsl_event_read_write_done_payload rw_done_payload = { 0 }; + uint64_t pa; + + REMOVE_DEBUG_TOKEN(packet->token); + buff_idx = packet->token; + + /* token is used differently for external mem */ + if (GSL_DP_DATA_MODE(dp_info) != GSL_DATA_MODE_EXTERN_MEM) { + if (buff_idx > GSL_MAX_NUM_DATA_BUFFERS) { + GSL_VERBOSE("Buff_idx %d returned as token is invalid", buff_idx); + return AR_EBADPARAM; + } + + if (dp_info->is_shmem_supported) + gsl_buff = &dp_info->buff_list[buff_idx]; + } else { + /* hacky. Allocate on stack since ext mem mode has no buff list */ + gsl_buff = &tmp; + } + + wr_done = GPR_PKT_GET_PAYLOAD( + data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2_t, packet); + status = wr_done->data_status; + pa = GSL_TO_64_BIT(wr_done->data_buf_addr_msw, wr_done->data_buf_addr_lsw); + + if (!dp_info->is_shmem_supported) + return gsl_handle_buff_done_nonshmem(dp_info, packet, + GSL_EVENT_ID_WRITE_DONE, cb, client_data, status, buff_idx); + + gsl_buff->size_from_spf = 0; + GSL_VERBOSE("Write_Done buf idx %d", packet->token); + + gsl_handle_buff_done_shmem(dp_info, cb, &rw_done_payload, buff_idx, pa, + status, gsl_buff, GSL_EVENT_ID_WRITE_DONE, client_data, NULL, + wr_done->md_status); + + if ((GSL_DP_DATA_MODE(dp_info) == GSL_DATA_MODE_SHMEM || + GSL_DP_DATA_MODE(dp_info) == GSL_DATA_MODE_EXTERN_MEM) && + dp_info->config.max_metadata_size > 0) { + /* free oldest metadata shmem buffer if any */ + if (dp_info->config.max_metadata_size > 0) + gsl_dequeue_internal_md_buff(dp_info); + } + return AR_EOK; +} + +int32_t gsl_dp_get_buff_info(struct gsl_data_path_info *dp_info, + struct gsl_cmd_get_shmem_buf_info *cfg) +{ + uint32_t i = 0, num_dp_buffs; + + if (!dp_info || !cfg) + return AR_EBADPARAM; + + if ((dp_info->config.attributes & GSL_ATTRIBUTES_DATA_MODE_MASK) == + GSL_DATA_MODE_PUSH_PULL) + /* Do not expose the push pull position buffer */ + num_dp_buffs = 1; + else + num_dp_buffs = dp_info->config.num_buffs; + + if (cfg->num_buffs >= num_dp_buffs) { + for (i = 0; i < num_dp_buffs; ++i) { + cfg->buffs[i].addr = + dp_info->buff_list[i].gsl_msg.shmem.v_addr; + cfg->buffs[i].metadata = + dp_info->buff_list[i].gsl_msg.shmem.metadata; + } + } + cfg->size = dp_info->config.buff_size; + cfg->num_buffs = num_dp_buffs; + + return AR_EOK; +} + +int32_t gsl_dp_get_pos_buff_info(struct gsl_data_path_info *dp_info, + struct gsl_cmd_get_shmem_buf_info *cfg) +{ + if (!dp_info || !cfg) + return AR_EBADPARAM; + + if (GSL_DP_DATA_MODE(dp_info) != GSL_DATA_MODE_PUSH_PULL) + return AR_EUNSUPPORTED; + + if (cfg->num_buffs >= 1) { + /* + * note in push_pull mode first internal buffer is data and next + * internal buffer is position buffer ALWAYS + */ + cfg->buffs[0].addr = dp_info->buff_list[1].gsl_msg.shmem.v_addr; + cfg->buffs[0].metadata = dp_info->buff_list[1].gsl_msg.shmem.metadata; + } + cfg->size = sizeof(struct sh_mem_pull_push_mode_position_buffer_t); + cfg->num_buffs = 1; + + return AR_EOK; +} + +uint32_t gsl_dp_get_processed_buff_cnt(struct gsl_data_path_info *dp_info) +{ + return dp_info->processed_buf_cnt; +} + +uint32_t gsl_dp_get_avail_buffer_size(struct gsl_data_path_info *dp_info) +{ + uint32_t buff_used_status = 0; + uint32_t available_buff_cnt = 0; + uint32_t available_bytes = 0; + + if (!dp_info) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(dp_info->lock); + available_buff_cnt = dp_info->config.num_buffs; + buff_used_status = dp_info->buff_used_status; + for (int i = 0; i < dp_info->config.num_buffs && buff_used_status != 0; i++) { + if (buff_used_status % 2 == 1) + available_buff_cnt--; + buff_used_status >>= 1; + } + + available_bytes = available_buff_cnt * dp_info->config.buff_size; + GSL_MUTEX_UNLOCK(dp_info->lock); + + return available_bytes; +} + +static void gsl_clear_internal_buf(struct gsl_data_path_info *dp_info) +{ + uint32_t i = 0; + uint32_t buf_idx = 0; + struct gsl_buff_internal *internal_buf = NULL; + gpr_packet_t *packet = NULL; + + if (dp_info->is_shmem_supported) + return; + /* + * This is to handle the scenario where the packets received at the GSL + * client is not freed, due to reasons like state change in client, + * there by eating up GPR datalink buffers. + */ + for (i = 0; i < dp_info->config.num_buffs; i++) { + internal_buf = gsl_find_next_avail_buffer(dp_info, &buf_idx); + + if (!internal_buf) + break; + + packet = (gpr_packet_t *)internal_buf->gsl_msg.payload; + __gpr_cmd_free(packet); + GSL_MUTEX_LOCK(dp_info->lock); + clear_bit(dp_info->buff_used_status, buf_idx); + GSL_MUTEX_UNLOCK(dp_info->lock); + } +} + +int32_t gsl_wait_for_all_buffs_to_be_avail(struct gsl_data_path_info *dp_info) +{ + int32_t rc = AR_EOK, local_buff_used_status; + uint32_t wait_flags = 0; + + GSL_MUTEX_LOCK(dp_info->lock); + local_buff_used_status = dp_info->buff_used_status; + GSL_MUTEX_UNLOCK(dp_info->lock); + + while (local_buff_used_status != 0) { + /* + * if a buffer came back after we release mutex and before we call + * below wait the signal status would be set and below wait will exit + * immediately. For SSR we only get this signal once, so bail. + */ + rc = gsl_signal_timedwait(&dp_info->dp_signal, + GSL_SPF_READ_WRITE_TIMEOUT_MS, &wait_flags, NULL, NULL); + if (rc != AR_EOK || wait_flags & GSL_SIG_EVENT_MASK_SSR) + break; + + GSL_MUTEX_LOCK(dp_info->lock); + local_buff_used_status = dp_info->buff_used_status; + GSL_MUTEX_UNLOCK(dp_info->lock); + } + + /* clear any metadata buffs */ + gsl_clear_internal_md_buff(dp_info); + /* clear any internal buffs */ + gsl_clear_internal_buf(dp_info); + + return rc; +} + +int32_t gsl_dp_queue_read_buffers_to_spf(struct gsl_data_path_info *dp_info) +{ + uint32_t rc = AR_EOK, i, j; + struct gsl_buff_internal *internal_buff = NULL; + struct gsl_metadata_buff_internal *internal_md_buf = NULL; + /* + * In-case of first read in blocking or non-blocking heap mode, push + * all buffers to spf + */ + if (GSL_DP_DATA_MODE(dp_info) != GSL_DATA_MODE_SHMEM && + GSL_DP_DATA_MODE(dp_info) != GSL_DATA_MODE_PUSH_PULL) { + for (j = 0; j < dp_info->config.num_buffs; ++j) { + internal_buff = gsl_find_next_avail_buffer(dp_info, &i); + if (internal_buff) { + if (!dp_info->is_shmem_supported) { + gsl_dp_read_nonshmem(dp_info, + dp_info->config.max_metadata_size, + dp_info->config.buff_size, i); + continue; + } + + if (dp_info->config.max_metadata_size > 0) { + /* + * blocking and non-blocking modes always use oob + * metadata if any + */ + internal_md_buf = gsl_enqueue_internal_md_buff(dp_info); + if (!internal_md_buf) { + GSL_ERR("failed to enqueue internal md buff"); + rc = AR_ENORESOURCE; + } else { + internal_md_buf->size = + dp_info->config.max_metadata_size; + } + } + + gsl_dp_read_shmem(dp_info, internal_buff, + internal_md_buf, 0, dp_info->config.buff_size, i); + } + } + } + + return rc; +} diff --git a/gsl/src/gsl_dls_client.c b/gsl/src/gsl_dls_client.c new file mode 100644 index 0000000..f57f02b --- /dev/null +++ b/gsl/src/gsl_dls_client.c @@ -0,0 +1,515 @@ +/** + * \file gsl_dls_client.C + * \brief + * Contains the implementation of the Data Logging Service (DLS) + * client. + * This module is responsible for delivering binary log + * packet data to the gsl realtime tunning client. GSL subscribes + * subscription to dls event notifications from SPF. The gsl + * realtime tuning client registers the log codes it wants to + * recieve data for. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_util_list.h" +#include "ar_osal_shmem.h" +#include "ar_osal_signal.h" +#include "ar_osal_types.h" +#include "ar_osal_mutex.h" +#include "ar_osal_log.h" +#include "ar_osal_file_io.h" +#include "gpr_ids_domains.h" +#include "gpr_api_inline.h" +#include "dls_api.h" +#include "dls_log_pkt_hdr_api.h" +#include "gsl_msg_builder.h" +#include "gsl_dls_client.h" +#include "gsl_mdf_utils.h" +#include "gsl_common.h" +#include "ar_osal_sys_id.h" + +/*dls client context structure */ +struct gsl_dls_client_ctxt dls_client_ctxt; + +int32_t gsl_dls_client_is_feature_supported() +{ +#if defined(ATS_DATA_LOGGING) + return AR_EOK; +#else + return AR_EUNSUPPORTED; +#endif +} + +static int32_t gsl_dls_client_alloc_dls_msg(uint32_t apm_cmd, uint32_t apm_hdr_size, + uint32_t event_param_data_size, gsl_msg_t *msg) { + int32_t rc = AR_EOK; + + //Will need to update if DLS is enabled for another master proc ID + if (gsl_mdf_utils_is_master_proc(GSL_GET_SPF_SS_MASK(AR_AUDIO_DSP))) { + rc = gsl_msg_alloc(apm_cmd, GSL_DLS_CLIENT_GPR_SRC_PORT, DLS_MODULE_INSTANCE_ID, + apm_hdr_size, 0, GPR_IDS_DOMAIN_ID_ADSP_V, event_param_data_size, true, msg); + if (AR_FAILED(rc)) + GSL_ERR("failed to allocate gsl msg for ADSP | status %d", rc); + } else { + rc = gsl_msg_alloc(apm_cmd, GSL_DLS_CLIENT_GPR_SRC_PORT, DLS_MODULE_INSTANCE_ID, + apm_hdr_size, 0, GPR_IDS_DOMAIN_ID_APPS_V, event_param_data_size, false, msg); + if (AR_FAILED(rc)) + GSL_ERR("failed to allocate gsl msg for APPS | status %d", rc); + } + + return rc; +} + +static int32_t gsl_dls_client_register_deregister_commit_log_buffer_event(enum gsl_dls_commit_log_buffer_register_enum_t event_register_flag) +{ + int32_t rc = AR_EOK; + gsl_msg_t gsl_msg; + apm_cmd_header_t *apm_hdr; + apm_module_register_events_t *event_payload; + uint32_t event_param_data_size = GSL_ALIGN_8BYTE(sizeof(apm_module_register_events_t)); + /* Register to APM_MODULE_EVENTS*/ + + gsl_memset(&gsl_msg, 0, sizeof(gsl_msg_t)); + + rc = gsl_dls_client_alloc_dls_msg(APM_CMD_REGISTER_MODULE_EVENTS, sizeof(*apm_hdr), + event_param_data_size, &gsl_msg); + if (AR_FAILED(rc)) { + GSL_ERR("failed to allocate dls msg | status %d", rc); + goto exit; + } + + apm_hdr = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, gsl_msg.gpr_packet); + apm_hdr->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + apm_hdr->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + apm_hdr->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + apm_hdr->payload_size = event_param_data_size; + + event_payload = (apm_module_register_events_t *)(gsl_msg.payload); + event_payload->module_instance_id = DLS_MODULE_INSTANCE_ID; + event_payload->event_id = DLS_DATA_EVENT_ID_COMMIT_LOG_BUFFER; + event_payload->error_code = 0; + event_payload->is_register = event_register_flag; + event_payload->event_config_payload_size = sizeof(apm_module_register_events_t); + + GSL_DBG("registering dls commit buffer event with spf..."); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &dls_client_ctxt.sig); + if (AR_FAILED(rc)){ + GSL_ERR("failed to register to dls commit buffer event. status %d"); + } + else { + GSL_DBG("successfully registered dls commit buffer event with spf"); + } + + gsl_msg_free(&gsl_msg); +exit: + return rc; +} + +int32_t gsl_dls_client_alloc_shmem_and_config_dls_buffer() +{ + int32_t rc = AR_EOK; + gsl_msg_t gsl_msg; + apm_cmd_header_t *apm_hdr; + apm_module_param_data_t *param_hdr; + dls_param_id_config_buffer_t *param_payload; + uint32_t dls_config_buffer_param_data_size = GSL_ALIGN_8BYTE(sizeof(apm_module_param_data_t) + + sizeof(dls_param_id_config_buffer_t)); + uint32_t dls_buffer_pool_shmem_sz = dls_client_ctxt.buffer_pool_config.buffer_size * + dls_client_ctxt.buffer_pool_config.buffer_count; + + /*Allocate shared memory for DLS Buffer pool*/ + rc = gsl_shmem_alloc(dls_buffer_pool_shmem_sz, AR_AUDIO_DSP, &dls_client_ctxt.dls_shmem); + if (rc) { + GSL_ERR("failed to allocate shmem for dls buffer pool. status %d", rc); + goto exit; + } + + gsl_memset(&gsl_msg, 0, sizeof(gsl_msg_t)); + + rc = gsl_dls_client_alloc_dls_msg(APM_CMD_SET_CFG, sizeof(*apm_hdr), + dls_config_buffer_param_data_size, &gsl_msg); + if (AR_FAILED(rc)) { + GSL_ERR("failed to allocate dls msg | status %d", rc); + goto exit; + } + + apm_hdr = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, gsl_msg.gpr_packet); + apm_hdr->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + apm_hdr->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + apm_hdr->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + apm_hdr->payload_size = dls_config_buffer_param_data_size; + + param_hdr = (apm_module_param_data_t *)(gsl_msg.payload); + param_hdr->module_instance_id = DLS_MODULE_INSTANCE_ID; + param_hdr->param_id = DLS_PARAM_ID_CONFIG_BUFFER; + param_hdr->param_size = sizeof(dls_param_id_config_buffer_t); + param_hdr->error_code = 0; + + param_payload = (dls_param_id_config_buffer_t *)(param_hdr + 1); + param_payload->buf_start_addr_lsw = (uint32_t) dls_client_ctxt.dls_shmem.spf_addr; + param_payload->buf_start_addr_msw = (uint32_t) (dls_client_ctxt.dls_shmem.spf_addr >> 32); + param_payload->is_cfg = 1; + param_payload->max_log_pkt_size = dls_client_ctxt.buffer_pool_config.buffer_size; + param_payload->mem_map_handle = dls_client_ctxt.dls_shmem.spf_mmap_handle; + param_payload->total_buf_size = dls_buffer_pool_shmem_sz; + + GSL_DBG("configuring dls buffers on spf"); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &dls_client_ctxt.sig); + if (AR_FAILED(rc)) { + GSL_ERR("failed to configure buffer with size :0x%x and buffer count = 0x%x. status %d", + dls_client_ctxt.buffer_pool_config.buffer_size, dls_client_ctxt.buffer_pool_config.buffer_count, rc); + } + else { + GSL_DBG("buffer configured with size :0x%x and buffer count = 0x%x", + dls_client_ctxt.buffer_pool_config.buffer_size, dls_client_ctxt.buffer_pool_config.buffer_count); + } + + gsl_msg_free(&gsl_msg); +exit: + + return rc; +} + +int32_t gsl_dls_client_create_buffer_pool(struct gsl_dls_buffer_pool_config_t *buffer_pool_config) +{ + int32_t rc = AR_EOK; + if (dls_client_ctxt.is_dls_buffer_configured) { + rc = gsl_shmem_free(&dls_client_ctxt.dls_shmem); + if (rc) + { + GSL_ERR("unable to unmap shared memory. App restart recommended. status %d", rc); + return rc; + } + } + + if ((buffer_pool_config->buffer_count < GSL_DLS_CLIENT_MIN_BUFFER_COUNT) || + (buffer_pool_config->buffer_count > GSL_DLS_CLIENT_MAX_BUFFER_COUNT)) { + GSL_ERR("invalid buffer configuration request. buffer count limit is :0x%x and 0x%x", + GSL_DLS_CLIENT_MIN_BUFFER_COUNT, GSL_DLS_CLIENT_MAX_BUFFER_COUNT); + return AR_EBADPARAM; + } + + if (buffer_pool_config->buffer_size < GSL_DLS_CLIENT_SHMEM_MIN_BUFFER_SZ || + buffer_pool_config->buffer_size > GSL_DLS_CLIENT_SHMEM_MAX_BUFFER_SZ) { + GSL_ERR("invalid Buffer Configuration request. buffer size limit is :0x%x and 0x%x", + GSL_DLS_CLIENT_SHMEM_MIN_BUFFER_SZ, GSL_DLS_CLIENT_SHMEM_MAX_BUFFER_SZ); + return AR_EBADPARAM; + } + + dls_client_ctxt.buffer_pool_config = *buffer_pool_config; + + rc = gsl_dls_client_register_deregister_commit_log_buffer_event(GLS_DLS_EVENT_FLAG_REGISTER_COMMIT_LOG_BUFFER); + if (AR_FAILED(rc)) + goto exit; + + rc = gsl_dls_client_alloc_shmem_and_config_dls_buffer(); + +exit: + + return rc; +} + +void gsl_dls_client_get_ready_dls_buffer_list(struct gsl_dls_ready_buffer_index_list_t *ready_buffer_index_list) +{ + dls_buf_hdr_t *dls_buffer_ptr = NULL; + uint32_t dls_buffer_offset = 0; + + if (!dls_client_ctxt.is_dls_buffer_configured) + return; + + gsl_memset(ready_buffer_index_list, 0, sizeof(struct gsl_dls_ready_buffer_index_list_t)); + + for (uint16_t buffer_index = 0; buffer_index < dls_client_ctxt.buffer_pool_config.buffer_count; buffer_index++) + { + dls_buffer_offset = (buffer_index * dls_client_ctxt.buffer_pool_config.buffer_size); + dls_buffer_ptr = (dls_buf_hdr_t *)((uint8_t *)dls_client_ctxt.dls_shmem.v_addr + dls_buffer_offset); + + if (DLS_BUF_READY != dls_buffer_ptr->buf_state) continue; + + ready_buffer_index_list->buffer_index_list[ready_buffer_index_list->buffer_count] = buffer_index; + ready_buffer_index_list->buffer_count++; + } + + if (ready_buffer_index_list->buffer_count == 0) + { + GSL_DBG("there are no ready dls buffers"); + } +} + +int32_t gsl_dls_client_get_log_buffer(uint32_t log_buffer_index, struct gls_dls_buffer_t *dls_log_buffer) +{ + int32_t rc = AR_EOK; + dls_buf_hdr_t *dls_buffer_ptr = NULL; + uint32_t dls_buffer_offset = 0; + uint8_t *dls_shmem_buffer_pool = NULL; + + if (!dls_client_ctxt.is_dls_buffer_configured) + return AR_ENOTREADY; + + if (log_buffer_index > dls_client_ctxt.buffer_pool_config.buffer_count) + return AR_ENOTEXIST; + + dls_buffer_offset = (log_buffer_index * dls_client_ctxt.buffer_pool_config.buffer_size); + dls_shmem_buffer_pool = (uint8_t *)dls_client_ctxt.dls_shmem.v_addr + dls_buffer_offset; + dls_buffer_ptr = (dls_buf_hdr_t *)(dls_shmem_buffer_pool); + + /* Skip the dls buffer header before sending it to the client since its not required by the client */ + dls_log_buffer->size = dls_buffer_ptr->buf_size - sizeof(dls_buf_hdr_t); + dls_log_buffer->buffer = dls_shmem_buffer_pool + sizeof(dls_buf_hdr_t); + + return rc; +} + +void gsl_dls_client_set_used_buffers(struct gsl_dls_ready_buffer_index_list_t *buffer_index_list) +{ + //Store used buffers in gsl dsl client context + gsl_memcpy(&dls_client_ctxt.used_buffers, sizeof(dls_client_ctxt.used_buffers), buffer_index_list, + sizeof(dls_client_ctxt.used_buffers)); +} + +int32_t gsl_dls_client_return_used_buffers(struct gsl_dls_ready_buffer_index_list_t *buffer_index_list) +{ + int32_t rc = AR_EFAILED; + apm_cmd_header_t *apm_hdr; + gsl_msg_t gsl_msg; + dls_data_cmd_buffer_return_t *dls_buf_ret_cfg; + uint32_t dls_buffer_offset = 0; + uint32_t signal_flags = 0; + uint32_t dls_buf_ret_cfg_size = 0; + + rc = gsl_signal_timedwait(&dls_client_ctxt.ready_buffer_sig, GSL_SPF_TIMEOUT_MS, + &signal_flags, NULL, NULL); + if (rc) { + GSL_ERR("ready buffer signal wait failed | status %d", rc); + return rc; + } + + buffer_index_list = &dls_client_ctxt.used_buffers; + + dls_buf_ret_cfg_size = GSL_ALIGN_8BYTE(sizeof(uint32_t) + + (buffer_index_list->buffer_count * sizeof(dls_buf_start_addr_t))); + + rc = gsl_dls_client_alloc_dls_msg(DLS_DATA_CMD_BUFFER_RETURN, sizeof(*apm_hdr), + dls_buf_ret_cfg_size, &gsl_msg); + if (AR_FAILED(rc)) { + GSL_ERR("failed to allocate dls msg for buffer return command | status %d", rc); + goto exit; + } + + dls_buf_ret_cfg = GPR_PKT_GET_PAYLOAD(dls_data_cmd_buffer_return_t, gsl_msg.gpr_packet); + dls_buf_ret_cfg->num_bufs = (uint32_t)buffer_index_list->buffer_count; + for (uint32_t i = 0; i < dls_buf_ret_cfg->num_bufs; i++) + { + dls_buffer_offset = (buffer_index_list->buffer_index_list[i] * dls_client_ctxt.buffer_pool_config.buffer_size); + dls_buf_ret_cfg->buf_start_addr[i].buf_addr_lsw = (uint32_t)(((uint64_t)dls_client_ctxt.dls_shmem.spf_addr + dls_buffer_offset) & 0x00000000FFFFFFFF); + dls_buf_ret_cfg->buf_start_addr[i].buf_addr_msw = (uint32_t)((((uint64_t)dls_client_ctxt.dls_shmem.spf_addr + dls_buffer_offset) & 0xFFFFFFFF00000000) >> 32); + dls_buf_ret_cfg->buf_start_addr[i].mem_map_handle = dls_client_ctxt.dls_shmem.spf_mmap_handle; + } + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &dls_client_ctxt.sig); + if (AR_FAILED(rc)) { + GSL_ERR("failed to return %d buffers to dls. status %d", dls_buf_ret_cfg->num_bufs, rc); + } + else { + GSL_DBG("returned buffers %d buffers to dls for reuse", dls_buf_ret_cfg->num_bufs); + } + + gsl_msg_free(&gsl_msg); +exit: + return rc; +} + +int32_t gsl_dls_client_register_deregister_log_code(uint32_t log_code, bool_t is_log_code_enabled) +{ + int32_t rc = AR_EOK; + apm_cmd_header_t *apm_hdr; + apm_module_param_data_t *param_hdr; + dls_param_id_enable_disable_log_code_t *param_payload; + gsl_msg_t gsl_msg; + uint16_t num_log_codes = 1; + uint32_t dls_log_code_cfg_size = GSL_ALIGN_8BYTE( + sizeof(apm_module_param_data_t) + + sizeof(dls_param_id_enable_disable_log_code_t) + + (num_log_codes * sizeof(uint32_t))); + + gsl_memset(&gsl_msg, 0, sizeof(gsl_msg_t)); + + rc = gsl_dls_client_alloc_dls_msg(APM_CMD_SET_CFG, sizeof(*apm_hdr), + dls_log_code_cfg_size, &gsl_msg); + if (AR_FAILED(rc)) { + GSL_ERR("failed to allocate dls msg | status %d", rc); + goto exit; + } + + apm_hdr = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, gsl_msg.gpr_packet); + apm_hdr->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + apm_hdr->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + apm_hdr->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + apm_hdr->payload_size = dls_log_code_cfg_size; + + param_hdr = (apm_module_param_data_t *)(gsl_msg.payload); + param_hdr->module_instance_id = DLS_MODULE_INSTANCE_ID; + param_hdr->param_id = DLS_PARAM_ID_ENABLE_DISABLE_LOG_CODE; + param_hdr->param_size = sizeof(dls_param_id_enable_disable_log_code_t) + + (num_log_codes * sizeof(uint32_t)); + param_hdr->error_code = 0; + + param_payload = (dls_param_id_enable_disable_log_code_t *)(param_hdr + 1); + param_payload->is_enabled = is_log_code_enabled? 1 : 0; + param_payload->num_log_codes = num_log_codes; + for (int i = 0; i < num_log_codes; i++) { + param_payload->log_codes[i] = log_code; + } + GSL_LOG_PKT("send_pkt", GSL_DLS_CLIENT_GPR_SRC_PORT, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*apm_hdr), gsl_msg.payload, + apm_hdr->payload_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &dls_client_ctxt.sig); + if (AR_FAILED(rc) && is_log_code_enabled){ + GSL_ERR("unable to register logcode 0x%x. status %d", log_code, rc); + } + else if (AR_FAILED(rc) && !is_log_code_enabled){ + GSL_ERR("unable to de-register logcode 0x%x. status %d", log_code, rc); + } + else if (AR_SUCCEEDED(rc) && is_log_code_enabled){ + GSL_DBG("registered logcode 0x%x. status %d", log_code, rc); + } + else if (AR_SUCCEEDED(rc) && !is_log_code_enabled){ + GSL_DBG("de-registered logcode 0x%x. status %d", log_code, rc); + } + + gsl_msg_free(&gsl_msg); + + exit: + return rc; +} + +static uint32_t gsl_dls_client_event_callback(gpr_packet_t *packet, void *callback_data) +{ + callback_data = NULL; + GSL_DBG("received opcode :0x%x ", packet->opcode); + switch (packet->opcode) { + case GPR_IBASIC_RSP_RESULT: + { + gpr_ibasic_rsp_result_t *p_gpr_rsp = (gpr_ibasic_rsp_result_t *)GPR_PKT_GET_PAYLOAD(void, packet); + GSL_DBG( + "DLS_CLIENT_GPR CB: ISR received GPR_IBASIC_RSP_RESULT, result(%lu),opcode(0x%lx)", + p_gpr_rsp->status, + p_gpr_rsp->opcode); + + if (p_gpr_rsp->status != AR_EOK) { + GSL_DBG( + "DLS_CLIENT_GPR CB: GPR_IBASIC_RSP_RESULT failed, result(%lu),clientToken(%lu)", + p_gpr_rsp->status, + packet->token); + } + + __gpr_cmd_free(packet); + gsl_signal_set(&dls_client_ctxt.sig, 0, 0, NULL); + break; + } + + case APM_EVENT_MODULE_TO_CLIENT: + { + apm_module_event_t *apm_event = NULL; + apm_event = GPR_PKT_GET_PAYLOAD(apm_module_event_t, packet); + if (DLS_DATA_EVENT_ID_COMMIT_LOG_BUFFER == apm_event->event_id) + { + GSL_DBG( + "recieved dls commit event: opcode(0x%x) event(0x%x) ", + packet->opcode, apm_event->event_id); + dls_client_ctxt.buffer_ready_callback(); + __gpr_cmd_free(packet); + gsl_signal_set(&dls_client_ctxt.ready_buffer_sig, 0, 0, NULL); + } + break; + } + default: + break; + } + return AR_EOK; +} + +int32_t gsl_dls_client_init(struct gsl_dls_buffer_pool_config_t *buffer_pool_config, GSL_DLS_CLIENT_BUFFER_READY_CALLBACK callback) +{ + int32_t rc = AR_EOK; + + rc = __gpr_cmd_register(GSL_DLS_CLIENT_GPR_SRC_PORT, gsl_dls_client_event_callback, &dls_client_ctxt); + if (rc) { + GSL_ERR("unable to register gsl dls client with gpr. status %d", rc); + return rc; + } + + rc = gsl_signal_create(&dls_client_ctxt.sig, &dls_client_ctxt.sig_lock); + if (rc) { + GSL_ERR("unable to create signal for dls events. status %d", rc); + __gpr_cmd_deregister(GSL_DLS_CLIENT_GPR_SRC_PORT); + return rc; + } + + rc = gsl_signal_create(&dls_client_ctxt.ready_buffer_sig, NULL); + GSL_ERR("Created ready buffer signal"); + if (rc) { + GSL_ERR("unable to create signal for ready buffer event | status %d", rc); + return rc; + } + + rc = gsl_dls_client_create_buffer_pool(buffer_pool_config); + if (rc) { + GSL_ERR("unable to create shared memory pool. status %d", rc); + gsl_signal_destroy(&dls_client_ctxt.sig); + __gpr_cmd_deregister(GSL_DLS_CLIENT_GPR_SRC_PORT); + return rc; + } + + /* todo : Move dls_client_ctxt.is_dls_buffer_configured = 1 to + * gsl_dls_client_event_callback, once GPR_Basic_Response + * contains payload which will identify PID for which it is sent + */ + dls_client_ctxt.is_dls_buffer_configured = 1; + dls_client_ctxt.buffer_ready_callback = callback; + + GSL_DBG("gsl dls client is initialized"); + return rc; +} + +int32_t gsl_dls_client_deinit() +{ + int32_t rc = AR_EOK; + GSL_DBG("deinitializing gls dls client"); + + gsl_dls_client_register_deregister_commit_log_buffer_event(GLS_DLS_EVENT_FLAG_DEREGISTER_COMMIT_LOG_BUFFER); + + rc = gsl_signal_destroy(&dls_client_ctxt.sig); + if (AR_FAILED(rc)) { + GSL_ERR("failed to destroy dls client signal. status %d", rc); + } + + rc = __gpr_cmd_deregister(GSL_DLS_CLIENT_GPR_SRC_PORT); + if (AR_FAILED(rc)) { + GSL_ERR("failed to deregister dls source port with gpr. status %d", rc); + } + + rc = gsl_shmem_free(&dls_client_ctxt.dls_shmem); + if (AR_FAILED(rc)) { + GSL_ERR("failed to free dls client shared memory. status %d", rc); + } + + rc = gsl_signal_destroy(&dls_client_ctxt.sig); + if (AR_FAILED(rc)) { + GSL_ERR("failed to destroy client context signal. status %d", rc); + } + + dls_client_ctxt.is_dls_buffer_configured = 0; + dls_client_ctxt.buffer_ready_callback = NULL; + return rc; +} diff --git a/gsl/src/gsl_dynamic_module_mgr.c b/gsl/src/gsl_dynamic_module_mgr.c new file mode 100644 index 0000000..3b2453c --- /dev/null +++ b/gsl/src/gsl_dynamic_module_mgr.c @@ -0,0 +1,498 @@ +/** + * \file gsl_dynamic_module_mgr.c + * + * \brief + * Manages the loading and unloading of Spf dynamic modules + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_dynamic_module_mgr.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" +#include "amdb_api.h" +#include "gpr_api.h" +#include "gpr_api_inline.h" +#include "gpr_ids_domains.h" +#include "gsl_common.h" +#include "acdb.h" +#include "apm_api.h" +#include "ar_osal_sys_id.h" +#include "gsl_shmem_mgr.h" +#include "gsl_spf_ss_state.h" + +#define GSL_DYNAMIC_MODULE_MGR_PORT 0x2005 + +struct gsl_dyn_modules_ctxt { + uint32_t num_dyn_modules; + + /* + * This is the payload sent from Spf as part of AMDB_CMD_RSP_LOAD_MODULES + * we keep the packet with us and dont free it back to GPR untill we send + * the unload modules command. This is because the response contains the + * handles that must be sent back during unload and the unload command + * to Spf takes the same payload + */ + struct gpr_packet_t *amdb_rsp[AR_SUB_SYS_ID_LAST + 1]; +}; + +ar_osal_mutex_t rsp_signal_lock; +struct gsl_signal rsp_signal; +struct gsl_dyn_modules_ctxt *gsl_dyn_mod_mgr_ctxt[AR_SUB_SYS_ID_LAST + 1] + = {NULL}; + +static uint32_t gsl_dynamic_mod_mgr_gpr_cb(gpr_packet_t *packet, void *cb_data) +{ + struct spf_cmd_basic_rsp *rsp; + uint32_t rc = AR_EOK; + + cb_data; /* Referencing to make compiler happy */ + + switch (packet->opcode) { + case GPR_IBASIC_RSP_RESULT: + rsp = GPR_PKT_GET_PAYLOAD(struct spf_cmd_basic_rsp, packet); + if (rsp->opcode == AMDB_CMD_REGISTER_MODULES || + rsp->opcode == AMDB_CMD_UNLOAD_MODULES || + rsp->opcode == AMDB_CMD_DEREGISTER_MODULES) { + rc = gsl_signal_set(&rsp_signal, + GSL_SIG_EVENT_MASK_SPF_RSP, rsp->status, packet); + /* do not free packet here as it will be freed by waiter */ + } else { + __gpr_cmd_free(packet); + } + break; + case AMDB_CMD_RSP_LOAD_MODULES: + rc = gsl_signal_set(&rsp_signal, + GSL_SIG_EVENT_MASK_SPF_RSP, 0, packet); + /* do not free packet here as it will be freed by waiter */ + break; + default: + __gpr_cmd_free(packet); + break; + } + + if (rc) + __gpr_cmd_free(packet); + + return AR_EOK; +} + +/* + * initialize the spf dynamic modules manager + * @param[in] rsp_signal signal used to wait for responses from spf, the + * signal should be created and initialized by caller + */ +int32_t gsl_dynamic_module_mgr_init(uint32_t num_master_procs, + uint32_t *master_procs) +{ + int32_t rc = AR_EOK; + uint32_t i = 0; + uint32_t j = 0; + bool_t is_shared_mem_supported = TRUE; + + if (!master_procs) { + GSL_ERR("Invalid argument master_procs"); + rc = AR_EBADPARAM; + goto exit; + } + + for (; i < num_master_procs; i++) { + __gpr_cmd_is_shared_mem_supported(master_procs[i], + &is_shared_mem_supported); + + if (!is_shared_mem_supported) + continue; + + gsl_dyn_mod_mgr_ctxt[master_procs[i]] = + gsl_mem_zalloc(sizeof(struct gsl_dyn_modules_ctxt)); + + if (!gsl_dyn_mod_mgr_ctxt[master_procs[i]]) { + GSL_ERR("Unable to allocate memory"); + goto free_ctxt; + } + + gsl_memset(gsl_dyn_mod_mgr_ctxt[master_procs[i]]->amdb_rsp, 0, + (AR_SUB_SYS_ID_LAST + 1) * sizeof(uintptr_t)); + } + + rc = ar_osal_mutex_create(&rsp_signal_lock); + if (rc) { + GSL_ERR("ar_osal_mutex_init failed %d", rc); + goto free_ctxt; + } + + rc = gsl_signal_create(&rsp_signal, &rsp_signal_lock); + if (rc) { + GSL_ERR("signal create failed %d", rc); + goto destroy_lock; + } + + rc = __gpr_cmd_register(GSL_DYNAMIC_MODULE_MGR_PORT, + gsl_dynamic_mod_mgr_gpr_cb, gsl_dyn_mod_mgr_ctxt); + if (rc) { + GSL_ERR("gpr register failed"); + goto destroy_signal; + } + + return rc; + +destroy_signal: + gsl_signal_destroy(&rsp_signal); +destroy_lock: + ar_osal_mutex_destroy(rsp_signal_lock); +free_ctxt: + for (j = 0; j < i; j++) { + gsl_mem_free(gsl_dyn_mod_mgr_ctxt[j]); + gsl_dyn_mod_mgr_ctxt[j] = NULL; + } +exit: + return rc; +} + +int32_t gsl_dynamic_module_mgr_deinit(void) +{ + uint32_t i = 0; + + __gpr_cmd_deregister(GSL_DYNAMIC_MODULE_MGR_PORT); + + for (; i <= AR_SUB_SYS_ID_LAST; i++) { + if (gsl_dyn_mod_mgr_ctxt[i]) { + gsl_mem_free(gsl_dyn_mod_mgr_ctxt[i]); + gsl_dyn_mod_mgr_ctxt[i] = NULL; + } + } + + gsl_signal_destroy(&rsp_signal); + ar_osal_mutex_destroy(rsp_signal_lock); + + return AR_EOK; +} + +static int32_t gsl_do_register_dynamic_modules(uint32_t master_proc, + bool_t dereg, gsl_acdb_handle_t handle) +{ + uint32_t reg_data_offset = 0, i = 0, rc = AR_EOK, total_reg_data_sz = 0; + struct gsl_shmem_alloc_data shmem_params; + AcdbAmdbDbHandle amdb_db_req; + AcdbBlob acdb_blob_rsp; + apm_cmd_header_t *apm_hdr; + uint64_t tmp_spf_addr = 0; + gpr_packet_t *send_pkt = NULL; + uint32_t spf_opcode = AMDB_CMD_REGISTER_MODULES; + uint32_t acdb_cmdid = ACDB_CMD_GET_AMDB_REGISTRATION_DATA_V2; + uint32_t found_proc_ids = 0x0; + + if (dereg) { + spf_opcode = AMDB_CMD_DEREGISTER_MODULES; + acdb_cmdid = ACDB_CMD_GET_AMDB_DEREGISTRATION_DATA_V2; + } + /* + * loop computes the size for module registration data for all proc_ids + */ + for (i = AR_SUB_SYS_ID_FIRST; i <= AR_SUB_SYS_ID_LAST; ++i) { + + /* if the current proc_id is not supported, skip */ + if (!gsl_spf_ss_state_is_ss_supported(master_proc, i)) + continue; + + amdb_db_req.proc_id = i; + amdb_db_req.acdb_handle = handle; + acdb_blob_rsp.buf_size = 0; + acdb_blob_rsp.buf = NULL; + rc = acdb_ioctl(acdb_cmdid, &amdb_db_req, sizeof(amdb_db_req), + &acdb_blob_rsp, sizeof(acdb_blob_rsp)); + if (rc != AR_EOK && rc != AR_ENOTEXIST) { + GSL_ERR("acdb get amdb_registration data failed %d", rc); + goto exit; + } + + if (rc == AR_ENOTEXIST || acdb_blob_rsp.buf_size == 0) { + /* + * no dynamic module related registration data exists for this + * module, move on to next proc_id + */ + rc = AR_EOK; + continue; + } + + set_bit(found_proc_ids, (i - 1)); + GSL_DBG("proc id: %d, found proc bit field: %d", i, found_proc_ids); + + /* 8 byte alignment required by Spf */ + total_reg_data_sz += GSL_ALIGN_8BYTE(acdb_blob_rsp.buf_size); + } + + if (total_reg_data_sz > 0) { + rc = gsl_shmem_alloc(total_reg_data_sz, master_proc, &shmem_params); + if (rc) + goto exit; + } else { + /* no dynamic registration data so we can skip */ + goto exit; + } + + /* for every proc_id query and register dynamic modules */ + reg_data_offset = 0; + for (i = AR_SUB_SYS_ID_FIRST; i <= AR_SUB_SYS_ID_LAST; ++i) { + + /* if the current proc_id is not supported, skip */ + if (!gsl_spf_ss_state_is_ss_supported(master_proc, i)) + continue; + + if (get_bit(found_proc_ids, i - 1) == 0) { + GSL_DBG("skipping proc id: %d, found proc bit field: %d", + i, found_proc_ids); + continue; + } + + amdb_db_req.proc_id = i; + amdb_db_req.acdb_handle = handle; + acdb_blob_rsp.buf = (uint8_t *)shmem_params.v_addr + reg_data_offset; + acdb_blob_rsp.buf_size = total_reg_data_sz; /* acdb returns fill sz */ + rc = acdb_ioctl(acdb_cmdid, &amdb_db_req, sizeof(amdb_db_req), + &acdb_blob_rsp, sizeof(acdb_blob_rsp)); + if (rc == AR_ENOTEXIST) { + /* continue to next proc id if no registration data */ + rc = AR_EOK; + continue; + } + if (rc != AR_EOK) { + GSL_ERR("acdb_ioctl get amdb registration data failed %d", rc); + goto free_shmem; + } + if (acdb_blob_rsp.buf_size != 0) { + /* send to spf */ + rc = gsl_allocate_gpr_packet(spf_opcode, + GSL_DYNAMIC_MODULE_MGR_PORT, AMDB_MODULE_INSTANCE_ID, + sizeof(*apm_hdr), 0, master_proc, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto free_shmem; + } + + apm_hdr = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, send_pkt); + apm_hdr->mem_map_handle = shmem_params.spf_mmap_handle; + tmp_spf_addr = shmem_params.spf_addr + reg_data_offset; + apm_hdr->payload_address_lsw = (uint32_t)(tmp_spf_addr); + apm_hdr->payload_address_msw = (uint32_t)(tmp_spf_addr >> 32); + apm_hdr->payload_size = acdb_blob_rsp.buf_size; + + GSL_LOG_PKT("send_pkt", GSL_DYNAMIC_MODULE_MGR_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*apm_hdr), acdb_blob_rsp.buf, + acdb_blob_rsp.buf_size); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, &rsp_signal); + if (rc) { + GSL_ERR("Register modules cmd 0x%x failure:%d", spf_opcode, rc); + goto free_shmem; + } + + /* increment offset to be used in next loop iteration */ + reg_data_offset += GSL_ALIGN_8BYTE(acdb_blob_rsp.buf_size); + total_reg_data_sz -= GSL_ALIGN_8BYTE(acdb_blob_rsp.buf_size); + } + } +free_shmem: + gsl_shmem_free(&shmem_params); + +exit: + return rc; +} + +/* + * load bootup time modules to spf + */ +int32_t gsl_do_load_bootup_dyn_modules(uint32_t master_proc, + gsl_acdb_handle_t handle) +{ + int32_t rc = AR_EOK; + uint32_t proc_id = AR_SUB_SYS_ID_FIRST; + AcdbAmdbDbHandle amdb_db_req; + AcdbBlob acdb_blob_rsp; + apm_cmd_header_t *apm_hdr; + uint8_t *spf_cmd = NULL; + gpr_packet_t *p_rsp_pkt = NULL, *send_pkt = NULL; + struct amdb_module_load_unload_t *load_cmd; + + if (gsl_dyn_mod_mgr_ctxt[master_proc] == NULL) + goto exit; + + /* TODO: only register if master proc is booting up */ + rc = gsl_do_register_dynamic_modules(master_proc, FALSE, handle); + if (rc) { + GSL_ERR("failed to register dynamic modules %d", rc); + goto exit; + } + + /* TODO: loop over all sybsystems. This is temporary. Non-preloaded + * modules will be loaded by spf on demand + */ + for (; proc_id <= AR_SUB_SYS_ID_LAST; ++proc_id) { + /* + * if the current proc_id is not supported, or we're handling SSR and + * this subsystem did NOT restart, skip + */ + if (!gsl_spf_ss_state_is_ss_supported(master_proc, proc_id)) + continue; + + /* query and load bootup time modules for current proc_id */ + amdb_db_req.proc_id = proc_id; + amdb_db_req.acdb_handle = handle; + + /* first query is for size */ + acdb_blob_rsp.buf = NULL; + acdb_blob_rsp.buf_size = 0; + rc = acdb_ioctl(ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES_V2, + &amdb_db_req, sizeof(amdb_db_req), + &acdb_blob_rsp, sizeof(acdb_blob_rsp)); + if (rc != AR_EOK && rc != AR_ENOTEXIST) { + GSL_ERR("acdb_ioctl failed %d", rc); + goto exit; + } + + if (rc == AR_ENOTEXIST || acdb_blob_rsp.buf_size == 0) { + /* its possible that a proc_id contains no bootup time modules */ + rc = AR_EOK; + continue; + } + + /* allocate memory and query for blob */ + rc = gsl_allocate_gpr_packet(AMDB_CMD_LOAD_MODULES, + GSL_DYNAMIC_MODULE_MGR_PORT, AMDB_MODULE_INSTANCE_ID, + acdb_blob_rsp.buf_size + sizeof(*apm_hdr), + 0, master_proc, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + + spf_cmd = GPR_PKT_GET_PAYLOAD(uint8_t, send_pkt); + apm_hdr = (apm_cmd_header_t *)spf_cmd; + gsl_memset(apm_hdr, 0, sizeof(*apm_hdr)); + apm_hdr->payload_size = acdb_blob_rsp.buf_size; + acdb_blob_rsp.buf = spf_cmd + sizeof(*apm_hdr); + rc = acdb_ioctl(ACDB_CMD_GET_AMDB_BOOTUP_LOAD_MODULES_V2, + &amdb_db_req, sizeof(amdb_db_req), + &acdb_blob_rsp, sizeof(acdb_blob_rsp)); + if (rc) { + GSL_ERR("acdb get amdb bootup load modules failed %d", rc); + goto free_gpr_pkt; + } + + GSL_LOG_PKT("send_pkt", GSL_DYNAMIC_MODULE_MGR_PORT, send_pkt, + sizeof(*send_pkt) + acdb_blob_rsp.buf_size + sizeof(*apm_hdr), + NULL, 0); + /* send to spf */ + rc = gsl_send_spf_cmd(&send_pkt, &rsp_signal, &p_rsp_pkt); + if (rc) { + GSL_ERR("Load modules cmd 0x%x failure:%d", + AMDB_CMD_LOAD_MODULES, rc); + goto exit; + } + if (p_rsp_pkt) { + load_cmd = GPR_PKT_GET_PAYLOAD(struct amdb_module_load_unload_t, + p_rsp_pkt); + if (load_cmd->error_code != AR_EOK) { + GSL_ERR("load cmd failed: spf status %d", + load_cmd->error_code); + rc = AR_EFAILED; + __gpr_cmd_free(p_rsp_pkt); + goto undo_module_registration; + } + + /* store the handles to be used in unload */ + if (gsl_dyn_mod_mgr_ctxt[master_proc]->amdb_rsp[proc_id]) + __gpr_cmd_free( + gsl_dyn_mod_mgr_ctxt[master_proc]->amdb_rsp[proc_id]); + gsl_dyn_mod_mgr_ctxt[master_proc]->amdb_rsp[proc_id] = p_rsp_pkt; + } + } + + goto exit; +undo_module_registration: + GSL_ERR("Deregistering modules due to load modules failure"); + gsl_do_register_dynamic_modules(master_proc, true, handle); + goto exit; + +free_gpr_pkt: + __gpr_cmd_free(send_pkt); +exit: + return rc; +} + +/* + * unload bootup time modules from spf + */ +int32_t gsl_do_unload_bootup_dyn_modules(uint32_t master_proc, + gsl_acdb_handle_t handle) +{ + int32_t first_rc = AR_EOK, rc = AR_EOK; + uint32_t proc_id = AR_SUB_SYS_ID_FIRST, load_rsp_pld_sz = 0; + struct amdb_module_load_unload_t *load_rsp_pld = NULL; + gpr_packet_t *send_pkt = NULL; + apm_cmd_header_t *apm_hdr = NULL; + + if (gsl_dyn_mod_mgr_ctxt[master_proc] == NULL) + return first_rc; + + for (; proc_id <= AR_SUB_SYS_ID_LAST; ++proc_id) { + /* + * if the current proc_id is not supported, skip. Also skip if no + * modules were loaded for current proc_id + */ + if (!gsl_spf_ss_state_is_ss_supported(master_proc, proc_id) || + !gsl_dyn_mod_mgr_ctxt[master_proc]->amdb_rsp[proc_id]) + continue; + + /* + * use the stored load rsp packet to do unload since it has the exact + * same payload. However we need to add apm_header_t in-between hence + * we need to allocate a new packet and do memcpy. + */ + load_rsp_pld = GPR_PKT_GET_PAYLOAD( + struct amdb_module_load_unload_t, + gsl_dyn_mod_mgr_ctxt[master_proc]->amdb_rsp[proc_id]); + load_rsp_pld_sz = GPR_PKT_GET_PAYLOAD_BYTE_SIZE( + gsl_dyn_mod_mgr_ctxt[master_proc]->amdb_rsp[proc_id]->header); + + rc = gsl_allocate_gpr_packet(AMDB_CMD_UNLOAD_MODULES, + GSL_DYNAMIC_MODULE_MGR_PORT, AMDB_MODULE_INSTANCE_ID, + sizeof(*apm_hdr) + load_rsp_pld_sz, 0, master_proc, + &send_pkt); + if (rc) { + if (!first_rc) + first_rc = rc; + GSL_ERR("Failed to allocate GPR packet %d", rc); + continue; + } + + apm_hdr = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, send_pkt); + gsl_memset((uint8_t *)apm_hdr, 0, sizeof(*apm_hdr)); + apm_hdr->payload_size = load_rsp_pld_sz; + gsl_memcpy((uint8_t *)apm_hdr+sizeof(*apm_hdr), load_rsp_pld_sz, + load_rsp_pld, load_rsp_pld_sz); + + /* we can now free the response packet */ + __gpr_cmd_free(gsl_dyn_mod_mgr_ctxt[master_proc]->amdb_rsp[proc_id]); + gsl_dyn_mod_mgr_ctxt[master_proc]->amdb_rsp[proc_id] = NULL; + + GSL_LOG_PKT("send_pkt", GSL_DYNAMIC_MODULE_MGR_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*apm_hdr) + load_rsp_pld_sz, NULL, 0); + /* + * send to spf + */ + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, &rsp_signal); + if (rc) { + if (!first_rc) + first_rc = rc; + GSL_ERR("Unload modules cmd 0x%x failure:%d", + AMDB_CMD_UNLOAD_MODULES, rc); + } + } + + rc = gsl_do_register_dynamic_modules(master_proc, true, handle); + if (rc) + GSL_ERR("failed to de-register dynamic modules %d", rc); + + return first_rc; +} diff --git a/gsl/src/gsl_global_persist_cal.c b/gsl/src/gsl_global_persist_cal.c new file mode 100644 index 0000000..1215ddc --- /dev/null +++ b/gsl/src/gsl_global_persist_cal.c @@ -0,0 +1,187 @@ +/** + * \file gsl_global_persist_cal.c + * + * \brief + * Manages global persist cal for subgraphs + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gsl_global_persist_cal.h" +#include "gsl_common.h" +#include "ar_osal_mutex.h" +#include "ar_osal_error.h" +#include "ar_util_list.h" + +struct gsl_global_persist_cal_pool { + ar_list_t cal_list; /**< list of all GP cals in the system */ + uint32_t num_cals; /**< number of entries in GP cal pool */ + ar_osal_mutex_t lock; /**< used to serialize operations on pool */ +} gpc_pool; + +static int32_t gsl_gp_cal_init(struct gsl_glbl_persist_cal *gpc, + uint32_t cal_id, uint32_t cal_data_size, uint32_t master_proc) +{ + uint32_t rc = AR_EOK; + + if (gpc == NULL) + return AR_EBADPARAM; + + gpc->ref_cnt = 0; + gpc->cal_id = cal_id; + gpc->cal_data_size = cal_data_size; + + rc = ar_list_init_node(&gpc->node); + if (rc) { + GSL_ERR("ar_list_init_node failed %d", rc); + goto exit; + } + + rc = gsl_shmem_alloc(cal_data_size, master_proc, &gpc->cal_data); + if (rc) { + GSL_ERR("shmem alloc for glbl persistent cal id %d failed %d", cal_id, + rc); + goto delete_list_node; + } + + /* skip in success case */ + goto exit; +delete_list_node: + ar_list_delete(&gpc_pool.cal_list, &gpc->node); +exit: + return rc; +} + +static int32_t gsl_gp_cal_deinit(struct gsl_glbl_persist_cal *gpc) +{ + uint32_t rc = AR_EOK; + + rc = gsl_shmem_free(&gpc->cal_data); + if (rc) + GSL_ERR("shmem free for glbl persistent cal id %d failed %d", + gpc->cal_id, rc); + + return rc; +} + +/* + * GLOBAL PERSIST CAL POOL MANAGEMENT + */ + +int32_t gsl_global_persist_cal_pool_init(void) +{ + int32_t rc = AR_EOK; + + gsl_memset(&gpc_pool, 0, sizeof(gpc_pool)); + rc = ar_osal_mutex_create(&gpc_pool.lock); + if (rc) { + GSL_ERR("ar_osal_mutex_create failed %d", rc); + goto exit; + } + + rc = ar_list_init(&gpc_pool.cal_list, NULL, NULL); + if (rc) + GSL_ERR("ar_list_init failed %d", rc); +exit: + return rc; +} + +int32_t gsl_global_persist_cal_pool_deinit(void) +{ + ar_osal_mutex_destroy(gpc_pool.lock); + ar_list_clear(&gpc_pool.cal_list); + return AR_EOK; +} + +struct gsl_glbl_persist_cal *gsl_global_persist_cal_pool_add(uint32_t cal_id, + uint32_t cal_data_size, struct gsl_shmem_alloc_data **cal_data, + uint32_t master_proc) +{ + ar_list_node_t *curr = NULL; + struct gsl_glbl_persist_cal *curr_gpc = NULL; + uint8_t cal_found = 0; + int32_t rc; + + GSL_MUTEX_LOCK(gpc_pool.lock); + + /* check if cal_id already exists in the pool */ + ar_list_for_each_entry(curr, &gpc_pool.cal_list) { + curr_gpc = get_container_base(curr, struct gsl_glbl_persist_cal, node); + if (!curr_gpc) { + GSL_ERR("null returned for curr_gpc\n"); + goto exit; + } + + if (curr_gpc->cal_id == cal_id) { + cal_found = 1; + break; + } + } + if (!cal_found) { + /* cal does not exist, so add it to pool */ + curr_gpc = gsl_mem_zalloc(sizeof(struct gsl_glbl_persist_cal)); + if (curr_gpc == NULL) + goto exit; + + rc = gsl_gp_cal_init(curr_gpc, cal_id, cal_data_size, master_proc); + if (rc) { + GSL_ERR("gsl_gp_cal_init failed %d", rc); + goto cleanup; + } + + rc = ar_list_add_tail(&gpc_pool.cal_list, &curr_gpc->node); + if (rc) { + GSL_ERR("ar_list_add_tail failed, %d", rc); + goto deinit; + } + + *cal_data = &curr_gpc->cal_data; + /* we only set cal_data if we need to fetch the data from ACDB */ + + ++(curr_gpc->ref_cnt); + ++gpc_pool.num_cals; + } else { + *cal_data = NULL; + } + goto exit; + +deinit: + gsl_gp_cal_deinit(curr_gpc); +cleanup: + gsl_mem_free(curr_gpc); + curr_gpc = NULL; +exit: + GSL_MUTEX_UNLOCK(gpc_pool.lock); + return curr_gpc; +} + +int32_t gsl_global_persist_cal_pool_remove(struct gsl_glbl_persist_cal *gpc) +{ + int32_t rc = AR_EOK; + + if (!gpc) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(gpc_pool.lock); + if (gpc->ref_cnt > 0) + --gpc->ref_cnt; + + if (gpc->ref_cnt == 0) { + rc = ar_list_delete(&gpc_pool.cal_list, &gpc->node); + if (rc) { + GSL_ERR("ar_list_delete failed %d", rc); + goto exit; + } + --gpc_pool.num_cals; + /* + * Do not free if we fail to remove from list, to preserve the + * integrity of the linked list + */ + gsl_gp_cal_deinit(gpc); + gsl_mem_free(gpc); + } +exit: + GSL_MUTEX_UNLOCK(gpc_pool.lock); + return rc; +} diff --git a/gsl/src/gsl_graph.c b/gsl/src/gsl_graph.c new file mode 100644 index 0000000..7b795a4 --- /dev/null +++ b/gsl/src/gsl_graph.c @@ -0,0 +1,5461 @@ +/** + * \file gsl_graph.c + * + * \brief + * Implement graph management layer for Graph Service Layer (GSL) + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "acdb.h" +#include "ar_osal_error.h" +#include "ar_osal_shmem.h" +#include "ar_osal_log.h" +#include "ar_util_data_log.h" +#include "ar_util_data_log_codes.h" +#include "gsl_graph.h" +#include "gpr_api_inline.h" +#include "apm_api.h" +#include "apm_sub_graph_api.h" +#include "wr_sh_mem_ep_api.h" +#include "rd_sh_mem_ep_api.h" +#include "sh_mem_pull_push_mode_api.h" +#include "gsl_global_persist_cal.h" +#include "gsl_subgraph_pool.h" +#include "gsl_common.h" +#include "gsl_msg_builder.h" +#include "gsl_spf_ss_state.h" +#include "gsl_mdf_utils.h" + +#define GSL_GPR_DST_PORT_APM (APM_MODULE_INSTANCE_ID) +#define GSL_4KB_MULTIPLE_SIZE(x) (((x) + 4095) & (~4095)) +#define IS_ONE_PARAM(param_size, payload_size) \ + ((GSL_ALIGN_8BYTE(param_size) + \ + sizeof(apm_module_param_data_t)) == payload_size) + +/* set config packets less than or equal to this size will be sent in-band */ +#define GSL_IN_BAND_SIZE_THRESHOLD 256 + +struct gsl_blob { + uint32_t size; /**< size of the blob */ + void *buf; /**< pointer to the blob */ +}; + +/* Used to return tags and module info data sorted by processor id to client */ +struct gsl_module_id_proc_info_entry { + uint32_t proc_domain_id; // process the modules are running on + uint32_t num_modules; // number of entries in module list + struct gsl_module_id_info_entry module_entry[]; // module list +}; + +struct gsl_module_id_proc_info { + uint32_t num_procs; // number of processors in proc_module_list + uint32_t list_size; //size of proc_module_list + struct gsl_module_id_proc_info_entry *proc_module_list; + // list of module ids and tags sorted by processor id +}; + +static uint8_t count_set_bits(uint32_t value) +{ + uint8_t lut[16] = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 }; + uint8_t n_set_bits = 0; + + while (value) { + n_set_bits += lut[value & 0xf]; + value >>= 4; + } + return n_set_bits; +} + +static bool_t is_sg_found(uint32_t sgid, struct gsl_subgraph **sgs, + uint32_t num_of_subgraphs) +{ + uint32_t i; + + for (i = 0; i < num_of_subgraphs; ++i) { + if (sgid == sgs[i]->sg_id) + return TRUE; + } + return FALSE; +} +static bool_t is_identical_gkv(struct gsl_key_vector *vect1, + struct gsl_key_vector *vect2) +{ + struct gsl_key_value_pair *kvp1; + struct gsl_key_value_pair *kvp2; + uint32_t i, j; + bool_t kvp_found; + + if (!vect1 || !vect2) + return AR_EBADPARAM; + + /** return false if dimension does not match */ + if (vect1->num_kvps != vect2->num_kvps) + return FALSE; + + kvp1 = vect1->kvp; + for (i = 0; i < vect1->num_kvps; ++i) { + kvp2 = vect2->kvp; + kvp_found = FALSE; + for (j = 0; j < vect2->num_kvps; ++j, ++kvp2) { + if (kvp2->key != kvp1->key) + continue; + if (kvp2->value == kvp1->value) { + kvp_found = TRUE; /**< key and value both matched */ + break; + } + } + if (kvp_found == FALSE) + return FALSE; /**< found at least one non-matching kvp */ + ++kvp1; + } + return TRUE; +} + +static void gsl_graph_add_gkv_to_list(struct gsl_graph *graph, + struct gsl_graph_gkv_node *gkv_node) +{ + GSL_MUTEX_LOCK(graph->gkv_list_lock); + ar_list_add_tail(&graph->gkv_list, &gkv_node->node); + ++graph->num_gkvs; + GSL_MUTEX_UNLOCK(graph->gkv_list_lock); + +} + +static void gsl_graph_remove_gkv_from_list(struct gsl_graph *graph, + struct gsl_graph_gkv_node *gkv_node) +{ + GSL_MUTEX_LOCK(graph->gkv_list_lock); + ar_list_delete(&graph->gkv_list, &gkv_node->node); + --graph->num_gkvs; + GSL_MUTEX_UNLOCK(graph->gkv_list_lock); + +} + +/** + * Allocates and returns subgraph objects to the caller. + * Caller should clear the memory for the subgraph objects after use. + */ +static struct gsl_subgraph **gsl_graph_get_sg_array(struct gsl_graph *graph, + uint32_t *num_sgs) +{ + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node; + uint32_t total_num_of_subgraphs = 0, num_of_subgraphs = 0, i; + uint32_t num_sg_to_compare = 0; + struct gsl_subgraph **sgs = NULL; + + *num_sgs = 0; + GSL_MUTEX_LOCK(graph->gkv_list_lock); + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + total_num_of_subgraphs += gkv_node->num_of_subgraphs; + } + sgs = gsl_mem_zalloc(total_num_of_subgraphs * + sizeof(struct gsl_subgraph *)); + if (!sgs) + goto done; + + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + num_sg_to_compare = num_of_subgraphs; + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + if (!is_sg_found(gkv_node->sg_array[i]->sg_id, sgs, + num_sg_to_compare)) + sgs[num_of_subgraphs++] = gkv_node->sg_array[i]; + } + } + *num_sgs = num_of_subgraphs; +done: + GSL_MUTEX_UNLOCK(graph->gkv_list_lock); + return sgs; +} + +/** + * Allocates and returns subgraph IDs and objects list to the caller. + * Caller should clear the memory after use. + */ +static int32_t gsl_graph_get_sgids_and_objs(struct gsl_graph *graph, + struct gsl_sgid_list *sgid_list, struct gsl_sgobj_list *sg_objs) +{ + uint32_t num_of_subgraphs = 0; + uint32_t *sgids, i; + struct gsl_subgraph **sg_array = NULL; + + sg_array = gsl_graph_get_sg_array(graph, &num_of_subgraphs); + if (!sg_array) + return AR_EFAILED; + + if (sgid_list && num_of_subgraphs) { + sgids = gsl_mem_zalloc(num_of_subgraphs * sizeof(uint32_t)); + if (!sgids) { + gsl_mem_free(sg_array); + return AR_ENOMEMORY; + } + for (i = 0; i < num_of_subgraphs; ++i) + sgids[i] = sg_array[i]->sg_id; + + sgid_list->sg_ids = sgids; + sgid_list->len = num_of_subgraphs; + } + + if (sg_objs && num_of_subgraphs) { + sg_objs->len = num_of_subgraphs; + sg_objs->sg_objs = sg_array; + } else + gsl_mem_free(sg_array); + + return AR_EOK; +} + +/** + * Search for a matching subgraph object from the list of given SG objects + * and subgraph ID + */ +static struct gsl_subgraph *gsl_graph_get_sg_ptr( + struct gsl_sgobj_list *sg_obj_list, uint32_t sgid) +{ + uint32_t i = 0; + struct gsl_subgraph *sg = NULL; + + for (i = 0; i < sg_obj_list->len; ++i) { + sg = sg_obj_list->sg_objs[i]; + if (sg->sg_id == sgid) + return sg; + } + return NULL; +} + +static void gsl_handle_eos(struct gsl_graph *graph, gpr_packet_t *packet) +{ + struct data_cmd_rsp_wr_sh_mem_ep_eos_rendered_t *spf_eos; + struct gsl_event_eos_payload eos_pld; + struct gsl_event_cb_params ev; + + spf_eos = GPR_PKT_GET_PAYLOAD( + struct data_cmd_rsp_wr_sh_mem_ep_eos_rendered_t, packet); + /* issue the callback to client */ + eos_pld.module_instance_id = spf_eos->module_instance_id; + if (spf_eos->render_status == WR_SH_MEM_EP_EOS_RENDER_STATUS_RENDERED) { + eos_pld.render_status = GSL_EOS_RENDERED; + } else if (spf_eos->render_status == + WR_SH_MEM_EP_EOS_RENDER_STATUS_DROPPED) { + eos_pld.render_status = GSL_EOS_DROPPED; + } else { + eos_pld.render_status = GSL_EOS_RENDERED; + GSL_ERR("Got invalid eos status %d from Spf", + spf_eos->render_status); + } + + ev.event_payload = &eos_pld; + ev.event_payload_size = sizeof(eos_pld); + ev.source_module_id = GSL_EVENT_SRC_MODULE_ID_GSL; + ev.event_id = GSL_EVENT_ID_EOS; + graph->cb(&ev, graph->client_data); +} + +static uint32_t gsl_gpr_callback(gpr_packet_t *packet, void *cb_data) +{ + struct gsl_graph *graph; + struct spf_cmd_basic_rsp *basic_rsp; + struct gsl_event_cb_params ev; + struct apm_module_event_t *module_ev; + uint32_t rc = AR_EOK, gpr_rc = AR_EOK; + + graph = (struct gsl_graph *)cb_data; + + GSL_DBG("got opcode %x", packet->opcode); + + switch (packet->opcode) { + case GPR_IBASIC_RSP_RESULT: + basic_rsp = GPR_PKT_GET_PAYLOAD(struct spf_cmd_basic_rsp, + packet); + switch (basic_rsp->opcode) { + /* do not free gpr packet in these cases as it is passed to waiter */ + case APM_CMD_GRAPH_OPEN: + case APM_CMD_GRAPH_PREPARE: + case APM_CMD_GRAPH_START: + case APM_CMD_GRAPH_SUSPEND: + case APM_CMD_GRAPH_STOP: + rc = gsl_signal_set(&graph->graph_signal[GRAPH_CTRL_GRP1_CMD_SIG], + GSL_SIG_EVENT_MASK_SPF_RSP, basic_rsp->status, packet); + break; + case APM_CMD_GRAPH_CLOSE: + rc = gsl_signal_set(&graph->graph_signal[GRAPH_CTRL_GRP3_CMD_SIG], + GSL_SIG_EVENT_MASK_SPF_RSP, basic_rsp->status, packet); + break; + case APM_CMD_GRAPH_FLUSH: + case APM_CMD_SET_CFG: + case APM_CMD_GET_CFG: + case APM_CMD_REGISTER_CFG: + case APM_CMD_DEREGISTER_CFG: + case APM_CMD_REGISTER_SHARED_CFG: + case APM_CMD_DEREGISTER_SHARED_CFG: + case APM_CMD_REGISTER_MODULE_EVENTS: + rc = gsl_signal_set(&graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG], + GSL_SIG_EVENT_MASK_SPF_RSP, basic_rsp->status, packet); + break; + case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT: + rc = gsl_handle_media_format_buff_done(&graph->write_info, packet); + break; + default: + /* free the packet if we will ignore it */ + gpr_rc = __gpr_cmd_free(packet); + break; + } + break; + case APM_CMD_RSP_GET_CFG: + rc = gsl_signal_set(&graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG], + GSL_SIG_EVENT_MASK_SPF_RSP, 0, packet); + /* do not free gpr packet as it is passed to waiter */ + break; + case DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2: + rc = gsl_handle_write_buff_done(&graph->write_info, packet, graph->cb, + graph->client_data); + /* + * We only update the processed_buf_cnt if we are in the STARTED state, + * note we do "try_lock" here because we want to avoid blocking in the + * callback. If locked it means the graph is in the middle of + * transitioning to STOPPED or to STARTED states and it's okay to skip + * incrementing in both cases + * + * We do not have access to graph state from within datapath, so we + * must check this here + */ + if (rc == AR_EOK + && ar_osal_mutex_try_lock(graph->graph_lock) == AR_EOK) { + if (gsl_graph_get_state(graph) == GRAPH_STARTED) + ++graph->write_info.processed_buf_cnt; + GSL_MUTEX_UNLOCK(graph->graph_lock); + } + gpr_rc = __gpr_cmd_free(packet); + break; + case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_DONE_V2: + rc = gsl_handle_read_buff_done(&graph->read_info, packet, graph->cb, + graph->client_data); + /* see comment for WR_SH_MEM_EP_DATA_BUFFER_DONE */ + if (rc == AR_EOK + && ar_osal_mutex_try_lock(graph->graph_lock) == AR_EOK) { + if (gsl_graph_get_state(graph) == GRAPH_STARTED) + ++graph->read_info.processed_buf_cnt; + GSL_MUTEX_UNLOCK(graph->graph_lock); + } + break; + case DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED: + graph = (struct gsl_graph *)cb_data; + gsl_handle_eos(graph, packet); + gpr_rc = __gpr_cmd_free(packet); + break; + case APM_EVENT_MODULE_TO_CLIENT: + graph = (struct gsl_graph *)cb_data; + /* issue the callback to client */ + module_ev = GPR_PKT_GET_PAYLOAD(struct apm_module_event_t, + packet); + ev.event_id = module_ev->event_id; + ev.event_payload_size = module_ev->event_payload_size; + ev.source_module_id = packet->src_port; + ev.event_payload = (void *)((int8_t *)module_ev + + sizeof(struct apm_module_event_t)); + graph->cb(&ev, graph->client_data); + gpr_rc = __gpr_cmd_free(packet); + break; + default: + GSL_DBG("unknown opcode %x freeing GPR rsp packet", packet->opcode); + gpr_rc = __gpr_cmd_free(packet); + break; + } + + if (rc) { + GSL_DBG("signal failed, freeing GPR rsp packet"); + gpr_rc = __gpr_cmd_free(packet); + } + + /* if any gpr free above fails all we can do is return error back to gpr */ + return gpr_rc; +} + +static int32_t gsl_apm_config_inband(struct gsl_graph *graph, + const uint8_t *payload, uint32_t payload_size, uint32_t opcode, + uint32_t dst_port, struct gpr_packet_t **p_rsp_pkt) +{ + int32_t rc = AR_EOK; + struct apm_cmd_header_t *apm_hdr; + gsl_msg_t gsl_msg; + struct ar_data_log_submit_info_t info; + struct ar_data_log_generic_pkt_info_t pkt_info; + + rc = gsl_msg_alloc(opcode, graph->src_port, dst_port, sizeof(*apm_hdr), 0, + graph->proc_id, GSL_ALIGN_8BYTE(payload_size), true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate gsl msg %d", rc); + goto exit; + } + + apm_hdr = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, gsl_msg.gpr_packet); + gsl_memset(apm_hdr, 0, sizeof(*apm_hdr) + GSL_ALIGN_8BYTE(payload_size)); + apm_hdr->payload_size = GSL_ALIGN_8BYTE(payload_size); + + /* copy payload into in-band buffer */ + if (payload_size > 0) + gsl_memcpy((uint8_t *)(gsl_msg.payload), GSL_ALIGN_8BYTE(payload_size), + payload, payload_size); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*apm_hdr) + + GSL_ALIGN_8BYTE(payload_size), NULL, 0); + + if (opcode == APM_CMD_SET_CFG) { + if (graph->rtc_conn_active) { + pkt_info.format = AR_LOG_PKT_GENERIC_FMT_CAL_BLOB; + pkt_info.token_id = 0; + pkt_info.log_time_stamp = 0; + + info.buffer = (int8_t *)apm_hdr + sizeof(*apm_hdr); + info.buffer_size = payload_size; + info.log_code = AR_DATA_LOG_CODE_ATS; + info.pkt_info = &pkt_info; + info.pkt_type = AR_DATA_LOG_PKT_TYPE_GENERIC; + info.session_id = 0; + + GSL_DBG("set custom config oob: caching buff %x to QACT", + info.buffer); + ar_data_log_submit(&info); + } + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + } else { //APM_CMD_GET_CFG + rc = gsl_send_spf_cmd(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG], p_rsp_pkt); + } + if (rc) + GSL_ERR("Graph cfg cmd 0x%x failure:%d", opcode, rc); + +exit: + return rc; +} + +static int32_t gsl_apm_get_config_inband(struct gsl_graph *graph, + uint8_t *payload, uint32_t *payload_size, uint32_t dst_port) +{ + int32_t rc = AR_EOK; + gpr_packet_t *rsp_pkt = NULL; + struct apm_cmd_rsp_get_cfg_t *get_cfg_rsp; + apm_module_param_data_t *param_data = (apm_module_param_data_t *)payload; + + rc = gsl_apm_config_inband(graph, payload, *payload_size, APM_CMD_GET_CFG, + dst_port, &rsp_pkt); + if (rc) + goto exit; + + if (!rsp_pkt) { + GSL_ERR("Received null response packet"); + rc = AR_EUNEXPECTED; + goto exit; + } + + get_cfg_rsp = GPR_PKT_GET_PAYLOAD(struct apm_cmd_rsp_get_cfg_t, rsp_pkt); + /* + * For multiple parameter case, copy payload on partial failures + * and success. + * For one parameter case, we fail if the rsp status is an error. + */ + if (get_cfg_rsp->status != AR_EOK && + IS_ONE_PARAM(param_data->param_size, *payload_size)) { + GSL_ERR("get config failed: spf status %d", get_cfg_rsp->status); + rc = AR_EFAILED; + goto exit; + } + + rc = gsl_memcpy(payload, *payload_size, (uint8_t *)rsp_pkt + + GPR_PKT_GET_HEADER_BYTE_SIZE(rsp_pkt->header) + + sizeof(apm_cmd_rsp_get_cfg_t), + GPR_PKT_GET_PAYLOAD_BYTE_SIZE(rsp_pkt->header) - + sizeof(apm_cmd_rsp_get_cfg_t)); + /* client allocated buffer, size could be too small and fail memcpy */ + if (rc) + GSL_ERR("memcpy failed %d", rc); + + /* update with size written */ + *payload_size = GPR_PKT_GET_PAYLOAD_BYTE_SIZE(rsp_pkt->header) - + sizeof(apm_cmd_rsp_get_cfg_t); + +exit: + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + + return rc; +} + +static int32_t gsl_apm_config_oob(struct gsl_graph *graph, + const uint8_t *payload, uint32_t payload_size, + uint32_t opcode, uint32_t dst_port) +{ + int32_t rc = AR_EOK; + struct apm_cmd_header_t *cmd_header; + gsl_msg_t gsl_msg; + struct ar_data_log_submit_info_t info; + struct ar_data_log_generic_pkt_info_t pkt_info; + struct apm_cmd_rsp_get_cfg_t *get_cfg_rsp; + gpr_packet_t *rsp_pkt = NULL; + apm_module_param_data_t *param_data = (apm_module_param_data_t *)payload; + + rc = gsl_msg_alloc(opcode, graph->src_port, dst_port, sizeof(*cmd_header), + 0, graph->proc_id, payload_size, false, &gsl_msg); + if (rc) { + GSL_ERR("gsl msg alloc failed:%d", rc); + goto exit; + } + + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + gsl_msg.gpr_packet); + cmd_header->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + cmd_header->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + cmd_header->payload_size = payload_size; + + /* copy payload into shared memory */ + gsl_memcpy(gsl_msg.payload, payload_size, (void *)payload, payload_size); + + if (opcode == APM_CMD_SET_CFG && graph->rtc_conn_active) { + /* dump config to QACT for use in RTC */ + + pkt_info.format = AR_LOG_PKT_GENERIC_FMT_CAL_BLOB; + pkt_info.token_id = 0; + pkt_info.log_time_stamp = 0; + + info.buffer = (int8_t *)gsl_msg.payload; + info.buffer_size = payload_size; + info.log_code = AR_DATA_LOG_CODE_ATS; + info.pkt_info = &pkt_info; + info.pkt_type = AR_DATA_LOG_PKT_TYPE_GENERIC; + info.session_id = 0; + + GSL_DBG("set custom config oob: caching buff %x to QACT", + info.buffer); + ar_data_log_submit(&info); + } + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*cmd_header), gsl_msg.payload, + payload_size); + + rc = gsl_send_spf_cmd(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG], &rsp_pkt); + if (rc) { + GSL_ERR("Graph cfg cmd 0x%x failure:%d", opcode, rc); + goto free_msg; + } + + if (opcode == APM_CMD_GET_CFG) { + get_cfg_rsp = GPR_PKT_GET_PAYLOAD(struct apm_cmd_rsp_get_cfg_t, + rsp_pkt); + /* + * For multiple parameter case, copy payload on partial failures + * and success. + * For one parameter case, we fail if the rsp status is an error. + */ + if (get_cfg_rsp->status != AR_EOK && + IS_ONE_PARAM(param_data->param_size, payload_size)) { + GSL_ERR("get cfg failed, spf status %d", get_cfg_rsp->status); + goto free_msg; + } + + rc = gsl_memcpy((void *)payload, payload_size, + gsl_msg.payload, payload_size); + if (rc) + GSL_ERR("memcpy failed %d", rc); + } + +free_msg: + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + gsl_msg_free(&gsl_msg); +exit: + return rc; +} + +static int32_t copy_key_vector(struct gsl_key_vector *out_kv, + const struct gsl_key_vector *inp_kv) +{ + struct gsl_key_value_pair *key_val_pairs; + size_t kvp_size; + + if (!inp_kv) { + out_kv->num_kvps = 0; + out_kv->kvp = NULL; + return AR_EOK; + } + + kvp_size = inp_kv->num_kvps * sizeof(struct gsl_key_value_pair); + key_val_pairs = gsl_mem_zalloc(kvp_size); + if (!key_val_pairs) + return AR_ENOMEMORY; + + out_kv->num_kvps = inp_kv->num_kvps; + if (out_kv->kvp) + gsl_mem_free(out_kv->kvp); + + gsl_memcpy(key_val_pairs, kvp_size, inp_kv->kvp, + inp_kv->num_kvps * sizeof(struct gsl_key_value_pair)); + + out_kv->kvp = key_val_pairs; + return AR_EOK; +} + +static void gsl_graph_update_gkv_node(struct gsl_graph_gkv_node *gkv_node, + const struct gsl_key_vector *gkv, const struct gsl_key_vector *ckv) +{ + copy_key_vector(&gkv_node->gkv, gkv); + if (ckv) + copy_key_vector(&gkv_node->ckv, ckv); + ar_list_init_node(&gkv_node->node); +} + +static int32_t gsl_acdb_get_subgraph_connections(AcdbSubgraph *sg_conn, + uint32_t num_sg_conn, struct gsl_blob *spf_blob) +{ + AcdbSubGraphList cmd_struct; + AcdbBlob rsp_struct; + int32_t rc = AR_EOK; + + cmd_struct.num_subgraphs = num_sg_conn; + cmd_struct.subgraphs = sg_conn; + + gsl_memset(&rsp_struct, 0, sizeof(rsp_struct)); + rsp_struct.buf_size = spf_blob->size; + rsp_struct.buf = spf_blob->buf; + + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_CONNECTIONS, &cmd_struct, + sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + + if (AR_SUCCEEDED(rc)) + spf_blob->size = rsp_struct.buf_size; + + return rc; +} + +static int32_t gsl_acdb_parse_sg_drv_prop_data(struct gsl_graph *graph, + struct gsl_sgobj_list *sg_obj_list, AcdbDriverPropertyData *prop_data) +{ + AcdbSubGraphPropertyData *p = NULL; + struct gsl_subgraph *sg; + uint32_t i, n; + int8_t *prop_payload; + AcdbPropertyData *prop_id_data = NULL; + struct sg_generic_t *sg_prop = NULL; + struct sg_type_t *sg_type_prop = NULL; + uint32_t proc_id = 0; + + /** parse driver property data for each SG */ + p = prop_data->sub_graph_prop_data; + for (i = 0; i < prop_data->num_sgid; ++i) { + sg = gsl_graph_get_sg_ptr(sg_obj_list, p->sg_id); + if (!sg) { + GSL_ERR("SG id %d not found in this GKV", p->sg_id); + return AR_EFAILED; + } + prop_payload = (int8_t *)p->prop_data; + n = 0; + while (n++ < p->num_props) { + prop_id_data = (AcdbPropertyData *)prop_payload; + switch (prop_id_data->prop_id) { + case SUB_GRAPH_PROP_ID_GENERIC: + sg_prop = + (struct sg_generic_t *)prop_id_data->prop_payload; + sg->drv_prop_data.routing_id = sg_prop->routing_id; + sg->drv_prop_data.is_flushable = sg_prop->is_flushable; + + /* Check if all the subgraphs have same routing id */ + if (proc_id == 0) { + proc_id = sg_prop->routing_id; + } else if (proc_id != sg_prop->routing_id) { + GSL_ERR("Routing id mismatch in graph for %d", + sg_prop->routing_id); + return AR_EFAILED; + } + break; + case SUB_GRAPH_PROP_ID_SG_TYPE: + sg_type_prop = (struct sg_type_t *)prop_id_data->prop_payload; + sg->sg_type_data.sg_type = sg_type_prop->sg_type; + break; + default: + GSL_ERR("unknown sg property id %d", prop_id_data->prop_id); + break; + } + prop_payload += sizeof(AcdbPropertyData) + + prop_id_data->prop_payload_size; + } + p = (AcdbSubGraphPropertyData *)prop_payload; + } + + if (proc_id != 0) + graph->proc_id = proc_id; + + return AR_EOK; +} + +static int32_t gsl_acdb_get_subgraph_data(struct gsl_sgid_list *sg_id_list, + const struct gsl_key_vector *gkv, struct gsl_blob *spf_blob, + AcdbDriverPropertyData *drv_blob) +{ + AcdbSgIdGraphKeyVector cmd_struct; + AcdbGetSubgraphDataRsp rsp_struct; + uint32_t cmd_struct_size, rsp_struct_size; + int32_t rc = AR_EOK; + + /* Form cmd and rsp structures */ + cmd_struct_size = sizeof(AcdbSgIdGraphKeyVector); + cmd_struct.num_sgid = sg_id_list->len; + cmd_struct.sg_ids = sg_id_list->sg_ids; + cmd_struct.graph_key_vector.num_keys = gkv->num_kvps; + cmd_struct.graph_key_vector.graph_key_vector = + (AcdbKeyValuePair *)gkv->kvp; + + rsp_struct_size = sizeof(AcdbGetSubgraphDataRsp); + gsl_memset(&rsp_struct, 0, rsp_struct_size); + rsp_struct.spf_blob.buf_size = spf_blob->size; + rsp_struct.spf_blob.buf = spf_blob->buf; + rsp_struct.driver_prop.size = drv_blob->size; + rsp_struct.driver_prop.sub_graph_prop_data = drv_blob->sub_graph_prop_data; + + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_DATA, &cmd_struct, + cmd_struct_size, &rsp_struct, rsp_struct_size); + + if (AR_SUCCEEDED(rc)) { + spf_blob->size = rsp_struct.spf_blob.buf_size; + drv_blob->num_sgid = rsp_struct.driver_prop.num_sgid; + drv_blob->size = rsp_struct.driver_prop.size; + } + + return rc; +} + +static void gsl_graph_ckv_list_print(AcdbKeyVectorList *rsp) +{ + uint32_t i = 0, j = 0; + uint8_t* pKv = NULL; + AcdbKeyVector *kvs = NULL; + + pKv = (uint8_t*)rsp->key_vector_list; + for (i = 0; i < rsp->num_key_vectors; i++) { + kvs = (AcdbKeyVector *)pKv; + if (!kvs) { + GSL_ERR("kvs is null"); + return; + } + GSL_VERBOSE("num_keys %d", kvs->num_keys); + for (j = 0; j < kvs->num_keys; j++) { + AcdbKeyValuePair kv = kvs->graph_key_vector[j]; + GSL_VERBOSE("key:0x%x, value:%x", kv.key, kv.value); + } + pKv += sizeof(uint32_t) + kvs->num_keys * sizeof(AcdbKeyValuePair); + } +} + +static void gsl_graph_check_ckvs(struct gsl_key_vector *gkv, struct gsl_key_vector *ckv) +{ + AcdbKeyVectorList rsp; + AcdbKeyVector *kvs = NULL; + uint8_t* pKv = NULL; + uint32_t i = 0, j = 0; + uint32_t key = 0; + int ckv_count = 0; + int rc = AR_EOK; + + rsp.list_size = 0; + rc = gsl_get_graph_ckvs(gkv, (void *)&rsp); + if (rc) { + GSL_ERR("gsl_get_graph_ckvs failed: %d", rc); + return; + } + + GSL_DBG("num_key_vectors %d, list_size %d", rsp.num_key_vectors, rsp.list_size); + rsp.key_vector_list = (AcdbKeyVector *)malloc(rsp.list_size); + if (!rsp.key_vector_list) { + GSL_ERR("malloc return failed"); + return; + } + + rc = gsl_get_graph_ckvs(gkv, (void *)&rsp); + if (rc) { + GSL_ERR("gsl_get_graph_ckvs failed: %d", rc); + goto exit; + } + + gsl_graph_ckv_list_print(&rsp); + + // get CKV count + pKv = (uint8_t*)rsp.key_vector_list; + for (i = 0; i < rsp.num_key_vectors; i++) { + kvs = (AcdbKeyVector *)pKv; + if (!kvs) { + GSL_ERR("kvs is null"); + return; + } + GSL_VERBOSE("num_keys %d", kvs->num_keys); + for (j = 0; j < kvs->num_keys; j++) { + AcdbKeyValuePair kv = kvs->graph_key_vector[j]; + GSL_VERBOSE("key:0x%x, value:%x", kv.key, kv.value); + if (key != kv.key) { + key = kv.key; + ckv_count++; + } + } + pKv += sizeof(uint32_t) + kvs->num_keys * sizeof(AcdbKeyValuePair); + } + + if (ckv_count != ckv->num_kvps) + GSL_ERR("CKVs mismatched. ACDB CKVs count %d CKVs sent from HAL count %d", ckv_count, ckv->num_kvps); + + exit: + if (rsp.key_vector_list) { + free(rsp.key_vector_list); + } +} + +static int32_t gsl_graph_send_nonpersist_cal(struct gsl_graph *graph, + struct gsl_sgid_list *sgid_list, + struct gsl_key_vector *prior_ckv, const struct gsl_key_vector *new_ckv, + const struct gsl_key_vector *gkv, + bool isCKVValidated) +{ + AcdbSgIdCalKeyVector cmd_struct; + AcdbBlob rsp_struct; + int32_t rc; + struct apm_cmd_header_t *cmd_header; + gsl_msg_t gsl_msg; + + cmd_struct.num_sg_ids = sgid_list->len; + cmd_struct.sg_ids = sgid_list->sg_ids; + cmd_struct.cal_key_vector_prior.num_keys = prior_ckv->num_kvps; + cmd_struct.cal_key_vector_prior.graph_key_vector = + (AcdbKeyValuePair *)prior_ckv->kvp; + cmd_struct.cal_key_vector_new.num_keys = new_ckv->num_kvps; + cmd_struct.cal_key_vector_new.graph_key_vector = + (AcdbKeyValuePair *)new_ckv->kvp; + + rsp_struct.buf = NULL; + rsp_struct.buf_size = 0; + + if (!isCKVValidated) + gsl_graph_check_ckvs(gkv, new_ckv); + + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_CALIBRATION_DATA_NONPERSIST, + &cmd_struct, sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc == AR_ENOTEXIST) { + /* avoid logging error if not exist */ + return rc; + } else if (rc) { + GSL_ERR("get non-persist data (size) failed %d", rc); + return rc; + } + + rc = gsl_msg_alloc(APM_CMD_SET_CFG, graph->src_port, GSL_GPR_DST_PORT_APM, + sizeof(*cmd_header), 0, graph->proc_id, rsp_struct.buf_size, false, + &gsl_msg); + if (rc) { + GSL_ERR("gsl msg alloc failed %d", rc); + return rc; + } + rsp_struct.buf = gsl_msg.payload; + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_CALIBRATION_DATA_NONPERSIST, + &cmd_struct, sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) { + GSL_ERR("get non-persist data (cal) failed %d", rc); + goto exit; + } + + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + gsl_msg.gpr_packet); + cmd_header->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + cmd_header->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + cmd_header->payload_size = rsp_struct.buf_size; + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*cmd_header), gsl_msg.payload, + cmd_header->payload_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) + GSL_ERR("send non-perist cal failed %d", rc); + +exit: + gsl_msg_free(&gsl_msg); + return rc; +} + +static int32_t gsl_graph_send_persist_cal(struct gsl_graph *graph, + struct gsl_sgobj_list *sg_objs, const struct gsl_key_vector *new_ckv) +{ + int32_t rc = AR_EOK; + struct apm_cmd_header_t *cmd_header; + struct gsl_subgraph *sg = NULL; + uint32_t i; + gpr_packet_t *send_pkt = NULL; + uint64_t paddr_w_offset = 0; + AcdbUintList sg_cma_status_list; + AcdbHwAccelSubgraphInfoReq cma_sg_info_req; + AcdbHwAccelSubgraphInfoRsp cma_sg_info; + bool_t is_shmem_supported = TRUE; + AcdbCmdGetSubgraphProcIdsReq req = {0,}; + AcdbCmdGetSubgraphProcIdsRsp rsp = {0,}; + + if (sg_objs->len == 0) + return AR_EOK; + + rc = __gpr_cmd_is_shared_mem_supported(graph->proc_id, &is_shmem_supported); + if (!is_shmem_supported) { + return AR_EUNSUPPORTED; + } else if (rc) { + GSL_ERR("GPR is shmem supported failed %d", rc) + goto exit; + } + + /* query for all SGs and their cma mem types */ + sg_cma_status_list.count = sg_objs->len; + sg_cma_status_list.list = gsl_mem_zalloc(sizeof(uint32_t)*sg_objs->len); + if (!sg_cma_status_list.list) { + rc = AR_ENOMEMORY; + goto exit; + } + + cma_sg_info.subgraph_list = + gsl_mem_zalloc(sizeof(AcdbHwAccelSubgraph)*sg_objs->len); + if (!cma_sg_info.subgraph_list) { + rc = AR_ENOMEMORY; + goto free_status_list; + } + cma_sg_info.list_size = sizeof(AcdbHwAccelSubgraph)*sg_objs->len; + cma_sg_info.num_subgraphs = sg_objs->len; + + /* fill request list. Note that these are in order */ + for (i = 0; i < sg_objs->len; ++i) { + if (sg_objs->sg_objs[i]) + sg_cma_status_list.list[i] = sg_objs->sg_objs[i]->sg_id; + } + cma_sg_info_req.subgraph_list = sg_cma_status_list; + + rc = acdb_ioctl(ACDB_CMD_GET_HW_ACCEL_SUBGRAPH_INFO, &cma_sg_info_req, + sizeof(cma_sg_info_req), &cma_sg_info, sizeof(cma_sg_info)); + if (rc) { + GSL_ERR("get HW ACCEL info failed %d", rc); + goto cleanup; + } + + for (i = 0; i < sg_objs->len; ++i) { + sg = sg_objs->sg_objs[i]; + + if (!sg) { + continue; + } else if (sg->start_ref_cnt > 0) { + /* + * persist cal will not be applied to started SGs - creates errors, + * especially with CMA + */ + GSL_DBG("Skipping persist cal for SG_ID %d: already started", + sg->sg_id); + continue; + } + + /* if persist cal is already regsitered for this SG de-register it */ + GSL_DBG("num procs - %d", sg->num_proc_ids); + for (int procid = 0; procid < sg->num_proc_ids; procid++) { + if (sg->persist_cal_data_per_proc[procid].persist_cal_data.handle) { + GSL_DBG("proc_id[%d] - %d", procid, sg->persist_cal_data_per_proc[procid].proc_id); + + rc = gsl_allocate_gpr_packet(APM_CMD_DEREGISTER_CFG, + graph->src_port, APM_MODULE_INSTANCE_ID, sizeof(*cmd_header), + 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + /* + * below offset used to skip acdb header before sending data to + * spf + */ + paddr_w_offset = sg->persist_cal_data_per_proc[procid].persist_cal_data.spf_addr + + sizeof(AcdbSgIdPersistData); + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + cmd_header->mem_map_handle = sg->persist_cal_data_per_proc[procid].persist_cal_data.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)paddr_w_offset; + cmd_header->payload_address_msw = (uint32_t)(paddr_w_offset >> 32); + cmd_header->payload_size = sg->persist_cal_data_per_proc[procid].persist_cal_data_size - + sizeof(AcdbSgIdPersistData); + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), + sg->persist_cal_data_per_proc[procid].persist_cal_data.v_addr, cmd_header->payload_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("Graph deregister cfg cmd 0x%x failure:%d", + APM_CMD_DEREGISTER_CFG, rc); + goto exit; + } + } + } + + /* if cma is already regsitered for this SG de-register it */ + if (sg->cma_persist_cfg_data.handle) { + + rc = gsl_allocate_gpr_packet(APM_CMD_DEREGISTER_CFG, + graph->src_port, APM_MODULE_INSTANCE_ID, sizeof(*cmd_header), + 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + /* + * below offset used to skip acdb header before sending data to + * spf + */ + paddr_w_offset = sg->cma_persist_cfg_data.spf_addr + + sizeof(AcdbSgIdPersistData); + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + cmd_header->mem_map_handle + = sg->cma_persist_cfg_data.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)paddr_w_offset; + cmd_header->payload_address_msw = (uint32_t)(paddr_w_offset >> 32); + cmd_header->payload_size = sg->cma_cal_data_size - + sizeof(AcdbSgIdPersistData); + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), + sg->cma_persist_cfg_data.v_addr, cmd_header->payload_size); + + send_pkt->client_data |= GSL_GPR_CMA_FLAG_BIT; + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("Graph deregister cfg cmd 0x%x failure:%d", + APM_CMD_DEREGISTER_CFG, rc); + goto exit; + } + + /* free after deregister (free handles hyp unassign too) */ + gsl_shmem_free(&sg->cma_persist_cfg_data); + sg->cma_persist_cfg_data.handle = NULL; + sg->cma_persist_cfg_data.v_addr = NULL; + sg->cma_cal_data_size = 0; + } + + /* determine whether there is CMA needed or not */ + switch (cma_sg_info.subgraph_list[i].mem_type) { + case ACDB_HW_ACCEL_MEM_DEFAULT: + case ACDB_HW_ACCEL_MEM_BOTH: + /* this is the non-CMA side */ + /* get num_procs and proc ids per SG from ACDB and store it in sg struct */ + + /* first call to get size */ + req.num_sg_ids = 1; + req.sg_ids = &sg->sg_id; + rsp.num_sg_ids = 0; + rsp.size = 0; + rsp.sg_proc_ids = NULL; + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_PROCIDS, &req, sizeof(req), &rsp, + sizeof(rsp)); + if (rc != AR_EOK && rc != AR_ENOTEXIST) { + GSL_ERR("ACDB get subgraph procids failed %d", rc); + return rc; + } + + rsp.sg_proc_ids = gsl_mem_zalloc(rsp.size); + if (!rsp.sg_proc_ids) { + rc = AR_ENOMEMORY; + return rc; + } + + /* next call to get data */ + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_PROCIDS, &req, sizeof(req), &rsp, + sizeof(rsp)); + if (rc != AR_EOK) { + GSL_ERR("ACDB get subgraph procids failed %d", rc); + goto free_sg_proc_ids; + } + sg->num_proc_ids = rsp.sg_proc_ids->num_proc_ids; + GSL_DBG("num procs - %d", sg->num_proc_ids); + for (int procid = 0; procid < sg->num_proc_ids; procid++) { + sg->persist_cal_data_per_proc[procid].proc_id = rsp.sg_proc_ids->proc_ids[procid]; + GSL_DBG("proc_id[%d] - %d", procid, sg->persist_cal_data_per_proc[procid].proc_id); + rc = gsl_subgraph_query_persist_cal_by_mem(sg, new_ckv, + ACDB_HW_ACCEL_MEM_DEFAULT, graph->proc_id, procid); + if (rc == AR_ENOTEXIST) { + goto continue_cma; + } else if (rc) { + GSL_ERR("persist cal query for sg_id %d failed %d", + sg->sg_id, rc); + goto cleanup; + } + + rc = gsl_allocate_gpr_packet(APM_CMD_REGISTER_CFG, + graph->src_port, GSL_GPR_DST_PORT_APM, sizeof(*cmd_header), + 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet for sg_id 0x%x %d", + sg->sg_id, rc); + goto cleanup; + } + /* + * below offset used to skip acdb header before sending data to + * spf + */ + paddr_w_offset = sg->persist_cal_data_per_proc[procid].persist_cal_data.spf_addr + + sizeof(AcdbSgIdPersistData); + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + send_pkt); + cmd_header->mem_map_handle = + sg->persist_cal_data_per_proc[procid].persist_cal_data.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)(paddr_w_offset); + cmd_header->payload_address_msw = + (uint32_t)(paddr_w_offset >> 32); + cmd_header->payload_size = sg->persist_cal_data_per_proc[procid].persist_cal_data_size + - sizeof(AcdbSgIdPersistData); + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), + (uint8_t *)sg->persist_cal_data_per_proc[procid].persist_cal_data.v_addr + + sizeof(AcdbSgIdPersistData), cmd_header->payload_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("send perist cal for sg_id 0x%x failed %d", + sg->sg_id, rc); + goto cleanup; + } + } +continue_cma: + /* do not break for BOTH, continue into cma*/ + if (cma_sg_info.subgraph_list[i].mem_type != ACDB_HW_ACCEL_MEM_BOTH) + break; + + case ACDB_HW_ACCEL_MEM_CMA: + /* persist_cal per proc_id support is not there for cma memory from AML */ + rc = gsl_subgraph_query_persist_cal_by_mem(sg, new_ckv, + ACDB_HW_ACCEL_MEM_CMA, graph->proc_id, 0); + if (rc == AR_ENOTEXIST) { + continue; + } else if (rc) { + GSL_ERR("cma persist cal query for sg_id %d failed %d", + sg->sg_id, rc); + goto cleanup; + } + + rc = gsl_allocate_gpr_packet(APM_CMD_REGISTER_CFG, + graph->src_port, GSL_GPR_DST_PORT_APM, sizeof(*cmd_header), + 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet for sg_id 0x%x %d", + sg->sg_id, rc); + goto cleanup; + } + + /* + * below offset used to skip acdb header before sending data to + * spf + */ + paddr_w_offset = sg->cma_persist_cfg_data.spf_addr + + sizeof(AcdbSgIdPersistData); + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + send_pkt); + cmd_header->mem_map_handle = + sg->cma_persist_cfg_data.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)(paddr_w_offset); + cmd_header->payload_address_msw = + (uint32_t)(paddr_w_offset >> 32); + cmd_header->payload_size = sg->cma_cal_data_size + - sizeof(AcdbSgIdPersistData); + + send_pkt->client_data |= GSL_GPR_CMA_FLAG_BIT; + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), + (uint8_t *)sg->cma_persist_cfg_data.v_addr + + sizeof(AcdbSgIdPersistData), cmd_header->payload_size); + + /* have mem filled, now assign it to the ML mem */ + rc = gsl_shmem_hyp_assign(sg->cma_persist_cfg_data.handle, + AR_DEFAULT_DSP, AR_APSS); + if (rc) { + GSL_ERR("hyp assign failed %d", rc); + goto cleanup; + } + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("send cma perist cal for sg_id 0x%x failed %d", + sg->sg_id, rc); + goto cleanup; + } + + break; + default: + GSL_ERR("unknown acdb hw accel mem type %d", + cma_sg_info.subgraph_list[i].mem_type); + rc = AR_EFAILED; + goto cleanup; + } + } +free_sg_proc_ids: + if(!rsp.sg_proc_ids) + gsl_mem_free(rsp.sg_proc_ids); +cleanup: + gsl_mem_free(cma_sg_info.subgraph_list); +free_status_list: + gsl_mem_free(sg_cma_status_list.list); + +exit: + return rc; +} + +static int32_t gsl_graph_send_global_persist_cal(struct gsl_graph *graph, + struct gsl_sgid_list *sgid_list, struct gsl_graph_gkv_node *gkv_node, + struct gsl_key_vector *prior_ckv, const struct gsl_key_vector *new_ckv) +{ + AcdbSgIdCalKeyVector cmd_struct; + AcdbGlbPsistIdentifierList rsp_id_list; + AcdbBlob rsp_blob; + AcdbGlbPsistCalInfo *cal_info; + uint8_t *cal_info_ptr; + struct gsl_shmem_alloc_data *cal_data; + int32_t rc; + uint32_t i, j; + uint32_t gpc_id; + struct apm_cmd_header_t *cmd_header; + gpr_packet_t *send_pkt = NULL; + struct gsl_glbl_persist_cal_iid_list *cal_iid_lists; + bool_t is_shmem_supported = TRUE; + + rc = __gpr_cmd_is_shared_mem_supported(graph->proc_id, &is_shmem_supported); + if (!is_shmem_supported) { + return AR_EUNSUPPORTED; + } else if (rc) { + GSL_ERR("GPR is shmem supported failed %d", rc) + goto exit; + } + + cmd_struct.num_sg_ids = sgid_list->len; + cmd_struct.sg_ids = sgid_list->sg_ids; + cmd_struct.cal_key_vector_prior.num_keys = prior_ckv->num_kvps; + cmd_struct.cal_key_vector_prior.graph_key_vector = + (AcdbKeyValuePair *)prior_ckv->kvp; + cmd_struct.cal_key_vector_new.num_keys = new_ckv->num_kvps; + cmd_struct.cal_key_vector_new.graph_key_vector = + (AcdbKeyValuePair *)new_ckv->kvp; + + rsp_id_list.global_persistent_cal_info = NULL; + rsp_id_list.num_glb_persist_identifiers = 0; + rsp_id_list.size = 0; + + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_GLB_PSIST_IDENTIFIERS, + &cmd_struct, sizeof(cmd_struct), &rsp_id_list, sizeof(rsp_id_list)); + if (rc == AR_ENOTEXIST) { + /* + * avoid printing error for the case where a graph does not have any + * global persist data + */ + GSL_DBG("get global persist identifiers size returned %d", rc); + goto exit; + } else if (rc) { + GSL_ERR("get global persist identifiers size failed %d", rc); + goto exit; + } + + /* if no global persist cals */ + if (rsp_id_list.size == 0 || rsp_id_list.num_glb_persist_identifiers == 0) + return AR_EOK; + + rsp_id_list.global_persistent_cal_info = gsl_mem_zalloc(rsp_id_list.size); + if (!rsp_id_list.global_persistent_cal_info) + return AR_ENOMEMORY; + + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_GLB_PSIST_IDENTIFIERS, + &cmd_struct, sizeof(cmd_struct), &rsp_id_list, sizeof(rsp_id_list)); + if (rc) { + GSL_ERR("get global persist identifiers failed %d", rc); + goto free_cal_info; + } + + cal_info_ptr = (uint8_t *) rsp_id_list.global_persistent_cal_info; + + /* now add the cals into the global pool */ + /* allocate space for each */ + gkv_node->glbl_persist_cal_list = + gsl_mem_zalloc(sizeof(struct gsl_glbl_persist_cal_iid_list) + * rsp_id_list.num_glb_persist_identifiers); + + if (!gkv_node->glbl_persist_cal_list) { + rc = AR_ENOMEMORY; + goto free_cal_info; + } + + cal_iid_lists = gkv_node->glbl_persist_cal_list; + + for (i = 0; i < rsp_id_list.num_glb_persist_identifiers; ++i) { + + cal_data = NULL; + rsp_blob.buf = NULL; + rsp_blob.buf_size = 0; + cal_info = (AcdbGlbPsistCalInfo *)cal_info_ptr; + + gpc_id = cal_info->cal_identifier; + + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_GLB_PSIST_CALDATA, &gpc_id, + sizeof(gpc_id), &rsp_blob, sizeof(rsp_blob)); + if (rc) { + GSL_ERR("get global persist identifiers size failed %d", rc); + goto cleanup; + } + + cal_iid_lists[i].gpcal = gsl_global_persist_cal_pool_add(gpc_id, + rsp_blob.buf_size, &cal_data, graph->proc_id); + + if (!cal_iid_lists[i].gpcal) { + GSL_ERR("Add to global cal pool failed for cal ID %d", gpc_id); + rc = AR_EFAILED; + goto cleanup; + } + + /* cal_data will be non-null if we need to fetch data */ + if (cal_data) { + rsp_blob.buf = cal_data->v_addr; + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_GLB_PSIST_CALDATA, &gpc_id, + sizeof(gpc_id), &rsp_blob, sizeof(rsp_blob)); + if (rc) { + GSL_ERR("get global persist calibration data failed %d", rc); + goto cleanup; + } + } else { + /* got null so entry already exists. Just point to it */ + cal_data = &(cal_iid_lists[i].gpcal->cal_data); + } + + /* register cal on each iid */ + for (j = 0; j < cal_info->num_iids; ++j) { + rc = gsl_allocate_gpr_packet(APM_CMD_REGISTER_SHARED_CFG, + graph->src_port, cal_info->iids[j], sizeof(*cmd_header), 0, + graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto cleanup; + } + + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + cmd_header->mem_map_handle = cal_data->spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t) cal_data->spf_addr; + cmd_header->payload_address_msw = + (uint32_t) (cal_data->spf_addr >> 32); + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), NULL, 0); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("Register shared cfg for iid %d failed:%d", + cal_info->iids[j], rc); + goto cleanup; + } + cal_iid_lists[i].iids[j] = cal_info->iids[j]; + ++cal_iid_lists[i].num_iids; + } + + /* AcdbGlbPsistCalInfo has variable size. Advance ptr to next object */ + cal_info_ptr += sizeof(AcdbGlbPsistCalInfo) + + sizeof(uint32_t)*cal_info->num_iids; + } + goto free_cal_info; + +cleanup: + gsl_mem_free(cal_iid_lists); +free_cal_info: + gsl_mem_free(rsp_id_list.global_persistent_cal_info); +exit: + return rc; +} + +static int32_t check_and_register_dynamic_pd(struct gsl_graph *graph, + struct gsl_sgid_list *sgids, uint32_t ss_mask, uint32_t *dyn_ss_mask) +{ + int32_t i = 0, j = 0, rc = AR_EOK; + uint32_t sg_ss_mask = 0; + uint32_t tmp_ss_masks[sgids->len]; + uint32_t tmp_dyn_ss_mask = 0; + + *dyn_ss_mask = 0; + GSL_DBG("proc_id %d, num subgraphs %d, ss_mask 0x%x", graph->proc_id, sgids->len, ss_mask); + if (ss_mask == (uint32_t) GSL_GET_SPF_SS_MASK(graph->proc_id)) + return AR_EOK; + + for (i = 0; i < sgids->len; ++i) { + gsl_mdf_utils_query_graph_ss_mask(&sgids->sg_ids[i], 1, &sg_ss_mask); + GSL_DBG("subgraph: id 0x%x, ss_mask 0x%x", sgids->sg_ids[i], sg_ss_mask); + if (sg_ss_mask == GSL_GET_SPF_SS_MASK(graph->proc_id)) + continue; + rc = gsl_mdf_utils_register_dynamic_pd(sg_ss_mask, graph->proc_id, graph->src_port, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG], &tmp_dyn_ss_mask); + *dyn_ss_mask |= tmp_dyn_ss_mask; + if (rc) { + GSL_ERR("dynamic pd registration failed, status %d", rc); + goto err_exit; + } + tmp_ss_masks[j++] = sg_ss_mask; + } + return rc; + +err_exit: + while (j-- > 0) + gsl_mdf_utils_deregister_dynamic_pd(tmp_ss_masks[j], graph->proc_id); + *dyn_ss_mask = 0; + return rc; + +} + +static int32_t check_and_deregister_dynamic_pd(struct gsl_graph *graph, + struct gsl_sgid_list *sgids) +{ + int32_t i = 0, rc = AR_EOK; + uint32_t sg_ss_mask = 0; + + GSL_DBG("proc_id %d, num subgraphs %d, ss_mask 0x%x", graph->proc_id, sgids->len, graph->ss_mask); + if (graph->ss_mask == (uint32_t) GSL_GET_SPF_SS_MASK(graph->proc_id)) + return AR_EOK; + + for (i = 0; i < sgids->len; ++i) { + gsl_mdf_utils_query_graph_ss_mask(&sgids->sg_ids[i], 1, &sg_ss_mask); + GSL_DBG("subgraph: id 0x%x, ss_mask 0x%x", sgids->sg_ids[i], sg_ss_mask); + if (sg_ss_mask == GSL_GET_SPF_SS_MASK(graph->proc_id)) + continue; + rc = gsl_mdf_utils_deregister_dynamic_pd(sg_ss_mask, graph->proc_id); + if (rc) + GSL_ERR("dynamic pd de-init failed, status %d", rc); + } + return rc; +} + +enum gsl_graph_states gsl_graph_update_state(struct gsl_graph *graph, + enum gsl_graph_states new_state) +{ + enum gsl_graph_states temp = graph->graph_state; + /* + * error is a sink state, once we go into this state we stay in it to block + * any further operations on the graph + */ + if (graph->graph_state != GRAPH_ERROR && + graph->graph_state != GRAPH_ERROR_ALLOW_CLEANUP) + graph->graph_state = new_state; + + return temp; //Return previous state. +} + +enum gsl_graph_states gsl_graph_get_state(struct gsl_graph *graph) +{ + return graph->graph_state; +} + +void gsl_graph_signal_event_all(struct gsl_graph *graph, + enum gsl_graph_sig_event_mask ev_flags) +{ + gsl_signal_set(&graph->graph_signal[GRAPH_CTRL_GRP1_CMD_SIG], + ev_flags, 0, NULL); + gsl_signal_set(&graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG], + ev_flags, 0, NULL); + gsl_signal_set(&graph->graph_signal[GRAPH_CTRL_GRP3_CMD_SIG], + ev_flags, 0, NULL); + if (graph->write_info.lock) + gsl_signal_set(&graph->write_info.dp_signal, + ev_flags, 0, NULL); + if (graph->read_info.lock) + gsl_signal_set(&graph->read_info.dp_signal, + ev_flags, 0, NULL); +} + +int32_t gsl_graph_init(struct gsl_graph *graph) +{ + int32_t rc = AR_EOK, i; + + rc = ar_osal_mutex_create(&graph->graph_lock); + if (rc) + goto exit; + + rc = ar_osal_mutex_create(&graph->get_set_cfg_lock); + if (rc) + goto destroy_graph_lock; + + rc = ar_osal_mutex_create(&graph->gkv_list_lock); + if (rc) + goto destroy_get_set_cfg_lock; + + graph->graph_state = GRAPH_IDLE; + + /* Default proc id is assumed to be ADSP */ + graph->proc_id = AR_DEFAULT_DSP; + + for (i = 0; i < GRAPH_CMD_SIG_MAX; ++i) { + /* + * use the same mutex for all signals to save memory, we can have a + * mutex per signal if we want to optimize further + */ + rc = gsl_signal_create(&graph->graph_signal[i], &graph->graph_lock); + if (rc) + goto destroy_graph_signals; //some signals may have been created + } + + /* lockless signal */ + rc = gsl_signal_create(&graph->transient_state_info.trans_state_change_sig, + NULL); + if (rc) + goto destroy_graph_signals; + + graph->num_gkvs = 0; + rc = ar_list_init(&graph->gkv_list, NULL, NULL); + if (AR_FAILED(rc)) { + GSL_ERR("failed to initialize gkv list: %d", rc); + goto destroy_flush_signal; + } + + gsl_graph_update_state(graph, GRAPH_OPENED); + goto exit; + +destroy_flush_signal: + ar_osal_signal_destroy( + graph->transient_state_info.trans_state_change_sig.sig); +destroy_graph_signals: + for (i = 0; i < GRAPH_CMD_SIG_MAX; ++i) + ar_osal_signal_destroy(graph->graph_signal[i].sig); + ar_osal_mutex_destroy(graph->gkv_list_lock); +destroy_get_set_cfg_lock: + ar_osal_mutex_destroy(graph->get_set_cfg_lock); +destroy_graph_lock: + ar_osal_mutex_destroy(graph->graph_lock); +exit: + return rc; +} + +int32_t gsl_graph_deinit(struct gsl_graph *graph) +{ + int32_t i; + + for (i = 0; i < GRAPH_CMD_SIG_MAX; ++i) + gsl_signal_destroy(&graph->graph_signal[i]); + + gsl_signal_destroy(&graph->transient_state_info.trans_state_change_sig); + + ar_osal_mutex_destroy(graph->get_set_cfg_lock); + ar_osal_mutex_destroy(graph->graph_lock); + graph->graph_state = GRAPH_IDLE; + + ar_list_clear(&graph->gkv_list); + ar_osal_mutex_destroy(graph->gkv_list_lock); + + return AR_EOK; +} + +int32_t gsl_acdb_get_graph(const struct gsl_key_vector *gkv, + uint32_t **sg_id_list, AcdbGetGraphRsp *sg_conn_info) +{ + AcdbGetGraphRsp rsp_struct; + AcdbGraphKeyVector cmd_struct; + AcdbSubgraph *sgs; + uint32_t cmd_struct_size, rsp_struct_size, num_dst_sgs; + int32_t rc, i, payload_size; + uint32_t num_of_subgraphs, *rsp_p, *sg_ids; + + /* Populate command structure */ + cmd_struct_size = sizeof(AcdbGraphKeyVector); + cmd_struct.num_keys = gkv->num_kvps; + cmd_struct.graph_key_vector = (AcdbKeyValuePair *)gkv->kvp; + + /** + * Populate response structure + * Response size is unknown here, so allocate minimum of 8 bytes, + * so ACDB SW can return the size to be allocated + */ + rsp_struct.subgraphs = NULL; + rsp_struct.size = 0; + rsp_struct.num_subgraphs = 0; + rsp_struct_size = sizeof(AcdbGetGraphRsp); + + rc = acdb_ioctl(ACDB_CMD_GET_GRAPH, &cmd_struct, cmd_struct_size, + &rsp_struct, rsp_struct_size); + if (rc) { + GSL_ERR("get_graph acdb ioctl for size failed: %d", rc); + goto exit; + } + /* + * Getting 0 subgraphs is a valid scenario, GSL should handle it by not + * opening any subgraphs on Spf + */ + if (rsp_struct.size == 0) { + GSL_DBG("zero size returned for get_graph: %d, size: %d", rc, + rsp_struct.size); + if (sg_conn_info) { + sg_conn_info->num_subgraphs = 0; + sg_conn_info->size = 0; + sg_conn_info->subgraphs = NULL; + } + if (sg_id_list) + *sg_id_list = NULL; + goto exit; + } + + sgs = gsl_mem_zalloc(rsp_struct.size); + if (!sgs) { + rc = AR_ENOMEMORY; + goto exit; + } + rsp_struct.subgraphs = sgs; + + rc = acdb_ioctl(ACDB_CMD_GET_GRAPH, &cmd_struct, cmd_struct_size, + &rsp_struct, rsp_struct_size); + if (rc) { + GSL_ERR("get_graph acdb ioctl for data failed: %d", rc); + goto free_sgs; + } + + /* rsp_struct: {num_of_subgraphs, size, */ + rsp_p = (uint32_t *)&rsp_struct; + payload_size = rsp_struct.size; + num_of_subgraphs = rsp_struct.num_subgraphs; + + /** + * create size twice the number of sub-graphs, first half to + * hold the sg_ids read from ACDB, second half to hold the sg_ids + * whose open_ref_cnt is equal to 1 + */ + sg_ids = gsl_mem_zalloc(2 * (size_t)num_of_subgraphs * sizeof(uint32_t)); + if (!sg_ids) { + rc = AR_ENOMEMORY; + goto free_sgs; + } + + rsp_p = (uint32_t *)rsp_struct.subgraphs; + i = 0; + while (payload_size > 0) { + sg_ids[i++] = *rsp_p++; + num_dst_sgs = *rsp_p++; + rsp_p += num_dst_sgs; + payload_size -= 4 * (2 + num_dst_sgs); + } + /** + * After successful parsing payload_size should become 0 + * Check if it becomes negative and return error to avoid + * illegal memory accesses + */ + if (payload_size < 0) { + rc = AR_EFAILED; + GSL_ERR("get_graph response parsing failed: %d", rc); + goto free_sg_ids; + } + *sg_id_list = sg_ids; + if (sg_conn_info) { + sg_conn_info->num_subgraphs = rsp_struct.num_subgraphs; + sg_conn_info->size = rsp_struct.size; + sg_conn_info->subgraphs = sgs; + } + + rc = 0; + +free_sg_ids: + if (rc) + gsl_mem_free(sg_ids); +free_sgs: + if (rc || !sg_conn_info) { + gsl_mem_free(sgs); + if (sg_conn_info) + sg_conn_info->subgraphs = NULL; + } +exit: + return rc; +} + +/* + * allocates and returns module_info for a given tag. Caller is responsible to + * free the module info. + */ +static int32_t _gsl_graph_get_module_tag_info(uint32_t *sg_id_list, + uint32_t num_sgs, uint32_t tag, struct gsl_module_id_info **module_info, + uint32_t *module_info_size) +{ + AcdbGetTaggedModulesReq acdb_req; + AcdbGetTaggedModulesRsp acdb_rsp; + struct gsl_module_id_info *mod_info; + uint32_t mod_info_size; + int32_t rc = AR_EOK; + + *module_info = NULL; + *module_info_size = 0; + acdb_req.num_sg_ids = num_sgs; + acdb_req.sg_ids = sg_id_list; + acdb_req.tag_id = tag; + acdb_rsp.num_tagged_mids = 0; + acdb_rsp.tagged_mid_list = NULL; + rc = acdb_ioctl(ACDB_CMD_GET_TAGGED_MODULES, &acdb_req, + sizeof(acdb_req), &acdb_rsp, sizeof(acdb_rsp)); + if (rc && rc != AR_ENOTEXIST) { + GSL_ERR("acdb_ioctl failed with err %d", rc); + return rc; + } + if (acdb_rsp.num_tagged_mids == 0) { + GSL_ERR("number of modules tagged with 0x%x are zero", tag); + return AR_ENOTEXIST; + } + mod_info_size = sizeof(struct gsl_module_id_info) + + (acdb_rsp.num_tagged_mids * sizeof(struct gsl_module_id_info_entry)); + mod_info = gsl_mem_zalloc(mod_info_size); + if (!mod_info) { + rc = AR_ENOMEMORY; + return rc; + } + mod_info->num_modules = acdb_rsp.num_tagged_mids; + acdb_rsp.tagged_mid_list = (AcdbModuleInstance *) + &mod_info->module_entry[0]; + rc = acdb_ioctl(ACDB_CMD_GET_TAGGED_MODULES, &acdb_req, + sizeof(acdb_req), &acdb_rsp, sizeof(acdb_rsp)); + if (rc) { + GSL_ERR("acdb_ioctl failed with err %d", rc); + goto cleanup; + } + *module_info = mod_info; + *module_info_size = mod_info_size; + +cleanup: + if (rc) + gsl_mem_free(mod_info); + return rc; +} + +int32_t _gsl_graph_get_module_proc_tag_info(uint32_t *sg_id_list, + uint32_t num_sgs, uint32_t tag, struct gsl_module_id_proc_info **proc_module_info) +{ + AcdbGetProcTaggedModulesReq acdb_req; + AcdbGetProcTaggedModulesRsp acdb_rsp; + int32_t rc = AR_EOK; + struct gsl_module_id_proc_info *proc_mod_info; + + acdb_req.num_sg_ids = num_sgs; + acdb_req.sg_ids = sg_id_list; + acdb_req.tag_id = tag; + acdb_rsp.num_procs = 0; + acdb_rsp.list_size = 0; + acdb_rsp.proc_tagged_module_list = NULL; + rc = acdb_ioctl(ACDB_CMD_GET_PROC_TAGGED_MODULES, &acdb_req, + sizeof(acdb_req), &acdb_rsp, sizeof(acdb_rsp)); + if (rc && rc != AR_ENOTEXIST) { + GSL_ERR("acdb_ioctl failed with err %d", rc); + return rc; + } + if (acdb_rsp.list_size == 0) { + GSL_ERR("number of modules tagged with 0x%x are zero", tag); + return AR_ENOTEXIST; + } + + //Allocate space for the process module list + acdb_rsp.proc_tagged_module_list = gsl_mem_zalloc(acdb_rsp.list_size); + if (!acdb_rsp.proc_tagged_module_list) { + rc = AR_ENOMEMORY; + return rc; + } + rc = acdb_ioctl(ACDB_CMD_GET_PROC_TAGGED_MODULES, &acdb_req, + sizeof(acdb_req), &acdb_rsp, sizeof(acdb_rsp)); + if (rc && rc != AR_ENOTEXIST) { + GSL_ERR("acdb_ioctl failed with err %d", rc); + if (acdb_rsp.proc_tagged_module_list) + gsl_mem_free(acdb_rsp.proc_tagged_module_list); + return rc; + } + if (rc) { + GSL_ERR("acdb_ioctl failed with err %d", rc); + goto cleanup; + } + //Allocate space for the top level gsl_module_id_proc_info struct + proc_mod_info = gsl_mem_zalloc(acdb_rsp.list_size + 8); + if (!proc_mod_info) { + rc = AR_ENOMEMORY; + return rc; + } + proc_mod_info->num_procs = acdb_rsp.num_procs; + proc_mod_info->list_size = acdb_rsp.list_size; + proc_mod_info->proc_module_list = + (struct gsl_module_id_proc_info_entry *)acdb_rsp.proc_tagged_module_list; + *proc_module_info = proc_mod_info; + + + cleanup: + if (rc && acdb_rsp.proc_tagged_module_list != NULL) + gsl_mem_free(acdb_rsp.proc_tagged_module_list); + return rc; +} + +int32_t gsl_graph_get_module_tag_info(const struct gsl_key_vector *gkv, + uint32_t tag, struct gsl_module_id_info **module_info, + uint32_t *module_info_size) +{ + int32_t rc = AR_EOK; + uint32_t *sg_id_list; + AcdbGetGraphRsp sg_conn_info; + + rc = gsl_acdb_get_graph(gkv, &sg_id_list, &sg_conn_info); + if (rc) { + GSL_ERR("get graph failed %d", rc); + return rc; + } + /* it's possible to get empty subgraph list from ACDB */ + if (sg_id_list == NULL || sg_conn_info.num_subgraphs == 0) { + rc = AR_ENOTEXIST; + return rc; + } + + rc = _gsl_graph_get_module_tag_info(sg_id_list, sg_conn_info.num_subgraphs, + tag, module_info, module_info_size); + + gsl_mem_free(sg_id_list); + gsl_mem_free(sg_conn_info.subgraphs); + return rc; +} + +int32_t gsl_graph_set_custom_config(struct gsl_graph *graph, + const uint8_t *payload, const uint32_t payload_size, + ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + apm_module_param_data_t *param_data = (apm_module_param_data_t *)payload; + uint32_t dst_port = GSL_GPR_DST_PORT_APM; + + GSL_MUTEX_LOCK(lock); + /* serialize all get/set operations on a graph */ + GSL_MUTEX_LOCK(graph->get_set_cfg_lock); + + /* This condition is satisfied if we have only 1 Param ID & + * Payload in the Query. Can be safely sent to the module + * itself instead of APM. + */ + if ((GSL_ALIGN_8BYTE(param_data->param_size) + + sizeof(apm_module_param_data_t)) == payload_size) { + dst_port = param_data->module_instance_id; + } else { + dst_port = GSL_GPR_DST_PORT_APM; + } + + if (payload_size <= GSL_IN_BAND_SIZE_THRESHOLD) + rc = gsl_apm_config_inband(graph, payload, payload_size, + APM_CMD_SET_CFG, dst_port, NULL); + else + rc = gsl_apm_config_oob(graph, payload, payload_size, APM_CMD_SET_CFG, + dst_port); + + if (rc) + GSL_ERR("Graph set custom cfg failed %d", rc); + + GSL_MUTEX_UNLOCK(graph->get_set_cfg_lock); + GSL_MUTEX_UNLOCK(lock); + + return rc; +} + +int32_t gsl_graph_get_custom_config(struct gsl_graph *graph, + uint8_t *payload, uint32_t payload_size, ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + apm_module_param_data_t *param_data = (apm_module_param_data_t *)payload; + uint32_t dst_port = GSL_GPR_DST_PORT_APM; + bool_t is_shmem_supported = TRUE; + + GSL_MUTEX_LOCK(lock); + GSL_MUTEX_LOCK(graph->get_set_cfg_lock); + + /* This condition is satisfied if we have only 1 Param ID & + * Payload in the Query. Can be safely sent to the module + * itself instead of APM. + */ + if ((GSL_ALIGN_8BYTE(param_data->param_size) + + sizeof(apm_module_param_data_t)) == payload_size) { + dst_port = param_data->module_instance_id; + } else { + dst_port = GSL_GPR_DST_PORT_APM; + } + + rc = __gpr_cmd_is_shared_mem_supported(graph->proc_id, &is_shmem_supported); + if (rc) { + GSL_ERR("GPR is shmem supported failed %d", rc) + goto exit; + } + + if (payload_size <= GSL_IN_BAND_SIZE_THRESHOLD || !is_shmem_supported) + rc = gsl_apm_get_config_inband(graph, payload, &payload_size, dst_port); + else + rc = gsl_apm_config_oob(graph, payload, payload_size, + APM_CMD_GET_CFG, dst_port); + + if (rc) + GSL_ERR("Graph get custom config failed %d", rc); + +exit: + GSL_MUTEX_UNLOCK(graph->get_set_cfg_lock); + GSL_MUTEX_UNLOCK(lock); + + return rc; +} + +int32_t gsl_graph_set_tagged_custom_config(struct gsl_graph *graph, + uint32_t tag, const uint8_t *payload, const size_t payload_size, + ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + struct gsl_sgid_list sg_id_list = {0, NULL}; + struct gsl_module_id_info *module_info; + struct apm_cmd_header_t *cmd_header; + uint32_t i, module_info_size; + uint8_t *cmd_payload; + gsl_msg_t gsl_msg; + + rc = gsl_graph_get_sgids_and_objs(graph, &sg_id_list, NULL); + if (rc) { + GSL_ERR("get sgidlist failed %d", rc); + return rc; + } + /* in-case no subgraphs are found then exit */ + if (!sg_id_list.sg_ids) { + rc = AR_ENOTEXIST; + goto exit; + } + + GSL_MUTEX_LOCK(lock); + /* serialize all get/set operations on a graph */ + GSL_MUTEX_LOCK(graph->get_set_cfg_lock); + + rc = _gsl_graph_get_module_tag_info(sg_id_list.sg_ids, + sg_id_list.len, tag, &module_info, &module_info_size); + if (rc) { + GSL_ERR("fail to get tagged module iid %d", rc); + goto cleanup; + } + + for (i = 0; i < module_info->num_modules; ++i) { + rc = gsl_msg_alloc(APM_CMD_SET_CFG, graph->src_port, + module_info->module_entry[i].module_iid, sizeof(*cmd_header), 0, + graph->proc_id, GSL_ALIGN_8BYTE(payload_size), true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto free_mem; + } + + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + gsl_msg.gpr_packet); + cmd_payload = (uint8_t *)cmd_header + sizeof(*cmd_header); + cmd_header->payload_size = (uint32_t)GSL_ALIGN_8BYTE(payload_size); + + gsl_memcpy(cmd_payload, GSL_ALIGN_8BYTE(payload_size), payload, + payload_size); + + /* clients don't know MIID. Set it here */ + *(uint32_t *)cmd_payload = module_info->module_entry[i].module_iid; + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*cmd_header) + + GSL_ALIGN_8BYTE(payload_size), NULL, 0); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("Graph set config failed:%d, miid: 0x%x", rc, + module_info->module_entry[i].module_iid); + goto free_msg; + } + gsl_msg_free(&gsl_msg); + } + + goto free_mem; +free_msg: + gsl_msg_free(&gsl_msg); +free_mem: + gsl_mem_free(module_info); +cleanup: + GSL_MUTEX_UNLOCK(graph->get_set_cfg_lock); + GSL_MUTEX_UNLOCK(lock); + gsl_mem_free(sg_id_list.sg_ids); +exit: + return rc; +} + +int32_t gsl_graph_set_tagged_custom_config_persist(struct gsl_graph *graph, + uint32_t tag, const uint8_t *payload, const uint32_t payload_size, + ar_osal_mutex_t lock) +{ + uint32_t i = 0, module_info_size; + int32_t rc = AR_EOK; + struct gsl_module_id_info *module_info = NULL; + uint8_t *cmd_payload; + struct apm_cmd_header_t *apm_hdr; + struct gsl_subgraph **sg_objs = NULL; + uint32_t num_sg_objs = 0; + gpr_packet_t *send_pkt = NULL; + bool_t is_shmem_supported = TRUE; + + rc = __gpr_cmd_is_shared_mem_supported(graph->proc_id, &is_shmem_supported); + if (!is_shmem_supported) { + return AR_EOK; + } else if (rc) { + GSL_ERR("GPR is shmem supported failed %d", rc) + goto exit; + } + + sg_objs = gsl_graph_get_sg_array(graph, &num_sg_objs); + if (!sg_objs) { + GSL_ERR("get sg objs failed %d", rc); + goto exit; + } + if (num_sg_objs == 0) { + rc = AR_ENOTEXIST; + goto free_sg_obs; + } + + GSL_MUTEX_LOCK(lock); + GSL_MUTEX_LOCK(graph->get_set_cfg_lock); + + for (i = 0; i < num_sg_objs; ++i) { + rc = _gsl_graph_get_module_tag_info(&sg_objs[i]->sg_id, 1, tag, + &module_info, &module_info_size); + if (rc == AR_ENOTEXIST) { + rc = AR_EOK; + continue; + } else if (rc) { + GSL_ERR("fail to get tagged module iid %d", rc); + goto cleanup; + } + + if (module_info_size == 0) + continue; + /* + * Check if this SG already has persistent cal we must de-reg and + * free it only if SG is in stopped/suspended state + */ + if (sg_objs[i]->user_persist_cfg_data.handle && + sg_objs[i]->start_ref_cnt == 0) { + + rc = gsl_allocate_gpr_packet(APM_CMD_DEREGISTER_CFG, + graph->src_port, module_info->module_entry[0].module_iid, + sizeof(*apm_hdr), 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("allocate gpr packet failed %d, miid: 0x%x", + rc, module_info->module_entry[0].module_iid); + continue; + } + apm_hdr = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, send_pkt); + + apm_hdr->mem_map_handle = + sg_objs[i]->user_persist_cfg_data.spf_mmap_handle; + apm_hdr->payload_address_lsw = (uint32_t) + sg_objs[i]->user_persist_cfg_data.spf_addr; + apm_hdr->payload_address_msw = + (uint32_t)(sg_objs[i]->user_persist_cfg_data.spf_addr >> 32); + apm_hdr->payload_size = sg_objs[i]->user_persist_cfg_data_size; + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*apm_hdr), + sg_objs[i]->user_persist_cfg_data.v_addr, + sg_objs[i]->user_persist_cfg_data_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc != AR_EOK) { + GSL_ERR("send dereg perist cal for sg_id 0x%x failed %d", + sg_objs[i]->sg_id, rc); + goto free_module_info; + } + + rc = gsl_shmem_free(&sg_objs[i]->user_persist_cfg_data); + if (rc != AR_EOK) + goto free_module_info; + } else if (sg_objs[i]->user_persist_cfg_data.handle) { + /* + * SG already has persistent data and it is already started + * do not update persistent cal in this case + */ + continue; + } + /* + * Store the persistent cal in this SGs context and register with + * Spf + */ + sg_objs[i]->user_persist_cfg_data_size = payload_size; + rc = gsl_shmem_alloc(sg_objs[i]->user_persist_cfg_data_size, + graph->proc_id, &sg_objs[i]->user_persist_cfg_data); + if (rc != AR_EOK) + goto free_module_info; + + cmd_payload = (uint8_t *)sg_objs[i]->user_persist_cfg_data.v_addr; + gsl_memcpy(cmd_payload, sg_objs[i]->user_persist_cfg_data_size, + payload, payload_size); + + rc = gsl_allocate_gpr_packet(APM_CMD_REGISTER_CFG, + graph->src_port, module_info->module_entry[0].module_iid, + sizeof(*apm_hdr), 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("allocate gpr packet failed %d", rc); + goto free_module_info; + } + apm_hdr = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, send_pkt); + + apm_hdr->mem_map_handle = + sg_objs[i]->user_persist_cfg_data.spf_mmap_handle; + apm_hdr->payload_address_lsw = (uint32_t) + sg_objs[i]->user_persist_cfg_data.spf_addr; + apm_hdr->payload_address_msw = + (uint32_t)(sg_objs[i]->user_persist_cfg_data.spf_addr >> 32); + apm_hdr->payload_size = payload_size; + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*apm_hdr), + sg_objs[i]->user_persist_cfg_data.v_addr, + sg_objs[i]->user_persist_cfg_data_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc != AR_EOK) { + GSL_ERR("send perist cal for sg_id 0x%x failed %d", + sg_objs[i]->sg_id, rc); + gsl_shmem_free(&sg_objs[i]->user_persist_cfg_data); + sg_objs[i]->user_persist_cfg_data_size = 0; + goto free_module_info; + } + gsl_mem_free(module_info); + } + + goto cleanup; /* skip freeing module_info in success case */ + +free_module_info: + gsl_mem_free(module_info); + +cleanup: + GSL_MUTEX_UNLOCK(graph->get_set_cfg_lock); + GSL_MUTEX_UNLOCK(lock); + +free_sg_obs: + gsl_mem_free(sg_objs); +exit: + return rc; +} + +int32_t gsl_graph_get_tagged_custom_config(struct gsl_graph *graph, + uint32_t tag, uint8_t *payload, uint32_t *payload_size, + ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + struct gsl_sgid_list sg_id_list = {0, NULL}; + struct gsl_module_id_info *module_info = NULL; + apm_module_param_data_t *param_data = (apm_module_param_data_t *)payload; + uint32_t module_info_size = 0; + uint32_t dst_port = GSL_GPR_DST_PORT_APM; + + rc = gsl_graph_get_sgids_and_objs(graph, &sg_id_list, NULL); + if (rc) { + GSL_ERR("get sgidlist failed %d", rc); + goto exit; + } + /* if no subgraphs are found then go to exit */ + if (!sg_id_list.sg_ids) { + *payload_size = 0; + rc = AR_ENOTEXIST; + goto exit; + } + + GSL_MUTEX_LOCK(lock); + GSL_MUTEX_LOCK(graph->get_set_cfg_lock); + + rc = _gsl_graph_get_module_tag_info(sg_id_list.sg_ids, sg_id_list.len, tag, + &module_info, &module_info_size); + if (rc) { + GSL_ERR("fail to get tagged module iid %d", rc); + goto cleanup; + } + + *(uint32_t *)payload = module_info->module_entry[0].module_iid; + + /* This condition is satisfied if we have only 1 Param ID & + * Payload in the Query. Can be safely sent to the module + * itself instead of APM. + */ + if ((GSL_ALIGN_8BYTE(param_data->param_size) + + sizeof(apm_module_param_data_t)) + == *payload_size) { + dst_port = module_info->module_entry[0].module_iid; + } else { + dst_port = GSL_GPR_DST_PORT_APM; + } + + if (*payload_size <= GSL_IN_BAND_SIZE_THRESHOLD) + rc = gsl_apm_get_config_inband(graph, payload, payload_size, dst_port); + else + rc = gsl_apm_config_oob(graph, payload, *payload_size, + APM_CMD_GET_CFG, dst_port); + + if (rc) { + GSL_ERR("Graph get config failed:%d, miid: 0x%x", rc, + module_info->module_entry[0].module_iid); + goto free_module_info; + } + +free_module_info: + gsl_mem_free(module_info); +cleanup: + GSL_MUTEX_UNLOCK(graph->get_set_cfg_lock); + GSL_MUTEX_UNLOCK(lock); + gsl_mem_free(sg_id_list.sg_ids); +exit: + return rc; +} + +static int32_t gsl_graph_set_sg_cal(struct gsl_graph *graph, + struct gsl_sgid_list *sgid_list, struct gsl_graph_gkv_node *gkv_node, + const struct gsl_key_vector *ckv, const struct gsl_key_vector *gkv, + bool isCKVValidated) +{ + int32_t rc = AR_EOK; + struct gsl_key_vector *prior_ckv = &gkv_node->ckv; + const struct gsl_key_vector *new_ckv = ckv; + struct gsl_sgobj_list sg_objs_list; + + /* + * if no new ckv is given it means we should set only the cal data which is + * not ckv depenedent. To get such data from acdb, acdb requires the prior + * ckv and new ckv must be set to empty ckv. + * Note: Once a ckv dependent cal is set then attempting to set the default + * has no affect. + */ + if (!ckv) { + if (prior_ckv->num_kvps == 0) { + new_ckv = &gkv_node->ckv; + } else { + /* + * client is attempting to set the default cal even though a ckv + * has been set + */ + goto exit; + } + } + + sg_objs_list.len = gkv_node->num_of_subgraphs; + sg_objs_list.sg_objs = gkv_node->sg_array; + + rc = gsl_graph_send_nonpersist_cal(graph, sgid_list, prior_ckv, new_ckv, gkv, isCKVValidated); + if (rc == AR_ENOTEXIST || rc == AR_EUNSUPPORTED) { + GSL_DBG("graph send non-persist cal warning %d", rc); + rc = AR_EOK; + } else if (rc) { + GSL_ERR("graph send non-persist cal failed %d", rc); + goto exit; + } + + /* + * persist calibration update in GRAPH_STARTED state is not required to be + * supported as there is no dynamic persist calibration supported by any + * SPF module without quality issues. persist cal handles this on sg-by-sg + * basis, global persist cal just skips if the graph is started. + */ + rc = gsl_graph_send_persist_cal(graph, &sg_objs_list, new_ckv); + if (rc == AR_ENOTEXIST || rc == AR_EUNSUPPORTED) { + GSL_DBG("graph send persist cal warning %d", rc); + rc = AR_EOK; + } else if (rc) { + GSL_ERR("graph send persist cal failed %d", rc); + goto exit; + } + + if (gsl_graph_get_state(graph) != GRAPH_STARTED) { + rc = gsl_graph_send_global_persist_cal(graph, sgid_list, gkv_node, + prior_ckv, new_ckv); + if (rc == AR_ENOTEXIST || rc == AR_EUNSUPPORTED) { + GSL_DBG("graph send global persist cal warning %d", rc); + rc = AR_EOK; + } else if (rc) { + GSL_ERR("graph send global persist cal failed %d", rc); + goto exit; + } + } + + /* only update cached ckv if a new ckv was provided */ + if (ckv && ckv->num_kvps) { + if (!gkv_node->ckv.kvp) { + gkv_node->ckv.kvp = gsl_mem_zalloc( + sizeof(struct gsl_key_value_pair) * ckv->num_kvps); + if (!gkv_node->ckv.kvp) { + rc = AR_ENOMEMORY; + goto exit; + } + } else if (ckv->num_kvps != gkv_node->ckv.num_kvps) { + GSL_ERR("Size mismatch in Cal key vector"); + rc = AR_EBADPARAM; + goto exit; + } + /* cache the new ckv */ + gkv_node->ckv.num_kvps = ckv->num_kvps; + gsl_memcpy(gkv_node->ckv.kvp, + sizeof(struct gsl_key_value_pair) * ckv->num_kvps, ckv->kvp, + sizeof(struct gsl_key_value_pair) * ckv->num_kvps); + } +exit: + return rc; +} + +static int32_t gsl_graph_close_sgids_and_connections(struct gsl_graph *graph, + struct gsl_sgid_list sgids, AcdbSubgraph *sg_conn, uint32_t num_sg_conn) +{ + int32_t rc = AR_EOK; + struct gsl_blob spf_sg_conn_blob; + uint32_t close_pld_size = 0, sg_list_pid_size = 0, padded_bytes, i; + int8_t *close_payload; + struct apm_cmd_header_t *cmd_header; + struct apm_module_param_data_t *param_data; + uint32_t param_size; + gsl_msg_t gsl_msg; + + /* Get subgraph data size for spf and drv blobs */ + GSL_DBG("num_sgid= %d", sgids.len); + GSL_DBG("sg list:"); + for (i = 0; i < sgids.len; ++i) + GSL_DBG("%x", sgids.sg_ids[i]); + gsl_print_sg_conn_info((uint32_t *)sg_conn, + num_sg_conn); + + /* Get sg connection blob size from ACDB */ + gsl_memset(&spf_sg_conn_blob, 0, sizeof(struct gsl_blob)); + if (num_sg_conn) { + rc = gsl_acdb_get_subgraph_connections(sg_conn, num_sg_conn, + &spf_sg_conn_blob); + if (rc == AR_ENOTEXIST) { + GSL_ERR("got 0 size for sg connection blob"); + rc = AR_EOK; + } else if (rc) {/* Continue closing SGs if rc is non-zero */ + GSL_ERR("failed to get size for sg connection blob %d", rc); + } + } + + /* + * Compute total size of the close command, it is equal to + * size of the SUB_GRAPH_LIST PID payload plus subgraph connection + * blob size + */ + if (sgids.len) + sg_list_pid_size = (uint32_t)(sizeof(struct apm_module_param_data_t) + + (sizeof(uint32_t) * (1 + (size_t)sgids.len))); + padded_bytes = GSL_PADDING_8BYTE_ALIGN(sg_list_pid_size); + close_pld_size += (GSL_ALIGN_8BYTE(sg_list_pid_size)) + + spf_sg_conn_blob.size; + + rc = gsl_msg_alloc(APM_CMD_GRAPH_CLOSE, graph->src_port, + GSL_GPR_DST_PORT_APM, sizeof(*cmd_header), 0, graph->proc_id, + close_pld_size, false, &gsl_msg); + if (rc) { + GSL_ERR("gsl msg alloc failed for close %d", rc); + goto exit; + } + + close_payload = (int8_t *)gsl_msg.payload; + /* construct SUB_GRAPH_LIST PID */ + if (sgids.len) { + param_data = (struct apm_module_param_data_t *) close_payload; + param_size = (1 + sgids.len) * sizeof(uint32_t); + param_data->module_instance_id = GSL_GPR_DST_PORT_APM; + param_data->param_id = APM_PARAM_ID_SUB_GRAPH_LIST; + param_data->param_size = param_size; + close_payload += sizeof(*param_data); + *((uint32_t *)close_payload) = sgids.len; + close_payload += sizeof(uint32_t); + gsl_memcpy(close_payload, close_pld_size, sgids.sg_ids, + sizeof(uint32_t) * sgids.len); + /* + * advance the close_payload by sgids.len words + * to store the connection blob (if any) + */ + close_payload += (sgids.len * sizeof(uint32_t)); + close_payload += padded_bytes; + } + /* construct Data/Control link PID by reading it from ACDB */ + if (spf_sg_conn_blob.size) { + spf_sg_conn_blob.buf = close_payload; + rc = gsl_acdb_get_subgraph_connections(sg_conn, num_sg_conn, + &spf_sg_conn_blob); + if (rc) { + GSL_ERR("Failed to get subgraph connection blob for close %d", rc); + /* Subtract sg_conn_blob size from close_pld_size */ + close_pld_size -= spf_sg_conn_blob.size; + } + } + + /* skip sending message to spf if SSR happened */ + if (gsl_graph_get_state(graph) != GRAPH_ERROR) { + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, gsl_msg.gpr_packet); + + cmd_header->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + cmd_header->payload_address_msw = + (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + cmd_header->payload_size = close_pld_size; + cmd_header->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*cmd_header), gsl_msg.payload, + close_pld_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP3_CMD_SIG]); + if (rc) + GSL_ERR("Graph close failed:%d", rc); + } + + gsl_msg_free(&gsl_msg); + +exit: + return rc; +} + +static int32_t gsl_graph_remove_sgs_w_props(struct gsl_graph_gkv_node *gkv_node, + struct gsl_cmd_properties *props) +{ + uint32_t i = 0, j = 0, k, num_removed_sgids = 0; + uint32_t *removed_sgids = 0; + struct gsl_subgraph **sg_list = gkv_node->sg_array; + AcdbSubgraph *sg_conn_entry = gkv_node->sg_conn_data.subgraphs; + AcdbSubgraph *next_sg_conn_entry = NULL; + size_t entry_size = 0; + size_t size_to_copy = 0; + size_t remaining_bytes = gkv_node->sg_conn_data.size; + size_t updated_total_sg_conn_size = gkv_node->sg_conn_data.size; + int32_t rc = AR_EOK; + uint8_t *mem_tmp = NULL; + + if (!props) { + rc = AR_EBADPARAM; + return rc; + } + + if (gkv_node->num_of_subgraphs == 0) + return AR_EOK; + + mem_tmp = gsl_mem_zalloc(gkv_node->sg_conn_data.size); + if (!mem_tmp) { + rc = AR_ENOMEMORY; + goto exit; + } + + removed_sgids = + gsl_mem_zalloc(gkv_node->num_of_subgraphs * sizeof(uint32_t)); + if (!removed_sgids) { + rc = AR_ENOMEMORY; + goto cleanup; + } + + /* next, remove all matching SGs and conns from those SGs*/ + while (i < gkv_node->num_of_subgraphs) { + /* + * find size of current entry in sg_conn data and start of next entry + */ + entry_size = sizeof(AcdbSubgraph) + + sg_conn_entry->num_dst_sgids * sizeof(uint32_t); + next_sg_conn_entry = (AcdbSubgraph *)((uint8_t *)sg_conn_entry + + entry_size); + remaining_bytes -= entry_size; + + /* if match, remove sg from sg_list and global pool */ + if (is_matching_sg_property(gkv_node->sg_array[i], props)) { + /* store SGID for removing conns later */ + removed_sgids[num_removed_sgids] = gkv_node->sg_array[i]->sg_id; + ++num_removed_sgids; + + gsl_sg_pool_remove(gkv_node->sg_array[i], FALSE); + + /* + * Remove the subgraph from this GKV + */ + for (k = i; k < gkv_node->num_of_subgraphs - 1; ++k) { + sg_list[k] = sg_list[k+1]; + /* right shift the bit corresopinging to sg k+1 by 1 */ + gkv_node->sg_start_mask |= + (gkv_node->sg_start_mask & (1 << (k + 1))) >> 1; + gkv_node->sg_stop_mask |= + (gkv_node->sg_stop_mask & (1 << (k + 1))) >> 1; + } + clear_bit(gkv_node->sg_start_mask, k); + clear_bit(gkv_node->sg_stop_mask, k); + --gkv_node->num_of_subgraphs; + + /* + * remove entry for sg from sg conn info blob, note assumption is + * that subgraph entries in conn blob are in same order as sg_array + */ + gsl_memcpy(mem_tmp, remaining_bytes, next_sg_conn_entry, + remaining_bytes); + gsl_memcpy(sg_conn_entry, remaining_bytes, mem_tmp, + remaining_bytes); + updated_total_sg_conn_size -= entry_size; + } else { + /* move to next entry */ + sg_conn_entry = next_sg_conn_entry; + ++i; + } + } + + i = 0; + remaining_bytes = updated_total_sg_conn_size; + sg_conn_entry = gkv_node->sg_conn_data.subgraphs; + + /* loop through remaining SG conns and strip conns to removed SGIDs */ + while (i < gkv_node->num_of_subgraphs) { + /* + * find size of current entry in sg_conn data. It may change so find + * next entry later + */ + entry_size = sizeof(AcdbSubgraph) + + sg_conn_entry->num_dst_sgids * sizeof(uint32_t); + remaining_bytes -= entry_size; + + /* for each removed SGID, see if we find a match in the list */ + for (k = 0; k < num_removed_sgids; ++k) { + j = 0; + while (j < sg_conn_entry->num_dst_sgids) { + if (sg_conn_entry->dst_sg_ids[j] == removed_sgids[k]) { + /* + * found match: this connection needs to be removed + * copy the rest of array back 1 uint32_t + */ + size_to_copy = remaining_bytes + + (sg_conn_entry->num_dst_sgids - j - 1) + * sizeof(uint32_t); + gsl_memcpy(mem_tmp, size_to_copy, + sg_conn_entry->dst_sg_ids + j + 1, size_to_copy); + gsl_memcpy(sg_conn_entry->dst_sg_ids + j, size_to_copy, + mem_tmp, size_to_copy); + --sg_conn_entry->num_dst_sgids; + entry_size -= sizeof(uint32_t); + updated_total_sg_conn_size -= sizeof(uint32_t); + } else { + /* only advance when we didn't overwrite */ + ++j; + } + } + } + + /* find start of next entry */ + next_sg_conn_entry = (AcdbSubgraph *)((uint8_t *)sg_conn_entry + + entry_size); + + sg_conn_entry = next_sg_conn_entry; + ++i; + } + + gkv_node->sg_conn_data.size = updated_total_sg_conn_size; + gkv_node->sg_conn_data.num_sgs = gkv_node->num_of_subgraphs; + + gsl_mem_free(removed_sgids); +cleanup: + gsl_mem_free(mem_tmp); +exit: + return rc; +} + +/** Graph close for single GKV. Called with open_close_mutex lock acquired */ +static int32_t gsl_graph_close_single_gkv(struct gsl_graph *graph, + struct gsl_graph_gkv_node *gkv_node, uint32_t num_force_close_sgs, + uint32_t *force_close_sgs, + struct gsl_graph_sg_conn_data *force_close_sg_conn, + struct gsl_cmd_properties *props, bool_t preserve_gkv_node) +{ + int32_t rc = AR_EOK; + struct gsl_subgraph *sg; + AcdbSubgraph *pruned_sg_conn, *sg_conn, *p; + uint8_t *pruned_sg_info = NULL; + uint32_t i, j, num_sg_conn = 0; + size_t pruned_sg_info_sz; + struct gsl_sgid_list pruned_sg_ids = {0, NULL}; + struct gsl_sgobj_list sg_obj_list; + uint32_t total_num_sgs_to_close = 0; + struct gsl_glbl_persist_cal *tmp_gpcal; + gpr_packet_t *send_pkt = NULL; + struct apm_cmd_header_t *cmd_header; + uint64_t paddr_w_offset = 0; + /* holds the number of pruned sgs plus number of force close sgs */ + + /* + * Allocate max size required to store pruned sg_id list and sg connection + * info. The allocation size takes into account the force close sg list + * as well as the force close sg connection info + */ + //TODO remove all force_close references + pruned_sg_info_sz = ((size_t)gkv_node->num_of_subgraphs + + num_force_close_sgs) * sizeof(uint32_t) + gkv_node->sg_conn_data.size; + if (force_close_sg_conn) + pruned_sg_info_sz += force_close_sg_conn->size; + + pruned_sg_info = gsl_mem_zalloc(pruned_sg_info_sz); + if (!pruned_sg_info) + return AR_ENOMEMORY; + + /* + * Copy the sgs in force close list to the head of pruned_sg_info, these + * sgs will always be closed + */ + if (force_close_sgs) + gsl_memcpy(pruned_sg_info, pruned_sg_info_sz, force_close_sgs, + sizeof(uint32_t) * num_force_close_sgs); + /* below we offset by num_force_close_sgs */ + pruned_sg_ids.sg_ids = (uint32_t *)(pruned_sg_info + (sizeof(uint32_t) * + num_force_close_sgs)); + pruned_sg_ids.len = 0; + (void)gsl_sg_pool_prune_sg_list(gkv_node->sg_array, + gkv_node->num_of_subgraphs, props, &pruned_sg_ids, NULL); + total_num_sgs_to_close = pruned_sg_ids.len + num_force_close_sgs; + + pruned_sg_conn = (AcdbSubgraph *)((int8_t *)pruned_sg_ids.sg_ids + + sizeof(uint32_t) * gkv_node->num_of_subgraphs); + + /* + * Copy the force close sg connection entries to head of + * pruned_sg_conn, these sg connections will always be closed + */ + p = pruned_sg_conn; + if (force_close_sg_conn) { + gsl_memcpy(p, force_close_sg_conn->size, + force_close_sg_conn->subgraphs, force_close_sg_conn->size); + p = (AcdbSubgraph *)((uint8_t *)p + force_close_sg_conn->size); + num_sg_conn = force_close_sg_conn->num_sgs; + } + + /* + * Now remove the children of each subgraph that is to be closed and + * update pruned_sg_conn as needed + */ + i = 0; + sg_conn = gkv_node->sg_conn_data.subgraphs; + while (i < gkv_node->num_of_subgraphs) { + rc = gsl_subgraph_remove_children(gkv_node->sg_array[i], sg_conn, + props, p); + if (p->num_dst_sgids) { + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + + p->num_dst_sgids); + ++num_sg_conn; + } + ++i; + sg_conn = (AcdbSubgraph *)((uint32_t *)sg_conn->dst_sg_ids + + sg_conn->num_dst_sgids); + } + + if (total_num_sgs_to_close == 0 && num_sg_conn == 0) { + /* nothing to close on spf */ + rc = AR_EOK; + goto free_pruned_sg_info; + } + + /* + * Now we know everything that needs to be closed, send close command to + * SPF + */ + pruned_sg_ids.sg_ids = (uint32_t *)pruned_sg_info; + pruned_sg_ids.len = total_num_sgs_to_close; + + /* deregister persistent calibration */ + for (i = 0; i < pruned_sg_ids.len; ++i) { + sg_obj_list.len = gkv_node->num_of_subgraphs; + sg_obj_list.sg_objs = gkv_node->sg_array; + sg = gsl_graph_get_sg_ptr(&sg_obj_list, pruned_sg_ids.sg_ids[i]); + if (!sg){ + GSL_ERR("Failed to get sg_ptr for index %d", i); + continue; + } + for (int procid = 0; procid < sg->num_proc_ids; procid++) { + if ( sg->persist_cal_data_per_proc[procid].persist_cal_data.handle) { + rc = gsl_allocate_gpr_packet(APM_CMD_DEREGISTER_CFG, + graph->src_port, APM_MODULE_INSTANCE_ID, sizeof(*cmd_header), + 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + continue; + } + /* + * below offset used to skip acdb header before sending data to + * spf + */ + paddr_w_offset = sg->persist_cal_data_per_proc[procid].persist_cal_data.spf_addr + + sizeof(AcdbSgIdPersistData); + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + cmd_header->mem_map_handle = sg->persist_cal_data_per_proc[procid].persist_cal_data.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)paddr_w_offset; + cmd_header->payload_address_msw = (uint32_t)(paddr_w_offset >> 32); + cmd_header->payload_size = sg->persist_cal_data_per_proc[procid].persist_cal_data_size - + sizeof(AcdbSgIdPersistData); + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), + sg->persist_cal_data_per_proc[procid].persist_cal_data.v_addr, cmd_header->payload_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("Graph deregister cfg cmd 0x%x failure:%d", + APM_CMD_DEREGISTER_CFG, rc); + } + } + } + if (sg && sg->user_persist_cfg_data.handle) { + rc = gsl_allocate_gpr_packet(APM_CMD_DEREGISTER_CFG, + graph->src_port, APM_MODULE_INSTANCE_ID, sizeof(*cmd_header), + 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + continue; + } + /* + * below offset used to skip acdb header before sending data to + * spf + */ + paddr_w_offset = sg->cma_persist_cfg_data.spf_addr + + sizeof(AcdbSgIdPersistData); + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + cmd_header->mem_map_handle + = sg->cma_persist_cfg_data.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)paddr_w_offset; + cmd_header->payload_address_msw = (uint32_t)(paddr_w_offset >> 32); + cmd_header->payload_size = sg->cma_cal_data_size - + sizeof(AcdbSgIdPersistData); + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), + sg->cma_persist_cfg_data.v_addr, cmd_header->payload_size); + + send_pkt->client_data |= GSL_GPR_CMA_FLAG_BIT; + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("Graph deregister cfg cmd 0x%x failure:%d", + APM_CMD_DEREGISTER_CFG, rc); + } + } + } + + rc = gsl_graph_close_sgids_and_connections(graph, pruned_sg_ids, + pruned_sg_conn, num_sg_conn); + + /** Free persist cal shared memory if exists */ + for (i = 0; i < pruned_sg_ids.len; ++i) { + sg_obj_list.len = gkv_node->num_of_subgraphs; + sg_obj_list.sg_objs = gkv_node->sg_array; + sg = gsl_graph_get_sg_ptr(&sg_obj_list, pruned_sg_ids.sg_ids[i]); + if (sg) { + for (int i = 0; i < sg->num_proc_ids; i++) { + if (sg->persist_cal_data_per_proc[i].persist_cal_data.handle) { + gsl_shmem_free(&sg->persist_cal_data_per_proc[i].persist_cal_data); + sg->persist_cal_data_per_proc[i].persist_cal_data.v_addr = NULL; + sg->persist_cal_data_per_proc[i].persist_cal_data.handle = NULL; + sg->persist_cal_data_per_proc[i].persist_cal_data_size = 0; + } + } + } + if (sg && sg->user_persist_cfg_data.handle) { + gsl_shmem_free(&sg->user_persist_cfg_data); + sg->user_persist_cfg_data.v_addr = NULL; + sg->user_persist_cfg_data.handle = NULL; + sg->user_persist_cfg_data_size = 0; + } + if (sg && sg->cma_persist_cfg_data.handle) { + GSL_VERBOSE("freeing cma data for sg 0x%x", sg->sg_id); + + /* Free handles the hyp_assign for ML memory */ + gsl_shmem_free(&sg->cma_persist_cfg_data); + sg->cma_persist_cfg_data.v_addr = NULL; + sg->cma_persist_cfg_data.handle = NULL; + sg->cma_cal_data_size = 0; + } + } + + /* + * skip freeing global persist cal if props are provided since gkv node + * itself wont be freed in this case. the global persist will be freed once + * client closes the entire gkv node + */ + if (props) + goto free_pruned_sg_info; + + /* Close any opened global persist cals */ + for (i = 0; i < gkv_node->num_of_gp_cals; ++i) { + + tmp_gpcal = gkv_node->glbl_persist_cal_list[i].gpcal; + + for (j = 0; j < gkv_node->glbl_persist_cal_list[i].num_iids; ++j) { + if (gsl_allocate_gpr_packet(APM_CMD_DEREGISTER_SHARED_CFG, + graph->src_port, gkv_node->glbl_persist_cal_list[i].iids[j], + sizeof(*cmd_header), 0, graph->proc_id, &send_pkt) != AR_EOK) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + continue; + } + + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + cmd_header->mem_map_handle = tmp_gpcal->cal_data.spf_mmap_handle; + cmd_header->payload_address_lsw = + (uint32_t)tmp_gpcal->cal_data.spf_addr; + cmd_header->payload_address_msw = + (uint32_t)(tmp_gpcal->cal_data.spf_addr >> 32); + + GSL_LOG_PKT("send_pkt", graph->src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), NULL, 0); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("Deregister shared cfg for iid %d failed:%d", + gkv_node->glbl_persist_cal_list[i].iids[j], rc); + continue; + } + } + gsl_global_persist_cal_pool_remove(tmp_gpcal); + } + if (gkv_node->glbl_persist_cal_list) { + gsl_mem_free(gkv_node->glbl_persist_cal_list); + gkv_node->glbl_persist_cal_list = NULL; + gkv_node->num_of_gp_cals = 0; + } + + rc = gsl_mdf_utils_deregister_dynamic_pd(graph->ss_mask, graph->proc_id); + if (rc) + GSL_ERR("dynamic pd de-init failed, status %d", rc); + +free_pruned_sg_info: + rc = check_and_deregister_dynamic_pd(graph, &pruned_sg_ids); + + if (props) { + rc = gsl_graph_remove_sgs_w_props(gkv_node, props); + } else { + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) + gsl_sg_pool_remove(gkv_node->sg_array[i], FALSE); + + if (!preserve_gkv_node) { + gsl_mem_free(gkv_node->sg_array); + gkv_node->sg_array = NULL; + gsl_mem_free(gkv_node->sg_conn_data.subgraphs); + gkv_node->sg_conn_data.subgraphs = NULL; + + gsl_mem_free(gkv_node->gkv.kvp); + gkv_node->gkv.kvp = NULL; + gsl_mem_free(gkv_node->ckv.kvp); + gkv_node->ckv.kvp = NULL; + } + } + gsl_mem_free(pruned_sg_info); + + return rc; +} + +/* + * This function adds SG ids and connections to the pool. It also updates the + * member variables of gkv_node structure:- num_of_subgraphs, sg_array and + * sg_connections. + * Output parameters: pruned list of SG ids and sg_connections + */ +static int32_t gsl_graph_add_and_prune_sgs_and_connections( + struct gsl_graph_gkv_node *gkv_node, struct gsl_sgid_list sg_list, + AcdbSubgraph *sg_conn_info, size_t sz_sg_conn, + struct gsl_sgid_list *pruned_sg_list, + struct gsl_graph_sg_conn_data *pruned_sg_connections, + struct gsl_sgid_list *existing_sgid_list, + struct gsl_graph_sg_conn_data *existing_sg_connections) +{ + int32_t rc = AR_EOK; + uint32_t i, num_sg_conn = 0, num_existing_conn = 0; + AcdbSubgraph *sg_conn = NULL, *pruned_sg_conn = NULL, *p, + *existing_sg_conn = NULL, *q = NULL; + + /** Init OUT parameters */ + pruned_sg_list->len = 0; + pruned_sg_list->sg_ids = NULL; + pruned_sg_connections->subgraphs = NULL; + pruned_sg_connections->num_sgs = 0; + + if (existing_sgid_list) { + existing_sgid_list->len = 0; + existing_sgid_list->sg_ids = NULL; + } + if (existing_sg_connections) { + existing_sg_connections->subgraphs = NULL; + existing_sg_connections->num_sgs = 0; + } + + if (sg_list.len == 0 && sz_sg_conn == 0) + return AR_EOK; /* nothing to be added */ + + gkv_node->num_of_subgraphs = sg_list.len; + gkv_node->sg_conn_data.num_sgs = sg_list.len; + gkv_node->sg_conn_data.size = sz_sg_conn; + /* below pointer is freed as part of graph close */ + gkv_node->sg_conn_data.subgraphs = sg_conn_info; + + /* Add graph's sub-graphs to sub-graph pool */ + gkv_node->sg_array = gsl_mem_zalloc(gkv_node->num_of_subgraphs * + sizeof(struct gsl_subgraph *)); + if (!gkv_node->sg_array) { + rc = AR_ENOMEMORY; + goto exit; + } + + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) + gkv_node->sg_array[i] = gsl_sg_pool_add(sg_list.sg_ids[i], FALSE); + /* + * allocate memory to store pruned sg list + */ + pruned_sg_list->len = 0; + pruned_sg_list->sg_ids = gsl_mem_zalloc(gkv_node->num_of_subgraphs * + sizeof(uint32_t)); + if (!pruned_sg_list->sg_ids) { + rc = AR_ENOMEMORY; + goto free_sg_array; + } + if (existing_sgid_list) { + existing_sgid_list->sg_ids = gsl_mem_zalloc(gkv_node->num_of_subgraphs * + sizeof(uint32_t)); + if (!existing_sgid_list->sg_ids) { + rc = AR_ENOMEMORY; + goto free_pruned_list; + } + } + + rc = gsl_sg_pool_prune_sg_list(gkv_node->sg_array, + gkv_node->num_of_subgraphs, NULL, pruned_sg_list, + existing_sgid_list); + if (AR_FAILED(rc)) { + GSL_ERR("subgraph prune for open failed: %d", rc); + goto remove_from_pool; + } + + /* Add and prune children for each subgraph-id in the graph */ + pruned_sg_conn = gsl_mem_zalloc(sz_sg_conn); + if (!pruned_sg_conn) { + rc = AR_ENOMEMORY; + goto remove_from_pool; + } + + if (existing_sg_connections) { + existing_sg_conn = gsl_mem_zalloc(sz_sg_conn); + if (!existing_sg_conn) { + rc = AR_ENOMEMORY; + goto remove_from_pool; + } + } + + i = 0; + sg_conn = sg_conn_info; + p = pruned_sg_conn; + if (existing_sg_conn) + q = existing_sg_conn; + + while (i < gkv_node->num_of_subgraphs) { + rc = gsl_subgraph_add_children(gkv_node->sg_array[i], sg_conn, p, q); + if (p->num_dst_sgids) { + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + + p->num_dst_sgids); /* move to next pruned_sg_conn row */ + ++num_sg_conn; + } + /* for existing, store all conn objects even empty from existing SGs. + * existing sg list is in same order as sg list. + */ + if (q && existing_sgid_list + && existing_sgid_list->sg_ids[num_existing_conn] + == gkv_node->sg_array[i]->sg_id) { + q = (AcdbSubgraph *)((uint32_t *)q->dst_sg_ids + + q->num_dst_sgids); /* move to next existing_sg_conn row */ + ++num_existing_conn; + } + + ++i; + sg_conn = (AcdbSubgraph *)((uint32_t *)sg_conn->dst_sg_ids + + sg_conn->num_dst_sgids); /* move to next sg_conn row */ + } + + /* now that all the children are added to pool, update their references */ + gsl_sg_pool_update_child_refs(); + + if (num_sg_conn) { + pruned_sg_connections->subgraphs = pruned_sg_conn; + pruned_sg_connections->num_sgs = num_sg_conn; + pruned_sg_connections->size = + (uint8_t *)p - (uint8_t *)pruned_sg_conn; + } else { + gsl_mem_free(pruned_sg_conn); + pruned_sg_conn = NULL; + pruned_sg_connections->num_sgs = 0; + pruned_sg_connections->size = 0; + pruned_sg_connections->subgraphs = NULL; + } + + if (num_existing_conn) { + existing_sg_connections->subgraphs = existing_sg_conn; + existing_sg_connections->num_sgs = num_sg_conn; + existing_sg_connections->size = + (uint8_t *)q - (uint8_t *)existing_sg_conn; + } else if (existing_sg_connections) { + gsl_mem_free(existing_sg_conn); + existing_sg_conn = NULL; + existing_sg_connections->num_sgs = 0; + existing_sg_connections->size = 0; + existing_sg_connections->subgraphs = NULL; + } + + rc = gsl_mdf_utils_query_graph_ss_mask(sg_list.sg_ids, + gkv_node->num_of_subgraphs, &gkv_node->spf_ss_mask); + if (rc != AR_EOK) { + GSL_ERR("failed to get spf_ss_mask %d", rc); + goto remove_sg_children; + } + + return rc; + +remove_sg_children: + p = sg_conn_info; + i = 0; + while (i < gkv_node->num_of_subgraphs) { + gsl_subgraph_remove_children(gkv_node->sg_array[i++], p, NULL, NULL); + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + p->num_dst_sgids); + } + + if (existing_sg_conn) { + gsl_mem_free(existing_sg_conn); + existing_sg_connections->num_sgs = 0; + existing_sg_connections->size = 0; + existing_sg_connections->subgraphs = NULL; + } +remove_from_pool: + if (pruned_sg_conn) + gsl_mem_free(pruned_sg_conn); + pruned_sg_connections->num_sgs = 0; + pruned_sg_connections->size = 0; + pruned_sg_connections->subgraphs = NULL; + + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) + gsl_sg_pool_remove(gkv_node->sg_array[i], FALSE); + if (existing_sgid_list) { + gsl_mem_free(existing_sgid_list->sg_ids); + existing_sgid_list->len = 0; + existing_sgid_list->sg_ids = NULL; + } +free_pruned_list: + gsl_mem_free(pruned_sg_list->sg_ids); + pruned_sg_list->len = 0; + pruned_sg_list->sg_ids = NULL; + +free_sg_array: + gsl_mem_free(gkv_node->sg_array); + +exit: + return rc; +} + +/** + * Opens SG IDS and Connections on Spf. Subgraph_Data and + * SG_Connections_Data are retrieved from the acdb for the given + * sgids and sg_connections and sent to Spf. Also applies calibration + * using ckv for the SGIDS that are opened on spf. + */ +static int32_t gsl_graph_open_sgids_and_connections(struct gsl_graph *graph, + struct gsl_graph_gkv_node *gkv_node, + struct gsl_sgid_list *sgids, struct gsl_graph_sg_conn_data *sg_conn, + struct gsl_key_vector *gkv, struct gsl_key_vector *ckv) +{ + uint32_t graph_open_size = 0, i; + struct gsl_blob spf_blob, spf_sg_conn_blob; + struct apm_cmd_header_t *open_cmd; + AcdbDriverPropertyData drv_blob; + int32_t rc = AR_EOK; + struct gsl_sgobj_list sg_obj_list; + gsl_msg_t gsl_msg; + bool_t is_shmem_supported = TRUE; + bool_t dyn_pd_registered = FALSE; + uint32_t dyn_ss_mask = 0; + + /* check if there are any sub-graphs or edges to open */ + if ((sgids->len == 0) && (sg_conn->num_sgs == 0)) + return AR_EOK; /**< nothing to open on SPF */ + + gsl_memset(&spf_blob, 0, sizeof(struct gsl_blob)); + gsl_memset(&drv_blob, 0, sizeof(AcdbDriverPropertyData)); + gsl_memset(&spf_sg_conn_blob, 0, sizeof(struct gsl_blob)); + + /** Get subgraph data size for spf and drv blobs */ + GSL_DBG("num_sgid= %d", sgids->len); + GSL_DBG("sg list:"); + for (i = 0; i < sgids->len; ++i) + GSL_DBG("%x", sgids->sg_ids[i]); + if (sgids->len) { + rc = gsl_acdb_get_subgraph_data(sgids, gkv, &spf_blob, &drv_blob); + if (rc) { + GSL_ERR("get subgraph data for size failed: %d", rc); + goto exit; + } + + /* + * Get graph proc id. Need driver blob only. + * Hence setting spf blob to NULL + */ + spf_blob.buf = NULL; + spf_blob.size = 0; + /* Alloc memory for SG driver property data */ + drv_blob.sub_graph_prop_data = gsl_mem_zalloc(drv_blob.size); + if (!drv_blob.sub_graph_prop_data) { + rc = AR_ENOMEMORY; + goto exit; + } + + /* + * spf_blob buf is set to NULL & size is set to 0, acdb returns + * driver blob, for spf blob we get back size only. + */ + rc = gsl_acdb_get_subgraph_data(sgids, gkv, &spf_blob, &drv_blob); + if (rc) { + GSL_ERR("get subgraph data failed %d", rc); + goto free_sg_prop_data; + } + + /* Parse driver prop data to get routing id */ + sg_obj_list.sg_objs = gkv_node->sg_array; + sg_obj_list.len = gkv_node->num_of_subgraphs; + + rc = gsl_acdb_parse_sg_drv_prop_data(graph, &sg_obj_list, &drv_blob); + if (rc) { + GSL_ERR("gsl_acdb_parse_sg_drv_prop_data failed with status %d", + rc); + goto free_sg_prop_data; + } + + if ((gsl_spf_ss_state_get(graph->proc_id) & gkv_node->spf_ss_mask) + != gkv_node->spf_ss_mask) { + + rc = AR_ENOTREADY; + goto free_sg_prop_data; + } + /* + * Allocate and map MDF client loaned memory in-case any of the new sgs + * requires any procs other than ADSP + */ + rc = __gpr_cmd_is_shared_mem_supported(graph->proc_id, + &is_shmem_supported); + if (rc) { + GSL_ERR("GPR is shmem supported failed %d", rc) + goto free_sg_prop_data; + } + if (is_shmem_supported) { + rc = check_and_register_dynamic_pd(graph, sgids, + gkv_node->spf_ss_mask, &dyn_ss_mask); + if (rc) { + GSL_ERR("dynamic pd create failed, status %d", rc); + goto free_sg_prop_data; + } + dyn_pd_registered = TRUE; + /* + * If there was a dynamic PD, the allocation would have happened + * already as part of check_and_register_dynamic_pd. + * Remove dynamic PD from ss mask. + */ + gsl_mdf_utils_shmem_alloc(gkv_node->spf_ss_mask & ~dyn_ss_mask, + graph->proc_id); + } + } + + /* Get subgraph connection data size for spf */ + if (sg_conn->num_sgs) { + gsl_print_sg_conn_info((uint32_t *)sg_conn->subgraphs, + sg_conn->num_sgs); + + rc = gsl_acdb_get_subgraph_connections(sg_conn->subgraphs, + sg_conn->num_sgs, &spf_sg_conn_blob); + if (rc == AR_ENOTEXIST) { + GSL_ERR("got 0 size for subgraph conn data, rc %d", rc); + rc = AR_EOK; + } else if (rc) { + GSL_ERR("get subgraph conn data for size failed: %d, size:%d", rc, + spf_sg_conn_blob.size); + goto free_sg_prop_data; + } + } + + graph_open_size = spf_blob.size + spf_sg_conn_blob.size; + if (graph_open_size == 0) { + GSL_ERR("spf blob size for open is zero"); + rc = AR_EFAILED; + goto free_sg_prop_data; + } + + /* + * Allocate shared memory to hold spf blob (sg data and connections) + * for OPEN command and map on SPF + */ + rc = gsl_msg_alloc(APM_CMD_GRAPH_OPEN, graph->src_port, + GSL_GPR_DST_PORT_APM, sizeof(*open_cmd), 0, graph->proc_id, + graph_open_size, false, &gsl_msg); + if (rc) { + GSL_ERR("GSL MSG alloc failed size: %d rc:%d", graph_open_size, rc); + goto free_sg_prop_data; + } + + if (spf_blob.size) { + spf_blob.buf = gsl_msg.payload; + /* Get both spf data blob and subgraph driver property blob */ + rc = gsl_acdb_get_subgraph_data(sgids, gkv, &spf_blob, &drv_blob); + if (rc) { + GSL_ERR("get subgraph data failed %d", rc); + goto free_gsl_msg; + } + } + + if (spf_sg_conn_blob.size) { + spf_sg_conn_blob.buf = (int8_t *)gsl_msg.payload + + spf_blob.size; + rc = gsl_acdb_get_subgraph_connections(sg_conn->subgraphs, + sg_conn->num_sgs, &spf_sg_conn_blob); + if (rc) { + GSL_ERR("get subgraph conn data failed: %d", rc); + goto free_gsl_msg; + } + } + + open_cmd = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, gsl_msg.gpr_packet); + open_cmd->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + open_cmd->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + open_cmd->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + open_cmd->payload_size = graph_open_size; + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*open_cmd), gsl_msg.payload, + graph_open_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP1_CMD_SIG]); + if (rc) { + GSL_ERR("Graph open failed:%d", rc); + goto free_gsl_msg; + } + + sg_obj_list.len = gkv_node->num_of_subgraphs; + sg_obj_list.sg_objs = gkv_node->sg_array; + + /* Apply cal */ + if (sgids->len) { + GSL_MUTEX_LOCK(graph->get_set_cfg_lock); + rc = gsl_graph_set_sg_cal(graph, sgids, gkv_node, ckv, gkv, false); + GSL_MUTEX_UNLOCK(graph->get_set_cfg_lock); + if (rc == AR_EUNSUPPORTED || rc == AR_ENOTEXIST) { + /* + * we let open succeed since ENOTEXIST is benign and EUNSUPPORTED is + * widespread. We should get everyone to fix their EUNSUPPORTEDs in + * the future by opening CRs. + */ + GSL_DBG("graph set cal failed:%d", rc); + rc = AR_EOK; + } else if (rc != AR_EOK) { + /* + * for other serious cal failures, we need to send close on SPF + * Caller function will handle the internal clean-up + * This is to ensure that GSL and SPF and client all have the same + * state of a graph. We must fail on set cal fail, since some cals + * e.g. speaker protection are essential + * + * we ignore RC of close fail -- cleanup function & preserve + * original error + */ + GSL_ERR("set sg cal failed, closing all opened SGs: %d", rc); + gsl_graph_close_sgids_and_connections(graph, *sgids, + sg_conn->subgraphs, sg_conn->num_sgs); + } + } + +free_gsl_msg: + gsl_msg_free(&gsl_msg); + +free_sg_prop_data: + gsl_mem_free(drv_blob.sub_graph_prop_data); + if (rc != AR_EOK && dyn_pd_registered) + gsl_mdf_utils_deregister_dynamic_pd(graph->ss_mask, graph->proc_id); + +exit: + return rc; +} + +/* Graph open for single GKV. Called with open_close_mutex lock acquired */ +static int32_t gsl_graph_open_single_gkv(struct gsl_graph *graph, + const struct gsl_key_vector *gkv, const struct gsl_key_vector *ckv, + struct gsl_graph_gkv_node *gkv_node) +{ + int32_t rc; + struct gsl_sgid_list pruned_sgids = {0, NULL}; + struct gsl_sgid_list sgids = {0, NULL}; + uint32_t i = 0; + AcdbGetGraphRsp sg_conn_info; + struct gsl_graph_sg_conn_data pruned_sg_conn = {0,}; + AcdbSubgraph *p; + + /* Get graph data from ACDB */ + rc = gsl_acdb_get_graph(gkv, &sgids.sg_ids, &sg_conn_info); + if (rc) { + GSL_ERR("acdb get graph failed %d", rc); + goto cleanup; + } + + /** + * Add SGIDs and connections to the pool. Get pruned sgid list + * sg connections after adding them to the pool. + */ + sgids.len = sg_conn_info.num_subgraphs; + pruned_sgids.len = 0; + pruned_sgids.sg_ids = NULL; + rc = gsl_graph_add_and_prune_sgs_and_connections(gkv_node, sgids, + sg_conn_info.subgraphs, sg_conn_info.size, &pruned_sgids, + &pruned_sg_conn, NULL, NULL); + if (rc) + goto cleanup; + + /** + * update the graph level ss_mask to reflect this gkv + */ + graph->ss_mask |= gkv_node->spf_ss_mask; + + /** Now open the pruned sgid list and connections */ + rc = gsl_graph_open_sgids_and_connections(graph, gkv_node, &pruned_sgids, + &pruned_sg_conn, (struct gsl_key_vector *)gkv, + (struct gsl_key_vector *)ckv); + if (AR_SUCCEEDED(rc)) { + /** Add GKV and CKV to GKV_node */ + gsl_graph_update_gkv_node(gkv_node, gkv, ckv); + gsl_graph_add_gkv_to_list(graph, gkv_node); + } else { + /* + * in the failure case, remove the sgids and connections + * of the given gkv from the pool + */ + p = gkv_node->sg_conn_data.subgraphs; + i = 0; + while (i < gkv_node->num_of_subgraphs) { + gsl_subgraph_remove_children(gkv_node->sg_array[i++], p, NULL, + NULL); + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + p->num_dst_sgids); + } + + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) + gsl_sg_pool_remove(gkv_node->sg_array[i], FALSE); + + gsl_mem_free(gkv_node->sg_array); + gsl_mem_free(gkv_node->sg_conn_data.subgraphs); + } + +cleanup: + if (pruned_sgids.sg_ids) + gsl_mem_free(pruned_sgids.sg_ids); + if (pruned_sg_conn.subgraphs) + gsl_mem_free(pruned_sg_conn.subgraphs); + if (sgids.sg_ids) + gsl_mem_free(sgids.sg_ids); + + return rc; +} + +static int32_t gsl_graph_suspend_check_and_stop_instead(struct gsl_graph *graph, + struct gsl_graph_gkv_node *gkv_node) +{ + uint32_t *sg_id_list, *num_sg, i; + int32_t rc = AR_EOK; + uint32_t *stop_payload, pld_size; + struct apm_cmd_header_t *cmd_header; + struct apm_module_param_data_t *module_param; + struct gsl_subgraph *sg; + gsl_msg_t gsl_msg; + + pld_size = (uint32_t)(sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE( + sizeof(uint32_t) * (1 + (size_t)gkv_node->num_of_subgraphs))); + + /* Allocate the maximum size that could be needed + * This stops us from having to memcpy into the packet, but needs larger + * initial packet allocation (see where we update payload size below) + */ + rc = gsl_msg_alloc(APM_CMD_GRAPH_STOP, graph->src_port, + GSL_GPR_DST_PORT_APM, pld_size, 0, graph->proc_id, 0, true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate gsl msg %d", rc); + goto exit; + } + + stop_payload = GPR_PKT_GET_PAYLOAD(uint32_t, gsl_msg.gpr_packet); + gsl_memset(stop_payload, 0, pld_size); + + module_param = (struct apm_module_param_data_t *) + ((int8_t *)stop_payload + sizeof(*cmd_header)); + module_param->module_instance_id = GSL_GPR_DST_PORT_APM; + module_param->param_id = APM_PARAM_ID_SUB_GRAPH_LIST; + + num_sg = (uint32_t *)((int8_t *)stop_payload + + sizeof(*cmd_header) + sizeof(*module_param)); + + *num_sg = 0; + sg_id_list = num_sg + 1; + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + sg = gkv_node->sg_array[i]; + /** + * send stop command for SGs + * which are stopped from other GKVs but in start state + * only in this GKV. + */ + if ((sg && test_bit(gkv_node->sg_start_mask, i) && + (sg->start_ref_cnt == 1) && (sg->stop_ref_cnt > 0))) { + *sg_id_list++ = sg->sg_id; + (*num_sg)++; + } + } + if ((*num_sg) == 0) { + GSL_DBG("NO SGs to stop in suspend context"); + rc = AR_EOK; + goto free_msg; + } + + /* + * update payload sizes based on actual number of subgraphs + * that need to be prepared + */ + pld_size = (uint32_t)(sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE(sizeof(uint32_t) * (1 + (size_t)(*num_sg)))); + cmd_header = (struct apm_cmd_header_t *)stop_payload; + cmd_header->payload_size = pld_size - (uint32_t)sizeof(*cmd_header); + module_param->param_size = (1 + (*num_sg)) * (uint32_t)sizeof(uint32_t); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + pld_size, NULL, 0); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP1_CMD_SIG]); + if (rc) + GSL_ERR("Graph stop failed:%d", rc); + +free_msg: + gsl_msg_free(&gsl_msg); +exit: + return rc; +} + +static int32_t gsl_graph_suspend_single_gkv(struct gsl_graph *graph, + struct gsl_graph_gkv_node *gkv_node) +{ + uint32_t *sg_id_list, *num_sg, i; + int32_t rc = AR_EOK; + uint32_t *suspend_payload, pld_size; + struct apm_cmd_header_t *cmd_header; + struct apm_module_param_data_t *module_param; + struct gsl_subgraph *sg; + gsl_msg_t gsl_msg; + + /* If some subgraphs are previously stopped from another GKV + * then send STOP instead of SUSPEND. + */ + rc = gsl_graph_suspend_check_and_stop_instead(graph, gkv_node); + if (rc) { + GSL_ERR("Failed to send stop in suspend context %d", rc); + goto exit; + } + /* now continue to suspend remaining subgraphs. */ + + pld_size = (uint32_t)(sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE( + sizeof(uint32_t) * (1 + (size_t)gkv_node->num_of_subgraphs))); + + /* Allocate the maximum size that could be needed + * This stops us from having to memcpy into the packet, but needs larger + * initial packet allocation (see where we update payload size below) + */ + rc = gsl_msg_alloc(APM_CMD_GRAPH_SUSPEND, graph->src_port, + GSL_GPR_DST_PORT_APM, pld_size, + 0, graph->proc_id, 0, true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate gsl msg %d", rc); + goto exit; + } + + suspend_payload = GPR_PKT_GET_PAYLOAD(uint32_t, gsl_msg.gpr_packet); + gsl_memset(suspend_payload, 0, pld_size); + + module_param = (struct apm_module_param_data_t *) + ((int8_t *)suspend_payload + sizeof(*cmd_header)); + module_param->module_instance_id = GSL_GPR_DST_PORT_APM; + module_param->param_id = APM_PARAM_ID_SUB_GRAPH_LIST; + + num_sg = (uint32_t *)((int8_t *)suspend_payload + + sizeof(*cmd_header) + sizeof(*module_param)); + + *num_sg = 0; + sg_id_list = num_sg + 1; + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + sg = gkv_node->sg_array[i]; + /* + * send suspend command to SGs started only by this GKV + * and are not stopped from any other GKV. + */ + if (sg && test_bit(gkv_node->sg_start_mask, i) && + (sg->start_ref_cnt == 1) && (sg->stop_ref_cnt == 0)) { + *sg_id_list++ = sg->sg_id; + (*num_sg)++; + } + } + if ((*num_sg) == 0) { + GSL_DBG("NO SGs to suspend"); + rc = AR_EOK; + goto decrement_ref_cnt; + } + + /* + * update payload sizes based on actual number of subgraphs + * that need to be prepared + */ + pld_size = (uint32_t)(sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE(sizeof(uint32_t) * (1 + (size_t)(*num_sg)))); + cmd_header = (struct apm_cmd_header_t *)suspend_payload; + cmd_header->payload_size = pld_size - (uint32_t)sizeof(*cmd_header); + module_param->param_size = (1 + (*num_sg)) * (uint32_t)sizeof(uint32_t); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + pld_size, NULL, 0); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP1_CMD_SIG]); + if (rc) { + GSL_ERR("Graph suspend failed:%d", rc); + goto free_msg; + } + +decrement_ref_cnt: + /* decrement start ref count for all SGs */ + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + sg = gkv_node->sg_array[i]; + if (sg && test_bit(gkv_node->sg_start_mask, i)) { + if (sg->start_ref_cnt > 0) + --sg->start_ref_cnt; + clear_bit(gkv_node->sg_start_mask, i); + } + } + +free_msg: + gsl_msg_free(&gsl_msg); +exit: + return rc; +} + +/* optional: props */ +static int32_t gsl_graph_stop_single_gkv(struct gsl_graph *graph, + struct gsl_graph_gkv_node *gkv_node, struct gsl_cmd_properties *props) +{ + uint32_t *sg_id_list, *num_sg, i; + int32_t rc = AR_EOK; + uint32_t *stop_payload, pld_size; + struct apm_cmd_header_t *cmd_header; + struct apm_module_param_data_t *module_param; + struct gsl_subgraph *sg; + gsl_msg_t gsl_msg; + + pld_size = (uint32_t)(sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE(sizeof(uint32_t) * + ((size_t)1 + gkv_node->num_of_subgraphs))); + + /* Allocate the maximum size that could be needed + * This stops us from having to memcpy into the packet, but needs larger + * initial packet allocation (see where we update payload size below) + */ + rc = gsl_msg_alloc(APM_CMD_GRAPH_STOP, graph->src_port, + GSL_GPR_DST_PORT_APM, pld_size, 0, graph->proc_id, 0, true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate gsl msg %d", rc); + goto exit; + } + + stop_payload = GPR_PKT_GET_PAYLOAD(uint32_t, gsl_msg.gpr_packet); + gsl_memset(stop_payload, 0, pld_size); + + module_param = (struct apm_module_param_data_t *) + ((int8_t *)stop_payload + sizeof(*cmd_header)); + module_param->module_instance_id = GSL_GPR_DST_PORT_APM; + module_param->param_id = APM_PARAM_ID_SUB_GRAPH_LIST; + + num_sg = (uint32_t *)((int8_t *)stop_payload + + sizeof(*cmd_header) + sizeof(*module_param)); + + *num_sg = 0; + sg_id_list = num_sg + 1; + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + if (gkv_node->sg_array[i]) { + sg = gkv_node->sg_array[i]; + } else { + GSL_ERR("gkv_node->sg_array[%d] is NULL, continuing", i); + continue; + } + + /* + * send stop command for SGs + * 1. if SG is started only by this GKV + * 2. if SG is suspended. + */ + if ((sg && test_bit(gkv_node->sg_start_mask, i) && + (sg->start_ref_cnt == 1)) && + (!props || is_matching_sg_property(sg, props))) { + *sg_id_list++ = sg->sg_id; + (*num_sg)++; + } else if ((sg && (sg->stop_ref_cnt == 0) && + (sg->start_ref_cnt == 0)) && + (!props || is_matching_sg_property(sg, props))) { + *sg_id_list++ = sg->sg_id; + (*num_sg)++; + } + } + if ((*num_sg) == 0) { + GSL_DBG("NO SGs to stop"); + rc = AR_EOK; + goto decrement_ref_cnt; + } + + /* + * update payload sizes based on actual number of subgraphs + * that need to be prepared + */ + pld_size = sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE(sizeof(uint32_t) * ((size_t)1 + (*num_sg))); + cmd_header = (struct apm_cmd_header_t *)stop_payload; + cmd_header->payload_size = (uint32_t)(pld_size - sizeof(*cmd_header)); + module_param->param_size = (1 + (*num_sg)) * sizeof(uint32_t); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + pld_size, NULL, 0); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP1_CMD_SIG]); + if (rc) { + GSL_ERR("Graph stop failed:%d", rc); + goto free_msg; + } + +decrement_ref_cnt: + /* decrement start ref count and increment stop ref count for all SGs */ + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + if (gkv_node->sg_array[i]) { + sg = gkv_node->sg_array[i]; + } else { + GSL_ERR("gkv_node->sg_array[%d] is NULL, continuing", i); + continue; + } + if ((sg && test_bit(gkv_node->sg_start_mask, i)) && + (!props || is_matching_sg_property(sg, props))) { + if (sg->start_ref_cnt > 0) + sg->start_ref_cnt--; + clear_bit(gkv_node->sg_start_mask, i); + } + if ((sg && !test_bit(gkv_node->sg_stop_mask, i)) && + (!props || is_matching_sg_property(sg, props))) { + sg->stop_ref_cnt++; + set_bit(gkv_node->sg_stop_mask, i); + } + } + +free_msg: + gsl_msg_free(&gsl_msg); +exit: + return rc; +} + +int32_t gsl_graph_set_config(struct gsl_graph *graph, + const struct gsl_key_vector *gkv, uint32_t tag, + const struct gsl_key_vector *tkv, ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + struct gsl_sgid_list sg_id_list = {0, NULL}; + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node = NULL; + bool_t is_found = FALSE; + uint32_t i = 0; + AcdbSgIdModuleTag cmd_struct; + AcdbBlob rsp_struct; + struct apm_cmd_header_t *cmd_header; + gsl_msg_t gsl_msg; + struct ar_data_log_submit_info_t info; + struct ar_data_log_generic_pkt_info_t pkt_info; + + if (!graph || !tkv) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(lock); + GSL_MUTEX_LOCK(graph->get_set_cfg_lock); + + if (gkv && gkv->num_kvps != 0) { + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + if (is_identical_gkv(&gkv_node->gkv, + (struct gsl_key_vector *)gkv)) { + is_found = TRUE; + break; + } + } + if (!is_found) { + GSL_ERR("input gkv not opened/added, cannot set config"); + rc = AR_EBADPARAM; + goto exit; + } + + sg_id_list.sg_ids = gsl_mem_zalloc(gkv_node->num_of_subgraphs * + sizeof(uint32_t)); + if (!sg_id_list.sg_ids) { + rc = AR_ENOMEMORY; + goto exit; + } + + sg_id_list.len = gkv_node->num_of_subgraphs; + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) + sg_id_list.sg_ids[i] = gkv_node->sg_array[i]->sg_id; + } else { + rc = gsl_graph_get_sgids_and_objs(graph, &sg_id_list, NULL); + if (rc) { + GSL_ERR("failed to get sgid list %d", rc); + goto exit; + } + if (sg_id_list.len == 0) { + rc = AR_ENOTEXIST; + goto exit; + } + } + + /* if there are no subgraphs found then goto exit */ + if (!sg_id_list.sg_ids) + goto exit; + + cmd_struct.num_sg_ids = sg_id_list.len; + cmd_struct.sg_ids = sg_id_list.sg_ids; + cmd_struct.module_tag.tag_id = tag; + cmd_struct.module_tag.tag_key_vector.num_keys = tkv->num_kvps; + cmd_struct.module_tag.tag_key_vector.graph_key_vector = + (AcdbKeyValuePair *)tkv->kvp; + rsp_struct.buf = NULL; + rsp_struct.buf_size = 0; + rc = acdb_ioctl(ACDB_CMD_GET_MODULE_TAG_DATA, &cmd_struct, + sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) { + GSL_ERR("Get module tag data for size failed %d", rc); + goto cleanup; + } + + rc = gsl_msg_alloc(APM_CMD_SET_CFG, graph->src_port, GSL_GPR_DST_PORT_APM, + sizeof(*cmd_header), 0, graph->proc_id, rsp_struct.buf_size, false, + &gsl_msg); + if (rc) { + GSL_ERR("gsl msg alloc failed %d", rc); + goto cleanup; + } + + rsp_struct.buf = gsl_msg.payload; + rc = acdb_ioctl(ACDB_CMD_GET_MODULE_TAG_DATA, &cmd_struct, + sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) { + GSL_ERR("Get module tag data for cal failed %d", rc); + goto free_msg; + } + + if (graph->rtc_conn_active) { + /* dump config to QACT */ + + pkt_info.format = AR_LOG_PKT_GENERIC_FMT_CAL_BLOB; + pkt_info.token_id = 0; + pkt_info.log_time_stamp = 0; + + info.buffer = (int8_t *)gsl_msg.payload; + info.buffer_size = rsp_struct.buf_size; + info.log_code = AR_DATA_LOG_CODE_ATS; + info.pkt_info = &pkt_info; + info.pkt_type = AR_DATA_LOG_PKT_TYPE_GENERIC; + info.session_id = 0; + + GSL_DBG("set_config: caching buffer %x to QACT", info.buffer); + ar_data_log_submit(&info); + } + + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + gsl_msg.gpr_packet); + cmd_header->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + cmd_header->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + cmd_header->payload_size = rsp_struct.buf_size; + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*cmd_header), gsl_msg.payload, + cmd_header->payload_size); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) + GSL_ERR("Graph set config failed %d", rc); + +free_msg: + gsl_msg_free(&gsl_msg); +cleanup: + gsl_mem_free(sg_id_list.sg_ids); +exit: + GSL_MUTEX_UNLOCK(graph->get_set_cfg_lock); + GSL_MUTEX_UNLOCK(lock); + + return rc; +} + +int32_t gsl_graph_set_cal(struct gsl_graph *graph, + const struct gsl_key_vector *gkv, + const struct gsl_key_vector *ckv, + ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + struct gsl_sgid_list sg_id_list = {0, NULL}; + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node = NULL; + bool_t is_found = FALSE; + uint32_t i = 0; + + if (!graph) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(lock); + GSL_MUTEX_LOCK(graph->get_set_cfg_lock); + + /** find matching gkv from the gkv node list */ + if (gkv && gkv->num_kvps != 0) { + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + if (is_identical_gkv(&gkv_node->gkv, + (struct gsl_key_vector *)gkv)) { + is_found = TRUE; + break; + } + } + if (!is_found) { + GSL_ERR("input gkv not opened/added, cannot set calibration"); + rc = AR_EBADPARAM; + goto exit; + } + } else { + curr = ar_list_get_head(&graph->gkv_list); + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + } + + sg_id_list.sg_ids = gsl_mem_zalloc(gkv_node->num_of_subgraphs * + sizeof(uint32_t)); + if (!sg_id_list.sg_ids) { + rc = AR_ENOMEMORY; + goto exit; + } + sg_id_list.len = gkv_node->num_of_subgraphs; + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) + sg_id_list.sg_ids[i] = gkv_node->sg_array[i]->sg_id; + + rc = gsl_graph_set_sg_cal(graph, &sg_id_list, gkv_node, ckv, gkv, true); + if (rc && rc != AR_ENOTEXIST) + GSL_ERR("set cal failed: %d", rc); + if (rc == AR_ENOTEXIST) + rc = AR_EOK; /* it is possible to get if client sends same ckv */ + gsl_mem_free(sg_id_list.sg_ids); + +exit: + GSL_MUTEX_UNLOCK(graph->get_set_cfg_lock); + GSL_MUTEX_UNLOCK(lock); + + return rc; +} + +int32_t gsl_graph_prepare(struct gsl_graph *graph, + ar_osal_mutex_t lock) +{ + uint32_t *sg_id_list, *num_sg, i, num_subgraphs = 0; + int32_t rc = AR_EOK; + uint32_t *prepare_payload, pld_size; + struct apm_cmd_header_t *cmd_header; + struct apm_module_param_data_t *module_param; + struct gsl_subgraph *sg, **sg_array = NULL; + struct gsl_sgobj_list sg_obj_list = {0, NULL}; + gsl_msg_t gsl_msg; + + if (!graph) + return AR_EBADPARAM; + + /* can be called with null GKV. Nothing to do */ + if (ar_list_is_empty(&graph->gkv_list)) + return AR_EOK; + + rc = gsl_graph_get_sgids_and_objs(graph, NULL, &sg_obj_list); + if (rc) { + GSL_ERR("failed to get subgraph objects"); + rc = AR_EFAILED; + goto exit; + } + num_subgraphs = sg_obj_list.len; + sg_array = sg_obj_list.sg_objs; + + pld_size = (uint32_t)(sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE(sizeof(uint32_t) * ((size_t)1 + num_subgraphs))); + + /* Allocate enough size for worst case */ + rc = gsl_msg_alloc(APM_CMD_GRAPH_PREPARE, graph->src_port, + GSL_GPR_DST_PORT_APM, pld_size, 0, graph->proc_id, 0, true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate gsl msg %d", rc); + goto free_sg_array; + } + + prepare_payload = GPR_PKT_GET_PAYLOAD(uint32_t, gsl_msg.gpr_packet); + module_param = (struct apm_module_param_data_t *) + ((int8_t *)prepare_payload + sizeof(*cmd_header)); + module_param->module_instance_id = GSL_GPR_DST_PORT_APM; + module_param->param_id = APM_PARAM_ID_SUB_GRAPH_LIST; + + num_sg = (uint32_t *)((int8_t *)prepare_payload + + sizeof(*cmd_header) + sizeof(*module_param)); + + GSL_MUTEX_LOCK(lock); + + *num_sg = 0; + sg_id_list = num_sg + 1; + for (i = 0; i < num_subgraphs; ++i) { + sg = sg_array[i]; + /* send prepare command only for SGs that are not in START state */ + if (sg && sg->start_ref_cnt == 0) { + *sg_id_list++ = sg->sg_id; + (*num_sg)++; + } + } + + if ((*num_sg) == 0) { + GSL_DBG("All SGs are in started state, nothing to prepare"); + rc = AR_EOK; + goto free_msg; + } + /* + * update payload sizes based on actual number of subgraphs + * that need to be prepared + */ + pld_size = sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE(sizeof(uint32_t) * ((size_t)1 + (*num_sg))); + cmd_header = (struct apm_cmd_header_t *)prepare_payload; + cmd_header->payload_size = (uint32_t)(pld_size - sizeof(*cmd_header)); + module_param->param_size = (uint32_t)(1 + (*num_sg)) * sizeof(uint32_t); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + pld_size, NULL, 0); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP1_CMD_SIG]); + if (rc) + GSL_ERR("Graph prepare failed:%d", rc); + +free_msg: + gsl_msg_free(&gsl_msg); + GSL_MUTEX_UNLOCK(lock); +free_sg_array: + gsl_mem_free(sg_array); +exit: + return rc; +} + +static int32_t gsl_graph_cache_datapath_miid(struct gsl_graph *graph, + struct gsl_data_path_info *dp_info, uint32_t tag, uint32_t mode) +{ + int32_t rc = AR_EOK; + struct gsl_sgid_list sg_id_list = {0, NULL}; + struct gsl_module_id_proc_info *proc_module_info; + + if ((mode & GSL_ATTRIBUTES_DATAPATH_SETUP_MASK) >> + GSL_ATTRIBUTES_DATAPATH_SETUP_SHIFT + == GSL_DATAPATH_SETUP_ALLOC_SHMEM_ONLY) { + /*don't do this for this mode specifically*/ + return AR_EOK; + } + + /* don't do this twice */ + if (tag == dp_info->cached_tag) + return AR_EOK; + + rc = gsl_graph_get_sgids_and_objs(graph, &sg_id_list, NULL); + if (rc) { + GSL_ERR("failed to get sgid list %d", rc); + return rc; + } + if (!sg_id_list.sg_ids) { + rc = AR_ENOTEXIST; + return rc; + } + + rc = _gsl_graph_get_module_proc_tag_info(sg_id_list.sg_ids, + sg_id_list.len, tag, &proc_module_info); + if (rc) { + GSL_ERR("fail to get write tag module iid %d", rc); + goto free_sg_ids; + } + if (proc_module_info->num_procs != 1) { + GSL_ERR("number of proc ids returned is %d, expected 1", + proc_module_info->num_procs); + rc = AR_EFAILED; + goto free_module_info; + } + /* + * cache the module, tag, and proc id, note we only cache for a single tag, it is + * assumed that each graph can have at most 1 write EP and 1 read EP + */ + dp_info->miid = + proc_module_info->proc_module_list->module_entry[0].module_iid; + dp_info->cached_tag = tag; + dp_info->master_proc_id = + proc_module_info->proc_module_list->proc_domain_id; + +free_module_info: + gsl_mem_free(proc_module_info->proc_module_list); + gsl_mem_free(proc_module_info); +free_sg_ids: + gsl_mem_free(sg_id_list.sg_ids); + + return rc; +} + +int32_t gsl_graph_config_data_path(struct gsl_graph *graph, + enum gsl_data_dir dir, struct gsl_cmd_configure_read_write_params *cfg) +{ + int32_t rc = AR_EOK; + struct gsl_data_path_info *dp_info; + uint32_t proc_id = graph->proc_id; + + /* + * Have to check graph state and cached miid outside of datapath + * module, as state is a property of graph and caching miid needs + * to loop through subgraphs + */ + GSL_MUTEX_LOCK(graph->graph_lock); + if (gsl_graph_get_state(graph) == GRAPH_STARTED) { + GSL_MUTEX_UNLOCK(graph->graph_lock); + rc = AR_EUNEXPECTED; + goto exit; + } + GSL_MUTEX_UNLOCK(graph->graph_lock); + + if (dir == GSL_DATA_DIR_READ) + dp_info = &graph->read_info; + else + dp_info = &graph->write_info; + + if (cfg->shmem_ep_tag) { + rc = gsl_graph_cache_datapath_miid(graph, dp_info, + cfg->shmem_ep_tag, cfg->attributes); + if (rc) { + GSL_ERR("cache data path miid failed %d", rc); + goto exit; + } + //Update the process id with the returned value + proc_id = dp_info->master_proc_id; + } + rc = gsl_dp_config_data_path(dp_info, cfg, graph->src_port, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG], dir, NULL, + proc_id); + if (rc) + GSL_ERR("configure data path failed %d", rc); + +exit: + return rc; +} + +/* + * Transfer the SG start mask and stop mask from old_gkv to new_gkv + */ +void gsl_transfer_sg_masks(struct gsl_graph_gkv_node *old_gkv_node, + struct gsl_graph_gkv_node *new_gkv_node) +{ + uint32_t i, j; + + for (i = 0; i < old_gkv_node->num_of_subgraphs; ++i) { + if (get_bit(old_gkv_node->sg_start_mask, i)) { + for (j = 0; j < new_gkv_node->num_of_subgraphs; ++j) { + if (old_gkv_node->sg_array[i]->sg_id + == new_gkv_node->sg_array[j]->sg_id) { + set_bit(new_gkv_node->sg_start_mask, j); + } + } + } + + if (get_bit(old_gkv_node->sg_stop_mask, i)) { + for (j = 0; j < new_gkv_node->num_of_subgraphs; ++j) { + if (old_gkv_node->sg_array[i]->sg_id + == new_gkv_node->sg_array[j]->sg_id) { + set_bit(new_gkv_node->sg_stop_mask, j); + } + } + } + } +} + +int32_t gsl_graph_start(struct gsl_graph *graph, + ar_osal_mutex_t lock) +{ + uint32_t *sg_id_list, *num_sg, i; + int32_t rc = AR_EOK; + uint32_t *start_payload, pld_size; + struct apm_cmd_header_t *cmd_header; + struct apm_module_param_data_t *module_param; + struct gsl_subgraph *sg; + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node = NULL; + gsl_msg_t gsl_msg; + + if (!graph) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(lock); + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, node); + if (!gkv_node) { + GSL_ERR("null returned for gkv_node\n"); + rc = AR_EBADPARAM; + goto unlock_mutex; + } + if (gkv_node->num_of_subgraphs == + count_set_bits(gkv_node->sg_start_mask)) + continue; + + pld_size = (uint32_t)(sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE(sizeof(uint32_t) * + ((size_t)1 + gkv_node->num_of_subgraphs))); + + /* Allocate enough size for worst case */ + rc = gsl_msg_alloc(APM_CMD_GRAPH_START, graph->src_port, + GSL_GPR_DST_PORT_APM, pld_size, 0, graph->proc_id, 0, true, + &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto unlock_mutex; + } + + start_payload = GPR_PKT_GET_PAYLOAD(uint32_t, gsl_msg.gpr_packet); + gsl_memset(start_payload, 0, pld_size); + + module_param = (struct apm_module_param_data_t *) + ((int8_t *)start_payload + sizeof(*cmd_header)); + module_param->module_instance_id = GSL_GPR_DST_PORT_APM; + module_param->param_id = APM_PARAM_ID_SUB_GRAPH_LIST; + + num_sg = (uint32_t *)((int8_t *)start_payload + + sizeof(*cmd_header) + sizeof(*module_param)); + + *num_sg = 0; + sg_id_list = num_sg + 1; + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + sg = gkv_node->sg_array[i]; + /* send start command only for SGs that are not in START state */ + if (sg && sg->start_ref_cnt == 0) { + *sg_id_list++ = sg->sg_id; + (*num_sg)++; + } + } + if ((*num_sg) == 0) { + GSL_DBG("All SGs are already in started state"); + rc = AR_EOK; + goto free_msg; + } + /* + * update payload sizes based on actual number of subgraphs + * that need to be prepared + */ + pld_size = sizeof(*cmd_header) + sizeof(*module_param) + + GSL_ALIGN_8BYTE(sizeof(uint32_t) * ((size_t)1 + (*num_sg))); + cmd_header = (struct apm_cmd_header_t *)start_payload; + cmd_header->payload_size = (uint32_t)(pld_size - sizeof(*cmd_header)); + module_param->param_size = + (uint32_t)((1 + (*num_sg)) * sizeof(uint32_t)); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + pld_size, NULL, 0); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP1_CMD_SIG]); + if (rc) { + GSL_ERR("Graph start failed:%d", rc); + gsl_msg_free(&gsl_msg); + goto unlock_mutex; + } + +free_msg: + gsl_msg_free(&gsl_msg); + + /* increment start ref count and decrement stop ref count + * for all SGs + */ + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + sg = gkv_node->sg_array[i]; + if (sg && !test_bit(gkv_node->sg_start_mask, i)) { + sg->start_ref_cnt++; + set_bit(gkv_node->sg_start_mask, i); + } + if (sg && test_bit(gkv_node->sg_stop_mask, i)) { + if (sg->stop_ref_cnt > 0) + sg->stop_ref_cnt--; + clear_bit(gkv_node->sg_stop_mask, i); + } + } + } + + /* + * if read buffers are configured then go ahead and queue them to spf + * but only do so if we are not already in STARTED state. It is + * possible that graph start is called multiple times while the graph is + * already in STARTED state in such cases we dont want to queue the buffers + */ + if (gsl_graph_get_state(graph) != GRAPH_STARTED && + graph->read_info.miid != 0) + gsl_dp_queue_read_buffers_to_spf(&graph->read_info); + + gsl_graph_update_state(graph, GRAPH_STARTED); +unlock_mutex: + GSL_MUTEX_UNLOCK(lock); + + return rc; +} + +int32_t gsl_graph_stop_with_properties(struct gsl_graph *graph, + struct gsl_cmd_properties *stop_props, ar_osal_mutex_t lock) +{ + struct gsl_key_vector *gkv = &stop_props->gkv; + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node = NULL; + bool_t is_found = FALSE; + int32_t rc = AR_EOK; + + if (!gkv->kvp || (gkv->num_kvps == 0)) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(lock); + + /** find matching gkv from the gkv node list */ + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + if (is_identical_gkv(&gkv_node->gkv, + (struct gsl_key_vector *)gkv)) { + is_found = TRUE; + break; + } + } + if (!is_found) { + GSL_ERR("input gkv not opened/added, cannot apply stop command"); + rc = AR_EBADPARAM; + goto exit; + } + rc = gsl_graph_stop_single_gkv(graph, gkv_node, stop_props); + + /** + * we don't wait for buffers to come back here as client does not use + * this to stop the SG with the shared mem endpoint + */ +exit: + GSL_MUTEX_UNLOCK(lock); + return rc; +} + +int32_t gsl_graph_suspend(struct gsl_graph *graph, + ar_osal_mutex_t lock) +{ + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node = NULL; + int32_t rc = AR_EOK; + + if (!graph) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(lock); + /** Proceed only if graph is in start state */ + if (gsl_graph_get_state(graph) != GRAPH_STARTED) { + rc = AR_EALREADY; + goto exit; + } + + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + if (!gkv_node) { + GSL_ERR("null returned for gkv_node\n"); + rc = AR_EBADPARAM; + goto exit; + } + if (gkv_node->sg_start_mask) { + /**< some or all of the SGs are started within this GKV */ + rc = gsl_graph_suspend_single_gkv(graph, gkv_node); + if (rc) + goto exit; + } + } + +exit: + GSL_MUTEX_UNLOCK(lock); + + return rc; +} + +int32_t gsl_graph_stop(struct gsl_graph *graph, + ar_osal_mutex_t lock) +{ + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node = NULL; + int32_t rc = AR_EOK; + uint32_t ev_flags = 0; + + if (!graph) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(lock); + /** Proceed only if graph is in start state */ + if (gsl_graph_get_state(graph) != GRAPH_STARTED) { + rc = AR_EALREADY; + goto unlock_mutex; + } + + GSL_MUTEX_LOCK(graph->graph_lock); + graph->transient_state_info.stop_in_prog = TRUE; + while (graph->transient_state_info.read_in_prog || + graph->transient_state_info.write_in_prog) { + GSL_MUTEX_UNLOCK(graph->graph_lock); + + /* wake up any blocking reads/writes and abort them */ + gsl_signal_set(&graph->read_info.dp_signal, GSL_SIG_EVENT_MASK_CLOSE, + 0, NULL); + gsl_signal_set(&graph->write_info.dp_signal, GSL_SIG_EVENT_MASK_CLOSE, + 0, NULL); + + /* Wait for read & write to complete */ + rc = gsl_signal_timedwait( + &graph->transient_state_info.trans_state_change_sig, + GSL_SPF_READ_WRITE_TIMEOUT_MS, &ev_flags, NULL, NULL); + if (rc) { + GSL_ERR("error waiting for read/write to resolve in graph_stop %d", + rc); + GSL_MUTEX_LOCK(graph->graph_lock); + break; + } else if (ev_flags & GSL_SIG_EVENT_MASK_SSR) { + GSL_MUTEX_LOCK(graph->graph_lock); + break; + } + GSL_MUTEX_LOCK(graph->graph_lock); + } + + gsl_graph_update_state(graph, GRAPH_STOPPED); + /** + * Whole graph is in STOPPED state now, so reset both read and + * write processed buf counters + */ + graph->write_info.processed_buf_cnt = 0; + graph->read_info.processed_buf_cnt = 0; + GSL_MUTEX_UNLOCK(graph->graph_lock); + + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + if (!gkv_node) { + GSL_ERR("null returned for gkv_node\n"); + rc = AR_EBADPARAM; + goto unlock_mutex; + } + { + /**< some or all of the SGs are started within this GKV */ + rc = gsl_graph_stop_single_gkv(graph, gkv_node, NULL); + if (rc) + goto stop_done; + } + } + + /* Ensure SPF does not hold onto stale buffers */ + if (gsl_graph_get_state(graph) != GRAPH_ERROR) { + gsl_wait_for_all_buffs_to_be_avail(&graph->read_info); + gsl_wait_for_all_buffs_to_be_avail(&graph->write_info); + } + +stop_done: + GSL_MUTEX_LOCK(graph->graph_lock); + graph->transient_state_info.stop_in_prog = FALSE; + GSL_MUTEX_UNLOCK(graph->graph_lock); + +unlock_mutex: + GSL_MUTEX_UNLOCK(lock); + + return rc; +} + +int32_t gsl_graph_flush(struct gsl_graph *graph, ar_osal_mutex_t lock) +{ + uint32_t *sg_id_list, *num_sg, i, num_of_subgraphs; + int32_t rc = AR_EOK; + uint32_t *flush_payload, pld_size, ev_flags = 0; + struct apm_cmd_header_t *cmd_header; + struct apm_module_param_data_t *module_param; + struct gsl_subgraph *sg, **sg_array = NULL; + struct gsl_sgobj_list sg_obj_list = {0, NULL}; + gsl_msg_t gsl_msg; + + if (!graph) + return AR_EBADPARAM; + + rc = gsl_graph_get_sgids_and_objs(graph, NULL, &sg_obj_list); + if (rc) { + GSL_ERR("failed to get sg objects"); + rc = AR_EFAILED; + goto exit; + } + num_of_subgraphs = sg_obj_list.len; + sg_array = sg_obj_list.sg_objs; + + pld_size = (uint32_t)(sizeof(*cmd_header) + sizeof(*module_param) + + sizeof(uint32_t) * ((size_t)1 + num_of_subgraphs)); + + /** Allocate enough size for worst case */ + rc = gsl_msg_alloc(APM_CMD_GRAPH_FLUSH, graph->src_port, + GSL_GPR_DST_PORT_APM, pld_size, 0, graph->proc_id, 0, true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate gsl msg %d", rc); + goto free_sg_array; + } + + flush_payload = GPR_PKT_GET_PAYLOAD(uint32_t, gsl_msg.gpr_packet); + gsl_memset(flush_payload, 0, pld_size); + + module_param = (struct apm_module_param_data_t *) + ((int8_t *)flush_payload + sizeof(*cmd_header)); + module_param->module_instance_id = GSL_GPR_DST_PORT_APM; + module_param->param_id = APM_PARAM_ID_SUB_GRAPH_LIST; + + num_sg = (uint32_t *)((int8_t *)flush_payload + + sizeof(*cmd_header) + sizeof(*module_param)); + + GSL_MUTEX_LOCK(lock); + + *num_sg = 0; + sg_id_list = num_sg + 1; + for (i = 0; i < num_of_subgraphs; ++i) { + sg = sg_array[i]; + /* send flush command only for SGs marked with flushable */ + if (sg && sg->drv_prop_data.is_flushable == 1) { + *sg_id_list++ = sg->sg_id; + (*num_sg)++; + } + } + if ((*num_sg) == 0) { + GSL_DBG("None of the SGs in the graph are flushable"); + rc = AR_EOK; + goto free_msg; + } + /* + * update payload sizes based on actual number of subgraphs + * that need to be flushed + */ + pld_size = sizeof(*cmd_header) + sizeof(*module_param) + + sizeof(uint32_t) * ((size_t)1 + (*num_sg)); + cmd_header = (struct apm_cmd_header_t *)flush_payload; + cmd_header->payload_size = (uint32_t)(pld_size - sizeof(*cmd_header)); + module_param->param_size = (uint32_t)((1 + (*num_sg)) * sizeof(uint32_t)); + + + GSL_MUTEX_LOCK(graph->graph_lock); + graph->transient_state_info.flush_in_prog = TRUE; + while (graph->transient_state_info.read_in_prog || + graph->transient_state_info.write_in_prog) { + GSL_MUTEX_UNLOCK(graph->graph_lock); + + /* wake up any blocking reads/writes and abort them */ + gsl_signal_set(&graph->write_info.dp_signal, + GSL_SIG_EVENT_MASK_CLOSE, 0, NULL); + gsl_signal_set(&graph->read_info.dp_signal, + GSL_SIG_EVENT_MASK_CLOSE, 0, NULL); + + /* Wait for read & write to complete */ + rc = gsl_signal_timedwait( + &graph->transient_state_info.trans_state_change_sig, + GSL_SPF_READ_WRITE_TIMEOUT_MS, &ev_flags, NULL, NULL); + if (rc) { + GSL_ERR("error waiting for read/write to resolve in flush %d", rc); + GSL_MUTEX_LOCK(graph->graph_lock); + break; + } + GSL_MUTEX_LOCK(graph->graph_lock); + } + GSL_MUTEX_UNLOCK(graph->graph_lock); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + pld_size, NULL, 0); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) { + GSL_ERR("Graph flush failed:%d", rc); + GSL_MUTEX_LOCK(graph->graph_lock); + graph->transient_state_info.flush_in_prog = FALSE; + GSL_MUTEX_UNLOCK(graph->graph_lock); + goto free_msg; + } + + /* Ensure SPF does not hold onto stale buffers */ + if (gsl_graph_get_state(graph) != GRAPH_ERROR) { + gsl_wait_for_all_buffs_to_be_avail(&graph->read_info); + gsl_wait_for_all_buffs_to_be_avail(&graph->write_info); + } + + GSL_MUTEX_LOCK(graph->graph_lock); + graph->transient_state_info.flush_in_prog = FALSE; + GSL_MUTEX_UNLOCK(graph->graph_lock); + + /* graph will not be restarted so we need to queue the buffers back now */ + gsl_dp_queue_read_buffers_to_spf(&graph->read_info); + +free_msg: + gsl_msg_free(&gsl_msg); + GSL_MUTEX_UNLOCK(lock); +free_sg_array: + gsl_mem_free(sg_array); +exit: + return rc; +} + +int32_t gsl_graph_write(struct gsl_graph *graph, uint32_t tag, + struct gsl_buff *buff, uint32_t *consumed_size) +{ + uint32_t rc = AR_EOK; + + /* if graph is in STOPPED or flush is in progress fail write */ + GSL_MUTEX_LOCK(graph->graph_lock); + if (graph->transient_state_info.flush_in_prog || + graph->transient_state_info.stop_in_prog) { + GSL_MUTEX_UNLOCK(graph->graph_lock); + GSL_DBG("Write skipped because graph is stopping or flushing"); + rc = AR_EIODATA; + goto exit; + } + graph->transient_state_info.write_in_prog = TRUE; + GSL_MUTEX_UNLOCK(graph->graph_lock); + + /* look-up module id from tag */ + if (graph->write_info.cached_tag != tag) { + rc = gsl_graph_cache_datapath_miid(graph, &graph->write_info, tag, + GSL_DATAPATH_SETUP_MODE(&graph->write_info.config)); + if (rc) { + GSL_ERR("cache write miid failed rc %d", rc); + goto end_write_state; + } + } + + rc = gsl_dp_write(&graph->write_info, buff, consumed_size); + +end_write_state: + GSL_MUTEX_LOCK(graph->graph_lock); + graph->transient_state_info.write_in_prog = FALSE; + gsl_signal_set(&graph->transient_state_info.trans_state_change_sig, 0, 0, + NULL); + GSL_MUTEX_UNLOCK(graph->graph_lock); + +exit: + return rc; +} + +int32_t gsl_graph_read(struct gsl_graph *graph, uint32_t tag, + struct gsl_buff *buff, uint32_t *filled_size) +{ + uint32_t rc = AR_EOK; + + /* if flush is in progress or graph is stopped fail the read */ + GSL_MUTEX_LOCK(graph->graph_lock); + if (graph->transient_state_info.flush_in_prog || + graph->transient_state_info.stop_in_prog) { + GSL_MUTEX_UNLOCK(graph->graph_lock); + GSL_DBG("Read skipped because graph is stopping or flushing"); + rc = AR_EIODATA; + goto exit; + } + graph->transient_state_info.read_in_prog = TRUE; + GSL_MUTEX_UNLOCK(graph->graph_lock); + + /* look-up module id from tag if not yet set */ + if (graph->read_info.cached_tag != tag) { + rc = gsl_graph_cache_datapath_miid(graph, &graph->read_info, tag, + GSL_DATAPATH_SETUP_MODE(&graph->read_info.config)); + if (rc) { + GSL_ERR("Failed to find MIID from tag %d", rc); + goto end_read_state; + } + } + + rc = gsl_dp_read(&graph->read_info, buff, filled_size); + +end_read_state: + GSL_MUTEX_LOCK(graph->graph_lock); + graph->transient_state_info.read_in_prog = FALSE; + gsl_signal_set(&graph->transient_state_info.trans_state_change_sig, 0, 0, + NULL); + GSL_MUTEX_UNLOCK(graph->graph_lock); + +exit: + return rc; +} + +int32_t gsl_graph_register_custom_event(struct gsl_graph *graph, + struct gsl_cmd_register_custom_event *reg_ev) +{ + int32_t rc = AR_EOK; + uint32_t spf_blob_sz = + GSL_ALIGN_8BYTE(sizeof(apm_module_register_events_t) + + reg_ev->event_config_payload_size); + struct apm_cmd_header_t *cmd_header; + apm_module_register_events_t *payload = NULL; + gsl_msg_t gsl_msg; + + rc = gsl_msg_alloc(APM_CMD_REGISTER_MODULE_EVENTS, graph->src_port, + reg_ev->module_instance_id, sizeof(struct apm_cmd_header_t), 0, + graph->proc_id, spf_blob_sz, true, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate gsl msg %d", rc); + goto exit; + } + + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + gsl_msg.gpr_packet); + gsl_memset(cmd_header, 0, spf_blob_sz + sizeof(struct apm_cmd_header_t)); + cmd_header->payload_size = + GSL_ALIGN_8BYTE(sizeof(apm_module_register_events_t) + + reg_ev->event_config_payload_size); + payload = (apm_module_register_events_t *)((uint8_t *)cmd_header + + sizeof(struct apm_cmd_header_t)); + payload->event_id = reg_ev->event_id; + payload->module_instance_id = reg_ev->module_instance_id; + payload->is_register = reg_ev->is_register; + payload->event_config_payload_size = reg_ev->event_config_payload_size; + gsl_memcpy((uint8_t *)payload + sizeof(apm_module_register_events_t), + reg_ev->event_config_payload_size, reg_ev->event_config_payload, + reg_ev->event_config_payload_size); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(struct apm_cmd_header_t) + + spf_blob_sz, NULL, 0); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + + gsl_msg_free(&gsl_msg); +exit: + return rc; +} + +int32_t gsl_graph_open(struct gsl_graph *graph, + const struct gsl_key_vector *gkv, const struct gsl_key_vector *ckv, + ar_osal_mutex_t lock) +{ + struct gsl_graph_gkv_node *gkv_node = NULL; + int32_t rc = AR_EOK; + + if (!graph) + return AR_EBADPARAM; + + if (gkv && gkv->num_kvps != 0) { + /** Memory to hold GKV, CKV, sg_array and num_of_subgraphs */ + gkv_node = gsl_mem_zalloc(sizeof(struct gsl_graph_gkv_node)); + if (!gkv_node) + return AR_ENOMEMORY; + } + + rc = __gpr_cmd_register(graph->src_port, gsl_gpr_callback, graph); + if (rc) + goto free_gkv_node; + + GSL_MUTEX_LOCK(lock); + /* It is possible to open a graph with a null GKV */ + if (gkv && gkv->num_kvps != 0) { + rc = gsl_graph_open_single_gkv(graph, gkv, ckv, gkv_node); + if (rc) { + GSL_ERR("graph open for single gkv failed %d", rc); + goto dereg_cmd; + } + } + GSL_MUTEX_UNLOCK(lock); + + return rc; + +dereg_cmd: + gsl_graph_update_state(graph, GRAPH_IDLE); + GSL_MUTEX_UNLOCK(lock); + __gpr_cmd_deregister(graph->src_port); +free_gkv_node: + gsl_mem_free(gkv_node); + return rc; +} + +int32_t gsl_graph_close(struct gsl_graph *graph, ar_osal_mutex_t lock) +{ + ar_list_node_t *curr = NULL; + int32_t first_rc = AR_EOK, rc = AR_EOK; + struct gsl_graph_gkv_node *gkv_node = NULL; + + GSL_MUTEX_LOCK(lock); + + while (!ar_list_is_empty(&graph->gkv_list)) { + curr = ar_list_get_tail(&graph->gkv_list); + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + rc = gsl_graph_close_single_gkv(graph, gkv_node, 0, NULL, NULL, NULL, + 0); + /* in case of SSR we will get AR_ESUBSYSRESET treat it as success */ + if (rc != AR_EOK && rc != AR_ESUBSYSRESET) { + if (first_rc == AR_EOK) + first_rc = rc; + GSL_ERR("graph_close failed for the cached key vector %d", rc); + } + + gsl_graph_remove_gkv_from_list(graph, gkv_node); + gsl_mem_free(gkv_node); + } + + /* + * signal close event to the graph to unblock any + * anyone waiting on spf reponse + */ + gsl_graph_signal_event_all(graph, GSL_SIG_EVENT_MASK_CLOSE); + + /* + * wait for any data buffers currently with Spf to get released, skip if + * we are in SSR state + */ + if (gsl_graph_get_state(graph) != GRAPH_ERROR) { + gsl_wait_for_all_buffs_to_be_avail(&graph->read_info); + gsl_wait_for_all_buffs_to_be_avail(&graph->write_info); + } + + if (graph->read_info.lock) + gsl_data_path_deinit(&graph->read_info); + if (graph->write_info.lock) + gsl_data_path_deinit(&graph->write_info); + + __gpr_cmd_deregister(graph->src_port); + + GSL_MUTEX_UNLOCK(lock); + + return first_rc; +} + +int32_t gsl_graph_close_with_properties(struct gsl_graph *graph, + struct gsl_cmd_properties *props, ar_osal_mutex_t lock) +{ + struct gsl_key_vector *gkv; + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node = NULL; + + bool_t is_found = FALSE; + int32_t rc = AR_EOK; + + if (!graph || !props) + return AR_EBADPARAM; + + gkv = &props->gkv; + + GSL_MUTEX_LOCK(lock); + + /** find matching gkv from the gkv node list */ + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + if (is_identical_gkv(&gkv_node->gkv, (struct gsl_key_vector *)gkv)) { + is_found = TRUE; + break; + } + } + if (!is_found) { + GSL_ERR("input gkv not opened/added"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_close_single_gkv(graph, gkv_node, 0, NULL, NULL, props, 0); + if (rc) + GSL_ERR("graph close singe gkv failed %d", rc); + /** + * we don't wait for buffers to come back here as client does not use + * this to close the SG with the shared mem endpoint + */ +exit: + GSL_MUTEX_UNLOCK(lock); + return rc; +} + +int32_t gsl_graph_add_new(struct gsl_graph *graph, + struct gsl_cmd_graph_select *new_graph, ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + struct gsl_graph_gkv_node *gkv_node = NULL; + struct gsl_key_vector *ckv = NULL; + + /* Memory to hold GKV, CKV, sg_array and num_of_subgraphs */ + gkv_node = gsl_mem_zalloc(sizeof(struct gsl_graph_gkv_node)); + if (!gkv_node) + return AR_ENOMEMORY; + + /* if no CKV passed, send null for default cal. Otherwise pass CKV */ + if (new_graph->cal_key_vect.num_kvps > 0) + ckv = &new_graph->cal_key_vect; + + GSL_MUTEX_LOCK(lock); + rc = gsl_graph_open_single_gkv(graph, &new_graph->graph_key_vector, + ckv, gkv_node); + GSL_MUTEX_UNLOCK(lock); + if (rc) { + GSL_ERR("graph open single gkv failed %d", rc); + gsl_mem_free(gkv_node); + } + + return rc; +} + +int32_t gsl_graph_remove_old(struct gsl_graph *graph, + struct gsl_cmd_remove_graph *old_graph, + ar_osal_mutex_t oc_lock, ar_osal_mutex_t ss_lock) +{ + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *gkv_node = NULL; + bool_t is_found = FALSE; + int32_t rc = AR_EOK; + + /** Find matching gkv_node with old_graph->gkv */ + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + if (is_identical_gkv(&gkv_node->gkv, &old_graph->graph_key_vector)) { + is_found = TRUE; + break; + } + } + if (!is_found) { + GSL_ERR("gkv not found, cannot remove from graph"); + rc = AR_EBADPARAM; + goto exit; + } + /** First issue stop for the SGs that need to be closed */ + GSL_MUTEX_LOCK(ss_lock); + if (gkv_node->sg_start_mask) { + rc = gsl_graph_stop_single_gkv(graph, gkv_node, NULL); + if (rc) + GSL_ERR("graph stop failed for single gkv %d", rc); + } + GSL_MUTEX_UNLOCK(ss_lock); + + /** Close the Subgraphs*/ + GSL_MUTEX_LOCK(oc_lock); + rc = gsl_graph_close_single_gkv(graph, gkv_node, 0, NULL, NULL, NULL, 0); + if (rc) + GSL_ERR("graph_close failed for single gkv %d", rc); + + gsl_graph_remove_gkv_from_list(graph, gkv_node); + gsl_mem_free(gkv_node); + GSL_MUTEX_UNLOCK(oc_lock); + +exit: + return rc; +} + +int32_t gsl_graph_change(struct gsl_graph *graph, + struct gsl_cmd_graph_select *cg, ar_osal_mutex_t lock) +{ + struct gsl_graph_gkv_node *gkv_node = NULL, *temp_node = NULL; + struct gsl_key_vector *gkv = &cg->graph_key_vector; + struct gsl_key_vector *ckv = &cg->cal_key_vect; + struct gsl_sgid_list sgids = {0, NULL}; + struct gsl_sgid_list pruned_sgids = {0, NULL}; + struct gsl_sgid_list existing_sgids = {0, NULL}; + AcdbGetGraphRsp sg_conn_info; + AcdbSubgraph *p; + struct gsl_graph_sg_conn_data pruned_sg_conn = { 0, }, + existing_sg_conn = { 0, }; + uint32_t i = 0; + int32_t rc = AR_EOK; + ar_list_node_t *curr = NULL; + bool_t is_gkv_node_added = false; + + /** Memory to hold GKV, CKV, sg_array and num_of_subgraphs */ + gkv_node = gsl_mem_zalloc(sizeof(struct gsl_graph_gkv_node)); + if (!gkv_node) + return AR_ENOMEMORY; + + /* Get graph data from ACDB */ + rc = gsl_acdb_get_graph(gkv, &sgids.sg_ids, &sg_conn_info); + if (rc) { + GSL_ERR("acdb get graph failed %d", rc); + goto exit; + } + /* if acdb returned empty list of subgraphs then do nothing */ + if (!sgids.sg_ids || sg_conn_info.num_subgraphs == 0) { + gsl_mem_free(gkv_node); + goto exit; + } + + GSL_MUTEX_LOCK(lock); + + /* + * Add new SGIDs and connections to the pool. Get pruned sgid list + * sg connections after adding them to the pool. + * We collect existing SG list and conns in case of error + */ + sgids.len = sg_conn_info.num_subgraphs; + pruned_sgids.len = 0; + pruned_sgids.sg_ids = NULL; + existing_sgids.len = 0; + existing_sgids.sg_ids = NULL; + rc = gsl_graph_add_and_prune_sgs_and_connections(gkv_node, + sgids, sg_conn_info.subgraphs, sg_conn_info.size, &pruned_sgids, + &pruned_sg_conn, &existing_sgids, &existing_sg_conn); + if (rc) + goto unlock_mutex; + + /* Close all the existing GKVs from the gkv_list nodes */ + gkv_node->sg_start_mask = 0; + gkv_node->sg_stop_mask = 0; + while (!ar_list_is_empty(&graph->gkv_list)) { + curr = ar_list_get_tail(&graph->gkv_list); + temp_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + gsl_transfer_sg_masks(temp_node, gkv_node); + + rc = gsl_graph_close_single_gkv(graph, temp_node, + 0, NULL, NULL, NULL, 0); + if (rc) { + GSL_ERR("graph_close failed for graph key vector %d", rc); + /* teardown error. Log it and continue -- nothing we can do here */ + } + + gsl_graph_remove_gkv_from_list(graph, temp_node); + gsl_mem_free(temp_node); + } + + /** Now open the pruned sgid list and connections */ + rc = gsl_graph_open_sgids_and_connections(graph, gkv_node, + &pruned_sgids, &pruned_sg_conn, gkv, ckv); + + /* + * Add GKV and CKV to GKV_node + * we do this for both success and failure since we update the SG list in + * failure case + */ + gsl_graph_update_gkv_node(gkv_node, gkv, ckv); + gsl_graph_add_gkv_to_list(graph, gkv_node); + is_gkv_node_added = true; + + if (rc) { + /* + * in the failure case, remove only the pruned SGIDs and conns from pool + * -- these are what is not open on SPF. Anything which was unmodified + * will still be open + * We preserve the GKV node so when client calls graph_close later, we + * will clean up those SGs properly. (may see an error in that close -- + * this would be benign and we would still close properly) + */ + + /* + * remove the conns which were new -- these do not necessarily belong + * only to new SGs + */ + p = pruned_sg_conn.subgraphs; + for (i = 0; i < pruned_sg_conn.num_sgs; ++i) { + gsl_subgraph_remove_children( + gsl_sg_pool_find(pruned_sg_conn.subgraphs[i].sg_id), p, NULL, + NULL); + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + p->num_dst_sgids); + } + /* then remove the new SGs */ + for (i = 0; i < pruned_sgids.len; ++i) + gsl_sg_pool_remove(gsl_sg_pool_find(pruned_sgids.sg_ids[i]), FALSE); + + /* + * now we must adjust the GKV node to represent what is still open + * on SPF. This is the set intersection of old GKV + new GKV, + * i.e. all the SGs & conns which were *not* pruned. We stored those + * when we did add & prune. + */ + + gsl_mem_free(gkv_node->sg_array); + gsl_mem_free(gkv_node->sg_conn_data.subgraphs); + + gkv_node->num_of_subgraphs = existing_sgids.len; + gkv_node->sg_array = gsl_mem_zalloc(gkv_node->num_of_subgraphs * + sizeof(struct gsl_subgraph *)); + if (!gkv_node->sg_array) { + rc = AR_ENOMEMORY; + goto cleanup; + } + + for (i = 0; i < existing_sgids.len; ++i) + gkv_node->sg_array[i] = gsl_sg_pool_find(existing_sgids.sg_ids[i]); + + gkv_node->sg_conn_data.subgraphs = existing_sg_conn.subgraphs; + gkv_node->sg_conn_data.size = existing_sg_conn.size; + gkv_node->sg_conn_data.num_sgs = existing_sg_conn.num_sgs; + + /* prevent this from being freed */ + existing_sg_conn.subgraphs = NULL; + } + +cleanup: + gsl_mem_free(pruned_sgids.sg_ids); + gsl_mem_free(pruned_sg_conn.subgraphs); + + gsl_mem_free(existing_sgids.sg_ids); + if (existing_sg_conn.subgraphs) + gsl_mem_free(existing_sg_conn.subgraphs); + +unlock_mutex: + GSL_MUTEX_UNLOCK(lock); +exit: + if (rc && !is_gkv_node_added) + gsl_mem_free(gkv_node); + + return rc; +} + +int32_t gsl_graph_prepare_to_change_single_gkv(struct gsl_graph *graph, + struct gsl_prepare_change_graph_single_gkv_params *params, + ar_osal_mutex_t lock) +{ + struct gsl_graph_gkv_node *old_node = NULL; + int32_t rc = AR_EOK; + uint32_t i, j, k = 0; + ar_list_node_t *curr = NULL; + bool_t old_gkv_found = false, skip_reopen_sg = false; + struct gsl_key_vector new_ckv = {0, NULL}; + struct gsl_sgid_list *preserved_sgids = NULL; + struct gsl_graph_sg_conn_data *pruned_plus_reopen_sg_conn = NULL; + AcdbSubgraph *sg_conn, *p; + + ar_list_for_each_entry(curr, &graph->gkv_list) { + old_node = get_container_base(curr, struct gsl_graph_gkv_node, node); + if (is_identical_gkv(¶ms->old_gkv, &old_node->gkv)) { + old_gkv_found = true; + GSL_DBG("Found the old gkv node"); + break; + } + } + + if (!old_gkv_found || old_node == NULL) { + rc = AR_ENOTEXIST; + goto exit; + } + uint32_t num_children = 0, num_sg_conn = old_node->sg_conn_data.num_sgs; + uint32_t *q = (uint32_t *)old_node->sg_conn_data.subgraphs; + + GSL_ERR("num_sg_conn = %d", num_sg_conn); + for (i = 0; i < num_sg_conn; ++i) { + GSL_ERR("sg %x has %d children:", *(q), num_children = *(q + 1)); + q += 2; + while (num_children) { + GSL_ERR("%x, ", *(q++)); + --num_children; + } + } + num_sg_conn = params->num_sgs; + q = (uint32_t *)params->sg_conn_info.subgraphs; + + GSL_ERR("num_sg_conn = %d", num_sg_conn); + for (i = 0; i < num_sg_conn; ++i) { + GSL_ERR("sg %x has %d children:", *(q), num_children = *(q + 1)); + q += 2; + while (num_children) { + GSL_ERR("%x, ", *(q++)); + --num_children; + } + } + + num_sg_conn = params->sg_conn_info_to_reopen.num_sgs; + q = (uint32_t *)params->sg_conn_info_to_reopen.subgraphs; + + GSL_ERR("num_sg_conn = %d", num_sg_conn); + for (i = 0; i < num_sg_conn; ++i) { + GSL_ERR("sg %x has %d children:", *(q), num_children = *(q + 1)); + q += 2; + while (num_children) { + GSL_ERR("%x, ", *(q++)); + --num_children; + } + } + + GSL_MUTEX_LOCK(lock); + + preserved_sgids = &old_node->rtc_cache.preserved_sgids; + pruned_plus_reopen_sg_conn = + &old_node->rtc_cache.pruned_plus_reopen_sg_conn; + + preserved_sgids->len = params->num_sgs + params->num_sgs_to_reopen; + if (preserved_sgids->len > 0) { + preserved_sgids->sg_ids = + gsl_mem_zalloc(preserved_sgids->len * sizeof(uint32_t)); + if (!preserved_sgids->sg_ids) { + rc = AR_ENOMEMORY; + GSL_MUTEX_UNLOCK(lock); + goto exit; + } + } + + pruned_plus_reopen_sg_conn->size = params->sg_conn_info.size + + params->sg_conn_info_to_reopen.size; + if (pruned_plus_reopen_sg_conn->size) { + pruned_plus_reopen_sg_conn->subgraphs = + gsl_mem_zalloc(pruned_plus_reopen_sg_conn->size); + if (!pruned_plus_reopen_sg_conn->subgraphs) { + rc = AR_ENOMEMORY; + goto free_pruned_sgs; + } + } + + /* + * All SGs which should stay open have their refcount incremented by 1 + * When we close on old GKV, they will stay open, but re-open SGs will be + * closed. + * We will do the opposite of this in change_single_GKV to + * restore the correct refcount. + * SGs to preserve are unmodified, existing SGs + */ + + for (i = 0; i < params->num_sgs; ++i) { + skip_reopen_sg = false; + /* skip modified SGs */ + for (j = 0; j < params->num_sgs_to_reopen; ++j) { + if (params->sgs[i] == params->sgs_to_reopen[j]) { + skip_reopen_sg = true; + break; + } + } + if (skip_reopen_sg) + continue; + /* skip new SGs */ + if (!gsl_sg_pool_find(params->sgs[i])) + continue; + + gsl_sg_pool_add(params->sgs[i], FALSE); + preserved_sgids->sg_ids[i] = params->sgs[i]; + ++k; + } + /* Was set to maximum for malloc. set to real size */ + preserved_sgids->len = k; + + /* + * For connections, we add all the new ones, then remove the pruned and + * reopen. This has the effect of only incrementing the conns which already + * existed (shared between old & new GKV) and which are not in reopen list. + * We preserve the list of conns we removed for use in change_single_gkv + */ + + sg_conn = params->sg_conn_info.subgraphs; + p = pruned_plus_reopen_sg_conn->subgraphs; + + i = 0; + k = 0; + while (i < params->num_sgs) { + gsl_subgraph_add_children(gsl_sg_pool_find(params->sgs[i]), + sg_conn, p, NULL); + if (p->num_dst_sgids) { + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + + p->num_dst_sgids); /* move to next pruned_sg_conn row */ + ++k; + } + ++i; + sg_conn = (AcdbSubgraph *)((uint32_t *)sg_conn->dst_sg_ids + + sg_conn->num_dst_sgids); /* move to next sg_conn row */ + } + + pruned_plus_reopen_sg_conn->num_sgs = k; + if (k) { + pruned_plus_reopen_sg_conn->size = + (uint8_t *)p - (uint8_t *)pruned_plus_reopen_sg_conn; + } else { + pruned_plus_reopen_sg_conn->size = 0; + } + + /* copy reopen SGs in after pruned SGs */ + if (params->sg_conn_info_to_reopen.num_sgs) { + pruned_plus_reopen_sg_conn->size += params->sg_conn_info_to_reopen.size; + gsl_memcpy(p, params->sg_conn_info.size + + params->sg_conn_info_to_reopen.size + - pruned_plus_reopen_sg_conn->size, + params->sg_conn_info_to_reopen.subgraphs, + params->sg_conn_info_to_reopen.size); + pruned_plus_reopen_sg_conn->num_sgs += + params->sg_conn_info_to_reopen.num_sgs; + } + + /* now close the pruned plus reopened to decrement refcount */ + p = pruned_plus_reopen_sg_conn->subgraphs; + for (i = 0; i < pruned_plus_reopen_sg_conn->num_sgs; ++i) { + gsl_subgraph_remove_children(gsl_sg_pool_find(p->sg_id), p, NULL, NULL); + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + p->num_dst_sgids); + } + /* haven't added anything new to pool, no need to adjust refs */ + + rc = gsl_graph_close_single_gkv(graph, old_node, 0, NULL, NULL, NULL, true); + if (rc) + GSL_ERR("graph_close failed for graph key vector %d", rc); + +free_pruned_sgs: + if (new_ckv.kvp) + gsl_mem_free(new_ckv.kvp); + + if (rc) { + /* + * these pointers are cached, hence only free for error conditions + */ + if (preserved_sgids->sg_ids) + gsl_mem_free(preserved_sgids->sg_ids); + if (pruned_plus_reopen_sg_conn->subgraphs) + gsl_mem_free(pruned_plus_reopen_sg_conn->subgraphs); + pruned_plus_reopen_sg_conn->subgraphs = NULL; + } + GSL_MUTEX_UNLOCK(lock); +exit: + + return rc; +} + +int32_t gsl_graph_change_single_gkv(struct gsl_graph *graph, + struct gsl_change_graph_single_gkv_params *params, + ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + uint32_t i = 0; + ar_list_node_t *curr = NULL; + struct gsl_graph_gkv_node *new_node, *old_node = NULL; + AcdbSubgraph *p = NULL; + struct gsl_sgid_list *preserved_sgids = NULL; + struct gsl_graph_sg_conn_data *pruned_plus_reopen_sg_conn = NULL; + bool_t gkv_found = false; + + if (graph->gkv_list.size == 0) + return AR_EBADPARAM; + + /* find the gkv node */ + ar_list_for_each_entry(curr, &graph->gkv_list) { + old_node = get_container_base(curr, struct gsl_graph_gkv_node, node); + if (is_identical_gkv(¶ms->old_gkv, &old_node->gkv)) { + /* found the gkv_node */ + gkv_found = true; + GSL_DBG("Found the old gkv node"); + break; + } + } + if (old_node == NULL) + return AR_EBADPARAM; + + preserved_sgids = &old_node->rtc_cache.preserved_sgids; + pruned_plus_reopen_sg_conn = + &old_node->rtc_cache.pruned_plus_reopen_sg_conn; + + if (!gkv_found || !preserved_sgids || !pruned_plus_reopen_sg_conn) + return AR_EBADPARAM; + + new_node = gsl_mem_zalloc(sizeof(struct gsl_graph_gkv_node)); + if (!new_node) + return AR_ENOMEMORY; + + GSL_MUTEX_LOCK(lock); + + /* Now open both the pruned and force re-open sgs */ + rc = gsl_graph_open_single_gkv(graph, ¶ms->new_gkv, ¶ms->new_ckv, + new_node); + if (rc) { + /* This will close all existing open SGs, even if it returns error */ + gsl_graph_close_single_gkv(graph, old_node, 0, NULL, 0, NULL, 0); + + goto cleanup; + } + + /* decrement refcnt of SGs we incremented in prepare */ + for (i = 0; i < preserved_sgids->len; ++i) { + gsl_sg_pool_remove( + gsl_sg_pool_find(preserved_sgids->sg_ids[i]), + FALSE); + } + + /* increment refcount on cached list of SG conns (all open now) */ + p = pruned_plus_reopen_sg_conn->subgraphs; + for (i = 0; i < pruned_plus_reopen_sg_conn->num_sgs; ++i) { + rc = gsl_subgraph_add_children(gsl_sg_pool_find(p->sg_id), + p, NULL, NULL); + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + + p->num_dst_sgids); /* move to next row */ + } + + /* + * decrement all SG conns to restore proper refcount + * We decrement all because we incremented the unmodified ones earlier, + * and we just incremented the new + re-opened ones so all are 1 too high + */ + p = new_node->sg_conn_data.subgraphs; + for (i = 0; i < new_node->num_of_subgraphs; ++i) { + gsl_subgraph_remove_children(new_node->sg_array[i], p, NULL, NULL); + p = (AcdbSubgraph *)((uint32_t *)p->dst_sg_ids + p->num_dst_sgids); + } + + copy_key_vector(&new_node->gkv, ¶ms->new_gkv); + + gsl_transfer_sg_masks(old_node, new_node); + +cleanup: + GSL_MUTEX_UNLOCK(lock); + + if (pruned_plus_reopen_sg_conn->num_sgs) + gsl_mem_free(pruned_plus_reopen_sg_conn->subgraphs); + if (preserved_sgids->sg_ids) + gsl_mem_free(preserved_sgids->sg_ids); + + if (!rc) { + if (old_node->ckv.kvp) + gsl_mem_free(old_node->ckv.kvp); + /* keep old node for cleanup at graph close in errors */ + gsl_graph_remove_gkv_from_list(graph, old_node); + gsl_mem_free(old_node); + } + + return rc; +} + +int32_t gsl_graph_change_set_config_helper(struct gsl_graph *graph, + uint32_t tag_data_size, uint8_t *tag_data) +{ + int32_t rc = AR_EOK; + struct apm_cmd_header_t *cmd_header; + gsl_msg_t gsl_msg; + + if (tag_data_size == 0 || !tag_data) + return AR_EBADPARAM; + + gsl_memset(&gsl_msg, 0, sizeof(gsl_msg_t)); + + rc = gsl_msg_alloc(APM_CMD_SET_CFG, graph->src_port, GSL_GPR_DST_PORT_APM, + sizeof(*cmd_header), 0, graph->proc_id, tag_data_size, false, &gsl_msg); + if (rc) { + GSL_ERR("Failed to allocate GSL msg %d", rc); + goto exit; + } + + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + gsl_msg.gpr_packet); + cmd_header->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + cmd_header->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + cmd_header->payload_size = tag_data_size; + + gsl_memcpy(gsl_msg.payload, tag_data_size, (void *)tag_data, tag_data_size); + + GSL_LOG_PKT("send_pkt", graph->src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*cmd_header), gsl_msg.payload, + cmd_header->payload_size); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &graph->graph_signal[GRAPH_CTRL_GRP2_CMD_SIG]); + if (rc) + GSL_ERR("Graph set config failed %d", rc); + + gsl_msg_free(&gsl_msg); +exit: + return rc; +} + +int32_t gsl_graph_get_tags_with_module_info( + const struct gsl_key_vector *graph_key_vect, + struct gsl_tag_module_info *tag_module_info, + size_t *tag_module_info_size) +{ + int32_t rc = AR_EOK; + AcdbCmdGetTagsFromGkvReq cmd_struct; + AcdbCmdGetTagsFromGkvRsp rsp_struct; + AcdbGraphKeyVector gkv; + + gkv.num_keys = graph_key_vect->num_kvps; + gkv.graph_key_vector = (AcdbKeyValuePair *)graph_key_vect->kvp; + cmd_struct.graph_key_vector = &gkv; + + rsp_struct.num_tags = 0; + if (!tag_module_info || *tag_module_info_size == 0) { + rsp_struct.list_size = 0; + rsp_struct.tag_module_list = NULL; + } else { + rsp_struct.list_size = (uint32_t)(*tag_module_info_size - + sizeof(struct gsl_tag_module_info)); + rsp_struct.tag_module_list = (AcdbTagModule *) + tag_module_info->tag_module_entry; + } + rc = acdb_ioctl(ACDB_CMD_GET_TAGS_FROM_GKV, &cmd_struct, + sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) { + GSL_ERR("acdb get tags from gkv failed with %d", rc); + return rc; + } + if (tag_module_info) + tag_module_info->num_tags = rsp_struct.num_tags; + + *tag_module_info_size = rsp_struct.list_size + + sizeof(struct gsl_tag_module_info); + + return rc; +} + +int32_t gsl_graph_get_tagged_data( + const struct gsl_key_vector *graph_key_vect, uint32_t tag, + struct gsl_key_vector *tag_key_vect, + uint8_t *payload, size_t *payload_size) +{ + int32_t rc = AR_EOK; + AcdbSgIdModuleTag cmd_struct = { 0 }; + AcdbBlob rsp_struct; + uint32_t *sgid_list = NULL; + AcdbGetGraphRsp sg_conn_info; + + rc = gsl_acdb_get_graph(graph_key_vect, &sgid_list, &sg_conn_info); + if (rc) { + GSL_ERR("acdb get graph failed for the given gkv %d", rc); + return rc; + } + /* it is possible that the GKV results in 0 subgraphs */ + if (!sgid_list || sg_conn_info.num_subgraphs == 0) { + *payload_size = 0; + return rc; + } + + cmd_struct.num_sg_ids = sg_conn_info.num_subgraphs; + cmd_struct.sg_ids = sgid_list; + cmd_struct.module_tag.tag_id = tag; + if (tag_key_vect) { + cmd_struct.module_tag.tag_key_vector.num_keys = tag_key_vect->num_kvps; + cmd_struct.module_tag.tag_key_vector.graph_key_vector = + (AcdbKeyValuePair *)tag_key_vect->kvp; + } + rsp_struct.buf = NULL; + rsp_struct.buf_size = 0; + rc = acdb_ioctl(ACDB_CMD_GET_MODULE_TAG_DATA, &cmd_struct, + sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) { + GSL_ERR("failed to get module tag data size %d", rc); + goto cleanup; + } + + if (payload) { + if (*payload_size < rsp_struct.buf_size) { + GSL_ERR("memory not sufficient for module tag data"); + rc = AR_ENEEDMORE; + goto set_payload_size; + } + rsp_struct.buf = payload; + rc = acdb_ioctl(ACDB_CMD_GET_MODULE_TAG_DATA, &cmd_struct, + sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) + GSL_ERR("failed to get module tag data %d", rc); + } +set_payload_size: + *payload_size = rsp_struct.buf_size; +cleanup: + gsl_mem_free(sgid_list); + gsl_mem_free(sg_conn_info.subgraphs); + return rc; +} diff --git a/gsl/src/gsl_hw_rsc_mgr.c b/gsl/src/gsl_hw_rsc_mgr.c new file mode 100644 index 0000000..349bc85 --- /dev/null +++ b/gsl/src/gsl_hw_rsc_mgr.c @@ -0,0 +1,321 @@ +/** + * \file gsl_hw_rsc_mgr.c + * + * \brief + * Main entry point for GSL hardware resource manager + + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_signal.h" +#include "ar_osal_error.h" +#include "gpr_api_inline.h" +#include "apm_api.h" +#include "prm_api.h" +#include "gsl_hw_rsc_intf.h" +#include "gsl_common.h" +#include "acdb.h" + +#define GSL_HW_RSC_SRC_PORT 0x2004 + +struct gsl_hw_rsc_ctxt_ { + /** + * Refcnt to track mgr's clients + */ + int32_t ref_cnt; + /** + * Mutex to be used when resource to be + * requested/released + */ + ar_osal_mutex_t rsc_lock; + /** + * Signal used to wait for responses from spf + */ + struct gsl_signal sig; + /** + * lock used in conjuction with above signal + */ + ar_osal_mutex_t sig_lock; + /** + * buffer in which to store response. Allocated and managed by client. + */ + void *rsp_buff; + /** + * size of rsp_buff. Initially holds size allocated by client. GSL sets to + * size written into buffer, if any. + */ + uint32_t rsp_buff_sz; +} gsl_hw_rsc_ctxt; + +static uint32_t gsl_hw_rsc_mgr_gpr_callback(gpr_packet_t *packet, void *cb_data) +{ + struct prm_cmd_rsp_hw_rsc_cfg_t *cmd_rsp; + struct gsl_hw_rsc_ctxt_ *ctxt; + struct spf_cmd_basic_rsp *basic_rsp; + uint32_t ret = 0; + + ctxt = (struct gsl_hw_rsc_ctxt_ *)cb_data; + switch (packet->opcode) { + case PRM_CMD_RSP_REQUEST_HW_RSC: + case PRM_CMD_RSP_RELEASE_HW_RSC: + cmd_rsp = GPR_PKT_GET_PAYLOAD( + struct prm_cmd_rsp_hw_rsc_cfg_t, packet); + ret = cmd_rsp->status; + if (!cmd_rsp->status) { + // differentiate request vs release on packet->opcode if needed + if (gsl_hw_rsc_ctxt.rsp_buff && gsl_hw_rsc_ctxt.rsp_buff_sz + >= GPR_PKT_GET_PAYLOAD_BYTE_SIZE(packet->header)) { + gsl_memcpy(gsl_hw_rsc_ctxt.rsp_buff, + gsl_hw_rsc_ctxt.rsp_buff_sz, (uint8_t *)cmd_rsp, + GPR_PKT_GET_PAYLOAD_BYTE_SIZE(packet->header)); + gsl_hw_rsc_ctxt.rsp_buff_sz = + GPR_PKT_GET_PAYLOAD_BYTE_SIZE(packet->header); + } + } + GSL_DBG("Received response 0x%x, status 0x%x", packet->opcode, + cmd_rsp->status); + gsl_signal_set(&ctxt->sig, GSL_SIG_EVENT_MASK_SPF_RSP, + cmd_rsp->status, NULL); + break; + case GPR_IBASIC_RSP_RESULT: + basic_rsp = GPR_PKT_GET_PAYLOAD(struct spf_cmd_basic_rsp, packet); + GSL_ERR("Received basic response 0x%x, status 0x%x", packet->opcode, + basic_rsp->status); + gsl_signal_set(&ctxt->sig, GSL_SIG_EVENT_MASK_SPF_RSP, + basic_rsp->status, NULL); + break; + default: + GSL_DBG("Received unsupported opcode 0x%x", packet->opcode); + break; + }; + + __gpr_cmd_free(packet); + return ret; +} + +/** Caller of this function should free the AcdbBlob*/ +static int32_t gsl_acdb_get_driver_data(uint32_t miid, + const struct gsl_key_vector *key_vect, AcdbBlob *payload) +{ + AcdbDriverData drv_data; + AcdbGraphKeyVector *acdb_key_vect = &drv_data.key_vector; + int32_t rc = AR_EOK; + + if (!payload) + return AR_EBADPARAM; + + payload->buf = NULL; + payload->buf_size = 0; + acdb_key_vect->num_keys = key_vect->num_kvps; + acdb_key_vect->graph_key_vector = (AcdbKeyValuePair *)key_vect->kvp; + drv_data.module_id = miid; + + rc = acdb_ioctl(ACDB_CMD_GET_DRIVER_DATA, &drv_data, sizeof(drv_data), + payload, sizeof(*payload)); + if (rc) { + GSL_ERR("failed to get size for driver data for miid: 0x%x, rc:%d", + miid, rc); + return rc; + } + if (payload->buf_size == 0) + return AR_EFAILED; + + payload->buf = gsl_mem_zalloc(payload->buf_size); + if (!payload->buf) + return AR_ENOMEMORY; + + rc = acdb_ioctl(ACDB_CMD_GET_DRIVER_DATA, &drv_data, sizeof(drv_data), + payload, sizeof(*payload)); + if (rc) { + GSL_ERR("failed to get driver data for miid: 0x%x, rc:%d", miid, rc); + gsl_mem_free(payload->buf); + } + + return rc; +} + +static int32_t gsl_command_hw_rsc_config(uint32_t miid, + const struct gsl_key_vector *key_vect, uint32_t cmd) +{ + /** Retrieve driver data from ACDB using MIID and key_vect */ + int32_t rc = AR_EOK; + AcdbBlob payload; + uint32_t cmd_payload_size = 0; + struct apm_cmd_header_t *cmd_header; + uint8_t *cmd_payload, *module_param; + gpr_packet_t *send_pkt = NULL; + + gsl_hw_rsc_ctxt.rsp_buff = NULL; //not used here, so don't write to it. + GSL_MUTEX_LOCK(gsl_hw_rsc_ctxt.rsc_lock); + rc = gsl_acdb_get_driver_data(miid, key_vect, &payload); + if (rc) { + GSL_MUTEX_UNLOCK(gsl_hw_rsc_ctxt.rsc_lock); + return rc; + } + cmd_payload_size = sizeof(*cmd_header) + payload.buf_size; + rc = gsl_allocate_gpr_packet(cmd, GSL_HW_RSC_SRC_PORT, + PRM_MODULE_INSTANCE_ID, cmd_payload_size, 0, + GSL_GPR_DST_DOMAIN_ID, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto free_payload_buf; + } + + cmd_payload = GPR_PKT_GET_PAYLOAD(uint8_t, send_pkt); + gsl_memset(cmd_payload, 0, cmd_payload_size); + + cmd_header = (struct apm_cmd_header_t *)cmd_payload; + cmd_header->payload_size = payload.buf_size; + module_param = cmd_payload + sizeof(*cmd_header); + gsl_memcpy(module_param, payload.buf_size, (uint8_t *)payload.buf, + payload.buf_size); + *(uint32_t *)module_param = PRM_MODULE_INSTANCE_ID; + + GSL_LOG_PKT("send_pkt", GSL_HW_RSC_SRC_PORT, send_pkt, sizeof(*send_pkt) + + cmd_payload_size, NULL, 0); + rc = gsl_send_spf_cmd(&send_pkt, &gsl_hw_rsc_ctxt.sig, NULL); + if (rc) + GSL_ERR("hw rsc cmd 0x%x failed:%d", cmd, rc); + +free_payload_buf: + gsl_mem_free(payload.buf); + GSL_MUTEX_UNLOCK(gsl_hw_rsc_ctxt.rsc_lock); + return rc; +} + +static int32_t gsl_command_hw_rsc_custom_config(const uint8_t *payload, + size_t payload_size, uint32_t cmd, void *buff, uint32_t *buff_size) +{ + int32_t rc = AR_EOK; + struct apm_cmd_header_t *cmd_header; + uint8_t *cmd_payload, *module_param; + gpr_packet_t *send_pkt = NULL; + + GSL_MUTEX_LOCK(gsl_hw_rsc_ctxt.rsc_lock); + + rc = gsl_allocate_gpr_packet(cmd, GSL_HW_RSC_SRC_PORT, + PRM_MODULE_INSTANCE_ID, sizeof(*cmd_header) + + GSL_ALIGN_8BYTE(payload_size), 0, + GSL_GPR_DST_DOMAIN_ID, &send_pkt); + + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + cmd_payload = GPR_PKT_GET_PAYLOAD(uint8_t, send_pkt); + gsl_memset(cmd_payload, 0, sizeof(*cmd_header) + + GSL_ALIGN_8BYTE(payload_size)); + + cmd_header = (struct apm_cmd_header_t *)cmd_payload; + cmd_header->payload_size = GSL_ALIGN_8BYTE(payload_size); + module_param = cmd_payload + sizeof(*cmd_header); + gsl_memcpy(module_param, GSL_ALIGN_8BYTE(payload_size), (void *)payload, + payload_size); + *(uint32_t *)module_param = PRM_MODULE_INSTANCE_ID; + + gsl_hw_rsc_ctxt.rsp_buff = buff; + gsl_hw_rsc_ctxt.rsp_buff_sz = (buff && buff_size) ? *buff_size : 0; + + GSL_LOG_PKT("send_pkt", GSL_HW_RSC_SRC_PORT, send_pkt, sizeof(*send_pkt) + + sizeof(*cmd_header) + GSL_ALIGN_8BYTE(payload_size), NULL, 0); + rc = gsl_send_spf_cmd(&send_pkt, &gsl_hw_rsc_ctxt.sig, NULL); + if (rc) + GSL_ERR("hw rsc cmd 0x%x failed:%d", cmd, rc); + if (rc == AR_ETIMEOUT) { + gsl_hw_rsc_ctxt.rsp_buff = NULL; + gsl_hw_rsc_ctxt.rsp_buff_sz = 0; + } + if (buff && buff_size) + *buff_size = gsl_hw_rsc_ctxt.rsp_buff_sz; +exit: + GSL_MUTEX_UNLOCK(gsl_hw_rsc_ctxt.rsc_lock); + return rc; +} + +int32_t gsl_request_hw_rsc_config(uint32_t miid, + const struct gsl_key_vector *key_vect) +{ + return gsl_command_hw_rsc_config(miid, key_vect, + PRM_CMD_REQUEST_HW_RSC); +} + +int32_t gsl_release_hw_rsc_config(uint32_t miid, + const struct gsl_key_vector *key_vect) +{ + return gsl_command_hw_rsc_config(miid, key_vect, + PRM_CMD_RELEASE_HW_RSC); +} + +int32_t gsl_request_hw_rsc_custom_config(const uint8_t *payload, + size_t payload_size, void *buff, uint32_t *buff_size) +{ + return gsl_command_hw_rsc_custom_config(payload, payload_size, + PRM_CMD_REQUEST_HW_RSC, buff, buff_size); +} + +int32_t gsl_release_hw_rsc_custom_config(const uint8_t *payload, + size_t payload_size, void *buff, uint32_t *buff_size) +{ + return gsl_command_hw_rsc_custom_config(payload, payload_size, + PRM_CMD_RELEASE_HW_RSC, buff, buff_size); +} + +int32_t gsl_hw_rsc_init(void) +{ + int32_t rc = AR_EOK; + + if (gsl_hw_rsc_ctxt.ref_cnt++ > 0) { + GSL_ERR("already initialized ref_cnt %d", gsl_hw_rsc_ctxt.ref_cnt); + goto exit; + } + rc = __gpr_cmd_register(GSL_HW_RSC_SRC_PORT, + gsl_hw_rsc_mgr_gpr_callback, &gsl_hw_rsc_ctxt); + if (rc) { + GSL_ERR("gpr register failed for src port 0x%x, rc: %d", + GSL_HW_RSC_SRC_PORT, rc); + gsl_hw_rsc_ctxt.ref_cnt = 0; + goto exit; + } + rc = ar_osal_mutex_create(&gsl_hw_rsc_ctxt.sig_lock); + if (rc) { + GSL_ERR("failed create mutex %d", rc); + goto gpr_deinit; + } + rc = ar_osal_mutex_create(&gsl_hw_rsc_ctxt.rsc_lock); + if (rc) { + GSL_ERR("failed create rsc mgr mutex %d", rc); + goto destroy_sig_mutex; + } + rc = gsl_signal_create(&gsl_hw_rsc_ctxt.sig, &gsl_hw_rsc_ctxt.sig_lock); + if (rc) { + GSL_ERR("failed to create signal %d", rc); + goto destroy_rsc_mutex; + } + + gsl_hw_rsc_ctxt.rsp_buff = NULL; + gsl_hw_rsc_ctxt.rsp_buff_sz = 0; +exit: + return rc; +destroy_rsc_mutex: + ar_osal_mutex_destroy(gsl_hw_rsc_ctxt.rsc_lock); +destroy_sig_mutex: + ar_osal_mutex_destroy(gsl_hw_rsc_ctxt.sig_lock); +gpr_deinit: + __gpr_cmd_deregister(GSL_HW_RSC_SRC_PORT); + return rc; +} + +int32_t gsl_hw_rsc_deinit(void) +{ + if (gsl_hw_rsc_ctxt.ref_cnt && (0 < --gsl_hw_rsc_ctxt.ref_cnt)) { + GSL_ERR("still in use ref_cnt %d", gsl_hw_rsc_ctxt.ref_cnt); + goto exit; + } + gsl_signal_destroy(&gsl_hw_rsc_ctxt.sig); + ar_osal_mutex_destroy(gsl_hw_rsc_ctxt.sig_lock); + ar_osal_mutex_destroy(gsl_hw_rsc_ctxt.rsc_lock); + __gpr_cmd_deregister(GSL_HW_RSC_SRC_PORT); +exit: + return AR_EOK; +} diff --git a/gsl/src/gsl_main.c b/gsl/src/gsl_main.c new file mode 100644 index 0000000..7c03816 --- /dev/null +++ b/gsl/src/gsl_main.c @@ -0,0 +1,2382 @@ +/** + * \file gsl_main.c + * + * \brief + * Main entry point for Graph Service Layer (GSL) + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_intf.h" +#include "acdb.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#include "ar_osal_shmem.h" +#include "ar_util_list.h" +#include "ar_util_data_log.h" +#include "ar_util_err_detection.h" +#include "ar_osal_mutex.h" +#include "ar_osal_sleep.h" +#include "ar_osal_string.h" +#include "ar_osal_sys_id.h" +#include "gsl_graph.h" +#include "gsl_subgraph_pool.h" +#include "gsl_global_persist_cal.h" +#include "gsl_common.h" +#include "gsl_shmem_mgr.h" +#include "gsl_spf_ss_state.h" +#include "gsl_mdf_utils.h" +#include "gsl_rtc_main.h" +#include "gsl_rtc.h" +#include "gsl_rtc_intf.h" +#include "gsl_dynamic_module_mgr.h" +#include "gpr_api.h" +#include "gpr_api_inline.h" +#include "gpr_ids_domains.h" +#include "apm_api.h" +#include "apm_memmap_api.h" +#include "apm_graph_properties.h" +#include "gsl_cshm_mgr.h" +#include +#include + +#if defined(GSL_LOG_PKT_ENABLE) || defined(GSL_LOG_DATA_ENABLE) +ar_fhandle pkt_log_fd = NULL; +char *gsl_str = "gsl_log_"; +ar_osal_mutex_t log_mutex; +#endif + + /* + * Increment if a change breaks backwards compatability + */ +#define GSL_MAJOR_VERSION 1 + +/* + * Increment if one or more new features are added + */ +#define GSL_MINOR_VERSION 0 + +/** max. number of use-case graphs, initialize to 16 */ +#define MAX_UC_GRAPHS 16 +#define GSL_MAGIC_WORD 0x47534C /* 'GSL' */ +#define GSL_MAGIC_WORD_MASK 0xFFFFFF +#define GSL_GRAPH_IDX_SHIFT 24 +#define GSL_GRAPH_SRC_PORT_MIN 0x2010 +#define GSL_GRAPH_SRC_PORT_MAX 0x2100 + +#define get_src_port(i) ((((i) + GSL_GRAPH_SRC_PORT_MIN) > \ + GSL_GRAPH_SRC_PORT_MAX) ? \ + GSL_GRAPH_SRC_PORT_MIN : ((i) + GSL_GRAPH_SRC_PORT_MIN)) + +#define GSL_MAIN_SRC_PORT 0x2003 + +#define GSL_DYN_DL_RETRY_MS (500) +#define GSL_DYN_DL_NUM_RETRIES 4 +#define GSL_DYN_DL_NUM_RETRIES_SSR 6 + +#define GSL_SS_RETRY_MS (10) + +struct gsl_rtgm_state_info { + + /* + * when non-zero it means rtgm operation is in progress + * QACT sends all prepares then all change + */ + uint32_t num_rtgm_in_prog; + + /* + * when true it means non-rtgm client operation is in progress such as + * read/write or set_cfg + */ + bool_t client_op_in_prog; + + /* + * signal to tell waiting rtgm operation when it is safe to proceed + */ + struct gsl_signal sig; +}; + +struct gsl_acdb_client_info { + ar_list_node_t node; /**< list node of each acdb client */ + struct gsl_acdb_data_files acdb_files; /**< client acdb file path info */ + struct gsl_acdb_file acdb_delta_file; + /**< client delta acdb file path info */ + gsl_acdb_handle_t acdb_handle; /**< acdb handle returned from AML */ +}; + +static struct gsl_ctxt_ { + void **graph_list; /**< list of all graphs, one per GSL handle */ + uint8_t graph_list_size; /**< size of graph list */ + uint32_t num_graphs; /**< number of active graphs */ + ar_osal_mutex_t open_close_lock; + /**< used to serialize open and close operations */ + ar_osal_mutex_t start_stop_lock; + /**< used to serialize start and stop operations */ + ar_osal_mutex_t graph_hdl_lock; + /**< used to serialize get/set graph_handle operations */ + struct gsl_signal rsp_signal; + /**< holds the status received in the readiness response */ + gsl_global_cb_func_ptr global_cb; + /**< callback used to notify global events to client */ + void *global_cb_client_data; + /**< client data that is passed back to client in the callback */ + struct gsl_rtgm_state_info rtgm_state_info; + /**< info used to sychronize rtgm and non-rtgm operations */ + bool_t spf_restart[AR_SUB_SYS_ID_LAST + 1]; + /**< on SPF SSR/PDR, we need to reconfigure shmem and dyn modules */ + bool_t rtc_conn_active; + /**< whether there is an active RTC session or not */ + ar_list_t acdb_client_list; /**< list of acdb clients from PVM and GVM */ + ar_osal_mutex_t acdb_client_lock; +} gsl_ctxt; + +static inline gsl_handle_t to_gsl_handle(uint8_t index) +{ + return (gsl_handle_t)((uintptr_t)(GSL_MAGIC_WORD | + (index << GSL_GRAPH_IDX_SHIFT))); +} + +static inline uint8_t to_gsl_graph_index(gsl_handle_t hdl) +{ + return ((uintptr_t)hdl >> GSL_GRAPH_IDX_SHIFT) & 0xff; +} + +static bool_t is_valid_gsl_hdl(gsl_handle_t hdl) +{ + if (((uintptr_t)hdl & GSL_MAGIC_WORD_MASK) != GSL_MAGIC_WORD) + return 0; + + return 1; +} + +/* + * If RTGM is in progrss returns failure. Otherwise sets the rtgm_state_info to + * "clint_operation_in_progress" and returns success + */ +static bool_t gsl_main_start_client_op(struct gsl_ctxt_ *ctxt) +{ + GSL_MUTEX_LOCK(ctxt->graph_hdl_lock); + if (ctxt->rtgm_state_info.num_rtgm_in_prog > 0) { + GSL_MUTEX_UNLOCK(ctxt->graph_hdl_lock); + return false; + } + ctxt->rtgm_state_info.client_op_in_prog = true; + GSL_MUTEX_UNLOCK(ctxt->graph_hdl_lock); + return true; +} + +static int32_t gsl_main_start_client_op_blocking(struct gsl_ctxt_ *ctxt) +{ + int32_t rc = AR_EOK; + uint32_t ev_flags = 0; + + GSL_MUTEX_LOCK(ctxt->graph_hdl_lock); + /* if RTGM is in-progress block */ + while (ctxt->rtgm_state_info.num_rtgm_in_prog > 0) { + GSL_MUTEX_UNLOCK(ctxt->graph_hdl_lock); + GSL_DBG("blocked due to RTGM"); + rc = gsl_signal_timedwait( + &ctxt->rtgm_state_info.sig, + GSL_SPF_READ_WRITE_TIMEOUT_MS, &ev_flags, NULL, NULL); + if (rc != AR_EOK) { + GSL_ERR("signal timed wait returned err %d", rc); + return rc; + } + GSL_MUTEX_LOCK(ctxt->graph_hdl_lock); + } + ctxt->rtgm_state_info.client_op_in_prog = true; + GSL_MUTEX_UNLOCK(ctxt->graph_hdl_lock); + + return rc; +} + +/* + * Clears "client_operation_in_progress" state if it was set + */ +static void gsl_main_end_client_op(struct gsl_ctxt_ *ctxt) +{ + GSL_MUTEX_LOCK(ctxt->graph_hdl_lock); + ctxt->rtgm_state_info.client_op_in_prog = false; + gsl_signal_set(&ctxt->rtgm_state_info.sig, GSL_SIG_EVENT_CLIENT_OP_DONE, + 0, NULL); + GSL_MUTEX_UNLOCK(ctxt->graph_hdl_lock); +} + +static struct gsl_graph *to_gsl_graph(gsl_handle_t graph_handle) +{ + struct gsl_graph *graph = NULL; + + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + + if (!is_valid_gsl_hdl(graph_handle)) + goto cleanup; + + graph = (struct gsl_graph *) + gsl_ctxt.graph_list[to_gsl_graph_index(graph_handle)]; + +cleanup: + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + + return graph; +} + +/** callback handles RTC callbacks */ +static int32_t gsl_rtc_callback(enum gsl_rtc_request_type req, void *cb_data) +{ + struct gsl_rtc_active_uc_info *info; + uint32_t size_remaining = 0, ev_flags = 0; + uint32_t size_to_copy = 0, gkv_node_size; + uint32_t gkv_bytes = 0, ckv_bytes = 0; + static uint32_t restart_list_position, restart_list_size; + static uint32_t *restart_handle_list; + struct gsl_graph *graph = NULL; + struct gsl_rtc_uc_data *uc_data = NULL; + uint8_t *payload; + uint8_t i; + struct gsl_rtc_param *rtc_cal_data; + struct gsl_rtc_persist_param *rtc_persist_cal_data; + struct gsl_rtc_prepare_change_graph_info *prep_change_graph_params; + struct gsl_rtc_change_graph_info *change_graph_params; + struct gsl_rtc_conn_info *rtc_conn_info; + + int32_t rc = AR_EOK; + + if (!cb_data) + return AR_EFAILED; + + GSL_ERR("GSL rtc request %d start", req); + switch (req) { + case GSL_RTC_GET_UC_INFO: + info = (struct gsl_rtc_active_uc_info *)cb_data; + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + size_remaining = info->total_size; + info->total_size = 0; + info->num_usecases = 0; + uc_data = info->uc_data; + if (uc_data) + gsl_memset(uc_data, 0, size_remaining); + GSL_MUTEX_LOCK(gsl_ctxt.open_close_lock); + for (i = 0; i < gsl_ctxt.graph_list_size; ++i) { + graph = (struct gsl_graph *)(gsl_ctxt.graph_list[i]); + if (graph && + (gsl_graph_get_state(graph) >= GRAPH_OPENED) && + (gsl_graph_get_state(graph) != GRAPH_ERROR) && + (gsl_graph_get_state(graph) != GRAPH_ERROR_ALLOW_CLEANUP)) { + gkv_node_size = gsl_rtc_graph_get_gkv_ckv_size(graph); + size_to_copy = gkv_node_size + sizeof(struct gsl_rtc_uc_data); + ++info->num_usecases; + info->total_size += size_to_copy; + if (uc_data && size_remaining >= size_to_copy) { + uc_data->graph_handle = + (uint32_t)(uintptr_t)to_gsl_handle(i); + payload = &uc_data->payload[0]; + gkv_bytes = gsl_rtc_graph_copy_gkvs(graph, payload, + &uc_data->num_gkvs); + ckv_bytes = gsl_rtc_graph_copy_ckvs(graph, + payload+gkv_bytes, &uc_data->num_ckvs); + payload = payload + gkv_bytes + ckv_bytes; + uc_data = (struct gsl_rtc_uc_data *)payload; + size_remaining -= size_to_copy; + } + } + } + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + break; + + case GSL_RTC_PREPARE_CHANGE_GRAPH: + /* + * check that no other client operation is in progress before starting + * RTGM, if it is then wait for it to complete + */ + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + while (gsl_ctxt.rtgm_state_info.client_op_in_prog) { + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + rc = gsl_signal_timedwait(&gsl_ctxt.rtgm_state_info.sig, + GSL_SPF_TIMEOUT_MS, &ev_flags, NULL, NULL); + if (rc) { + GSL_ERR("signal timedwait failed %d", rc); + goto exit; + } + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + } + ++gsl_ctxt.rtgm_state_info.num_rtgm_in_prog; + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + + GSL_MUTEX_LOCK(gsl_ctxt.open_close_lock); + prep_change_graph_params = (struct gsl_rtc_prepare_change_graph_info *) + cb_data; + graph = to_gsl_graph( + (gsl_handle_t)(uintptr_t)prep_change_graph_params->graph_handle); + if (!graph) { + GSL_ERR("rtc failed got invalid graph_handle %d", + prep_change_graph_params->graph_handle); + rc = AR_EBADPARAM; + goto unlock_mutex; + } + + if (gsl_graph_get_state(graph) == GRAPH_STARTED) { + + if (!restart_handle_list) { + /* allocate list of graphs to restart. max size is all graphs*/ + restart_list_position = 0; + restart_list_size = 0; + /* we use restart_list_size when stopping + * and restart_list_position when starting + */ + restart_handle_list = + gsl_mem_zalloc(gsl_ctxt.num_graphs * sizeof(uint32_t)); + if (!restart_handle_list) { + rc = AR_ENOMEMORY; + goto unlock_mutex; + } + } + + rc = gsl_graph_stop(graph, gsl_ctxt.start_stop_lock); + if (rc) { + GSL_ERR("rtc failed to stop graph rc %d", rc); + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + break; + } + + /* keep track of all graphs we stop here + * Client must sends change cmds in exact same order + */ + restart_handle_list[restart_list_size] = + prep_change_graph_params->graph_handle; + ++restart_list_size; + } + rc = gsl_rtc_internal_prepare_change_graph(graph, + prep_change_graph_params, NULL); + if (rc) { + GSL_ERR("rtc failed to prepare for change graph rc %d", rc); + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); //todo fix + } + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + break; + + case GSL_RTC_CHANGE_GRAPH: + GSL_MUTEX_LOCK(gsl_ctxt.open_close_lock); + change_graph_params = (struct gsl_rtc_change_graph_info *)cb_data; + graph = to_gsl_graph((gsl_handle_t)(uintptr_t) + change_graph_params->graph_handle); + if (!graph) { + GSL_ERR("rtc failed got invalid graph_handle %d", + change_graph_params->graph_handle); + rc = AR_EBADPARAM; + goto unlock_mutex; + } + + rc = gsl_rtc_internal_change_graph(graph, change_graph_params, NULL); + if (rc) { + GSL_ERR("rtc failed to change graph rc %d", rc); + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + break; // TODO This is bad state forever . + } + + if (change_graph_params->tag_data_size) { + rc = gsl_graph_change_set_config_helper(graph, + change_graph_params->tag_data_size, + change_graph_params->tag_data); + if (rc) { + GSL_ERR("failed to set cfg on changed graph %d", rc); + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + break; + } + } + /* + * the graph would have been stopped by PREPARE_CHANGE_GRAPH so start + * it back again here + */ + if (restart_handle_list && change_graph_params->graph_handle + == restart_handle_list[restart_list_position]) { + + /* clear restart list if no more to be restarted */ + if (++restart_list_position == restart_list_size) { + gsl_mem_free(restart_handle_list); + restart_list_position = 0; + restart_list_size = 0; + restart_handle_list = NULL; + } + + rc = gsl_graph_start(graph, gsl_ctxt.start_stop_lock); + if (rc) + GSL_ERR("rtc failed to restart graph rc %d", rc); + } + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + + /* Decrement counter to finish this rtgm operation. Signal if no more */ + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + if (--gsl_ctxt.rtgm_state_info.num_rtgm_in_prog == 0) + gsl_signal_set(&gsl_ctxt.rtgm_state_info.sig, + GSL_SIG_EVENT_MASK_RTGM_DONE, 0, NULL); + GSL_ERR("tvl end of RTGM, num in prog: %d", + gsl_ctxt.rtgm_state_info.num_rtgm_in_prog); + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + break; + + case GSL_RTC_CONN_INFO_CHANGE: + GSL_MUTEX_LOCK(gsl_ctxt.open_close_lock); + rtc_conn_info = (struct gsl_rtc_conn_info *)cb_data; + switch (rtc_conn_info->state) { + case GSL_RTC_CONNECTION_STATE_START: + gsl_ctxt.rtc_conn_active = true; + break; + case GSL_RTC_CONNECTION_STATE_STOP: + gsl_ctxt.rtc_conn_active = false; + /* stop graphs from logging cfg info to diag */ + for (i = 0; i < gsl_ctxt.graph_list_size; ++i) { + /* list not necessarily contiguous, check for null */ + if (!gsl_ctxt.graph_list[i]) + continue; + + ((struct gsl_graph *)gsl_ctxt.graph_list[i]) + ->rtc_conn_active = false; + } + break; + default: + rc = AR_EUNSUPPORTED; + + } + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + break; + default: + GSL_MUTEX_LOCK(gsl_ctxt.open_close_lock); + if ((req == GSL_RTC_GET_PERSIST_DATA) || + (req == GSL_RTC_SET_PERSIST_DATA)) { + rtc_persist_cal_data = (struct gsl_rtc_persist_param *)cb_data; + graph = to_gsl_graph( + (gsl_handle_t)(uintptr_t)rtc_persist_cal_data->graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto unlock_mutex; + } + if (req == GSL_RTC_GET_PERSIST_DATA) + rc = gsl_rtc_graph_get_persist_data(graph, + rtc_persist_cal_data->sgid, rtc_persist_cal_data->proc_id, + rtc_persist_cal_data->total_size, + &rtc_persist_cal_data->sg_cal_data); + else + rc = gsl_rtc_graph_set_persist_data(graph, + rtc_persist_cal_data); + } else if ((req == GSL_RTC_GET_NON_PERSIST_DATA) || + (req == GSL_RTC_SET_NON_PERSIST_DATA)) { + rtc_cal_data = (struct gsl_rtc_param *)cb_data; + graph = to_gsl_graph((gsl_handle_t) + (uintptr_t)rtc_cal_data->graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto unlock_mutex; + } + if (req == GSL_RTC_GET_NON_PERSIST_DATA) + rc = gsl_rtc_graph_get_non_persist_data(graph, + rtc_cal_data->total_size, rtc_cal_data->sg_cal_data); + else + rc = gsl_rtc_graph_set_non_persist_data(graph, + rtc_cal_data->total_size, rtc_cal_data->sg_cal_data); + } else { + rc = AR_EFAILED; + } +unlock_mutex: + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + break; + } +exit: + if (rc) + GSL_ERR("GSL rtc request %d failed %d", req, rc); + + return rc; +} + +/** + * callback handles ssr events and returns the list of impacted + * graph handles + * \param[in] state: indicates whether the subsystems are up or dn + * \param[in] spf_ss_state: bitmask indicating impacted subsystems + */ +static void gsl_main_ssr_callback(enum spf_ss_state_t state, + uint32_t spf_ss_mask) +{ + struct gsl_global_event_svc_dn_payload client_pld = {.num_handles = 0, + .handle_list = NULL}; + uint32_t num_graph_handles = 0; + uint8_t i = 0; + struct gsl_graph *graph; + bool_t master_proc_ssr = gsl_mdf_utils_is_master_proc(spf_ss_mask); + uint32_t master_proc = gsl_mdf_utils_get_master_proc_id(spf_ss_mask); + + /* + * Invalid subsystem mask. + * The subsystem mask provided should be present in one of the processor + * groups. + */ + if (master_proc == 0) + return; + gsl_cshm_handle_ssr(state, spf_ss_mask); + if (state == GSL_SPF_SS_STATE_DN) { + /* + * unblock any memory map operations in progress, for now assume master + * is ADSP this assumption may need to be revisited in the future + */ + if (master_proc_ssr) + gsl_shmem_signal_ssr(master_proc); + + /* allocate memory to store the graph handles to be sent to client */ + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + + if (gsl_ctxt.num_graphs > 0) { + client_pld.handle_list = + gsl_mem_zalloc(sizeof(gsl_handle_t)*gsl_ctxt.num_graphs); + if (!client_pld.handle_list) { + GSL_ERR("No memory"); + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + return; + } + + /* build the list of impacted handles */ + for (i = 0; i < gsl_ctxt.graph_list_size; ++i) { + if (!gsl_ctxt.graph_list[i]) + continue; + + graph = (struct gsl_graph *)(gsl_ctxt.graph_list[i]); + + /* check if a ss this graph depends is down */ + if ((spf_ss_mask & graph->ss_mask) == 0) + continue; + + if (gsl_graph_get_state(graph) != GRAPH_IDLE && + gsl_graph_get_state(graph) != GRAPH_ERROR && + gsl_graph_get_state(graph) != GRAPH_ERROR_ALLOW_CLEANUP) { + + /* + * if master is down go to GRAPH_ERROR state as no cleanup + * on SPF is required. If a satellite is down go to + * GRAPH_ERROR_ALLOW_CLEANUP as we still need to issue + * close to to SPF for this graph + */ + if (master_proc_ssr) + gsl_graph_update_state(graph, GRAPH_ERROR); + else + gsl_graph_update_state(graph, + GRAPH_ERROR_ALLOW_CLEANUP); + /* + * signal SSR event to the graph to unblock + * anyone waiting on spf reponse, + * if it's not already closed + */ + gsl_graph_signal_event_all(graph, + GSL_SIG_EVENT_MASK_SSR); + } + + client_pld.handle_list[num_graph_handles++] = + to_gsl_handle(i); + } + } + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + client_pld.num_handles = num_graph_handles; + + /* + * notify mdf utils that some ss are restarted, ideally this should be + * done as part of UP handling but since some clients dont wait for + * the UP call back before attempting to re-open graphs we have to do + * it here + */ + gsl_mdf_utils_notify_ss_restarted(spf_ss_mask); + + /* reset error detection context */ + ar_err_det_reset_ctxt(master_proc); + + /* issue callback to client */ + if (gsl_ctxt.global_cb) + gsl_ctxt.global_cb(GSL_GLOBAL_EVENT_AUDIO_SVC_DN, &client_pld, + sizeof(client_pld), gsl_ctxt.global_cb_client_data); + /* free the handle_list memory */ + if (client_pld.handle_list) + gsl_mem_free(client_pld.handle_list); + } else { /* GSL_SPF_SS_STATE_UP */ + if (master_proc_ssr) { + gsl_ctxt.spf_restart[master_proc] = TRUE; + /* clear ssr state from shmem mgr */ + gsl_shmem_clear_ssr(master_proc); + } + + /* issue callback to client */ + if (gsl_ctxt.global_cb) + gsl_ctxt.global_cb(GSL_GLOBAL_EVENT_AUDIO_SVC_UP, NULL, 0, + gsl_ctxt.global_cb_client_data); + } +} + +static uint32_t gsl_main_gpr_callback(gpr_packet_t *packet, void *cb_data) +{ + struct apm_cmd_rsp_get_spf_status_t *spf_status_rsp; + struct spf_cmd_basic_rsp *basic_rsp; + struct gsl_ctxt_ *ctxt; + uint32_t status = AR_EOK; + + switch (packet->opcode) { + case APM_CMD_RSP_GET_SPF_STATE: + spf_status_rsp = + GPR_PKT_GET_PAYLOAD(struct apm_cmd_rsp_get_spf_status_t, packet); + ctxt = (struct gsl_ctxt_ *)cb_data; + gsl_signal_set(&ctxt->rsp_signal, GSL_SIG_EVENT_MASK_SPF_RSP, + spf_status_rsp->status, NULL); + __gpr_cmd_free(packet); + break; + case GPR_IBASIC_RSP_RESULT: + basic_rsp = GPR_PKT_GET_PAYLOAD(struct spf_cmd_basic_rsp, packet); + ctxt = (struct gsl_ctxt_ *)cb_data; + /* + * Ignore basic rsp for APM_CMD_RSP_GET_SPF_STATE, SPF will send this + * with status EFAILED if the APM service is not yet regsitered with + * GPR. We treat this as a regular polling timeout and retry sending by + * sending the GET_SPF_STATE again after timeout. + */ + if (basic_rsp->opcode != APM_CMD_GET_SPF_STATE) + gsl_signal_set(&ctxt->rsp_signal, GSL_SIG_EVENT_MASK_SPF_RSP, + basic_rsp->status, packet); + /* do not free, it will be freed by waiter */ + else + __gpr_cmd_free(packet); + break; + default: + __gpr_cmd_free(packet); + status = AR_EFAILED; + break; + } + + return status; +} + +static gsl_handle_t get_graph_handle(struct gsl_graph *graph) +{ + void **tmp; + gsl_handle_t hdl = 0; + uint8_t i; + + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + + for (i = 0; i < gsl_ctxt.graph_list_size; i++) { + if (!gsl_ctxt.graph_list[i]) + break; + } + if (i == gsl_ctxt.graph_list_size) { + tmp = gsl_mem_realloc(gsl_ctxt.graph_list, + sizeof(void *) * ((size_t)gsl_ctxt.graph_list_size), + sizeof(void *) * ((size_t)gsl_ctxt.graph_list_size + + (MAX_UC_GRAPHS >> 1))); + if (!tmp) + goto exit; + + gsl_ctxt.graph_list_size += (MAX_UC_GRAPHS >> 1); + gsl_ctxt.graph_list = tmp; + } + + hdl = to_gsl_handle(i); + graph->src_port = get_src_port(i); + gsl_ctxt.graph_list[i] = (void *)graph; + ++gsl_ctxt.num_graphs; +exit: + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + return hdl; +} + +static void release_graph_handle(gsl_handle_t hdl) +{ + int32_t i; + + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + + i = to_gsl_graph_index(hdl); + gsl_ctxt.graph_list[i] = NULL; + --gsl_ctxt.num_graphs; + + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); +} + +void gsl_get_version(uint32_t *major, uint32_t *minor) +{ + if (!major || !minor) + return; + + *major = GSL_MAJOR_VERSION; + *minor = GSL_MINOR_VERSION; +} + +static int32_t gsl_do_spf_readiness_check( + uint32_t max_num_ready_checks, uint32_t ready_check_interval_ms, + uint32_t proc_id) +{ + uint32_t i = 0, event_flags = 0, spf_status = 0; + gpr_cmd_alloc_ext_t gpr_args; + int32_t rc = AR_EOK; + gpr_packet_t *send_pkt = NULL; + + gpr_args.src_domain_id = GPR_IDS_DOMAIN_ID_APPS_V; + gpr_args.dst_domain_id = (uint8_t) proc_id; + gpr_args.src_port = GSL_MAIN_SRC_PORT; + gpr_args.dst_port = APM_MODULE_INSTANCE_ID; + gpr_args.opcode = APM_CMD_GET_SPF_STATE; + gpr_args.token = 0; + gpr_args.client_data = 0; + gpr_args.payload_size = 0; + gpr_args.ret_packet = &send_pkt; + + for (i = 0; i < max_num_ready_checks; ++i) { + rc = __gpr_cmd_alloc_ext(&gpr_args); + if (rc) { + GSL_ERR("Failed to allocate shmem map pkt %d", rc); + goto exit; + } + + GSL_LOG_PKT("send_pkt", GSL_MAIN_SRC_PORT, send_pkt, sizeof(*send_pkt), + NULL, 0); + + rc = __gpr_cmd_async_send(send_pkt); + if (rc == AR_ENOTREADY) { + /* Remote side not UP yet. Retry */ + ar_osal_micro_sleep(GSL_TIMEOUT_US(ready_check_interval_ms)); + continue; + } else if (rc) { + GSL_ERR("GPR async send failed %d", rc); + __gpr_cmd_free(send_pkt); + goto exit; + } + + GSL_DBG("Wait for Spf readiness rsp"); + rc = gsl_signal_timedwait(&gsl_ctxt.rsp_signal, + ready_check_interval_ms, &event_flags, &spf_status, NULL); + if (rc == AR_ETIMEOUT) { + /* timed out continue polling */ + rc = AR_ENOTREADY; + continue; + } else { + if (event_flags & GSL_SIG_EVENT_MASK_SSR) { + /** SSR occured, bailout */ + rc = AR_ESUBSYSRESET; + goto exit; + } else if (event_flags & GSL_SIG_EVENT_MASK_SPF_RSP) { + GSL_DBG("Got Spf readiness rsp with %d", spf_status); + if (spf_status == APM_SPF_STATE_READY) { + /* Spf is Ready */ + rc = AR_EOK; + goto exit; + } else { + rc = AR_ENOTREADY; + } + } + ar_osal_micro_sleep(GSL_TIMEOUT_US(ready_check_interval_ms)); + } + } +exit: + return rc; +} + +int32_t gsl_get_driver_data(const uint32_t module_id, + const struct gsl_key_vector *key_vect, void *data_payload, + uint32_t *data_payload_size) +{ + AcdbDriverData acdb_req = { 0, }; + AcdbBlob acdb_rsp = { 0, }; + int32_t rc = AR_EOK; + + /* query acdb */ + acdb_req.key_vector.num_keys = key_vect->num_kvps; + acdb_req.key_vector.graph_key_vector = + (AcdbKeyValuePair *)key_vect->kvp; + acdb_req.module_id = module_id; + acdb_rsp.buf = data_payload; + acdb_rsp.buf_size = *data_payload_size; + rc = acdb_ioctl(ACDB_CMD_GET_DRIVER_DATA, &acdb_req, sizeof(acdb_req), + &acdb_rsp, sizeof(acdb_rsp)); + if (rc != AR_EOK) + GSL_ERR("acdb query ACDB_CMD_GET_DRIVER_DATA failed %d", rc); + + *data_payload_size = acdb_rsp.buf_size; + return rc; +} + +int32_t gsl_get_graph_tkvs(const struct gsl_key_vector *graph_key_vect, + struct gsl_tag_key_vector_list *data_payload) +{ + int32_t rc = AR_EOK; + + if (graph_key_vect == NULL) + return AR_EBADPARAM; + /* query acdb */ + rc = acdb_ioctl(ACDB_CMD_GET_GRAPH_TAG_KVS, graph_key_vect, + sizeof(*graph_key_vect), (void *)data_payload, sizeof(struct gsl_tag_key_vector_list)); + if (rc != AR_EOK) + GSL_ERR("acdb query ACDB_CMD_GET_GRAPH_TAG_KVS failed %d", rc); + + return rc; +} + +int32_t gsl_get_graph_ckvs(const struct gsl_key_vector *graph_key_vect, + struct gsl_key_vector_list *data_payload) +{ + + int32_t rc = AR_EOK; + AcdbGraphKeyVector cmd_struct; + + if (graph_key_vect == NULL) { + GSL_ERR("graph_key_vect is NULL"); + return AR_EBADPARAM; + } + + /* need to construct AcdbKeyVector because it is packed, gsl_kv isn't */ + cmd_struct.num_keys = graph_key_vect->num_kvps; + cmd_struct.graph_key_vector = (AcdbKeyValuePair *)graph_key_vect->kvp; + + /* query acdb */ + rc = acdb_ioctl(ACDB_CMD_GET_GRAPH_CAL_KVS, &cmd_struct, + sizeof(cmd_struct), (void *)data_payload, sizeof(struct gsl_key_vector_list)); + if (rc != AR_EOK) + GSL_ERR("acdb query ACDB_CMD_GET_GRAPH_CAL_KVS failed %d", rc); + + return rc; +} + +int32_t gsl_get_driver_module_kvs(uint32_t driver_id, + struct gsl_key_vector_list *data_payload) +{ + int32_t rc = AR_EOK; + + /* query acdb */ + rc = acdb_ioctl(ACDB_CMD_GET_DRIVER_MODULE_KVS, &driver_id, + sizeof(driver_id), (void *)data_payload, sizeof(struct gsl_key_vector_list)); + if (rc != AR_EOK) + GSL_ERR("acdb query ACDB_CMD_GET_DRIVER_MODULE_KVS failed %d", rc); + + return rc; +} + +int32_t gsl_get_supported_gkvs(uint32_t *key_ids, + const uint32_t num_key_ids, struct gsl_key_vector_list *data_payload) +{ + AcdbUintList uint_list = { 0, }; + int32_t rc = AR_EOK; + + /* query acdb */ + uint_list.count = num_key_ids; + uint_list.list = key_ids; + + rc = acdb_ioctl(ACDB_CMD_GET_SUPPORTED_GKVS, &uint_list, + sizeof(uint_list), (void *)data_payload, sizeof(struct gsl_key_vector_list)); + if (rc != AR_EOK) + GSL_ERR("acdb query ACDB_CMD_GET_SUPPORTED_GKVS failed %d", rc); + + return rc; +} + +int32_t gsl_init(struct gsl_init_data *init_data) +{ + uint32_t rc = AR_EOK; + uint32_t supported_ss_mask = 0, tmp_supported_ss_mask = 0; + uint32_t i = 0, j = 0; + uint32_t num_master_procs = 0; + uint32_t *master_procs = NULL; + uint32_t num_procs = 0; + struct proc_domain_type *proc_domains = NULL; + bool_t is_shmem_supported = TRUE; + + ar_log_init(); + + rc = gpr_init(); + if (rc) { + GSL_ERR("gpr init failed %d", rc); + return rc; + } + + /* initialize data logging */ + rc = ar_data_log_init(); + if (rc) { + GSL_ERR("ar data logging init failed %d", rc); + rc = AR_EOK; + } + + /* initialize acdb */ + rc = acdb_init((AcdbDataFiles *)init_data->acdb_files, + (AcdbFile *)init_data->acdb_delta_file); + + if (rc) { + GSL_ERR("acdb_init failed %d", rc); + goto deinit_gpr; + } + + gsl_spf_timeouts_init(); + + rc = gsl_sg_pool_init(); + if (rc) { + GSL_ERR("gsl_sg_pool_init failed %d", rc); + goto deinit_acdb; + } + + rc = gsl_global_persist_cal_pool_init(); + if (rc) { + GSL_ERR("gsl_global_persist_cal_pool_init failed %d", rc); + goto deinit_sgpool; + } + + ar_list_init(&gsl_ctxt.acdb_client_list, NULL, NULL); + ar_osal_mutex_create(&gsl_ctxt.acdb_client_lock); + gsl_ctxt.graph_list_size = MAX_UC_GRAPHS; + gsl_ctxt.graph_list = gsl_mem_zalloc(gsl_ctxt.graph_list_size * + sizeof(void *)); + if (!gsl_ctxt.graph_list) { + rc = AR_ENOMEMORY; + goto deinit_gpcpool; + } + + gsl_ctxt.num_graphs = 0; + + rc = ar_osal_mutex_create(&gsl_ctxt.open_close_lock); + if (rc) { + GSL_ERR("ar_osal_mutex_init failed %d", rc); + goto free_graph_list; + } + + rc = ar_osal_mutex_create(&gsl_ctxt.graph_hdl_lock); + if (rc) { + GSL_ERR("graph hdl lock create failed %d", rc); + goto destroy_open_close_lock; + } + + rc = ar_osal_mutex_create(&gsl_ctxt.start_stop_lock); + if (rc) { + GSL_ERR("start_stop mutex create failed %d", rc); + goto destroy_graph_hdl_lock; + } + + rc = gsl_dp_create_cache_refcount_lock(); + if (rc) { + GSL_ERR("external mem cache refcount mutex create failed %d", rc); + goto destroy_start_stop_lock; + } + + GSL_PKT_LOG_INIT(); + GSL_PKT_LOG_OPEN(AR_FOPEN_WRITE_ONLY); + + /* + * use open close_lock here as no sessions will be active at init time + * so this lock is available for use to use. + */ + rc = gsl_signal_create(&gsl_ctxt.rsp_signal, &gsl_ctxt.open_close_lock); + if (rc) { + GSL_ERR("signal create failed %d", rc); + goto destroy_ext_mem_cache_lock; + } + + rc = gsl_signal_create(&gsl_ctxt.rtgm_state_info.sig, NULL); + if (rc) { + GSL_ERR("signal create failed %d", rc); + goto destroy_rsp_signal; + } + gsl_ctxt.rtgm_state_info.client_op_in_prog = false; + gsl_ctxt.rtgm_state_info.num_rtgm_in_prog = 0; + + rc = __gpr_cmd_register(GSL_MAIN_SRC_PORT, gsl_main_gpr_callback, + &gsl_ctxt); + if (rc) { + GSL_ERR("gpr register failed"); + goto destroy_rtgm_state_signal; + } + + rc = gsl_mdf_utils_init(); + if (rc) { + GSL_ERR("gsl_mdf_utils_init failed %d", rc); + goto gpr_deregister; + } + + /* Get no of master proc ids */ + gsl_mdf_utils_get_master_proc_ids(&num_master_procs, + master_procs); + master_procs = gsl_mem_zalloc( + sizeof(uint32_t)*(num_master_procs)); + + if (master_procs == NULL) { + rc = AR_ENOMEMORY; + goto gpr_deregister; + } + + /* Get all master proc ids */ + gsl_mdf_utils_get_master_proc_ids(&num_master_procs, + master_procs); + gsl_mdf_utils_get_proc_domain_info(&proc_domains, &num_procs); + if (!proc_domains) + num_procs = 0; + + for (i = 0; i < num_master_procs; i++) { + /* perform Spf readiness check */ + rc = gsl_do_spf_readiness_check(init_data->max_num_ready_checks, + init_data->ready_check_interval_ms, master_procs[i]); + if (rc) + goto mdf_utils_deinit; + + gsl_mdf_utils_get_supported_ss_info_from_master_proc( + master_procs[i], + &supported_ss_mask); + tmp_supported_ss_mask = supported_ss_mask; + /* Reset dynamic PD mask. Dynamic PDs will be handled + * during use case boundary + */ + for (j = 0; j < num_procs; ++j) { + if (proc_domains[j].proc_type == DYNAMIC_PD) + supported_ss_mask &= + ~(GSL_GET_SPF_SS_MASK(proc_domains[j].proc_id)); + } + + rc = gsl_send_spf_satellite_info(master_procs[i], + supported_ss_mask, GSL_MAIN_SRC_PORT, &gsl_ctxt.rsp_signal); + if (rc) { + GSL_ERR("gsl_send_spf_satellite_info failed %d", rc); + goto mdf_utils_deinit; + } + + rc = gsl_spf_ss_state_init(master_procs[i], tmp_supported_ss_mask, + gsl_main_ssr_callback); + if (rc) { + GSL_ERR("gsl_spf_ss_state_init failed %d", rc); + goto mdf_utils_deinit; + } + /* @TODO: Remove below code once we rely on UP notifications from Spf */ + gsl_spf_ss_state_set(master_procs[i], AR_SUB_SYS_IDS_MASK, + //GSL_GET_SPF_SS_MASK(master_procs[i]), + GSL_SPF_SS_STATE_UP); + } + + rc = gsl_msg_builder_init(num_master_procs, master_procs); + if (rc) { + GSL_ERR("msg builder init failed %d", rc); + goto spf_ss_state_deinit; + } + + for (i = 0; i < num_master_procs; i++) { + gsl_mdf_utils_get_supported_ss_info_from_master_proc( + master_procs[i], + &supported_ss_mask); + + /* Reset dynamic PD mask. Dynamic PDs will + * be handled during use case boundary + */ + for (j = 0; j < num_procs; ++j) { + if (proc_domains[j].proc_type == DYNAMIC_PD) + supported_ss_mask &= + ~(GSL_GET_SPF_SS_MASK(proc_domains[j].proc_id)); + } + __gpr_cmd_is_shared_mem_supported(master_procs[i], &is_shmem_supported); + + if (is_shmem_supported) { + /* Temp fix: Map memory to other MDF modules. + * assume all up by now + */ + rc = gsl_mdf_utils_shmem_alloc(supported_ss_mask, + master_procs[i]); + if ((rc != AR_EOK) && (rc != AR_EUNSUPPORTED)) { + GSL_ERR("failed to alloc loaned shmem %d", rc) + goto msg_builder_deinit; + } + } + } + + rc = gsl_dynamic_module_mgr_init(num_master_procs, master_procs); + if (rc) { + GSL_ERR("dynamic module registration failed %d", rc) + goto msg_builder_deinit; + } + + for (i = 0; i < num_master_procs; i++) { + /* retry for up to 2 seconds to help in cases + * where ADSP RPC thread not ready + * + * TODO: Remove this once we are checking for + * dynamic download readiness with IPC + */ + for (j = 0; j < GSL_DYN_DL_NUM_RETRIES; ++j) { + rc = gsl_do_load_bootup_dyn_modules(master_procs[i], NULL); + if (rc) + ar_osal_micro_sleep(GSL_TIMEOUT_US(GSL_DYN_DL_RETRY_MS)); + else + break; + } + + if (rc != AR_EOK && rc != AR_ENOTEXIST) { + GSL_ERR("dynamic module load failed %d", rc); + goto dyn_module_mgr_deinit; + } + } + + /** initialize gsl rtc layer */ + rc = gsl_rtc_init(gsl_rtc_callback); + if (rc) { + GSL_ERR("gsl rtc init failed %d", rc); + goto dyn_module_mgr_deinit; + } + + for (i = AR_SUB_SYS_ID_FIRST; i <= AR_SUB_SYS_ID_LAST; i++) + gsl_ctxt.spf_restart[i] = FALSE; + + GSL_PKT_LOG_CLOSE(); + gsl_mem_free(master_procs); + return rc; + +dyn_module_mgr_deinit: + gsl_dynamic_module_mgr_deinit(); +msg_builder_deinit: + gsl_msg_builder_deinit(); +spf_ss_state_deinit: + for (j = 0; j < num_master_procs; j++) + gsl_spf_ss_state_deinit(master_procs[j]); +mdf_utils_deinit: + for (; j < i; j++) + gsl_spf_ss_state_deinit(master_procs[j]); + gsl_mdf_utils_deinit(); +gpr_deregister: + __gpr_cmd_deregister(GSL_MAIN_SRC_PORT); +destroy_rtgm_state_signal: + gsl_signal_destroy(&gsl_ctxt.rtgm_state_info.sig); +destroy_rsp_signal: + gsl_signal_destroy(&gsl_ctxt.rsp_signal); +destroy_ext_mem_cache_lock: + gsl_dp_destroy_cache_refcount_lock(); +destroy_start_stop_lock: + GSL_PKT_LOG_CLOSE(); + ar_osal_mutex_destroy(gsl_ctxt.start_stop_lock); +destroy_graph_hdl_lock: + ar_osal_mutex_destroy(gsl_ctxt.graph_hdl_lock); +destroy_open_close_lock: + ar_osal_mutex_destroy(gsl_ctxt.open_close_lock); +free_graph_list: + gsl_mem_free(gsl_ctxt.graph_list); +deinit_gpcpool: + gsl_global_persist_cal_pool_deinit(); +deinit_sgpool: + gsl_sg_pool_deinit(); +deinit_acdb: + acdb_deinit(); +deinit_gpr: + ar_data_log_deinit(); + gpr_deinit(); + ar_log_deinit(); + + gsl_mem_free(master_procs); + return rc; +} + +void gsl_deinit(void) +{ + uint32_t i; + uint32_t num_master_procs = 0; + uint32_t *master_procs = NULL; + + for (uint8_t j = 0; j < gsl_ctxt.graph_list_size; ++j) { + if (gsl_ctxt.graph_list[j]) + gsl_close(to_gsl_handle(j)); + } + + GSL_PKT_LOG_OPEN(AR_FOPEN_WRITE_ONLY_APPEND); + + /* Get no of master procs */ + gsl_mdf_utils_get_master_proc_ids(&num_master_procs, + master_procs); + master_procs = gsl_mem_zalloc( + sizeof(uint32_t)*(num_master_procs)); + + if (master_procs != NULL) { + /* Get all master proc ids */ + gsl_mdf_utils_get_master_proc_ids(&num_master_procs, + master_procs); + + for (i = 0; i < num_master_procs; i++) + gsl_do_unload_bootup_dyn_modules(master_procs[i], NULL); + } + + gsl_dynamic_module_mgr_deinit(); + gsl_rtc_deinit(); + gsl_mdf_utils_deinit(); + gsl_msg_builder_deinit(); + if (master_procs != NULL) { + for (i = 0; i < num_master_procs; i++) + gsl_spf_ss_state_deinit(master_procs[i]); + gsl_mem_free(master_procs); + } + acdb_deinit(); + gsl_global_persist_cal_pool_deinit(); + gsl_sg_pool_deinit(); + __gpr_cmd_deregister(GSL_MAIN_SRC_PORT); + gsl_signal_destroy(&gsl_ctxt.rsp_signal); + gsl_signal_destroy(&gsl_ctxt.rtgm_state_info.sig); + gsl_dp_destroy_cache_refcount_lock(); + ar_osal_mutex_destroy(gsl_ctxt.open_close_lock); + ar_osal_mutex_destroy(gsl_ctxt.start_stop_lock); + ar_osal_mutex_destroy(gsl_ctxt.graph_hdl_lock); + gsl_mem_free(gsl_ctxt.graph_list); + ar_data_log_deinit(); + gpr_deinit(); + GSL_PKT_LOG_CLOSE(); + GSL_PKT_LOG_DEINIT(); + ar_log_deinit(); +} + +int32_t gsl_register_global_event_cb(gsl_global_cb_func_ptr global_cb, + void *client_data) +{ + gsl_ctxt.global_cb = global_cb; + gsl_ctxt.global_cb_client_data = client_data; + + return AR_EOK; +} + +int32_t gsl_open(const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect, gsl_handle_t *graph_handle) +{ + int32_t rc = AR_EOK; + struct gsl_graph *graph = NULL; + gsl_handle_t hdl = 0; + uint32_t supported_ss_mask = 0; + uint32_t num_procs = 0; + struct proc_domain_type *proc_domains = NULL; + bool_t is_shmem_supported = TRUE; + uint8_t i = 0; + uint8_t j = 0; + int32_t ss_retry_count = 10; + + if (graph_handle == NULL) + return AR_EBADPARAM; + + GSL_PKT_LOG_OPEN(AR_FOPEN_WRITE_ONLY_APPEND); + + graph = gsl_mem_zalloc(sizeof(struct gsl_graph)); + if (graph == NULL) + return AR_ENOMEMORY; + + /** get graph handle and assign a source port */ + hdl = get_graph_handle(graph); + if (!hdl) { + rc = AR_ENOMEMORY; + goto cleanup; + } + + GSL_MUTEX_LOCK(gsl_ctxt.open_close_lock); + for (i = AR_SUB_SYS_ID_FIRST; i <= AR_SUB_SYS_ID_LAST; i++) { + if (gsl_ctxt.spf_restart[i]) { + + // handle master proc restarting + gsl_shmem_remap_pre_alloc(i); + gsl_mdf_utils_get_supported_ss_info_from_master_proc(i, &supported_ss_mask); + gsl_mdf_utils_get_proc_domain_info(&proc_domains, &num_procs); + if (!proc_domains) + num_procs = 0; + /* Reset dynamic PD mask. It will be handled after dynamic PD is initialized. */ + for (j = 0; j < num_procs; ++j) { + if (proc_domains[j].proc_type == DYNAMIC_PD) + supported_ss_mask &= ~(GSL_GET_SPF_SS_MASK(proc_domains[j].proc_id)); + } + rc = gsl_send_spf_satellite_info(i, supported_ss_mask, + GSL_MAIN_SRC_PORT, &gsl_ctxt.rsp_signal); + if (rc) { + GSL_ERR("gsl_send_spf_satellite_info failed for master_proc %d rc %d", i, rc); + continue; + } + + __gpr_cmd_is_shared_mem_supported(i, &is_shmem_supported); + if (is_shmem_supported) { + rc = gsl_mdf_utils_shmem_alloc(supported_ss_mask, i); + if (rc != AR_EOK && rc != AR_EUNSUPPORTED) { + GSL_ERR("failed to alloc loaned shmem for master_proc %d rc %d", i, rc); + continue; + } + } + /* retry for up to 3 seconds to help in cases + where ADSP RPC thread not ready */ + for (j = 0; j < GSL_DYN_DL_NUM_RETRIES_SSR; ++j) { + rc = gsl_do_load_bootup_dyn_modules(i, NULL); + if (rc) { + ar_osal_micro_sleep(GSL_TIMEOUT_US(GSL_DYN_DL_RETRY_MS)); + } else { + gsl_ctxt.spf_restart[i] = FALSE; + break; + } + } + } + } + GSL_MUTEX_UNLOCK(gsl_ctxt.open_close_lock); + + /* + * Initialize graph instance and register to GPR to + * receive/send commands/events/data from spf + * State is updated under lock to sync with SSR + */ + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + rc = gsl_graph_init(graph); + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + if (rc) { + GSL_ERR("graph_init failed %d", rc); + goto release_handle; + } + + while (ss_retry_count--) { + rc = gsl_graph_open(graph, graph_key_vect, cal_key_vect, gsl_ctxt.open_close_lock); + if (AR_ESUBSYSRESET == rc) { + GSL_INFO("wait subsystem online, remaining retry count: %d", ss_retry_count); + ar_osal_micro_sleep(GSL_TIMEOUT_US(GSL_SS_RETRY_MS)); + continue; + } else if (rc) { + GSL_ERR("graph_open failed %d", rc); + goto deinit; + } + break; + } + // If it comes out from while() with a AR_ESUBSYSRESET even after ss_retry_count's retry, + // we should goto deinit. + if (AR_ESUBSYSRESET == rc) + goto deinit; + + *graph_handle = hdl; + + if (gsl_ctxt.rtc_conn_active) + graph->rtc_conn_active = true; + + return rc; + +deinit: + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + gsl_graph_deinit(graph); + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); +release_handle: + release_graph_handle(hdl); +cleanup: + gsl_mem_free(graph); + GSL_PKT_LOG_CLOSE(); + return rc; +} + +int32_t gsl_close(gsl_handle_t graph_handle) +{ + int32_t rc = AR_EOK; + struct gsl_graph *graph = NULL; + + /* if RTGM is in-progress block close */ + rc = gsl_main_start_client_op_blocking(&gsl_ctxt); + if (rc) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) + return AR_EBADPARAM; + + /** Stop graph if not already done */ + rc = gsl_graph_stop(graph, gsl_ctxt.start_stop_lock); + if (rc && (rc != AR_EALREADY)) + GSL_ERR("graph stop failed %d", rc); + + rc = gsl_graph_close(graph, gsl_ctxt.open_close_lock); + if (rc) + GSL_ERR("gsl_graph_close failed %d", rc); + + release_graph_handle(graph_handle); + + GSL_MUTEX_LOCK(gsl_ctxt.graph_hdl_lock); + gsl_graph_deinit(graph); + GSL_MUTEX_UNLOCK(gsl_ctxt.graph_hdl_lock); + + gsl_mem_free(graph); + + gsl_main_end_client_op(&gsl_ctxt); + GSL_PKT_LOG_CLOSE(); + + return rc; +} + +int32_t gsl_set_cal(gsl_handle_t graph_handle, + const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + if (!gsl_main_start_client_op(&gsl_ctxt)) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + /* check if graph is in SSR */ + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!cal_key_vect) { + GSL_ERR("cal key vector not specified"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_set_cal(graph, graph_key_vect, cal_key_vect, + gsl_ctxt.open_close_lock); + if (rc != AR_EOK && rc != AR_ENOTEXIST) { + GSL_ERR("graph set cal failed: %d", rc); + goto exit; + } + /* in-cases where the new CKV is same as old CKV we should not fail */ + if (rc == AR_ENOTEXIST) + rc = AR_EOK; +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_set_config(gsl_handle_t graph_handle, + const struct gsl_key_vector *graph_key_vect, + uint32_t tag, const struct gsl_key_vector *tag_key_vect) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + if (!gsl_main_start_client_op(&gsl_ctxt)) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!tag_key_vect) { + GSL_ERR("tag key vector not specified"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_set_config(graph, graph_key_vect, tag, tag_key_vect, + NULL); + if (rc) + GSL_ERR("graph set config failed: %d", rc); + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_set_custom_config(gsl_handle_t graph_handle, + const uint8_t *payload, const uint32_t payload_size) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + if (!gsl_main_start_client_op(&gsl_ctxt)) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!payload || (payload_size == 0)) { + GSL_ERR("payload is null or size is zero"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_set_custom_config(graph, payload, payload_size, NULL); + if (rc) + GSL_ERR("graph set custom config failed: %d", rc); + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_set_tagged_custom_config(gsl_handle_t graph_handle, uint32_t tag, + const uint8_t *payload, const size_t payload_size) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + if (!gsl_main_start_client_op(&gsl_ctxt)) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!payload || (payload_size == 0)) { + GSL_ERR("payload is null or size is zero"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_set_tagged_custom_config(graph, tag, payload, + payload_size, NULL); + if (rc) + GSL_ERR("graph set tagged custom config failed: %d", rc); + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_set_tagged_custom_config_persist(gsl_handle_t graph_handle, + uint32_t tag, const uint8_t *payload, const uint32_t payload_size) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + if (!gsl_main_start_client_op(&gsl_ctxt)) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!payload || (payload_size == 0)) { + GSL_ERR("payload is null or size is zero"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_set_tagged_custom_config_persist(graph, tag, payload, + payload_size, gsl_ctxt.start_stop_lock); + if (rc) + GSL_ERR("graph set tagged custom config persist failed: %d", rc); + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_get_custom_config(gsl_handle_t graph_handle, uint8_t *payload, + uint32_t size) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + if (!gsl_main_start_client_op(&gsl_ctxt)) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!payload || (size == 0)) { + GSL_ERR("payload is null or size is zero"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_get_custom_config(graph, payload, size, NULL); + if (rc) + GSL_ERR("graph get custom config failed: %d", rc); + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_get_tagged_custom_config(gsl_handle_t graph_handle, uint32_t tag, + uint8_t *payload, uint32_t *size) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + if (!gsl_main_start_client_op(&gsl_ctxt)) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!payload || (size == 0)) { + GSL_ERR("payload is null or size is zero"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_get_tagged_custom_config(graph, tag, payload, size, NULL); + if (rc) + GSL_ERR("graph get tagged custom config failed: %d", rc); + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_ioctl(gsl_handle_t graph_handle, + enum gsl_cmd_id cmd_id, void *cmd_payload, size_t cmd_payload_sz) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + uint32_t i; + struct gsl_cmd_graph_select *ag = NULL, *cg = NULL; + struct gsl_cmd_remove_graph *rg = NULL; + + if (!gsl_main_start_client_op(&gsl_ctxt)) { + rc = AR_ENOTREADY; + goto exit; + } + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + switch (cmd_id) { + case GSL_CMD_PREPARE: + rc = gsl_graph_prepare(graph, gsl_ctxt.start_stop_lock); + if (rc) + GSL_ERR("graph prepare ioctl failed %d", rc); + break; + + case GSL_CMD_START: + rc = gsl_graph_start(graph, gsl_ctxt.start_stop_lock); + if (rc) + GSL_ERR("graph start ioctl failed %d", rc); + break; + + case GSL_CMD_SUSPEND: + rc = gsl_graph_suspend(graph, gsl_ctxt.start_stop_lock); + if (rc) + GSL_ERR("graph suspend ioctl failed %d", rc); + break; + + case GSL_CMD_STOP: + if (cmd_payload && + (cmd_payload_sz != sizeof(struct gsl_cmd_properties))) { + rc = AR_EBADPARAM; + break; + } + + if (cmd_payload) + rc = gsl_graph_stop_with_properties(graph, + (struct gsl_cmd_properties *)cmd_payload, + gsl_ctxt.start_stop_lock); + else + rc = gsl_graph_stop(graph, gsl_ctxt.start_stop_lock); + if (rc) + GSL_ERR("graph stop ioctl failed %d", rc); + break; + + case GSL_CMD_CONFIGURE_READ_PARAMS: + if (cmd_payload_sz != + sizeof(struct gsl_cmd_configure_read_write_params)) { + rc = AR_EBADPARAM; + GSL_ERR("cfg read params ioctl, inv payload size %d expected %d", + cmd_payload_sz, + sizeof(struct gsl_cmd_configure_read_write_params)); + break; + } + + rc = gsl_graph_config_data_path(graph, GSL_DATA_DIR_READ, + (struct gsl_cmd_configure_read_write_params *) cmd_payload); + if (rc) + GSL_ERR("configure read params ioctl failed %d", rc); + break; + + case GSL_CMD_CONFIGURE_WRITE_PARAMS: + if (cmd_payload_sz != + sizeof(struct gsl_cmd_configure_read_write_params)) { + rc = AR_EBADPARAM; + GSL_ERR("cfg write params ioctl, inv payload size %d expected %d", + cmd_payload_sz, + sizeof(struct gsl_cmd_configure_read_write_params)); + break; + } + + rc = gsl_graph_config_data_path(graph, GSL_DATA_DIR_WRITE, + (struct gsl_cmd_configure_read_write_params *) cmd_payload); + if (rc) + GSL_ERR("configure write params ioctl failed %d", rc); + break; + + case GSL_CMD_GET_READ_BUFF_INFO: + if (cmd_payload_sz < sizeof(struct gsl_cmd_get_shmem_buf_info)) { + rc = AR_EBADPARAM; + GSL_ERR("read buff info ioctl, inv payload size %d expected gt %d", + cmd_payload_sz, + sizeof(struct gsl_cmd_get_shmem_buf_info)); + break; + } + + rc = gsl_dp_get_buff_info(&graph->read_info, + (struct gsl_cmd_get_shmem_buf_info *)cmd_payload); + if (rc) + GSL_ERR("get read params ioctl failed %d", rc); + break; + + case GSL_CMD_GET_WRITE_BUFF_INFO: + if (cmd_payload_sz < sizeof(struct gsl_cmd_get_shmem_buf_info)) { + rc = AR_EBADPARAM; + GSL_ERR("write buff info ioctl, inv payload size %d, expected %d", + cmd_payload_sz, + sizeof(struct gsl_cmd_get_shmem_buf_info)); + break; + } + + rc = gsl_dp_get_buff_info(&graph->write_info, + (struct gsl_cmd_get_shmem_buf_info *)cmd_payload); + if (rc) + GSL_ERR("get write params ioctl failed %d", rc); + break; + + case GSL_CMD_GET_READ_POS_BUFF_INFO: + if (cmd_payload_sz < sizeof(struct gsl_cmd_get_shmem_buf_info)) { + rc = AR_EBADPARAM; + GSL_ERR("get rd pos buf ioctl, inv payload size %d expected gt %d", + cmd_payload_sz, + sizeof(struct gsl_cmd_get_shmem_buf_info)); + break; + } + + rc = gsl_dp_get_pos_buff_info(&graph->read_info, + (struct gsl_cmd_get_shmem_buf_info *)cmd_payload); + if (rc) + GSL_ERR("get rd pos buf ioctl failed %d", rc); + break; + + case GSL_CMD_GET_WRITE_POS_BUFF_INFO: + if (cmd_payload_sz < sizeof(struct gsl_cmd_get_shmem_buf_info)) { + rc = AR_EBADPARAM; + GSL_ERR("get wr pos buf ioctl, inv payload size %d expected gt %d", + cmd_payload_sz, + sizeof(struct gsl_cmd_get_shmem_buf_info)); + break; + } + + rc = gsl_dp_get_pos_buff_info(&graph->write_info, + (struct gsl_cmd_get_shmem_buf_info *)cmd_payload); + if (rc) + GSL_ERR("get wr pos buf ioctl failed %d", rc); + break; + + case GSL_CMD_FREE_READ_BUFF: + for (i = 0; i < graph->write_info.config.num_buffs; ++i) + gsl_msg_free(&graph->write_info.buff_list[i].gsl_msg); + break; + + case GSL_CMD_FREE_WRITE_BUFF: + for (i = 0; i < graph->read_info.config.num_buffs; ++i) + gsl_msg_free(&graph->read_info.buff_list[i].gsl_msg); + break; + + case GSL_CMD_EOS: + rc = gsl_dp_write_send_eos(&graph->write_info); + if (rc) + GSL_ERR("eos ioctl failed %d", rc); + break; + + case GSL_CMD_REGISTER_CUSTOM_EVENT: + if (cmd_payload_sz < sizeof(struct gsl_cmd_register_custom_event)) { + rc = AR_EBADPARAM; + GSL_ERR("reg cust event ioctl, inv payload size %d, expected %d", + cmd_payload_sz, sizeof(struct gsl_cmd_register_custom_event)); + break; + } + + rc = gsl_graph_register_custom_event(graph, + (struct gsl_cmd_register_custom_event *) cmd_payload); + if (rc) + GSL_ERR("register custom event failed %d", rc); + break; + + case GSL_CMD_FLUSH: + rc = gsl_graph_flush(graph, gsl_ctxt.open_close_lock); + if (rc) + GSL_ERR("graph flush ioctl failed %d", rc); + break; + + case GSL_CMD_ADD_GRAPH: + ag = (struct gsl_cmd_graph_select *)cmd_payload; + + if (!ag || !ag->graph_key_vector.kvp || + (ag->graph_key_vector.num_kvps == 0)) { + GSL_ERR("add_graph: graph key vector not specified"); + break; + } + rc = gsl_graph_add_new(graph, ag, gsl_ctxt.open_close_lock); + if (rc) + GSL_ERR("add graph ioctl failed %d", rc); + break; + + case GSL_CMD_REMOVE_GRAPH: + rg = (struct gsl_cmd_remove_graph *)cmd_payload; + + if (!rg || !rg->graph_key_vector.kvp || + (rg->graph_key_vector.num_kvps == 0)) { + GSL_ERR("remove_graph: graph key vector not specified"); + break; + } + rc = gsl_graph_remove_old(graph, rg, gsl_ctxt.open_close_lock, + gsl_ctxt.start_stop_lock); + if (rc) + GSL_ERR("remove graph ioctl failed %d", rc); + break; + + case GSL_CMD_CHANGE_GRAPH: + cg = (struct gsl_cmd_graph_select *)cmd_payload; + + if (!cg || !cg->graph_key_vector.kvp || + (cg->graph_key_vector.num_kvps == 0)) { + GSL_ERR("change_graph: graph key vector not specified"); + break; + } + rc = gsl_graph_change(graph, cg, gsl_ctxt.open_close_lock); + if (rc) + GSL_ERR("change graph ioctl failed %d", rc); + break; + + case GSL_CMD_CLOSE_WITH_PROPS: + if (cmd_payload && + (cmd_payload_sz != sizeof(struct gsl_cmd_properties))) { + rc = AR_EBADPARAM; + break; + } + rc = gsl_graph_close_with_properties(graph, + (struct gsl_cmd_properties *)cmd_payload, + gsl_ctxt.open_close_lock); + if (rc) + GSL_ERR("close with properties ioctl failed %d", rc); + break; + + case GSL_CMD_QUERY_GRAPH_DELAY: + case GSL_CMD_MAX: + break; + + } + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_read(gsl_handle_t graph_handle, uint32_t tag, + struct gsl_buff *buff, uint32_t *filled_size) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + GSL_VERBOSE("ENTER handle=%d, buff size=%d", graph_handle, buff->size); + + /* if RTGM is in-progress block read */ + rc = gsl_main_start_client_op_blocking(&gsl_ctxt); + if (rc) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!buff) { + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_read(graph, tag, buff, filled_size); + if (rc != AR_EOK && rc != AR_ENORESOURCE) + GSL_ERR("gsl_graph_read failed err %d", rc); + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_write(gsl_handle_t graph_handle, uint32_t tag, + struct gsl_buff *buff, uint32_t *consumed_size) +{ + struct gsl_graph *graph; + int32_t rc = AR_EOK; + + GSL_VERBOSE("ENTER handle=%d, buff size=%d", graph_handle, buff->size); + + /* if RTGM is in-progress block write */ + rc = gsl_main_start_client_op_blocking(&gsl_ctxt); + if (rc) + return rc; + + graph = to_gsl_graph(graph_handle); + if (!graph) { + rc = AR_EBADPARAM; + goto exit; + } + + if (gsl_graph_get_state(graph) == GRAPH_ERROR || + gsl_graph_get_state(graph) == GRAPH_ERROR_ALLOW_CLEANUP) { + rc = AR_ESUBSYSRESET; + goto exit; + } + + if (!buff) { + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_graph_write(graph, tag, buff, consumed_size); + if (rc != AR_EOK && rc != AR_ENORESOURCE) + GSL_ERR("gsl_graph_write failed: consumed_size:%d, rc:%d", + *consumed_size, rc); + +exit: + gsl_main_end_client_op(&gsl_ctxt); + + return rc; +} + +int32_t gsl_register_event_cb(gsl_handle_t graph_handle, + gsl_cb_func_ptr cb, void *client_data) +{ + struct gsl_graph *graph = NULL; + + /* no need to synchronize with rtgm as it doesnt do anything with spf */ + + graph = to_gsl_graph(graph_handle); + if (!graph) + return AR_EBADPARAM; + + graph->cb = cb; + graph->client_data = client_data; + + return AR_EOK; +} + +int32_t gsl_get_tagged_data( + const struct gsl_key_vector *graph_key_vect, uint32_t tag, + struct gsl_key_vector *tag_key_vect, uint8_t *payload, + size_t *payload_size) +{ + int32_t rc = AR_EOK; + + /* no need to synchronize with rtgm as it doesnt do anything with spf */ + + if (!graph_key_vect) + return AR_EBADPARAM; + + if (!payload_size) + return AR_EBADPARAM; + + rc = gsl_graph_get_tagged_data(graph_key_vect, tag, tag_key_vect, + payload, payload_size); + + return rc; +} + +int32_t gsl_get_tagged_module_info( + const struct gsl_key_vector *graph_key_vect, uint32_t tag, + struct gsl_module_id_info **module_info, uint32_t *module_info_size) +{ + int32_t rc = AR_EOK; + + /* no need to synchronize with rtgm as it doesnt do anything with spf */ + + if (!graph_key_vect) + return AR_EBADPARAM; + + if (!module_info || !module_info_size) + return AR_EBADPARAM; + + *module_info = NULL; + *module_info_size = 0; + rc = gsl_graph_get_module_tag_info(graph_key_vect, tag, + module_info, module_info_size); + + return rc; +} + +int32_t gsl_get_tags_with_module_info( + const struct gsl_key_vector *graph_key_vect, void *tag_module_info, + size_t *tag_module_info_size) +{ + int32_t rc = AR_EOK; + + /* no need to synchronize with rtgm as it doesnt do anything with spf */ + + if (!graph_key_vect) + return AR_EBADPARAM; + + if (!tag_module_info_size) + return AR_EBADPARAM; + + rc = gsl_graph_get_tags_with_module_info(graph_key_vect, + (struct gsl_tag_module_info *)tag_module_info, + tag_module_info_size); + + return rc; +} + +int32_t gsl_enable_acdb_persistence(uint8_t enable_flag) +{ + return acdb_ioctl(ACDB_CMD_ENABLE_PERSISTANCE, &enable_flag, + sizeof(enable_flag), NULL, 0); +} + +int32_t gsl_set_cal_data_to_acdb( + const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect, uint8_t *payload, + uint32_t payload_size) +{ + int32_t rc = AR_EOK; + AcdbSetCalDataReq cmd_struct; + + cmd_struct.graph_key_vector.num_keys = graph_key_vect->num_kvps; + cmd_struct.graph_key_vector.graph_key_vector = + (AcdbKeyValuePair *) graph_key_vect->kvp; + cmd_struct.cal_key_vector.num_keys = cal_key_vect->num_kvps; + cmd_struct.cal_key_vector.graph_key_vector + = (AcdbKeyValuePair *)cal_key_vect->kvp; + cmd_struct.cal_blob_size = payload_size; + cmd_struct.cal_blob = payload; + + rc = acdb_ioctl(ACDB_CMD_SET_CAL_DATA, &cmd_struct, + sizeof(cmd_struct), NULL, 0); + if (rc) + GSL_ERR("acdb set calibration data failed with %d", rc); + + return rc; +} + +int32_t gsl_get_cal_data_from_acdb( + const struct gsl_key_vector *graph_key_vect, + const struct gsl_key_vector *cal_key_vect, uint32_t num_modules, + uint8_t *param_list, void *payload, uint32_t *payload_size) +{ + int32_t rc = AR_EOK; + AcdbGetCalDataReq cmd_struct; + AcdbBlob rsp_struct = { 0 }; + + if (!payload_size) + return AR_EBADPARAM; + + cmd_struct.graph_key_vector.num_keys = graph_key_vect->num_kvps; + cmd_struct.graph_key_vector.graph_key_vector = + (AcdbKeyValuePair *) graph_key_vect->kvp; + cmd_struct.cal_key_vector.num_keys = cal_key_vect->num_kvps; + cmd_struct.cal_key_vector.graph_key_vector + = (AcdbKeyValuePair *)cal_key_vect->kvp; + cmd_struct.num_module_instance = num_modules; + cmd_struct.instance_param_list = (AcdbModuleParamList *)param_list; + + if (payload) { + rsp_struct.buf = payload; + rsp_struct.buf_size = *payload_size; + } + + rc = acdb_ioctl(ACDB_CMD_GET_CAL_DATA, &cmd_struct, + sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) + GSL_ERR("acdb get calibration data failed with %d", rc); + + *payload_size = rsp_struct.buf_size; + + return rc; +} + +int32_t gsl_set_tag_data_to_acdb( + const struct gsl_key_vector *graph_key_vect, uint32_t tag_id, + const struct gsl_key_vector *tag_key_vect, uint8_t *payload, + uint32_t payload_size) +{ + int32_t rc = AR_EOK; + AcdbSetTagDataReq cmd_struct; + + cmd_struct.graph_key_vector.num_keys = graph_key_vect->num_kvps; + cmd_struct.graph_key_vector.graph_key_vector = + (AcdbKeyValuePair *) graph_key_vect->kvp; + cmd_struct.module_tag.tag_id = tag_id; + cmd_struct.module_tag.tag_key_vector.num_keys = tag_key_vect->num_kvps; + cmd_struct.module_tag.tag_key_vector.graph_key_vector + = (AcdbKeyValuePair *)tag_key_vect->kvp; + cmd_struct.blob_size = payload_size; + cmd_struct.blob = payload; + + rc = acdb_ioctl(ACDB_CMD_SET_TAG_DATA, &cmd_struct, + sizeof(cmd_struct), NULL, 0); + if (rc) + GSL_ERR("acdb set tag data failed with %d", rc); + + return rc; +} + +int32_t gsl_get_tag_data_from_acdb( + const struct gsl_key_vector *graph_key_vect, uint32_t tag_id, + const struct gsl_key_vector *tag_key_vect, uint32_t num_modules, + uint8_t *param_list, void *payload, uint32_t *payload_size) +{ + int32_t rc = AR_EOK; + AcdbGetTagDataReq cmd_struct; + AcdbBlob rsp_struct = { 0 }; + + if (!payload_size) + return AR_EBADPARAM; + + cmd_struct.graph_key_vector.num_keys = graph_key_vect->num_kvps; + cmd_struct.graph_key_vector.graph_key_vector = + (AcdbKeyValuePair *) graph_key_vect->kvp; + cmd_struct.module_tag.tag_id = tag_id; + cmd_struct.module_tag.tag_key_vector.num_keys = tag_key_vect->num_kvps; + cmd_struct.module_tag.tag_key_vector.graph_key_vector = + (AcdbKeyValuePair *) tag_key_vect->kvp; + cmd_struct.num_module_instance = num_modules; + cmd_struct.instance_param_list = (AcdbModuleParamList *)param_list; + + if (payload) { + rsp_struct.buf = payload; + rsp_struct.buf_size = *payload_size; + } + + rc = acdb_ioctl(ACDB_CMD_GET_TAG_DATA, &cmd_struct, + sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) + GSL_ERR("acdb get tag data failed with %d", rc); + + *payload_size = rsp_struct.buf_size; + + return rc; +} + +int32_t gsl_set_temp_path_to_acdb(uint32_t path_length, const char_t *temp_path) +{ + int32_t rc = AR_EOK; + AcdbSetTempPathReq cmd_struct; + + cmd_struct.path_length = path_length; + + ar_strcpy((char_t *)cmd_struct.path, MAX_FILENAME_LENGTH - 1, + temp_path, path_length); + + rc = acdb_ioctl(ACDB_CMD_SET_TEMP_PATH, &cmd_struct, + sizeof(cmd_struct), NULL, 0); + if (rc) + GSL_ERR("acdb set temp path failed with %d", rc); + + return rc; +} + +int32_t gsl_get_graph_alias(const struct gsl_key_vector *graph_key_vect, + char_t *alias, uint32_t *alias_len) +{ + int32_t rc = AR_EOK; + AcdbString rsp_struct = { 0, }; + AcdbGraphKeyVector cmd_struct; + + /* need to construct AcdbKeyVector because it is packed, gsl_kv isn't */ + + cmd_struct.num_keys = graph_key_vect->num_kvps; + cmd_struct.graph_key_vector = (AcdbKeyValuePair *)graph_key_vect->kvp; + + rsp_struct.length = *alias_len; + rsp_struct.string = alias; + + rc = acdb_ioctl(ACDB_CMD_GET_GRAPH_ALIAS, &cmd_struct, sizeof(cmd_struct), + &rsp_struct, sizeof(rsp_struct)); + *alias_len = rsp_struct.length; + if (rc) + GSL_ERR("acdb get graph alias failed %d, len %d", rc, *alias_len); + + return rc; +} + +int32_t gsl_get_processed_buff_cnt(gsl_handle_t graph_handle, + enum gsl_data_dir dir, uint32_t *cnt) +{ + struct gsl_graph *graph; + + /* no need to synchronize with rtgm as it doesnt do anything with spf */ + + graph = to_gsl_graph(graph_handle); + if (!graph) + return AR_EBADPARAM; + + if (gsl_graph_get_state(graph) == GRAPH_ERROR) + return AR_ESUBSYSRESET; + + if (dir == GSL_DATA_DIR_READ) + *cnt = gsl_dp_get_processed_buff_cnt(&graph->read_info); + else + *cnt = gsl_dp_get_processed_buff_cnt(&graph->write_info); + + return AR_EOK; +} + +int32_t gsl_get_avail_buffer_size(gsl_handle_t graph_handle, enum gsl_data_dir dir, + uint32_t *bytes) +{ + struct gsl_graph *graph; + + /* no need to synchronize with rtgm as it doesnt do anything with spf */ + + graph = to_gsl_graph(graph_handle); + if (!graph) + return AR_EBADPARAM; + + if (gsl_graph_get_state(graph) == GRAPH_ERROR) + return AR_ESUBSYSRESET; + + if (dir == GSL_DATA_DIR_READ) + *bytes = gsl_dp_get_avail_buffer_size(&graph->read_info); + else + *bytes = gsl_dp_get_avail_buffer_size(&graph->write_info); + + return AR_EOK; +} + +int32_t gsl_add_database(struct gsl_acdb_data_files *acdb_data_files, + struct gsl_acdb_file *writable_file_path, + gsl_acdb_handle_t *acdb_handle) +{ + int32_t rc = AR_EOK; + acdb_handle_t acdb_hdl; + struct gsl_acdb_client_info *client = NULL; + + client = gsl_mem_zalloc(sizeof(struct gsl_acdb_client_info)); + if (!client) + return AR_ENOMEMORY; + GSL_MUTEX_LOCK(gsl_ctxt.acdb_client_lock); + rc = acdb_add_database((AcdbDatabaseFiles *)acdb_data_files, + (AcdbFile *)writable_file_path, &acdb_hdl); + if (rc != AR_EOK) { + GSL_ERR("add acdb database into global heap failure"); + goto exit; + } + rc = gsl_do_load_bootup_dyn_modules(AR_DEFAULT_DSP, + (gsl_acdb_handle_t)acdb_hdl); + if (rc) { + GSL_ERR("load bootup dync modules failure when adding acdb database"); + goto remove_acdb; + } + gsl_memcpy((uint8_t *)&client->acdb_files, + sizeof(struct gsl_acdb_data_files), + acdb_data_files, sizeof(struct gsl_acdb_data_files)); + + if (writable_file_path != NULL) + gsl_memcpy((uint8_t *)&client->acdb_delta_file, + sizeof(struct gsl_acdb_file), + writable_file_path, sizeof(struct gsl_acdb_file)); + + client->acdb_handle = (gsl_acdb_handle_t)acdb_hdl; + ar_list_init_node(&client->node); + rc = ar_list_add_tail(&gsl_ctxt.acdb_client_list, &client->node); + *acdb_handle = (gsl_acdb_handle_t)acdb_hdl; + GSL_MUTEX_UNLOCK(gsl_ctxt.acdb_client_lock); + return rc; + +remove_acdb: + acdb_remove_database(&acdb_hdl); +exit: + gsl_mem_free(client); + GSL_MUTEX_UNLOCK(gsl_ctxt.acdb_client_lock); + return rc; +} + +int32_t gsl_remove_database(gsl_acdb_handle_t acdb_handle) +{ + uint32_t rc = AR_EOK; + ar_list_node_t *client_node = NULL; + struct gsl_acdb_client_info *client = NULL; + bool_t client_found = FALSE; + + GSL_MUTEX_LOCK(gsl_ctxt.acdb_client_lock); + + ar_list_for_each_entry(client_node, &gsl_ctxt.acdb_client_list) { + client = get_container_base(client_node, + struct gsl_acdb_client_info, node); + if (acdb_handle == client->acdb_handle) { + client_found = TRUE; + break; + } + } + + if (client_found == FALSE) { + GSL_ERR("invalid acdb handle"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_do_unload_bootup_dyn_modules(AR_DEFAULT_DSP, acdb_handle); + if (rc) { + GSL_ERR("deregister dyn module by handle exited"); + goto exit; + } + + rc = acdb_remove_database(&client->acdb_handle); + if (rc) { + GSL_ERR("remove acdb files from data base exited"); + goto exit; + } + + ar_list_delete(&gsl_ctxt.acdb_client_list, &client->node); +exit: + GSL_MUTEX_UNLOCK(gsl_ctxt.acdb_client_lock); + return rc; +} diff --git a/gsl/src/gsl_mdf_utils.c b/gsl/src/gsl_mdf_utils.c new file mode 100644 index 0000000..f6c3867 --- /dev/null +++ b/gsl/src/gsl_mdf_utils.c @@ -0,0 +1,673 @@ +/** + * \file gsl_mdf_utils.c + * + * \brief + * Multi-DSP framework utilities library + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_mdf_utils.h" +#include "ar_osal_error.h" +#include "ar_osal_types.h" +#include "ar_osal_sys_id.h" +#include "ar_osal_shmem.h" +#include "ar_osal_dyn_pd.h" +#include "acdb.h" +#include "gsl_common.h" +#include "gsl_msg_builder.h" +#include "gpr_api_inline.h" + + /** + * This structure represents a goup of susbsytems that share a common client + * loaned memory allocation + */ +struct gsl_spf_ss_group { + /* bit mask that represents the set of subsystems in this group */ + uint32_t ss_mask; + + /* bit mask indicates if the corresponding ss has been restarted */ + uint32_t ss_restarted_flags; + /* + * used to store the size of client loaned memory in bytes, this is read + * from ACDB + */ + uint32_t loaned_mem_sz; + /* + * master proc id + */ + uint32_t master_proc; + /* hold the shmem allocation */ + struct gsl_shmem_alloc_data loaned_mem; +}; + + +struct gsl_mdf_info { + /* + * number of ss groups + */ + uint32_t num_ss_groups; + /* + * list of ss groups + */ + struct gsl_spf_ss_group *ss_groups; + /* + * master proc mask + */ + uint32_t master_proc_mask; + /* number of subsystems */ + uint32_t num_procs; + /* susbystems domain type information */ + struct proc_domain_type *pd_info; + /* dynamic pd reference count */ + uint32_t pd_init_ref_cnt[AR_SUB_SYS_ID_LAST + 1]; + /* dynamic pd deinit pending used to skip PD DOWN treated as crash */ + bool_t pd_deinit_pending[AR_SUB_SYS_ID_LAST + 1]; + +} _gsl_glb_mdf_info = {0, NULL, 0, 0, NULL, {0}, {FALSE}}; + +static bool_t is_initialized = FALSE; + +bool_t gsl_mdf_utils_is_dynamic_pd(uint32_t proc_id) +{ + uint32_t i = 0; + + for (i = 0; i < _gsl_glb_mdf_info.num_procs; ++i) { + if (_gsl_glb_mdf_info.pd_info[i].proc_id == proc_id && + _gsl_glb_mdf_info.pd_info[i].proc_type == DYNAMIC_PD) + return TRUE; + } + return FALSE; +} + +bool_t gsl_mdf_utils_get_dynamic_pd_state(uint32_t proc_id) +{ + if ((proc_id >= AR_SUB_SYS_ID_FIRST && proc_id <= AR_SUB_SYS_ID_LAST) && + _gsl_glb_mdf_info.pd_init_ref_cnt[proc_id] && + !_gsl_glb_mdf_info.pd_deinit_pending[proc_id]) + return TRUE; + + return FALSE; +} + +uint32_t gsl_mdf_utils_query_graph_ss_mask(uint32_t *sg_id_list, + uint32_t num_sgs, uint32_t *ss_mask) +{ + int32_t rc = AR_EOK; + AcdbCmdGetSubgraphProcIdsReq req = {0,}; + AcdbCmdGetSubgraphProcIdsRsp rsp; + uint32_t i = 0, j = 0; + AcdbSgProcIdsMap *p = NULL; + + if (!ss_mask || !sg_id_list) + return AR_EBADPARAM; + + /* first call to get size */ + req.num_sg_ids = num_sgs; + req.sg_ids = sg_id_list; + rsp.num_sg_ids = 0; + rsp.size = 0; + rsp.sg_proc_ids = NULL; + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_PROCIDS, &req, sizeof(req), &rsp, + sizeof(rsp)); + if (rc != AR_EOK && rc != AR_ENOTEXIST) { + GSL_ERR("ACDB get subgraph procids failed %d", rc); + return rc; + } else if (rc == AR_ENOTEXIST) { + /* if not ss*/ + *ss_mask = GSL_GET_SPF_SS_MASK(AR_DEFAULT_DSP); + return AR_EOK; + } + + rsp.sg_proc_ids = gsl_mem_zalloc(rsp.size); + if (!rsp.sg_proc_ids) { + rc = AR_ENOMEMORY; + return rc; + } + + /* next call to get data */ + rc = acdb_ioctl(ACDB_CMD_GET_SUBGRAPH_PROCIDS, &req, sizeof(req), &rsp, + sizeof(rsp)); + if (rc != AR_EOK) { + GSL_ERR("ACDB get subgraph procids failed %d", rc); + goto free_sg_proc_ids; + } + + *ss_mask = 0; + p = rsp.sg_proc_ids; + for (i = 0; i < rsp.num_sg_ids; ++i) { + for (j = 0; j < p->num_proc_ids; ++j) + *ss_mask |= GSL_GET_SPF_SS_MASK(p->proc_ids[j]); + /* move p forward to the next SG entry */ + p = (AcdbSgProcIdsMap *)((uint32_t *)p + 2 + p->num_proc_ids); + } + +free_sg_proc_ids: + gsl_mem_free(rsp.sg_proc_ids); + return AR_EOK; +} + +int32_t gsl_mdf_utils_get_master_proc_ids(uint32_t *num_masters, + uint32_t master_proc_ids[]) +{ + uint32_t i = 0; + + if (num_masters == NULL) + return AR_EBADPARAM; + if (master_proc_ids == NULL) { + *num_masters = _gsl_glb_mdf_info.num_ss_groups; + } else { + for (i = 0; i < _gsl_glb_mdf_info.num_ss_groups; i++) + master_proc_ids[i] = _gsl_glb_mdf_info.ss_groups[i].master_proc; + } + return AR_EOK; +} + +int32_t gsl_mdf_utils_get_supported_ss_info_from_master_proc( + uint32_t master_proc, + uint32_t *supported_ss_mask) +{ + int32_t rc = AR_ENOTEXIST; + uint32_t i = 0; + + for (; i < _gsl_glb_mdf_info.num_ss_groups; i++) { + if (_gsl_glb_mdf_info.ss_groups[i].master_proc == master_proc) { + *supported_ss_mask = _gsl_glb_mdf_info.ss_groups[i].ss_mask; + rc = AR_EOK; + return rc; + } + } + return rc; +} + +int32_t gsl_mdf_utils_get_proc_domain_info( + proc_domain_type_t **proc_domains, uint32_t *num_procs) +{ + if (!proc_domains || !num_procs) + return AR_EBADPARAM; + *num_procs = _gsl_glb_mdf_info.num_procs; + *proc_domains = _gsl_glb_mdf_info.pd_info; + return AR_EOK; +} + +bool_t gsl_mdf_utils_is_master_proc(uint32_t spf_ss_mask) +{ + if (spf_ss_mask & _gsl_glb_mdf_info.master_proc_mask) + return TRUE; + return FALSE; +} + +uint32_t gsl_mdf_utils_get_master_proc_id(uint32_t spf_ss_mask) +{ + uint32_t i = 0; + + for (; i < _gsl_glb_mdf_info.num_ss_groups; i++) { + if (_gsl_glb_mdf_info.ss_groups[i].ss_mask & spf_ss_mask) + return _gsl_glb_mdf_info.ss_groups[i].master_proc; + } + return 0; +} + +int32_t gsl_mdf_utils_get_supported_ss_info_from_acdb(void) +{ + AcdbDriverData acdb_req = { 0, }; + AcdbBlob acdb_rsp = { 0, }; + struct proc_group_info_params_t *grps = NULL; + struct per_group_shmem_info_t *p = { 0, }; + struct proc_domain_info *pd = NULL; + struct proc_domain_type *pt = NULL; + int32_t rc = AR_EOK; + uint32_t i = 0, j = 0, *tmp_p = NULL, *tmp_pos = NULL; + bool_t found = FALSE; + + /* first query for size */ + acdb_req.key_vector.num_keys = 0; + acdb_req.module_id = GSL_MULTI_DSP_FWK_DATA_MID; + acdb_rsp.buf = NULL; + acdb_rsp.buf_size = 0; + rc = acdb_ioctl(ACDB_CMD_GET_DRIVER_DATA, &acdb_req, sizeof(acdb_req), + &acdb_rsp, sizeof(acdb_rsp)); + if (rc != AR_EOK && rc != AR_ENOTEXIST) { + GSL_ERR("acdb query ACDB_CMD_GET_DRIVER_DATA failed %d", rc); + return rc; + } else if (rc == AR_ENOTEXIST) { + /* if MDF driver data is not found, assume we only have ADSP */ + _gsl_glb_mdf_info.num_ss_groups = 1; + _gsl_glb_mdf_info.num_procs = 0; + _gsl_glb_mdf_info.pd_info = NULL; + _gsl_glb_mdf_info.ss_groups = + gsl_mem_zalloc(sizeof(struct gsl_spf_ss_group)); + + if (_gsl_glb_mdf_info.ss_groups == NULL) { + rc = AR_ENOMEMORY; + return rc; + } + + _gsl_glb_mdf_info.ss_groups[0].master_proc = AR_DEFAULT_DSP; + _gsl_glb_mdf_info.ss_groups[0].ss_mask = + GSL_GET_SPF_SS_MASK(AR_DEFAULT_DSP); + _gsl_glb_mdf_info.ss_groups[0].loaned_mem_sz = 0; + _gsl_glb_mdf_info.master_proc_mask = + GSL_GET_SPF_SS_MASK(AR_DEFAULT_DSP); + + return AR_EOK; + } + + acdb_rsp.buf = gsl_mem_zalloc(acdb_rsp.buf_size); + if (!acdb_rsp.buf) { + rc = AR_ENOMEMORY; + return rc; + } + + rc = acdb_ioctl(ACDB_CMD_GET_DRIVER_DATA, &acdb_req, sizeof(acdb_req), + &acdb_rsp, sizeof(acdb_rsp)); + if (rc != AR_EOK) { + GSL_ERR("acdb query ACDB_CMD_GET_DRIVER_DATA failed %d", rc); + goto exit; + } + + tmp_p = (uint32_t *)acdb_rsp.buf; + /* MID */ + if (*tmp_p++ != GSL_MULTI_DSP_FWK_DATA_MID) { + GSL_ERR("got incorrect MID from ACDB %d", *((uint32_t *)acdb_rsp.buf)); + goto exit; + } + + acdb_rsp.buf_size -= 4; /* PARAM ID GSL_MULTI_DSP_FWK_DATA_MID size */ + while (acdb_rsp.buf_size > 0) { + if (*tmp_p == PARAM_ID_PROC_GROUP_INFO_PARAMS) { + tmp_pos = tmp_p; + ++tmp_p; /* Skip Param ID */ + ++tmp_p; /* skip SIZE */ + grps = (struct proc_group_info_params_t *)tmp_p; + _gsl_glb_mdf_info.num_ss_groups = grps->num_proc_groups; + + _gsl_glb_mdf_info.ss_groups = gsl_mem_zalloc( + grps->num_proc_groups * + sizeof(struct gsl_spf_ss_group)); + + if (_gsl_glb_mdf_info.ss_groups == NULL) { + rc = AR_ENOMEMORY; + goto exit; + } + + /* make p point to group list */ + p = (struct per_group_shmem_info_t *)((uint8_t *)grps + + sizeof(struct proc_group_info_params_t)); + for (; i < grps->num_proc_groups; ++i) { + _gsl_glb_mdf_info.ss_groups[i].ss_mask = 0; + _gsl_glb_mdf_info.ss_groups[i].master_proc = p->master_proc; + _gsl_glb_mdf_info.ss_groups[i].ss_mask |= + GSL_GET_SPF_SS_MASK(p->master_proc); + _gsl_glb_mdf_info.master_proc_mask |= + GSL_GET_SPF_SS_MASK(p->master_proc); + for (j = 0; j < p->num_satellite_procs; ++j) { + _gsl_glb_mdf_info.ss_groups[i].ss_mask |= + GSL_GET_SPF_SS_MASK(p->satellite_proc_ids[j]); + } + /* store the client loaned mem size for this group */ + _gsl_glb_mdf_info.ss_groups[i].loaned_mem_sz = p->shmem_size; + + /* add this group's subsystems to global supported ss mask */ + + /* move p forward to next processor group */ + p = (struct per_group_shmem_info_t *)((uint8_t *)p + + sizeof(struct per_group_shmem_info_t) + + p->num_satellite_procs * sizeof(uint32_t)); + } + acdb_rsp.buf_size -= ((void *)p - (void *)tmp_pos); + tmp_p = (uint32_t *)p; + } else if (*tmp_p == PARAM_ID_PROC_DOMAIN_INFO) { + tmp_pos = tmp_p; + ++tmp_p; /* Skip Param ID */ + ++tmp_p; /* Skip Size */ + pd = (struct proc_domain_info *)tmp_p; + _gsl_glb_mdf_info.num_procs = pd->num_procs; + _gsl_glb_mdf_info.pd_info = gsl_mem_zalloc( + pd->num_procs * sizeof(struct proc_domain_type)); + + if (_gsl_glb_mdf_info.pd_info == NULL) { + rc = AR_ENOMEMORY; + goto exit; + } + pt = pd->domain_type; + for (i = 0; i < pd->num_procs; ++i) { + _gsl_glb_mdf_info.pd_info[i].proc_id = pt->proc_id; + _gsl_glb_mdf_info.pd_info[i].proc_type = pt->proc_type; + ++pt; + } + acdb_rsp.buf_size -= ((void *)pt - (void *)tmp_pos); + tmp_p = (uint32_t *)pt; + } else { + GSL_ERR("got incorrect PID from ACDB %d", + *((uint32_t *)acdb_rsp.buf)); + goto exit; + } + } + if (grps == NULL) { + rc = AR_ENOTEXIST; + goto exit; + } + for (i = 0; i < _gsl_glb_mdf_info.num_procs; ++i) { + found = FALSE; + for (j = 0; j < grps->num_proc_groups; ++j) { + if ((GSL_TEST_SPF_SS_BIT(_gsl_glb_mdf_info.ss_groups[j].ss_mask, + _gsl_glb_mdf_info.pd_info[i].proc_id))) { + found = TRUE; + break; + } + } + if (found == FALSE) { + GSL_ERR("group info does not have proc %d", + _gsl_glb_mdf_info.pd_info[i].proc_id); + break; + } + } + +exit: + gsl_mem_free(acdb_rsp.buf); + if (rc && _gsl_glb_mdf_info.ss_groups) + free(_gsl_glb_mdf_info.ss_groups); + if (rc && _gsl_glb_mdf_info.pd_info) + free(_gsl_glb_mdf_info.pd_info); + + return rc; +} + +void gsl_mdf_utils_notify_ss_restarted(uint32_t restarted_ss_mask) +{ + uint32_t i = 0; + struct gsl_spf_ss_group *grp = NULL; + uint32_t tmp_ss_mask = 0; + + /* search through the group proc_ids and find matching ss_mask */ + for (i = 0; i < _gsl_glb_mdf_info.num_ss_groups; ++i) { + grp = &_gsl_glb_mdf_info.ss_groups[i]; + + /* + * if master is crashed then mark all ss in the group as restarted + * this is required because we need to remap to all satellites if + * the master crashed. For now we assume ADSP is the master. + */ + if (GSL_TEST_SPF_SS_BIT(restarted_ss_mask, grp->master_proc)) { + grp->ss_restarted_flags = grp->ss_mask; + } else { + tmp_ss_mask = grp->ss_mask & restarted_ss_mask; + /* + * Check if any ss in the current group is restarted + */ + if (tmp_ss_mask) + grp->ss_restarted_flags = tmp_ss_mask; + } + } +} + +/* + * finds the proc group object matching ss_mask and allocates the loaned memory + * for it + */ +int32_t gsl_mdf_utils_shmem_alloc(uint32_t ss_mask, uint32_t master_proc) +{ + int32_t rc = AR_EOK; + uint32_t i = 0; + struct gsl_spf_ss_group *grp = NULL; + uint32_t tmp_ss_mask = 0; + + /* noop if this graph only depends on master proc */ + if (ss_mask == (uint32_t) GSL_GET_SPF_SS_MASK(master_proc)) + goto exit; + + /* search through the group proc_ids and find matching ss_mask */ + for (i = 0; i < _gsl_glb_mdf_info.num_ss_groups; ++i) { + grp = &_gsl_glb_mdf_info.ss_groups[i]; + /* + * If ss_mask is all clear it means we have allocated for all the + * required subsystems. + */ + if (!ss_mask) + break; + /* + * If loaned shmem for this group is already allocated, see if remap + * is required to any ss due to ssr or map if dynamic pd. + */ + if (grp->loaned_mem.handle) { + if (grp->ss_restarted_flags) { + gsl_shmem_map_allocation_to_spf(&grp->loaned_mem, + GSL_SHMEM_LOANED, grp->ss_restarted_flags, + master_proc); + grp->ss_restarted_flags = 0; + /* + * Clear bits corresponding to current group to indicate that + * we have already allocated memory for them + */ + ss_mask &= ~grp->ss_mask; + } + /* + * If a group contains both dynamic and static dynamic pds, + * the loaned memory already gets allocated at boot up but the + * mapping for dynamic pd gets skipped as dynamic pd is created + * and released during use case boundary. Check and map memory + * for dynamic pd. + */ + tmp_ss_mask = grp->ss_mask & ss_mask; + if (tmp_ss_mask) { + GSL_DBG("map dyn pd loaned mem, ss_mask 0x%x", tmp_ss_mask); + rc = gsl_shmem_map_dynamic_pd(&grp->loaned_mem, + GSL_SHMEM_LOANED, tmp_ss_mask, grp->master_proc); + if (rc != AR_EOK) + goto exit; + } + ss_mask &= ~tmp_ss_mask; + continue; + } else if (grp->ss_restarted_flags) { + /* + * ss_restarted_flags is used to indicate if remap + * is needed for allocated loaned shmem. If there's + * no loaned shmem allocated, this flag can be reset. + */ + grp->ss_restarted_flags = 0; + } + + tmp_ss_mask = grp->ss_mask & ss_mask; + /* + * Check if any ss in the current group is needed by the graph (note: + * a ss can appear in only one group) + */ + if (tmp_ss_mask) { + GSL_DBG("Allocate loaned memory, ss_mask 0x%x", tmp_ss_mask); + rc = gsl_shmem_alloc_ext(grp->loaned_mem_sz, tmp_ss_mask, + GSL_SHMEM_LOANED, 0, grp->master_proc, &grp->loaned_mem); + if (rc != AR_EOK) { + GSL_ERR("shmem alloc failed %d", rc); + break; + } + /* + * Clear bits corresponding to current group to indicate that we + * have already allocated memory for them' + */ + ss_mask &= ~tmp_ss_mask; + } + } + /* if we did not find a matching group for atleast one ss then error out */ + if (ss_mask) + rc = AR_ENOTEXIST; + +exit: + return rc; +} + +/* + * frees the mdf shmem for the request ss_mask. + */ +int32_t gsl_mdf_utils_shmem_free(uint32_t ss_mask) +{ + int32_t rc = AR_EOK; + uint32_t i = 0; + struct gsl_spf_ss_group *grp = NULL; + uint32_t tmp_ss_mask = 0; + + /* loop through the groups and free the shmem for each */ + for (i = 0; i < _gsl_glb_mdf_info.num_ss_groups; ++i) { + grp = &_gsl_glb_mdf_info.ss_groups[i]; + if (grp->loaned_mem.handle) { + if (ss_mask == AR_SUB_SYS_IDS_MASK || + gsl_shmem_get_mapped_ss_mask(&grp->loaned_mem) == ss_mask) { + + GSL_DBG("free loaned memory, ss_mask 0x%x", ss_mask); + rc = gsl_shmem_free(&grp->loaned_mem); + if (rc == AR_EOK) + grp->loaned_mem.handle = NULL; + else + GSL_ERR("shmem free failed %d", rc); + } else { + /* + * if both static and dynamic pd are present, + * unmap dynamic pd memory. + */ + tmp_ss_mask = grp->ss_mask & ss_mask; + if (tmp_ss_mask) { + GSL_DBG("unmap dyn pd loaned mem, ss_mask 0x%x", tmp_ss_mask); + gsl_shmem_unmap_dynamic_pd(&grp->loaned_mem, + tmp_ss_mask, grp->master_proc); + } + ss_mask &= ~tmp_ss_mask; + if (!ss_mask) + break; + } + } + } + + return rc; +} + +/* + * Creates dynamic PD and allocates shared memory. + */ +int32_t gsl_mdf_utils_register_dynamic_pd(uint32_t ss_mask, + uint32_t master_proc_id, uint32_t src_port, + struct gsl_signal *sig, uint32_t *dyn_ss_mask) +{ + int32_t rc = AR_EOK; + uint32_t sys_id = AR_SUB_SYS_ID_FIRST, tmp_ss_mask = 0, sm = 0; + uint32_t tmp_pd_list[AR_SUB_SYS_ID_LAST] = {0}, pd_cnt = 0; + + if (!dyn_ss_mask) + return AR_EBADPARAM; + *dyn_ss_mask = 0; + tmp_ss_mask = ss_mask; + while (tmp_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(ss_mask, sys_id)) { + if (sys_id == master_proc_id || + !gsl_mdf_utils_is_dynamic_pd(sys_id)) + goto next; + + *dyn_ss_mask |= GSL_GET_SPF_SS_MASK(sys_id); + if (_gsl_glb_mdf_info.pd_init_ref_cnt[sys_id] == 0) { + GSL_DBG("initialize dynamic pd %d", sys_id); + rc = ar_osal_dyn_pd_init(sys_id); + if (rc) { + GSL_ERR("ar_osal_dyn_pd_init failed %d", rc); + goto de_init_pd; + } + ++_gsl_glb_mdf_info.pd_init_ref_cnt[sys_id]; + tmp_pd_list[pd_cnt++] = sys_id; + sm = GSL_GET_SPF_SS_MASK(sys_id) | + GSL_GET_SPF_SS_MASK(master_proc_id); + GSL_DBG("Allocate memory ss_mask 0x%x", sm); + rc = gsl_mdf_utils_shmem_alloc(sm, master_proc_id); + if (rc != AR_EOK) { + GSL_ERR("failed to alloc loaned shmem %d", rc); + goto de_init_pd; + } + GSL_DBG("send spf satellite info, ss_mask 0x%x", sm); + rc = gsl_send_spf_satellite_info(master_proc_id, sm, src_port, sig); + if (rc != AR_EOK) { + GSL_ERR("failed to send satellite info, error %d, ss_mask 0x%x", + rc, ss_mask); + gsl_mdf_utils_shmem_free(sm); + goto de_init_pd; + } + } else { + ++_gsl_glb_mdf_info.pd_init_ref_cnt[sys_id]; + tmp_pd_list[pd_cnt++] = sys_id; + } + } + next: + ++sys_id; + tmp_ss_mask >>= 1; + } + return rc; + +de_init_pd: + while (pd_cnt > 0) { + --pd_cnt; + if (_gsl_glb_mdf_info.pd_init_ref_cnt[tmp_pd_list[pd_cnt]] == 1) + ar_osal_dyn_pd_deinit(tmp_pd_list[pd_cnt]); + --_gsl_glb_mdf_info.pd_init_ref_cnt[tmp_pd_list[pd_cnt]]; + } + return rc; +} + +/* + * Releases dynamic PD and deallocates shared memory. + */ +int32_t gsl_mdf_utils_deregister_dynamic_pd(uint32_t ss_mask, + uint32_t master_proc_id) +{ + int32_t rc = AR_EOK; + uint32_t sys_id = AR_SUB_SYS_ID_FIRST, tmp_ss_mask = 0, sm = 0; + uint32_t tmp_pd_list[AR_SUB_SYS_ID_LAST] = {0}, pd_cnt = 0; + + tmp_ss_mask = ss_mask; + while (tmp_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(ss_mask, sys_id)) { + if (sys_id == master_proc_id || + !gsl_mdf_utils_is_dynamic_pd(sys_id)) { + goto next; + } + if (_gsl_glb_mdf_info.pd_init_ref_cnt[sys_id] == 1) { + sm = GSL_GET_SPF_SS_MASK(sys_id) | + GSL_GET_SPF_SS_MASK(master_proc_id); + GSL_DBG("Free memory ss_mask 0x%x", sm); + rc = gsl_mdf_utils_shmem_free(sm); + if (rc != AR_EOK) + GSL_ERR("failed to free loaned shmem %d", rc); + GSL_DBG("deinitialize dynamic pd %d", sys_id); + + _gsl_glb_mdf_info.pd_deinit_pending[sys_id] = TRUE; + ar_osal_dyn_pd_deinit(sys_id); + _gsl_glb_mdf_info.pd_deinit_pending[sys_id] = FALSE; + } + if (_gsl_glb_mdf_info.pd_init_ref_cnt[sys_id] > 0) + --_gsl_glb_mdf_info.pd_init_ref_cnt[sys_id]; + } + next: + ++sys_id; + tmp_ss_mask >>= 1; + } + return rc; +} + +int32_t gsl_mdf_utils_init(void) +{ + if (!is_initialized) { + gsl_memset(&_gsl_glb_mdf_info, 0, sizeof(_gsl_glb_mdf_info)); + is_initialized = TRUE; + return gsl_mdf_utils_get_supported_ss_info_from_acdb(); + } + return AR_EOK; +} + +int32_t gsl_mdf_utils_deinit(void) +{ + int32_t rc = AR_EOK; + + if (is_initialized) { + is_initialized = FALSE; + rc = gsl_mdf_utils_shmem_free(AR_SUB_SYS_IDS_MASK); + gsl_mem_free(_gsl_glb_mdf_info.ss_groups); + gsl_mem_free(_gsl_glb_mdf_info.pd_info); + gsl_memset(&_gsl_glb_mdf_info, 0, sizeof(_gsl_glb_mdf_info)); + } + return rc; +} diff --git a/gsl/src/gsl_msg_builder.c b/gsl/src/gsl_msg_builder.c new file mode 100644 index 0000000..93811f5 --- /dev/null +++ b/gsl/src/gsl_msg_builder.c @@ -0,0 +1,138 @@ +/** + * \file gsl_msg_builder.c + * + * \brief + * Manages memory that is to be sent to Spf. + * Allocates shared memory or does non shared memory operations + * depending on the availability of shared memory b/n GSL & SPF domain. + * + * GSL sessions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "gsl_msg_builder.h" +#include "gsl_shmem_mgr.h" +#include "gpr_api_inline.h" +#include "ar_osal_sys_id.h" +#include "gsl_common.h" + +static bool_t supports_shared_mem[AR_SUB_SYS_ID_LAST+1] = {FALSE}; + +int32_t gsl_msg_free(gsl_msg_t *msg) +{ + if (!msg) + return AR_EBADPARAM; + + if (msg->shmem.handle != NULL) { + gsl_shmem_free(&msg->shmem); + msg->shmem.handle = NULL; + } + + if (msg->gpr_packet) { + __gpr_cmd_free(msg->gpr_packet); + msg->gpr_packet = NULL; + } + + return AR_EOK; +} + +/* Allocate shared memory & GPR packet */ +int32_t gsl_msg_alloc(uint32_t opcode, uint32_t src_port, + uint32_t dst_port, uint32_t gpr_payload_size, + uint32_t token, uint32_t dest_domain, + uint32_t oob_payload_size, bool_t force_inband, + gsl_msg_t *msg) +{ + return gsl_msg_alloc_ext(opcode, src_port, dst_port, gpr_payload_size, + token, dest_domain, oob_payload_size, force_inband, + GSL_GET_SPF_SS_MASK(dest_domain), 0, 0, msg); +} + +int32_t gsl_msg_alloc_ext(uint32_t opcode, uint32_t src_port, + uint32_t dst_port, uint32_t gpr_payload_size, + uint32_t token, uint32_t dest_domain, + uint32_t oob_payload_size, bool_t force_inband, + uint32_t spf_ss_mask, uint32_t flags, + uint32_t platform_info, gsl_msg_t *msg) +{ + int32_t rc = AR_EOK; + + if (!msg) { + rc = AR_EBADPARAM; + goto exit; + } + + if (force_inband || + (!supports_shared_mem[dest_domain])) { + rc = gsl_allocate_gpr_packet(opcode, src_port, dst_port, + gpr_payload_size + oob_payload_size, + token, dest_domain, + &msg->gpr_packet); + + if (rc) { + GSL_ERR("Failed to allocate gpr packet of size %d", + gpr_payload_size + oob_payload_size); + goto exit; + } + + msg->payload = GPR_PKT_GET_PAYLOAD(uint8_t, msg->gpr_packet); + gsl_memset(msg->payload, 0, (size_t)gpr_payload_size + oob_payload_size); + msg->payload += gpr_payload_size; + gsl_memset(&msg->shmem, 0, sizeof(struct gsl_shmem_alloc_data)); + } else { + rc = gsl_allocate_gpr_packet(opcode, src_port, dst_port, + gpr_payload_size, token, + dest_domain, &msg->gpr_packet); + + if (rc) { + GSL_ERR("Failed to allocate gpr packet of size %d", + gpr_payload_size); + goto exit; + } + + gsl_memset(&msg->shmem, 0, sizeof(struct gsl_shmem_alloc_data)); + + if (oob_payload_size != 0) { + rc = gsl_shmem_alloc_ext(oob_payload_size, spf_ss_mask, flags, + platform_info, dest_domain, &msg->shmem); + if (rc) { + __gpr_cmd_free(msg->gpr_packet); + GSL_ERR("Failed to allocate shared mem of size %d", + oob_payload_size); + goto exit; + } + } + msg->payload = msg->shmem.v_addr; + } + + msg->proc_id = dest_domain; +exit: + return rc; +} + +int32_t gsl_msg_builder_init(uint32_t num_master_procs, + uint32_t *master_procs) +{ + int32_t rc = AR_EOK; + uint32_t i = 0; + + for (; i < num_master_procs; i++) + __gpr_cmd_is_shared_mem_supported(master_procs[i], + &supports_shared_mem[master_procs[i]]); + + rc = gsl_shmem_init(num_master_procs, master_procs); + + return rc; +} + +int32_t gsl_msg_builder_deinit(void) +{ + int32_t rc = AR_EOK; + + rc = gsl_shmem_deinit(); + + return rc; +} diff --git a/gsl/src/gsl_rtc.c b/gsl/src/gsl_rtc.c new file mode 100644 index 0000000..8fe18f5 --- /dev/null +++ b/gsl/src/gsl_rtc.c @@ -0,0 +1,555 @@ +/** + * \file gsl_rtc.c + * + * \brief + * Implement GSL RTC functionalities + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_error.h" +#include "ar_util_list.h" +#include "gsl_rtc.h" +#include "gsl_rtc_intf.h" +#include "gsl_msg_builder.h" +#include "gsl_common.h" +#include "gsl_mdf_utils.h" +#include "apm_api.h" +#include "gpr_ids_domains.h" +#include "gpr_packet.h" +#include "gpr_api_inline.h" + +#define GSL_RTC_SRC_PORT 0x2006 + +static struct gsl_rtc_internal_ctxt { + struct gsl_signal sig; + ar_osal_mutex_t sig_lock; + uint32_t src_port; +} rtc_internal_ctxt; + +static struct gsl_subgraph *gsl_graph_get_sg_ptr(struct gsl_graph *graph, + uint32_t sg_id) +{ + ar_list_node_t *curr = NULL;; + struct gsl_graph_gkv_node *gkv_node; + uint32_t i = 0; + + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + for (i = 0; i < gkv_node->num_of_subgraphs; ++i) { + if (gkv_node->sg_array[i]->sg_id == sg_id) + return gkv_node->sg_array[i]; + } + } + return NULL; +} + +static uint32_t gsl_rtc_gpr_callback(gpr_packet_t *packet, void *cb_data) +{ + struct gsl_rtc_internal_ctxt *ctxt = NULL; + struct spf_cmd_basic_rsp *basic_rsp; + uint32_t rc = AR_EOK; + + ctxt = (struct gsl_rtc_internal_ctxt *)cb_data; + switch (packet->opcode) { + case GPR_IBASIC_RSP_RESULT: + basic_rsp = GPR_PKT_GET_PAYLOAD(struct spf_cmd_basic_rsp, packet); + switch (basic_rsp->opcode) { + case APM_CMD_GET_CFG: + case APM_CMD_SET_CFG: + case APM_CMD_REGISTER_CFG: + case APM_CMD_DEREGISTER_CFG: + gsl_signal_set(&ctxt->sig, GSL_SIG_EVENT_MASK_SPF_RSP, + basic_rsp->status, NULL); + break; + default: + GSL_DBG("unknown opcode %x freeing GPR rsp packet", + basic_rsp->opcode); + break; + } + rc = __gpr_cmd_free(packet); + break; + case APM_CMD_RSP_GET_CFG: + rc = gsl_signal_set(&ctxt->sig, GSL_SIG_EVENT_MASK_SPF_RSP, + 0, packet); + break; + default: + GSL_DBG("unknown opcode %x freeing GPR rsp packet", packet->opcode); + rc = __gpr_cmd_free(packet); + break; + } + + /* Free gpr packet if signal set failed */ + if (rc) { + GSL_DBG("signal failed, freeing GPR rsp packet"); + rc = __gpr_cmd_free(packet); + } + + return rc; +} + +int32_t gsl_rtc_internal_init(void) +{ + int32_t rc = AR_EOK; + + rc = ar_osal_mutex_create(&rtc_internal_ctxt.sig_lock); + if (rc) { + GSL_ERR("ar_osal_mutex_create failed %d", rc); + return rc; + } + + rc = gsl_signal_create(&rtc_internal_ctxt.sig, &rtc_internal_ctxt.sig_lock); + if (rc) { + GSL_ERR("gsl_signal_create failed %d", rc); + goto destroy_lock; + } + + rtc_internal_ctxt.src_port = GSL_RTC_SRC_PORT; + + rc = __gpr_cmd_register(rtc_internal_ctxt.src_port, + gsl_rtc_gpr_callback, &rtc_internal_ctxt); + if (rc) { + GSL_ERR("gpr register callback failed %d", rc); + goto destroy_signal; + } + + return rc; + +destroy_signal: + gsl_signal_destroy(&rtc_internal_ctxt.sig); +destroy_lock: + ar_osal_mutex_destroy(rtc_internal_ctxt.sig_lock); + return rc; +} + +int32_t gsl_rtc_internal_deinit(void) +{ + __gpr_cmd_deregister(rtc_internal_ctxt.src_port); + gsl_signal_destroy(&rtc_internal_ctxt.sig); + ar_osal_mutex_destroy(rtc_internal_ctxt.sig_lock); + + return AR_EOK; +} + + +uint32_t gsl_rtc_graph_copy_gkvs(struct gsl_graph *graph, uint8_t *payload, + uint32_t *num_gkvs) +{ + uint32_t gkv_bytes = 0; + struct gsl_rtc_key_vector *gkv; + ar_list_node_t *curr = NULL;; + struct gsl_graph_gkv_node *gkv_node; + + *num_gkvs = 0; + gkv_bytes = 0; + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + + (*num_gkvs)++; + gkv = (struct gsl_rtc_key_vector *)(payload + gkv_bytes); + gkv->num_kvps = gkv_node->gkv.num_kvps; + + if (gkv_node->gkv.num_kvps != 0) { + gsl_memcpy(gkv->kvp, + gkv->num_kvps * sizeof(struct gsl_key_value_pair), + gkv_node->gkv.kvp, + gkv_node->gkv.num_kvps * sizeof(struct gsl_key_value_pair)); + } + gkv_bytes += GSL_RTC_GKV_SIZE_BYTES(gkv_node->gkv.num_kvps); + } + return gkv_bytes; +} + +uint32_t gsl_rtc_graph_copy_ckvs(struct gsl_graph *graph, uint8_t *payload, + uint32_t *num_ckvs) +{ + uint32_t ckv_bytes = 0; + struct gsl_rtc_key_vector *ckv; + ar_list_node_t *curr = NULL;; + struct gsl_graph_gkv_node *gkv_node; + + *num_ckvs = 0; + ckv_bytes = 0; + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + + (*num_ckvs)++; + ckv = (struct gsl_rtc_key_vector *)(payload + ckv_bytes); + ckv->num_kvps = gkv_node->ckv.num_kvps; + + if (gkv_node->ckv.num_kvps != 0) { + gsl_memcpy(ckv->kvp, + ckv->num_kvps * sizeof(struct gsl_key_value_pair), + gkv_node->ckv.kvp, + gkv_node->ckv.num_kvps * sizeof(struct gsl_key_value_pair)); + } + ckv_bytes += GSL_RTC_GKV_SIZE_BYTES(gkv_node->ckv.num_kvps); + } + return ckv_bytes; +} + +uint32_t gsl_rtc_graph_get_gkv_ckv_size(struct gsl_graph *graph) +{ + ar_list_node_t *curr = NULL;; + struct gsl_graph_gkv_node *gkv_node; + uint32_t gkv_node_size = 0; + + ar_list_for_each_entry(curr, &graph->gkv_list) { + gkv_node = get_container_base(curr, struct gsl_graph_gkv_node, + node); + gkv_node_size += GSL_RTC_GKV_SIZE_BYTES(gkv_node->gkv.num_kvps); + gkv_node_size += GSL_RTC_GKV_SIZE_BYTES(gkv_node->ckv.num_kvps); + } + + return gkv_node_size; +} + +int32_t gsl_rtc_graph_get_persist_data(struct gsl_graph *graph, uint32_t sgid, + uint32_t proc_id, uint32_t *total_size, uint8_t **sg_cal_data) +{ + struct gsl_subgraph *sg; + + sg = gsl_graph_get_sg_ptr(graph, sgid); + if (!sg) { + GSL_ERR("no subgraph with sgid 0x%x", sgid); + return AR_ENOTEXIST; + } + if (!total_size || !sg_cal_data) + return AR_EFAILED; + + for (int persist_cal_idx = 0; persist_cal_idx < sg->num_proc_ids; persist_cal_idx++) { + if (sg->persist_cal_data_per_proc[persist_cal_idx].proc_id == proc_id) { + if (sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr) + *sg_cal_data = sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr; + *total_size = sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data_size; + } + } + + return AR_EOK; +} + +int32_t gsl_rtc_graph_get_non_persist_data(struct gsl_graph *graph, + uint32_t total_size, uint8_t *sg_cal_data) +{ + int32_t rc = AR_EOK; + apm_cmd_header_t *cmd_header; + gpr_packet_t *rsp_pkt = NULL; + gsl_msg_t gsl_msg; + struct apm_cmd_rsp_get_cfg_t *get_cfg_rsp; + bool_t is_shmem_supported = TRUE; + + __gpr_cmd_is_shared_mem_supported(graph->proc_id, &is_shmem_supported); + if (sg_cal_data == NULL) { + GSL_ERR("sg_cal_data is NULL"); + rc = AR_EBADPARAM; + goto exit; + } + + rc = gsl_msg_alloc(APM_CMD_GET_CFG, rtc_internal_ctxt.src_port, + APM_MODULE_INSTANCE_ID, sizeof(*cmd_header), + 0, graph->proc_id, total_size, false, &gsl_msg); + + if (rc) { + GSL_ERR("gsl msg alloc failed %d", rc); + goto exit; + } + + gsl_memcpy(gsl_msg.payload, total_size, sg_cal_data, total_size); + + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + gsl_msg.gpr_packet); + cmd_header->payload_size = total_size; + + GSL_LOG_PKT("send_pkt", rtc_internal_ctxt.src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*cmd_header), gsl_msg.payload, + cmd_header->payload_size); + + if (!is_shmem_supported) { + rc = gsl_send_spf_cmd(&gsl_msg.gpr_packet, + &rtc_internal_ctxt.sig, &rsp_pkt); + if (rc || !rsp_pkt) { + GSL_ERR("Graph get cfg cmd 0x%x failure:%d", APM_CMD_GET_CFG, rc); + goto free_gsl_msg; + } + + get_cfg_rsp = GPR_PKT_GET_PAYLOAD(struct apm_cmd_rsp_get_cfg_t, + rsp_pkt); + if (get_cfg_rsp->status != AR_EOK) { + GSL_ERR("Graph get config failed: spf status %d", + get_cfg_rsp->status); + rc = AR_EFAILED; + goto free_gsl_msg; + } + + gsl_memcpy(sg_cal_data, total_size, (uint8_t *)get_cfg_rsp + + sizeof(apm_cmd_rsp_get_cfg_t), total_size); + } else { + cmd_header->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + cmd_header->payload_address_msw = + (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &rtc_internal_ctxt.sig); + if (rc) + GSL_ERR("Graph get cfg cmd 0x%x failure:%d", APM_CMD_GET_CFG, rc); + + gsl_memcpy(sg_cal_data, total_size, gsl_msg.payload, total_size); + } + +free_gsl_msg: + gsl_msg_free(&gsl_msg); + +exit: + if (rsp_pkt != NULL) { + __gpr_cmd_free(rsp_pkt); + rsp_pkt = NULL; + } + return rc; +} + +int32_t gsl_rtc_graph_set_non_persist_data(struct gsl_graph *graph, + uint32_t total_size, uint8_t *sg_cal_data) +{ + int32_t rc = AR_EOK; + struct apm_cmd_header_t *cmd_header; + gsl_msg_t gsl_msg; + + rc = gsl_msg_alloc(APM_CMD_SET_CFG, rtc_internal_ctxt.src_port, + APM_MODULE_INSTANCE_ID, sizeof(*cmd_header), + 0, graph->proc_id, total_size, false, &gsl_msg); + + if (rc) { + GSL_ERR("gsl msg alloc failed %d", rc); + goto exit; + } + + gsl_memcpy(gsl_msg.payload, total_size, sg_cal_data, total_size); + + cmd_header = GPR_PKT_GET_PAYLOAD(struct apm_cmd_header_t, + gsl_msg.gpr_packet); + cmd_header->mem_map_handle = gsl_msg.shmem.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)gsl_msg.shmem.spf_addr; + cmd_header->payload_address_msw = (uint32_t)(gsl_msg.shmem.spf_addr >> 32); + cmd_header->payload_size = total_size; + + GSL_LOG_PKT("send_pkt", rtc_internal_ctxt.src_port, gsl_msg.gpr_packet, + sizeof(*gsl_msg.gpr_packet) + sizeof(*cmd_header), gsl_msg.payload, + cmd_header->payload_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&gsl_msg.gpr_packet, + &rtc_internal_ctxt.sig); + if (rc) + GSL_ERR("Graph set cfg cmd 0x%x failure:%d", APM_CMD_SET_CFG, rc); + + gsl_msg_free(&gsl_msg); + +exit: + return rc; +} + +int32_t gsl_rtc_graph_set_persist_data(struct gsl_graph *graph, + struct gsl_rtc_persist_param *params) +{ + int32_t rc = AR_EOK; + struct apm_cmd_header_t *cmd_header; + struct gsl_subgraph *sg; + gpr_packet_t *send_pkt = NULL; + uint64_t cal_paddr_w_offset = 0; + + if (!graph) + return AR_EFAILED; + sg = gsl_graph_get_sg_ptr(graph, params->sgid); + if (!sg) + return AR_EFAILED; + + if (sg->num_proc_ids > + sizeof(sg->persist_cal_data_per_proc) / + sizeof(sg->persist_cal_data_per_proc[0])) { + GSL_ERR("num_proc_ids invalid: %d", sg->num_proc_ids); + return AR_EBADPARAM; + } + GSL_DBG("num procs per SG - %d", sg->num_proc_ids); + for (int persist_cal_idx = 0; persist_cal_idx < sg->num_proc_ids; persist_cal_idx++) { + if (sg->persist_cal_data_per_proc[persist_cal_idx].proc_id == params->proc_id) { + if (!sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr) + return AR_EFAILED; + + GSL_DBG("proc_id[%d] - %d", persist_cal_idx, sg->persist_cal_data_per_proc[persist_cal_idx].proc_id); + + rc = gsl_allocate_gpr_packet(APM_CMD_DEREGISTER_CFG, + rtc_internal_ctxt.src_port, APM_MODULE_INSTANCE_ID, + sizeof(*cmd_header), 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + /* + * below offset used to skip acdb header before sending data to + * spf + */ + cal_paddr_w_offset = sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.spf_addr + + sizeof(AcdbSgIdPersistData); + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + cmd_header->mem_map_handle = sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)cal_paddr_w_offset; + cmd_header->payload_address_msw = (uint32_t)(cal_paddr_w_offset >> 32); + cmd_header->payload_size = sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data_size - + sizeof(AcdbSgIdPersistData); + + GSL_LOG_PKT("send_pkt", rtc_internal_ctxt.src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr, + cmd_header->payload_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &rtc_internal_ctxt.sig); + if (rc) { + GSL_ERR("Graph deregister cfg cmd 0x%x failure:%d", + APM_CMD_DEREGISTER_CFG, rc); + return rc; + } + + /* if user did not pass data, then read from acdb */ + if (!params->sg_cal_data) { + rc = gsl_subgraph_query_persist_cal_by_mem(sg, + (struct gsl_key_vector *)params->ckv, ACDB_HW_ACCEL_MEM_DEFAULT, + graph->proc_id, persist_cal_idx); + if (rc) { + GSL_ERR("Failed to query persist cal %d", rc); + goto exit; + } + } else { + rc = gsl_subgraph_set_persist_cal(sg, params->sg_cal_data, + *params->total_size, graph->proc_id, persist_cal_idx); + if (rc) { + GSL_ERR("Failed to set persist cal %d", rc); + goto exit; + } + } + + rc = gsl_allocate_gpr_packet(APM_CMD_REGISTER_CFG, + rtc_internal_ctxt.src_port, APM_MODULE_INSTANCE_ID, + sizeof(*cmd_header), 0, graph->proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + /* + * below offset used to skip acdb header before sending data to + * spf + */ + cal_paddr_w_offset = sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.spf_addr + + sizeof(AcdbSgIdPersistData); + + cmd_header = GPR_PKT_GET_PAYLOAD(apm_cmd_header_t, send_pkt); + cmd_header->mem_map_handle = sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.spf_mmap_handle; + cmd_header->payload_address_lsw = (uint32_t)cal_paddr_w_offset; + cmd_header->payload_address_msw = (uint32_t)(cal_paddr_w_offset >> 32); + cmd_header->payload_size = sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data_size - + sizeof(AcdbSgIdPersistData); + + GSL_LOG_PKT("send_pkt", rtc_internal_ctxt.src_port, send_pkt, + sizeof(*send_pkt) + sizeof(*cmd_header), sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr, + cmd_header->payload_size); + + rc = gsl_send_spf_cmd_wait_for_basic_rsp(&send_pkt, + &rtc_internal_ctxt.sig); + if (rc) + GSL_ERR("Graph register cfg cmd 0x%x failure:%d", + APM_CMD_REGISTER_CFG, rc); + } + } +exit: + return rc; +} + +int32_t gsl_rtc_internal_prepare_change_graph(struct gsl_graph *graph, + struct gsl_rtc_prepare_change_graph_info *rtc_params, + ar_osal_mutex_t lock) +{ + struct gsl_prepare_change_graph_single_gkv_params cg_params = { 0, }; + uint32_t *p, num_sgs = 0, i = 0; + int32_t rc = AR_EOK; + + if (!graph || !rtc_params || + (rtc_params->size_of_sg_conn_info == 0 && rtc_params->num_sgs > 0)) + /* last check prevents null deref of cg_params.sgs */ + return AR_EBADPARAM; + + cg_params.old_gkv.num_kvps = rtc_params->old_gkv->num_kvps; + cg_params.old_gkv.kvp = rtc_params->old_gkv->kvp; + + if (rtc_params->size_of_sg_conn_info > 0) { + cg_params.sgs = gsl_mem_zalloc(rtc_params->num_sgs * sizeof(uint32_t)); + if (!cg_params.sgs) { + GSL_ERR("out of memory"); + rc = AR_ENOMEMORY; + goto exit; + } + } + /* + * Below loop is to copy the sgids + */ + p = rtc_params->sg_conn_info; + for (i = 0; i < rtc_params->num_sgs; ++i) { + cg_params.sgs[i] = *p; + /* skip over subgraph_id, size and child subgraph list */ + ++p; + p = p + *p + 1; + } + + gsl_print_sg_conn_info((uint32_t *)rtc_params->sg_conn_info, + rtc_params->num_sgs); + + cg_params.num_sgs = rtc_params->num_sgs; + cg_params.sg_conn_info.num_sgs = num_sgs; /* yes duplicated I know... */ + cg_params.sg_conn_info.size = rtc_params->size_of_sg_conn_info; + cg_params.sg_conn_info.subgraphs = + (AcdbSubgraph *)rtc_params->sg_conn_info; + + cg_params.num_sgs_to_reopen = rtc_params->num_modified_sgs; + cg_params.sgs_to_reopen = rtc_params->modified_sgs; + cg_params.sg_conn_info_to_reopen.num_sgs = + rtc_params->num_modified_sg_connections; + cg_params.sg_conn_info_to_reopen.size = + rtc_params->size_of_modified_sg_conn_info; + cg_params.sg_conn_info_to_reopen.subgraphs = + (AcdbSubgraph *)rtc_params->modified_sg_conn_info; + + rc = gsl_graph_prepare_to_change_single_gkv(graph, &cg_params, lock); + if (rc) + GSL_ERR("prepare_to_change_single_gkv failed rc %d", rc); + + gsl_mem_free(cg_params.sgs); +exit: + return rc; +} + +int32_t gsl_rtc_internal_change_graph(struct gsl_graph *graph, + struct gsl_rtc_change_graph_info *rtc_params, + ar_osal_mutex_t lock) +{ + int32_t rc = AR_EOK; + struct gsl_change_graph_single_gkv_params cg_params; + + if (!graph || !rtc_params) + return AR_EBADPARAM; + + cg_params.old_gkv.num_kvps = rtc_params->old_gkv->num_kvps; + cg_params.old_gkv.kvp = rtc_params->old_gkv->kvp; + + cg_params.new_gkv.num_kvps = rtc_params->new_gkv->num_kvps; + cg_params.new_gkv.kvp = rtc_params->new_gkv->kvp; + + cg_params.new_ckv.num_kvps = rtc_params->new_ckv->num_kvps; + cg_params.new_ckv.kvp = rtc_params->new_ckv->kvp; + + rc = gsl_graph_change_single_gkv(graph, &cg_params, lock); + if (rc) + GSL_ERR("change_single_gkv failed rc %d", rc); + + return rc; +} diff --git a/gsl/src/gsl_rtc_main.c b/gsl/src/gsl_rtc_main.c new file mode 100644 index 0000000..4d03f94 --- /dev/null +++ b/gsl/src/gsl_rtc_main.c @@ -0,0 +1,134 @@ +/** + * \file gsl_rtc_main.c + * + * \brief + * Real Time Calibration API implementation layer + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_error.h" +#include "gsl_rtc_intf.h" +#include "gsl_rtc_main.h" +#include "gsl_common.h" +#include "gsl_rtc.h" +#include "ar_osal_log_pkt_op.h" + +struct gsl_rtc_ctxt { + /* + * callback invoked whenever there is an SSR up or down event + */ + gsl_rtc_cb_t rtc_cb; +} rtc_ctxt; + +static bool_t is_gsl_rtc_inited(void) +{ + if (!rtc_ctxt.rtc_cb) { + GSL_ERR("GSL rtc not initialized"); + return FALSE; + } + return TRUE; +} + +int32_t gsl_rtc_get_active_usecase_info(struct gsl_rtc_active_uc_info *info) +{ + if (!is_gsl_rtc_inited()) + return AR_EFAILED; + + return rtc_ctxt.rtc_cb(GSL_RTC_GET_UC_INFO, info); +} + +int32_t gsl_rtc_get_persist_data(struct gsl_rtc_persist_param *rtc_param) +{ + if (!rtc_param) + return AR_EBADPARAM; + + if (!is_gsl_rtc_inited()) + return AR_EFAILED; + + return rtc_ctxt.rtc_cb(GSL_RTC_GET_PERSIST_DATA, rtc_param); +} + +int32_t gsl_rtc_get_non_persist_data(struct gsl_rtc_param *rtc_param) +{ + if (!rtc_param) + return AR_EBADPARAM; + + if (!is_gsl_rtc_inited()) + return AR_EFAILED; + + return rtc_ctxt.rtc_cb(GSL_RTC_GET_NON_PERSIST_DATA, rtc_param); +} + +int32_t gsl_rtc_set_persist_data(struct gsl_rtc_persist_param *rtc_param) +{ + if (!rtc_param) + return AR_EBADPARAM; + + if (!is_gsl_rtc_inited()) + return AR_EFAILED; + + return rtc_ctxt.rtc_cb(GSL_RTC_SET_PERSIST_DATA, rtc_param); +} + +int32_t gsl_rtc_set_non_persist_data(struct gsl_rtc_param *rtc_param) +{ + if (!rtc_param) + return AR_EBADPARAM; + + if (!is_gsl_rtc_inited()) + return AR_EFAILED; + + return rtc_ctxt.rtc_cb(GSL_RTC_SET_NON_PERSIST_DATA, rtc_param); +} + +int32_t gsl_rtc_prepare_change_graph( + struct gsl_rtc_prepare_change_graph_info *rtc_param) +{ + if (!rtc_param) + return AR_EBADPARAM; + + if (!is_gsl_rtc_inited()) + return AR_EFAILED; + + return rtc_ctxt.rtc_cb(GSL_RTC_PREPARE_CHANGE_GRAPH, rtc_param); +} + +int32_t gsl_rtc_change_graph(struct gsl_rtc_change_graph_info *rtc_param) +{ + if (!is_gsl_rtc_inited()) + return AR_EFAILED; + + return rtc_ctxt.rtc_cb(GSL_RTC_CHANGE_GRAPH, rtc_param); +} + +int32_t gsl_rtc_notify_conn_state(struct gsl_rtc_conn_info *rtgm_session_info) +{ + if (!rtgm_session_info) + return AR_EBADPARAM; + + if (!is_gsl_rtc_inited()) + return AR_EFAILED; + + return rtc_ctxt.rtc_cb(GSL_RTC_CONN_INFO_CHANGE, rtgm_session_info); +} + +int32_t gsl_rtc_init(gsl_rtc_cb_t cb) +{ + int32_t rc = AR_EOK; + + rc = gsl_rtc_internal_init(); + if (rc) + return rc; + + rtc_ctxt.rtc_cb = cb; + return rc; +} + +int32_t gsl_rtc_deinit(void) +{ + gsl_rtc_internal_deinit(); + rtc_ctxt.rtc_cb = NULL; + return AR_EOK; +} diff --git a/gsl/src/gsl_shmem_mgr.c b/gsl/src/gsl_shmem_mgr.c new file mode 100644 index 0000000..7ca3a04 --- /dev/null +++ b/gsl/src/gsl_shmem_mgr.c @@ -0,0 +1,1920 @@ +/** + * \file gsl_shmem_mgr.c + * + * \brief + * Manages shared memory allocations across all graphs in the system + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include "gsl_shmem_mgr.h" +#include "ar_osal_shmem.h" +#include "ar_util_list.h" +#include "ar_osal_mutex.h" +#include "ar_osal_signal.h" +#include "ar_osal_error.h" +#include "ar_osal_sys_id.h" +#include "gsl_common.h" +#include "apm_memmap_api.h" +#include "apm_api.h" +#include "gpr_ids_domains.h" +#include "gpr_api_inline.h" +#include "gsl_spf_ss_state.h" +#include "gsl_mdf_utils.h" + +/** + * all pages must have size that is a multiple of this + */ +#define GSL_SHMEM_MGR_PAGE_SZ_SHIFT 12 /* page size = 4096 */ +#define GSL_SHMEM_MGR_PAGE_SZ (1 << GSL_SHMEM_MGR_PAGE_SZ_SHIFT) +#define GSL_SHMEM_MGR_CONVERT_BYTES_TO_PAGES(size_bytes)\ +((size_bytes) >> GSL_SHMEM_MGR_PAGE_SZ_SHIFT) + +/* set maximum scratch memory allocation size to be equal to 4 pages */ +#define GSL_SHMEM_MAX_SCRATCH_ALLOC_SZ (GSL_SHMEM_MGR_PAGE_SZ<<2) +#define GSL_SHMEM_MAX_FRAMES_IN_SCRATCH_ALLOC \ +(GSL_SHMEM_MAX_SCRATCH_ALLOC_SZ >> GSL_SHMEM_MGR_FRAME_SZ_SHIFT) + +/* size of the pre-allocated page, set to 32K */ +#define GSL_SHMEM_PRE_ALLOC_SIZE (GSL_SHMEM_MAX_SCRATCH_ALLOC_SZ<<1) + +/** + * A single page contains multiple frames + */ +#define GSL_SHMEM_MGR_CONVERT_BYTES_TO_FRAMES(size_bytes)\ +((size_bytes) >> GSL_SHMEM_MGR_FRAME_SZ_SHIFT) + +/** + * number of bins + */ +#define GSL_SHMEM_MGR_NUM_BINS 3 +#define GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH 0 +#define GSL_SHMEM_MGR_BIN_IDX_SCRATCH 1 +#define GSL_SHMEM_MGR_BIN_IDX_DEDICATED 2 + + /** we use LSB in size field to indicate whether a block is used or free */ +#define GSL_SHMEM_MGR_BLOCK_SZ_USED_BIT_MASK 0x0001 +#define GSL_SHMEM_SRC_PORT 0x2002 + +#define GSL_SHMEM_IS_OFFSET_MODE(type) \ +(((ar_shmem_buffer_index_type_t)(type)) == AR_SHMEM_BUFFER_OFFSET) + +struct gsl_apm_mem_map { + struct apm_cmd_shared_mem_map_regions_t mmap_header; + struct apm_shared_map_region_payload_t mmap_payload; +}; + +struct gsl_apm_mem_map_satellite { + struct apm_cmd_shared_satellite_mem_map_regions_t mmap_header; + struct apm_shared_map_region_payload_t mmap_payload; +}; + +struct gsl_shmem_block { + /** + * Address of the block that is returned back to caller + */ + void *base_addr; + /** + * Since size is FRAME aligned use LSB as used/free bit. + * USED = 1 + * FREE = 0 + */ + uint32_t size_bytes; + /** + * index of the preceeding block, used in merge operation + * -1 indicates there is no predecessor + */ + int16_t predecessor_idx; + /** + * index of the successor block, used in merge operation + * -1 indicates there is no successor + */ + int16_t successor_idx; +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + /** + * Actual size that was requested by client for this block, this might be + * smaller than the block size as it need not be a multiple of FRAME_SIZE + */ + int32_t requested_size_bytes; +#endif + +}; + +struct gsl_shmem_page { + ar_list_node_t node; + /** size of this page */ + uint32_t size_bytes; + /** maximum number of blocks */ + uint32_t max_num_blocks; + /** holds information returned from ar_osal shmem during allocation */ + ar_shmem_info shmem_info; + /** holds the handle returned from spf once the page is mapped */ + uint32_t spf_handle; + /** bitmask used to store the spf subsystems this page is mapped to */ + uint32_t spf_ss_mask; + /** index of the bin this page belongs to */ + uint32_t bin_idx; + /* we need to keep this list around as it is needed in free */ + ar_shmem_proc_info ss_id_list[AR_SUB_SYS_ID_LAST]; + /** master proc id to which this page is mapped to */ + uint32_t master_proc; + /** list of all used and empty blocks */ + struct gsl_shmem_block blocks[]; +}; + +/** + * Represents a single bin which hold a set of pages + */ +struct gsl_shmem_bin { + /** number of pages in this bin */ + uint32_t num_pages; + /** holds the page metadata objects for this bin, one per page */ + struct ar_list_t page_list; +}; + +#define MAX_PENDING_MEMMAP_PACKETS 3 +struct gsl_shmem_mgr_ctxt { + /** lock used to synchronize alloc and free operations */ + ar_osal_mutex_t mutex; + /** + * array of bins + * Pages fall into different bins based on attributes and page size + * according to below set of rules: + * bins[0] holds scratch memory pages that are pre-allocated, these are + * pages that get allocated at init time and freed at de-init + * bins[1] scratch memory growth space, holds pages of size up to 16K + * bins[2] holds dedicated pages and pages >16K which are also treated as + * dedicated + * bins[3] holds CMA pages, which are specifically for offloading to other + * mem allocations on SPF and need to be handled with different flags + * through osal and SPF + */ + struct gsl_shmem_bin bins[GSL_SHMEM_MGR_NUM_BINS]; + + /** + * holds a pointer the page that is currently being mapped to spf, this + * used to store the spf handle when we receive a response from spf + */ + struct gsl_shmem_page *page_being_mapped; + /** + * Signal used to wait for responses from spf + */ + struct gsl_signal sig; + /** + * lock used in conjuction with above signal + */ + ar_osal_mutex_t sig_lock; + /** + * gpr unconsumed pending memory map packet pointer + */ + void *pending_memmap_packet_list[MAX_PENDING_MEMMAP_PACKETS]; + /** + * gpr unconsumed pending memory map handle + */ + uint32_t pending_memmap_handle_list[MAX_PENDING_MEMMAP_PACKETS]; + /** + * gpr unconsumed pending memory map packet list index + */ + int32_t pending_memmap_packet_index; + /** + * cache gpr memory map shared memory info flags if error happened + */ + uint32_t error_memmap_shmem_info_flags; + /** + * gpr memory map count + */ + int32_t memmap_count; +}; + +#ifdef GSL_SHMEM_MGR_STATS_ENABLE +static struct gsl_shmem_stats { + /** + * size in bytes of memory currently mapped to Spf, this will be a + * multiple of page size + */ + uint32_t curr_bytes_mapped; + /** + * size in bytes of memory currently allocated to GSL, this will be a + * multiple of frame size + */ + uint32_t curr_bytes_allocated; + /** + * size in bytes of memory currently requested by client + */ + uint32_t curr_bytes_requested; + /** + * size in bytes of peak memory mapped to Spf, this will be a multiple + * of page size + */ + uint32_t max_bytes_mapped; + /** + * size in bytes of peak memory mapped to Spf, this will be a multuple + * of frame size + */ + uint32_t max_bytes_allocated; + /** + * size in bytes of peak memory requested by client + */ + uint32_t max_bytes_requested; +} stats; +#endif + +static struct gsl_shmem_mgr_ctxt *ctxt[AR_SUB_SYS_ID_LAST + 1] = {NULL}; + +static uint32_t gsl_shmem_gpr_callback(gpr_packet_t *packet, void *cb_data) +{ + uint32_t rc = AR_EOK; + uint32_t master_proc = packet->src_domain_id; + + cb_data; /* Referencing to keep compiler happy */ + + if (ctxt[master_proc] != NULL) { + if (ctxt[master_proc]->sig.gpr_packet) { + // if there was a pending gpr packet that never got consumed + gpr_packet_t *unconsumed_packet = + (gpr_packet_t *)ctxt[master_proc]->sig.gpr_packet; + if (unconsumed_packet->opcode == APM_CMD_RSP_SHARED_MEM_MAP_REGIONS && + ctxt[master_proc]->memmap_count > 0) { + /** + * the uncomsumed gpr packet was for memory map, need to + * unmap it from spf. Since it's not good to handle in the + * callback here which may break the sequence. So, cache the + * unconsumed pending packet and unmap it later. + */ + gsl_shmem_cache_pending_memmap_packets(master_proc, + ctxt[master_proc]->sig.gpr_packet); + } + } + if (packet->token != ctxt[master_proc]->sig.expected_packet_token) { + // there is a delay packet received which may be caused by timeout before. + if (packet->opcode == APM_CMD_RSP_SHARED_MEM_MAP_REGIONS && + ctxt[master_proc]->memmap_count > 0) { + /** + * same way to cache the delay memory map rsp packet + * and unmap it later + */ + gsl_shmem_cache_pending_memmap_packets(master_proc, (void *)packet); + } + } + rc = gsl_signal_set(&ctxt[master_proc]->sig, GSL_SIG_EVENT_MASK_SPF_RSP, + AR_EOK, packet); + if (rc) + __gpr_cmd_free(packet); + } + + /* do not free packet, it will be freed by waiter */ + return 0; +} + +static int32_t gsl_shmem_handle_rsp(gpr_packet_t *rsp, uint32_t master_proc_id, + uint32_t expected_opcode) +{ + struct apm_cmd_rsp_shared_mem_map_regions_t *mmap_regions; + struct apm_cmd_rsp_shared_satellite_mem_map_regions_t *mdf_mmap_regions; + struct spf_cmd_basic_rsp *basic_rsp; + int32_t rc = AR_EOK; + if (expected_opcode != rsp->opcode) { + GSL_ERR("Recieved unexpected rsp opcode %x, expected %x", + rsp->opcode, expected_opcode); + rc = AR_EUNEXPECTED; + goto end; + } + switch (rsp->opcode) { + case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS: + mmap_regions = GPR_PKT_GET_PAYLOAD( + struct apm_cmd_rsp_shared_mem_map_regions_t, rsp); + ctxt[master_proc_id]->page_being_mapped->spf_handle = + mmap_regions->mem_map_handle; + if (ctxt[master_proc_id]->page_being_mapped->spf_handle == 0) { + GSL_ERR("received null handle from spf"); + rc = AR_EFAILED; + } + break; + + case APM_CMD_RSP_SHARED_SATELLITE_MEM_MAP_REGIONS: + mdf_mmap_regions = GPR_PKT_GET_PAYLOAD( + struct apm_cmd_rsp_shared_satellite_mem_map_regions_t, rsp); + if (mdf_mmap_regions->mem_map_handle == 0) { + GSL_ERR("received null satellite handle from spf"); + rc = AR_EFAILED; + } + break; + + case GPR_IBASIC_RSP_RESULT: + basic_rsp = GPR_PKT_GET_PAYLOAD(struct spf_cmd_basic_rsp, + rsp); + switch (basic_rsp->opcode) { + case APM_CMD_SHARED_MEM_MAP_REGIONS: + case APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS: + case APM_CMD_RSP_SHARED_SATELLITE_MEM_MAP_REGIONS: + case APM_CMD_SHARED_MEM_UNMAP_REGIONS: + case APM_CMD_SHARED_SATELLITE_MEM_UNMAP_REGIONS: + if (basic_rsp->status) { + GSL_ERR("received failure %x from spf", basic_rsp->status); + rc = AR_EFAILED; + } + break; + + default: + GSL_ERR("unsupported opcode %d encountered in GPR SHMEM response", + basic_rsp->opcode); + rc = AR_EFAILED; + break; + }; + break; + }; +end: + __gpr_cmd_free(rsp); + return rc; +} + +/* Memory map 1-region of given size */ +static int32_t gsl_shmem_map_page_to_spf(struct gsl_shmem_page *page, + uint32_t flags, uint32_t spf_ss_map_mask) +{ + struct gsl_apm_mem_map *mmap; + struct gsl_apm_mem_map_satellite *mmap_sat; + int32_t rc = AR_EOK; + gpr_cmd_alloc_ext_t gpr_args; + uint32_t tmp_spf_ss_mask, spf_ss_mask_sans_adsp; + uint32_t sys_id = AR_SUB_SYS_ID_FIRST; + gpr_packet_t *send_pkt = NULL, *rsp_pkt = NULL; + uint8_t cma_client_data = 0; + uint32_t master_proc_id = page->master_proc; + bool_t dynamic_pd = FALSE; + + /* if this is a CMA page we need to set client data on all gpr packets */ + if ((page->shmem_info.flags & (AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG + << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) != 0) + cma_client_data = GSL_GPR_CMA_FLAG_BIT; + + /* + * if the spf master or any of the satellites is down skip mapping and + * retrun ENOTREADY + */ + if ((gsl_spf_ss_state_get(master_proc_id) & spf_ss_map_mask) != + spf_ss_map_mask) + return AR_ENOTREADY; + + // check if there are some peneding memmap packets need to be unmmaped. + gsl_shmem_check_and_unmap_cache_pending_packets(master_proc_id); + + spf_ss_mask_sans_adsp = spf_ss_map_mask & + ~GSL_GET_SPF_SS_MASK(master_proc_id); + tmp_spf_ss_mask = spf_ss_mask_sans_adsp; + while (tmp_spf_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(spf_ss_mask_sans_adsp, sys_id)) { + if (gsl_mdf_utils_is_dynamic_pd(sys_id)) { + dynamic_pd = TRUE; + break; + } + } + ++sys_id; + tmp_spf_ss_mask >>= 1; + } + + /* first map to master (assumed to be adsp currently) */ + if (GSL_TEST_SPF_SS_BIT(spf_ss_map_mask, master_proc_id)) { + /* + * Set client_data based on is_offset flag, this tells gpr in kernel to + * replace the MSW/LSW fields in the MMAP with actual physical address + * instead of the handle that got returned from osal, this is a hack to + * get around linux limitation where PA cannot be returned to + * user-space from kernel + */ + gpr_args.client_data = GSL_SHMEM_IS_OFFSET_MODE( + page->shmem_info.index_type); + + gpr_args.src_domain_id = GPR_IDS_DOMAIN_ID_APPS_V; + gpr_args.dst_domain_id = (uint8_t) master_proc_id; + gpr_args.src_port = GSL_SHMEM_SRC_PORT; + gpr_args.dst_port = APM_MODULE_INSTANCE_ID; + gpr_args.opcode = APM_CMD_SHARED_MEM_MAP_REGIONS; + gpr_args.payload_size = sizeof(*mmap); + gpr_args.token = 0; + gpr_args.ret_packet = &send_pkt; + rc = __gpr_cmd_alloc_ext(&gpr_args); + if (rc) { + GSL_ERR("Failed to allocate shmem map pkt %d", rc); + goto exit; + } + + mmap = GPR_PKT_GET_PAYLOAD(struct gsl_apm_mem_map, send_pkt); + mmap->mmap_header.mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL; + mmap->mmap_header.num_regions = 1; + mmap->mmap_header.property_flag = page->shmem_info.index_type << + APM_MEMORY_MAP_SHIFT_IS_OFFSET_MODE; + mmap->mmap_header.property_flag |= page->shmem_info.mem_type << + APM_MEMORY_MAP_SHIFT_IS_VIRTUAL; + if (flags & GSL_SHMEM_LOANED) + mmap->mmap_header.property_flag |= + APM_MEMORY_MAP_BIT_MASK_IS_MEM_LOANED; + if (flags & GSL_SHMEM_MAP_UNCACHED) + mmap->mmap_header.property_flag |= + APM_MEMORY_MAP_BIT_MASK_IS_UNCACHED; + if (dynamic_pd) + mmap->mmap_header.property_flag |= + APM_MEMORY_MAP_LOANED_MEMORY_HEAP_MNGR_TYPE_SAFE_HEAP << + APM_MEMORY_MAP_SHIFT_LOANED_MEMORY_HEAP_MNGR_TYPE; + + mmap->mmap_payload.shm_addr_lsw = page->shmem_info.ipa_lsw; + mmap->mmap_payload.shm_addr_msw = page->shmem_info.ipa_msw; + mmap->mmap_payload.mem_size_bytes = page->size_bytes; + + send_pkt->client_data |= cma_client_data; + + /* + * set current page being mapped so handle can be updated in the + * callback + */ + ctxt[master_proc_id]->page_being_mapped = page; + + GSL_LOG_PKT("send_pkt", GSL_SHMEM_SRC_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*mmap), NULL, 0); + + ctxt[master_proc_id]->memmap_count++; + rc = gsl_send_spf_cmd(&send_pkt, &ctxt[master_proc_id]->sig, &rsp_pkt); + if (rc) { + GSL_ERR("send spf cmd failed with err %d", rc); + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + goto exit; + } + if (!rsp_pkt) { + GSL_ERR("Received null response packet"); + rc = AR_EUNEXPECTED; + goto exit; + } + + rc = gsl_shmem_handle_rsp(rsp_pkt, master_proc_id, + APM_CMD_RSP_SHARED_MEM_MAP_REGIONS); + if (rc) { + GSL_ERR("handle shmem response failed %d", rc); + goto exit; + } + } + + /* map the shared memory to satellite subsystems if any */ + sys_id = AR_SUB_SYS_ID_FIRST; + tmp_spf_ss_mask = spf_ss_mask_sans_adsp; + while (tmp_spf_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(spf_ss_mask_sans_adsp, sys_id)) { + rc = gsl_allocate_gpr_packet( + APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS, GSL_SHMEM_SRC_PORT, + APM_MODULE_INSTANCE_ID, sizeof(*mmap_sat), 0, master_proc_id, + &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet:%d", rc); + goto exit; + } + + mmap_sat = GPR_PKT_GET_PAYLOAD(struct gsl_apm_mem_map_satellite, + send_pkt); + + mmap_sat->mmap_header.satellite_proc_domain_id = sys_id; + mmap_sat->mmap_header.master_mem_handle = page->spf_handle; + mmap_sat->mmap_header.mem_pool_id = + APM_MEMORY_MAP_SHMEM8_4K_POOL; + mmap_sat->mmap_header.num_regions = 1; + mmap_sat->mmap_header.property_flag = + page->shmem_info.index_type << + APM_MEMORY_MAP_SHIFT_IS_OFFSET_MODE; + mmap_sat->mmap_header.property_flag |= + page->shmem_info.mem_type << APM_MEMORY_MAP_SHIFT_IS_VIRTUAL; + if (flags & GSL_SHMEM_LOANED) + mmap_sat->mmap_header.property_flag |= + APM_MEMORY_MAP_BIT_MASK_IS_MEM_LOANED; + /* + * For dynamic PD set address type to indicate gpr kernel + * driver to skip conversion to physical address and pass + * the handle as is to DSP. + */ + if (dynamic_pd) + mmap_sat->mmap_header.property_flag |= + APM_MEMORY_MAP_MEMORY_ADDRESS_TYPE_FD << + APM_MEMORY_MAP_SHIFT_MEMORY_ADDRESS_TYPE; + + mmap_sat->mmap_payload.shm_addr_lsw = page->shmem_info.ipa_lsw; + mmap_sat->mmap_payload.shm_addr_msw = page->shmem_info.ipa_msw; + mmap_sat->mmap_payload.mem_size_bytes = page->size_bytes; + + send_pkt->client_data |= cma_client_data; + + GSL_LOG_PKT("send_pkt", GSL_SHMEM_SRC_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*mmap_sat), NULL, 0); + + rc = gsl_send_spf_cmd(&send_pkt, &ctxt[master_proc_id]->sig, + &rsp_pkt); + if (rc) { + GSL_ERR("Mem map satellite failed:%d", rc); + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + goto exit; + } + if (!rsp_pkt) { + GSL_ERR("Received null response packet"); + rc = AR_EUNEXPECTED; + goto exit; + } + rc = gsl_shmem_handle_rsp(rsp_pkt, master_proc_id, + APM_CMD_RSP_SHARED_SATELLITE_MEM_MAP_REGIONS); + if (rc) { + GSL_ERR("handle shmem response failed %d", rc); + goto exit; + } + } + ++sys_id; + tmp_spf_ss_mask >>= 1; + } + +exit: + if (rc){ + ctxt[master_proc_id]->error_memmap_shmem_info_flags = page->shmem_info.flags; + } + return rc; +} + +static int32_t gsl_shmem_unmap_page_from_spf(struct gsl_shmem_page *page, + uint32_t spf_ss_unmap_mask) +{ + struct apm_cmd_shared_mem_unmap_regions_t *payload; + struct apm_cmd_shared_satellite_mem_unmap_regions_t *payload_sat; + int32_t rc = AR_EOK; + uint32_t tmp_spf_ss_mask, spf_ss_mask_sans_adsp; + uint32_t sys_id = AR_MODEM_DSP; + gpr_packet_t *send_pkt = NULL, *rsp_pkt = NULL; + uint8_t cma_client_data = 0; + uint32_t master_proc_id = page->master_proc; + + /* if the spf master or any satellites are down silently skip unmap */ + if ((gsl_spf_ss_state_get(master_proc_id) & spf_ss_unmap_mask) != + page->spf_ss_mask) + return AR_EOK; + + /* if this is a CMA page we need to set client data on all gpr packets */ + if ((page->shmem_info.flags & (AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG + << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) != 0) + cma_client_data = GSL_GPR_CMA_FLAG_BIT; + + /* + * firstly unmap from satellites, adsp does not require this step hence we + * clear its bit to skip. + */ + spf_ss_mask_sans_adsp = spf_ss_unmap_mask & + ~GSL_GET_SPF_SS_MASK(master_proc_id); + tmp_spf_ss_mask = spf_ss_mask_sans_adsp; + while (tmp_spf_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(spf_ss_mask_sans_adsp, sys_id)) { + rc = gsl_allocate_gpr_packet( + APM_CMD_SHARED_SATELLITE_MEM_UNMAP_REGIONS, GSL_SHMEM_SRC_PORT, + APM_MODULE_INSTANCE_ID, sizeof(*payload_sat), 0, master_proc_id, + &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + payload_sat = GPR_PKT_GET_PAYLOAD( + struct apm_cmd_shared_satellite_mem_unmap_regions_t, send_pkt); + payload_sat->satellite_proc_domain_id = sys_id; + payload_sat->master_mem_handle = page->spf_handle; + + send_pkt->client_data |= cma_client_data; + + GSL_LOG_PKT("send_pkt", GSL_SHMEM_SRC_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*payload_sat), NULL, 0); + rc = gsl_send_spf_cmd(&send_pkt, &ctxt[master_proc_id]->sig, + &rsp_pkt); + if (rc || !rsp_pkt) { + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + goto exit; + } + rc = gsl_shmem_handle_rsp(rsp_pkt, master_proc_id, + GPR_IBASIC_RSP_RESULT); + if (rc) + goto exit; + } + ++sys_id; + tmp_spf_ss_mask >>= 1; + } + + /* now unmap from master */ + if (GSL_TEST_SPF_SS_BIT(spf_ss_unmap_mask, master_proc_id)) { + rc = gsl_allocate_gpr_packet(APM_CMD_SHARED_MEM_UNMAP_REGIONS, + GSL_SHMEM_SRC_PORT, APM_MODULE_INSTANCE_ID, sizeof(*payload), 0, + master_proc_id, &send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + goto exit; + } + payload = GPR_PKT_GET_PAYLOAD( + struct apm_cmd_shared_mem_unmap_regions_t, send_pkt); + payload->mem_map_handle = page->spf_handle; + + send_pkt->client_data |= cma_client_data; + + GSL_LOG_PKT("send_pkt", GSL_SHMEM_SRC_PORT, send_pkt, + sizeof(*send_pkt) + sizeof(*payload), NULL, 0); + ctxt[master_proc_id]->memmap_count--; + rc = gsl_send_spf_cmd(&send_pkt, &ctxt[master_proc_id]->sig, &rsp_pkt); + if (rc || !rsp_pkt) { + if (rsp_pkt) + __gpr_cmd_free(rsp_pkt); + goto exit; + } + rc = gsl_shmem_handle_rsp(rsp_pkt, master_proc_id, + GPR_IBASIC_RSP_RESULT); + } +exit: + return rc; +} + +/** + * Allocates a new page of a given size and adds it to the provided bin, + * it is callers responsibility to ensure that the correct bin_idx is + * provided that matches the size being allocated. + * note, this function does not do error checking on parameters + * + * /param[in] page_size: size of the page to allocate, must be a multiple of + * GSL_SHMEM_MGR_MIN_PAGE_SZ + */ +static int32_t allocate_page(uint32_t page_size, uint32_t bin_idx, + uint32_t spf_ss_mask, uint32_t flags, uint32_t platform_info, + uint64_t ext_mem_hdl, uint32_t master_proc_id, + struct gsl_shmem_page **new_page) +{ + int32_t rc = AR_EOK; + struct gsl_shmem_bin *bin = &ctxt[master_proc_id]->bins[bin_idx]; + struct gsl_shmem_page *page = NULL; + uint32_t tmp_spf_ss_mask = spf_ss_mask; + uint8_t sys_id = AR_SUB_SYS_ID_FIRST; + uint32_t max_num_blocks = 1; + uint32_t num_procs = 0; + struct proc_domain_type *proc_domains = NULL; + uint32_t dynamic_proc_ss_mask = 0, i = 0; + + /* + * if we are in the dedicated bin then we only need one block since we + * dont allow multiple client allocations in this bin, otherwise determine + * max number of blocks based on page size + */ + if (bin_idx != GSL_SHMEM_MGR_BIN_IDX_DEDICATED) + max_num_blocks = GSL_SHMEM_MGR_CONVERT_BYTES_TO_FRAMES(page_size); + + /* create a page entry */ + page = gsl_mem_zalloc(sizeof(struct gsl_shmem_page) + + max_num_blocks * sizeof(struct gsl_shmem_block)); + if (page == NULL) { + *new_page = NULL; + return AR_ENOMEMORY; + } + page->max_num_blocks = max_num_blocks; + page->master_proc = master_proc_id; + + /* allocate shared memory for page */ + page->shmem_info.platform_info = platform_info; + page->shmem_info.buf_size = page_size; + page->shmem_info.cache_type = AR_SHMEM_UNCACHED; + + page->shmem_info.num_sys_id = 0; + page->shmem_info.sys_id = page->ss_id_list; + + gsl_mdf_utils_get_proc_domain_info(&proc_domains, &num_procs); + if (!proc_domains) + num_procs = 0; + for (i = 0; i < num_procs; ++i) { + if (proc_domains[i].proc_type == DYNAMIC_PD) + dynamic_proc_ss_mask |= + GSL_GET_SPF_SS_MASK(proc_domains[i].proc_id); + } + /* populate ss_id_list based on spf_ss_mask */ + while (tmp_spf_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(spf_ss_mask, sys_id)) { + page->ss_id_list[page->shmem_info.num_sys_id].proc_id = sys_id; + if (GSL_TEST_SPF_SS_BIT(dynamic_proc_ss_mask, sys_id)) { + page->ss_id_list[page->shmem_info.num_sys_id].proc_type = + DYNAMIC_PD; + page->ss_id_list[page->shmem_info.num_sys_id].is_active = + TRUE; + } else { + page->ss_id_list[page->shmem_info.num_sys_id].proc_type = + STATIC_PD; + } + ++page->shmem_info.num_sys_id; + } + ++sys_id; + tmp_spf_ss_mask >>= 1; + } + + /* set special flag for CMA allocations */ + if (flags & GSL_SHMEM_CMA) + page->shmem_info.flags = + AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG + << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG; + + if (ext_mem_hdl == GSL_EXT_MEM_HDL_NOT_ALLOCD) { + rc = ar_shmem_alloc(&page->shmem_info); + if (rc) { + GSL_ERR("ar_shmem_alloc failed with error %d", rc); + goto free_gsl_mem; + } + } else { + /* pass the alloc handle on the PA. This will be converted by OSAL */ + page->shmem_info.pa_lsw = (uint32_t)ext_mem_hdl; + page->shmem_info.pa_msw = (uint32_t)(ext_mem_hdl >> 32); + + GSL_VERBOSE("map ext mem page extmemhdl: 0x%x pamsw 0x%x, palsw 0x%x", + ext_mem_hdl, page->shmem_info.pa_msw, page->shmem_info.pa_lsw); + + rc = ar_shmem_map(&page->shmem_info); + if (rc) { + GSL_ERR("ar_shmem_map failed with error %d", rc); + goto free_gsl_mem; + } + } + + if (page->shmem_info.mem_type == AR_SHMEM_VIRTUAL_MEMORY) { + page->shmem_info.ipa_lsw = + (uint32_t)((uintptr_t)page->shmem_info.vaddr); + page->shmem_info.ipa_msw = + (uint64_t)((uintptr_t)page->shmem_info.vaddr) >> 32; + } + page->bin_idx = bin_idx; + page->size_bytes = page_size; + page->spf_ss_mask = spf_ss_mask; + rc = gsl_shmem_map_page_to_spf(page, flags, page->spf_ss_mask); + if (rc) { + GSL_ERR("failed to map page with spf error %d", rc); + goto free_shmem; + } + + /* + * initialize free and used block lists, + */ + /* add page entry to bin */ + rc = ar_list_init_node(&page->node); + if (rc) { + GSL_ERR("ar_list_init_node failed with error %d", rc); + goto unmap_page; + } + + rc = ar_list_add_tail(&bin->page_list, &page->node); + if (rc) { + GSL_ERR("ar_list_add_tail failed with error %d", rc); + goto unmap_page; + } + + /* mark entire page as a single free block */ + page->blocks[0].base_addr = page->shmem_info.vaddr; + page->blocks[0].size_bytes = page_size; /* LSB of size is assumed 0 */ + page->blocks[0].predecessor_idx = -1; + page->blocks[0].successor_idx = -1; + + bin->num_pages += 1; + *new_page = page; +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + stats.curr_bytes_mapped += page_size; + if (stats.curr_bytes_mapped > stats.max_bytes_mapped) + stats.max_bytes_mapped = stats.curr_bytes_mapped; +#endif + + goto exit; + +unmap_page: + gsl_shmem_unmap_page_from_spf(page, page->spf_ss_mask); +free_shmem: + if (ext_mem_hdl == GSL_EXT_MEM_HDL_NOT_ALLOCD) + ar_shmem_free(&page->shmem_info); + else + ar_shmem_unmap(&page->shmem_info); + page->shmem_info.vaddr = NULL; + page->shmem_info.pa_lsw = 0; + page->shmem_info.pa_msw = 0; + +free_gsl_mem: + gsl_mem_free(page); + *new_page = NULL; +exit: + return rc; +} + +static int32_t free_page(int32_t bin_idx, + struct gsl_shmem_page *page, bool_t is_ext_mem) +{ + int32_t rc = AR_EOK, rc1 = AR_EOK; + uint32_t master_proc_id = page->master_proc; + uint32_t sys_id = AR_SUB_SYS_ID_FIRST; + struct gsl_shmem_bin *bin = &ctxt[master_proc_id]->bins[bin_idx]; + + rc = gsl_shmem_unmap_page_from_spf(page, page->spf_ss_mask); + if (rc) { + GSL_ERR("failed to unmap page from spf %d", rc); + rc1 = rc; + } + /* + * Dynamic pd DSP unmap happens in OSAL. If this page is getting + * freed during pd is down, indicate OSAL to skip sending unmap + * command to DSP. + */ + if ((gsl_spf_ss_state_get(master_proc_id) & page->spf_ss_mask) != + page->spf_ss_mask) { + while (sys_id < AR_SUB_SYS_ID_LAST) { + if (page->ss_id_list[sys_id].proc_type == DYNAMIC_PD) { + GSL_DBG("set pd down flag for proc_id %d", + page->ss_id_list[sys_id].proc_id); + page->ss_id_list[sys_id].is_active = FALSE; + } + ++sys_id; + } + } + /* if this is a CMA page, hyp-unassign here */ + if ((page->shmem_info.flags & (AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG + << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) != 0) + gsl_shmem_hyp_assign(page, AR_APSS, AR_DEFAULT_DSP); + if (!is_ext_mem) { + rc = ar_shmem_free(&page->shmem_info); + if (rc) { + GSL_ERR("ar_shmem_free failed with error %d", rc); + if (!rc1) + rc1 = rc; + } + } else { + GSL_VERBOSE("unmap ext_mem page %d vaddr 0x%x pa_msw 0x%x, pa_lsw 0x%x", + is_ext_mem, page->shmem_info.vaddr, page->shmem_info.pa_msw, + page->shmem_info.pa_lsw); + + rc = ar_shmem_unmap(&page->shmem_info); + if (rc) { + GSL_ERR("ar_shmem_unmap failed with error %d", rc); + if (!rc1) + rc1 = rc; + } + } + + rc = ar_list_delete(&bin->page_list, &page->node); + if (rc) { + GSL_ERR("ar_list_delete failed with error %d", rc); + if (!rc1) + rc1 = rc; + } + +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + stats.curr_bytes_mapped -= page->size_bytes; +#endif + + gsl_mem_free(page); + bin->num_pages -= 1; + + return rc1; +} + +static void *do_alloc_block(struct gsl_shmem_page *page, + int16_t found_block_idx, uint32_t frame_aligned_sz) +{ + uint32_t i = 0; + /* Validate block index is within bounds */ + if (found_block_idx < 0 || found_block_idx >= (int16_t)page->max_num_blocks) { + GSL_ERR("do_alloc_block: invalid block index %d (max=%u)", + found_block_idx, page->max_num_blocks); + return NULL; + } + + /* Retrieve the original size of the current block (excluding the used bit) */ + uint32_t old_sz = page->blocks[found_block_idx].size_bytes & + ~GSL_SHMEM_MGR_BLOCK_SZ_USED_BIT_MASK; + if (!old_sz) { + GSL_ERR("do_alloc_block: zero-size block page=%p idx=%d", + page, found_block_idx); + return NULL; + } + + /* Requested size cannot be larger than the original free size */ + if (old_sz < frame_aligned_sz) { + GSL_ERR("do_alloc_block: block too small sz=0x%x < req=0x%x page=%p idx=%d", + old_sz, frame_aligned_sz, page, found_block_idx); + return NULL; + } + + int32_t found_block_successor_idx = + page->blocks[found_block_idx].successor_idx; + + if (page->blocks[found_block_idx].size_bytes > frame_aligned_sz) { + /* + * find available entry in block list and use it for new free block + * Note: max_num_blocks is set to page_size/frame_size, this ensures + * that there is always an entry available in blocks[] for the worst + * case fragmenation + */ + for (i = 0; i < page->max_num_blocks; ++i) { + if (page->blocks[i].base_addr == NULL) { + /* found an available entry, use it as a new free block */ + page->blocks[i].base_addr = + (char *)(page->blocks[found_block_idx].base_addr) + + frame_aligned_sz; + page->blocks[i].size_bytes = + page->blocks[found_block_idx].size_bytes - + frame_aligned_sz; + /* + * make the successor of the found block point to the new block + */ + if (found_block_successor_idx != -1) + page->blocks[found_block_successor_idx].predecessor_idx = + (int16_t) i; + + /* make the new empty block a successor of the found block */ + page->blocks[i].predecessor_idx = found_block_idx; + page->blocks[i].successor_idx = + page->blocks[found_block_idx].successor_idx; + page->blocks[found_block_idx].successor_idx = (int16_t) i; + break; + } + } + } + + /* update used block info and mark it as used */ + page->blocks[found_block_idx].size_bytes = frame_aligned_sz; + page->blocks[found_block_idx].size_bytes |= + GSL_SHMEM_MGR_BLOCK_SZ_USED_BIT_MASK; + + return page->blocks[found_block_idx].base_addr; +} + +/** + * returns the size of the resulting free block after freeing and merging with + * neighbors + */ +static uint32_t do_free_block(struct gsl_shmem_page *page, + uint16_t freed_block_idx) +{ + int16_t successor_idx = page->blocks[freed_block_idx].successor_idx; + int16_t predecessor_idx = page->blocks[freed_block_idx].predecessor_idx; + int16_t successor_successor_idx = 0; + uint32_t resulting_free_block_sz = 0; + + /* found block, mark it as free */ + page->blocks[freed_block_idx].size_bytes &= + ~GSL_SHMEM_MGR_BLOCK_SZ_USED_BIT_MASK; + + /* + * if successor is available and marked as free, + * merge successor into freed block + */ + if ((successor_idx != -1) && !(page->blocks[successor_idx].size_bytes & + GSL_SHMEM_MGR_BLOCK_SZ_USED_BIT_MASK)) { + successor_successor_idx = page->blocks[successor_idx].successor_idx; + + page->blocks[freed_block_idx].size_bytes += + page->blocks[successor_idx].size_bytes; + page->blocks[freed_block_idx].successor_idx = successor_successor_idx; + + if (successor_successor_idx != -1) + page->blocks[successor_successor_idx].predecessor_idx = + freed_block_idx; + + /* mark successor entry as available */ + page->blocks[successor_idx].base_addr = NULL; + page->blocks[successor_idx].predecessor_idx = -1; + page->blocks[successor_idx].successor_idx = -1; + page->blocks[successor_idx].size_bytes = 0; + } + + /* + * store the size this is the resulting free block size so far + */ + resulting_free_block_sz = page->blocks[freed_block_idx].size_bytes; + + /* + * if predecessor is availble and marked as free, + * merge freed block into predecessor + */ + if ((predecessor_idx != -1) && !(page->blocks[predecessor_idx].size_bytes & + GSL_SHMEM_MGR_BLOCK_SZ_USED_BIT_MASK)) { + page->blocks[predecessor_idx].size_bytes += + page->blocks[freed_block_idx].size_bytes; + successor_idx = page->blocks[freed_block_idx].successor_idx; + page->blocks[predecessor_idx].successor_idx = successor_idx; + + if (successor_idx != -1) + page->blocks[successor_idx].predecessor_idx = predecessor_idx; + + /* mark freed block entry as available */ + page->blocks[freed_block_idx].base_addr = NULL; + page->blocks[freed_block_idx].predecessor_idx = -1; + page->blocks[freed_block_idx].successor_idx = -1; + page->blocks[freed_block_idx].size_bytes = 0; + + /* + * update resulting free block size to reflect the size of the + * resulting free block after we merged with predecessor + */ + resulting_free_block_sz = page->blocks[predecessor_idx].size_bytes; + } + + return resulting_free_block_sz; +} + +int32_t gsl_shmem_alloc(uint32_t size_bytes, uint32_t master_proc_id, + struct gsl_shmem_alloc_data *alloc_data) +{ + return gsl_shmem_alloc_ext(size_bytes, + GSL_GET_SPF_SS_MASK(master_proc_id), 0, 0, master_proc_id, + alloc_data); +} + +int32_t gsl_shmem_alloc_ext(uint32_t size_bytes, uint32_t spf_ss_mask, + uint32_t flags, uint32_t platform_info, uint32_t master_proc_id, + struct gsl_shmem_alloc_data *alloc_data) +{ + int32_t rc = AR_EOK; + uint32_t size_frame_aligned = 0, size_page_aligned = 0, bin_idx = 0; + struct gsl_shmem_page *page; + uint64_t offset = 0; + uint32_t i = 0; + int16_t j; + bool_t block_found = false; + ar_list_node_t *itr = NULL; + + if (!alloc_data || size_bytes == 0) + return AR_EBADPARAM; + + if (!ctxt[master_proc_id]) + return AR_EUNSUPPORTED; + + size_frame_aligned = (size_bytes + GSL_SHMEM_MGR_FRAME_SZ - 1) & + (~(GSL_SHMEM_MGR_FRAME_SZ - 1)); + size_page_aligned = (size_frame_aligned + GSL_SHMEM_MGR_PAGE_SZ - 1) & + (~(GSL_SHMEM_MGR_PAGE_SZ - 1)); + + /* + * if the memory is requested as dedicated page or is used for any non + * SPF master SS or larger than 16K, then keep it in the last bin so it + * wont be shared across allocations + */ + if (flags & GSL_SHMEM_DEDICATED_PAGE || flags & GSL_SHMEM_CMA || + spf_ss_mask & ~GSL_GET_SPF_SS_MASK(master_proc_id) || + size_page_aligned >= GSL_SHMEM_MAX_SCRATCH_ALLOC_SZ) + bin_idx = GSL_SHMEM_MGR_BIN_IDX_DEDICATED; + else + bin_idx = GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH; + + /* + * since we do not divide the pages in the last bin to frames, we set + * size_frame_aligned to be same as size_page_aligned + */ + if (bin_idx == GSL_SHMEM_MGR_BIN_IDX_DEDICATED) + size_frame_aligned = size_page_aligned; + + GSL_MUTEX_LOCK(ctxt[master_proc_id]->mutex); + /* + * scan through all bins and try to find if a suitable free block is + * available. Note: We purposely dont search in the last bin as this + * holds either dedicated pages or very large size pages which are meant + * for single allocations only + */ + for (i = bin_idx; i <= GSL_SHMEM_MGR_BIN_IDX_SCRATCH; ++i) { + if (ctxt[master_proc_id]->bins[i].num_pages == 0) + continue; + + ar_list_for_each_entry(itr, &ctxt[master_proc_id]->bins[i].page_list) { + page = get_container_base(itr, struct gsl_shmem_page, node); + + /* search for free block */ + j = 0; + while (j != -1) { + if (!(page->blocks[j].size_bytes & + GSL_SHMEM_MGR_BLOCK_SZ_USED_BIT_MASK) && + (size_frame_aligned <= page->blocks[j].size_bytes)) { + + /* found suitable block */ + alloc_data->handle = page; + alloc_data->spf_mmap_handle = page->spf_handle; + alloc_data->v_addr = do_alloc_block(page, j, + size_frame_aligned); + /* add null check for do_alloc_block */ + if (!alloc_data->v_addr) { + GSL_ERR("do_alloc_block returned NULL " + "for current page %p", page); + alloc_data->handle = NULL; + alloc_data->spf_mmap_handle = 0; + rc = AR_EFAILED; + goto exit; + } + /* compute PA for this block */ + uintptr_t base = (uintptr_t)page->shmem_info.vaddr; + uintptr_t addr = (uintptr_t)alloc_data->v_addr; + if (addr >= base) { + offset = (uint64_t)(addr - base); + } else { + GSL_ERR("Failed to calculate offset because" + "addr(0x%lx)v_addr = NULL; + alloc_data->handle = NULL; + alloc_data->spf_mmap_handle = 0; + /* Break inner loop to try next page */ + break; + } + if (GSL_SHMEM_IS_OFFSET_MODE(page->shmem_info.index_type)) { + alloc_data->spf_addr = offset; + } else { + alloc_data->spf_addr = + ((uint64_t)page->shmem_info.ipa_msw << 32) + + page->shmem_info.ipa_lsw + offset; + } + alloc_data->metadata = page->shmem_info.metadata; + block_found = true; +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + page->blocks[j].requested_size_bytes = size_bytes; +#endif + break; + } + j = page->blocks[j].successor_idx; + } + if (block_found) + break; + } + if (block_found) + break; + } + + if (!block_found) { + /* no suitable block found in existing pages, allocate a new page */ + + if (bin_idx == GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH) + bin_idx = GSL_SHMEM_MGR_BIN_IDX_SCRATCH; + + rc = allocate_page(size_page_aligned, bin_idx, spf_ss_mask, flags, + platform_info, GSL_EXT_MEM_HDL_NOT_ALLOCD, master_proc_id, &page); + if (rc) + goto exit; + alloc_data->handle = page; + alloc_data->v_addr = do_alloc_block(page, 0, size_frame_aligned); + alloc_data->spf_mmap_handle = page->spf_handle; + /* add null check for do_alloc_block */ + if (!alloc_data->v_addr) { + GSL_ERR("do_alloc_block returned NULL for new page %p free it", page); + alloc_data->handle = NULL; + alloc_data->spf_mmap_handle = 0; + rc = free_page(bin_idx, page, 0); + if (rc) { + GSL_ERR("Failed to free page after allocation failure: %d", rc); + goto exit; + } + rc = AR_EFAILED; + goto exit; + } + /* compute PA for this block */ + uintptr_t base = (uintptr_t)page->shmem_info.vaddr; + uintptr_t addr = (uintptr_t)alloc_data->v_addr; + if (addr >= base) { + offset = (uint64_t)(addr - base); + } else { + GSL_ERR("Failed to calculate offset because addr(0x%lx)v_addr = NULL; + alloc_data->handle = NULL; + alloc_data->spf_mmap_handle = 0; + rc = free_page(bin_idx, page, 0); + if (rc) { + GSL_ERR("Failed to free page after allocation failure: %d", rc); + goto exit; + } + rc = AR_EFAILED; + goto exit; + } + if (GSL_SHMEM_IS_OFFSET_MODE(page->shmem_info.index_type)) + alloc_data->spf_addr = offset; + else + alloc_data->spf_addr = + ((uint64_t) page->shmem_info.ipa_msw << 32) + + page->shmem_info.ipa_lsw + offset; + alloc_data->metadata = page->shmem_info.metadata; +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + page->blocks[0].requested_size_bytes = size_bytes; +#endif + } + +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + stats.curr_bytes_requested += size_bytes; + if (stats.curr_bytes_requested >= stats.max_bytes_requested) + stats.max_bytes_requested = stats.curr_bytes_requested; + + stats.curr_bytes_allocated += size_frame_aligned; + if (stats.curr_bytes_allocated >= stats.max_bytes_allocated) + stats.max_bytes_allocated = stats.curr_bytes_allocated; + GSL_LOG_PKT("mem_stat", GSL_SHMEM_SRC_PORT, &stats, + sizeof(struct gsl_shmem_stats), NULL, 0); +#endif + +exit: + GSL_MUTEX_UNLOCK(ctxt[master_proc_id]->mutex); + return rc; +} + +int32_t gsl_shmem_free(struct gsl_shmem_alloc_data *alloc_data) +{ + struct gsl_shmem_page *page; + int16_t freed_block_idx = 0; + uint32_t resulting_free_block_sz = 0, bin_idx = 0; + int32_t rc = AR_EOK; + bool_t found_block = false; + uint32_t master_proc_id; + + if (!alloc_data) + return AR_EBADPARAM; + + if (!alloc_data->handle) + return AR_EBADPARAM; + + page = alloc_data->handle; + master_proc_id = page->master_proc; + bin_idx = page->bin_idx; + + if (!ctxt[master_proc_id]) + return AR_EUNSUPPORTED; + + GSL_MUTEX_LOCK(ctxt[master_proc_id]->mutex); + + /* find the block in page and free it */ + while (freed_block_idx != (int16_t)(-1)) { + if (page->blocks[freed_block_idx].base_addr == alloc_data->v_addr) { +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + stats.curr_bytes_requested -= + page->blocks[freed_block_idx].requested_size_bytes; + stats.curr_bytes_allocated -= + page->blocks[freed_block_idx].size_bytes & + ~GSL_SHMEM_MGR_BLOCK_SZ_USED_BIT_MASK; +#endif + /* found the block being freed */ + resulting_free_block_sz = do_free_block(page, freed_block_idx); + found_block = true; + break; + } + + freed_block_idx = page->blocks[freed_block_idx].successor_idx; + } + + /* check if the page can be freed back to system */ + if (found_block && resulting_free_block_sz == page->size_bytes) { + /* + * do not free page if it belongs to bin 0, this will be freed during + * deinit + */ + if (bin_idx > GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH) + rc = free_page(bin_idx, page, 0); + } + + if (!found_block) + rc = AR_ENOTEXIST; + +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + GSL_LOG_PKT("mem_stat", GSL_SHMEM_SRC_PORT, &stats, + sizeof(struct gsl_shmem_stats), NULL, 0); +#endif + GSL_MUTEX_UNLOCK(ctxt[master_proc_id]->mutex); + + return rc; +} + +int32_t gsl_shmem_unmap_allocation(struct gsl_shmem_alloc_data *alloc_data, + uint32_t ss_mask_to_unmap_to) +{ + int32_t rc = AR_EOK; + struct gsl_shmem_page *page = alloc_data->handle; + uint32_t master_proc_id = page->master_proc; + + rc = gsl_shmem_unmap_page_from_spf(page, ss_mask_to_unmap_to); + if (rc) + GSL_ERR("failed to unmap page from spf %d", rc); + + ar_shmem_unmap(&page->shmem_info); + + return rc; +} +int32_t gsl_shmem_map_extern_mem(uint64_t ext_mem_hdl, uint32_t size_bytes, + uint32_t master_proc_id, struct gsl_shmem_alloc_data *alloc_data) +{ + int32_t rc = AR_EOK; + uint32_t size_page_aligned = 0; + struct gsl_shmem_page *page = NULL; + + if (!ctxt[master_proc_id]) { + rc = AR_EUNSUPPORTED; + return rc; + } + + size_page_aligned = (size_bytes + GSL_SHMEM_MGR_PAGE_SZ - 1) & + (~(GSL_SHMEM_MGR_PAGE_SZ - 1)); + + GSL_MUTEX_LOCK(ctxt[master_proc_id]->mutex); + + // won't actually allocate when we send an ext_mem_handle, it will only map + rc = allocate_page(size_page_aligned, GSL_SHMEM_MGR_BIN_IDX_DEDICATED, + GSL_GET_SPF_SS_MASK(master_proc_id), 0, 0, ext_mem_hdl, master_proc_id, + &page); + if (rc) { + GSL_ERR("failed to allocate page %d", rc); + goto exit; + } + + alloc_data->handle = page; + alloc_data->v_addr = page->shmem_info.vaddr; + alloc_data->spf_mmap_handle = page->spf_handle; + alloc_data->metadata = page->shmem_info.metadata; + /* compute PA for this block */ + if (GSL_SHMEM_IS_OFFSET_MODE(page->shmem_info.index_type)) + alloc_data->spf_addr = 0; + else + alloc_data->spf_addr = + ((uint64_t)page->shmem_info.ipa_msw << 32) + + page->shmem_info.ipa_lsw; + +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + GSL_LOG_PKT("mem_stat", GSL_SHMEM_SRC_PORT, &stats, + sizeof(struct gsl_shmem_stats), NULL, 0); +#endif + +exit: + GSL_MUTEX_UNLOCK(ctxt[master_proc_id]->mutex); + return rc; +} + +int32_t gsl_shmem_unmap_extern_mem(struct gsl_shmem_alloc_data alloc_data) +{ + int32_t rc = AR_EOK; + struct gsl_shmem_page *page = alloc_data.handle; + uint32_t master_proc_id = 0; + + if (!alloc_data.handle) + return AR_EBADPARAM; + + if (!page) + return AR_EBADPARAM; + + master_proc_id = page->master_proc; + + if (!ctxt[master_proc_id]) { + rc = AR_EUNSUPPORTED; + goto exit; + } + + GSL_MUTEX_LOCK(ctxt[master_proc_id]->mutex); + /* + * we know that external mem is always in dedicated + * and must be allocated before free + */ + rc = free_page(GSL_SHMEM_MGR_BIN_IDX_DEDICATED, alloc_data.handle, + TRUE); + + GSL_MUTEX_UNLOCK(ctxt[master_proc_id]->mutex); + +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + GSL_LOG_PKT("mem_stat", GSL_SHMEM_SRC_PORT, &stats, + sizeof(struct gsl_shmem_stats), NULL, 0); +#endif + +exit: + return rc; +} + +void gsl_shmem_signal_ssr(uint32_t master_proc_id) +{ + if (!ctxt[master_proc_id]) + return; + + gsl_signal_set(&ctxt[master_proc_id]->sig, GSL_SIG_EVENT_MASK_SSR, 0, NULL); +} + +void gsl_shmem_clear_ssr(uint32_t master_proc_id) +{ + if (!ctxt[master_proc_id]) + return; + + gsl_signal_clear(&ctxt[master_proc_id]->sig, GSL_SIG_EVENT_MASK_SSR); +} + +/* re-map pre-allocated pages to ADSP after it restarts */ +void gsl_shmem_remap_pre_alloc(uint32_t master_proc_id) +{ + ar_list_node_t *iter = NULL; + struct gsl_shmem_page *page = NULL; + + if (!ctxt[master_proc_id]) + return; + + iter = ctxt[master_proc_id]->bins[GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH] + .page_list.dummy.next; + while (iter != + &ctxt[master_proc_id]->bins[GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH] + .page_list.dummy) { + page = (struct gsl_shmem_page *) iter; + gsl_shmem_map_page_to_spf(page, 0, page->spf_ss_mask); + iter = iter->next; + } +} + +void gsl_shmem_cache_pending_memmap_packets(uint32_t master_proc_id, void *gpr_packet) +{ + for (int i = 0; i < MAX_PENDING_MEMMAP_PACKETS; i++) { + //check if the packet is duplicated + if(ctxt[master_proc_id]->pending_memmap_packet_list[i] && + ((struct gpr_packet_t *)ctxt[master_proc_id]-> + pending_memmap_packet_list[i])->token == + ((struct gpr_packet_t *)gpr_packet)->token) { + return; + } + } + int32_t index = ctxt[master_proc_id]->pending_memmap_packet_index; + struct apm_cmd_rsp_shared_mem_map_regions_t *mmap_regions; + mmap_regions = GPR_PKT_GET_PAYLOAD( + struct apm_cmd_rsp_shared_mem_map_regions_t, gpr_packet); + + if (!ctxt[master_proc_id]->pending_memmap_packet_list[index]) + ctxt[master_proc_id]->pending_memmap_packet_list[index] = + (struct gpr_packet_t *)gsl_mem_zalloc(sizeof(struct gpr_packet_t)); + if (ctxt[master_proc_id]->pending_memmap_packet_list[index]) { + gsl_memcpy(ctxt[master_proc_id]->pending_memmap_packet_list[index], + sizeof(struct gpr_packet_t), + gpr_packet, + sizeof(struct gpr_packet_t)); + ctxt[master_proc_id]->pending_memmap_handle_list[index] = + mmap_regions->mem_map_handle; + } else { + GSL_ERR("Failed to allocate mem for caching the pending memory packet!"); + return; + } + if (++index == MAX_PENDING_MEMMAP_PACKETS) { + GSL_INFO("Warning: buffer limit exceeded. Resetting index to 0."); + index = 0; + } + ctxt[master_proc_id]->pending_memmap_packet_index = index; +} + +uint32_t gsl_shmem_check_and_unmap_cache_pending_packets(uint32_t master_proc_id) { + int32_t rc = AR_EOK; + gpr_packet_t *unmap_send_pkt = NULL, *unmap_rsp_pkt = NULL; + gpr_packet_t *pending_pkt = NULL; + uint8_t cma_client_data = 0; + struct apm_cmd_shared_mem_unmap_regions_t *unmap_payload; + for (int i = 0; i < MAX_PENDING_MEMMAP_PACKETS && + ctxt[master_proc_id]->pending_memmap_packet_list[i]; i++) { + pending_pkt = (gpr_packet_t *)ctxt[master_proc_id]->pending_memmap_packet_list[i]; + if ((ctxt[master_proc_id]->error_memmap_shmem_info_flags & + (AR_SHMEM_BIT_MASK_HW_ACCELERATOR_FLAG + << AR_SHMEM_SHIFT_HW_ACCELERATOR_FLAG)) != 0) { + cma_client_data = GSL_GPR_CMA_FLAG_BIT; + } else { + cma_client_data = 0; + } + switch (pending_pkt->opcode) { + case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS: + if (ctxt[master_proc_id]->memmap_count == 0) { + GSL_DBG("the pending packet has been handled."); + break; + } + rc = gsl_allocate_gpr_packet(APM_CMD_SHARED_MEM_UNMAP_REGIONS, + GSL_SHMEM_SRC_PORT, APM_MODULE_INSTANCE_ID, + sizeof(*unmap_payload), 0, + pending_pkt->src_domain_id, + &unmap_send_pkt); + if (rc) { + GSL_ERR("Failed to allocate GPR packet %d", rc); + break; + } + unmap_payload = + GPR_PKT_GET_PAYLOAD(struct + apm_cmd_shared_mem_unmap_regions_t, + unmap_send_pkt); + unmap_payload->mem_map_handle = + ctxt[master_proc_id]->pending_memmap_handle_list[i]; + unmap_send_pkt->client_data |= cma_client_data; + GSL_LOG_PKT("send_pkt", GSL_SHMEM_SRC_PORT, + unmap_send_pkt, + sizeof(*unmap_send_pkt) + + sizeof(*unmap_payload), + NULL, 0); + ctxt[master_proc_id]->memmap_count--; + rc = gsl_send_spf_cmd(&unmap_send_pkt, + &ctxt[master_proc_id]->sig, + &unmap_rsp_pkt); + if (rc || !unmap_rsp_pkt) { + if (unmap_rsp_pkt) + __gpr_cmd_free(unmap_rsp_pkt); + break; + } + rc = gsl_shmem_handle_rsp(unmap_rsp_pkt, + pending_pkt->src_domain_id, GPR_IBASIC_RSP_RESULT); + gsl_mem_free(ctxt[master_proc_id]->pending_memmap_packet_list[i]); + ctxt[master_proc_id]->pending_memmap_packet_list[i] = NULL; + break; + + default: + GSL_ERR("unsupported opcode %d encountered in unmap pending mem packet from spf", + pending_pkt->opcode); + rc = AR_EFAILED; + break; + }; + } + +exit: + return rc; +} + +/* + * map an allocation to specified subsystems only + */ +int32_t gsl_shmem_map_allocation_to_spf( + const struct gsl_shmem_alloc_data *alloc_data, + uint32_t flags, uint32_t ss_mask_to_map_to, uint32_t master_proc_id) +{ + int32_t rc = AR_EBADPARAM; + struct gsl_shmem_page *page = NULL; + + if (!ctxt[master_proc_id]) + return AR_EUNSUPPORTED; + + if (alloc_data) { + page = (struct gsl_shmem_page *)alloc_data->handle; + rc = gsl_shmem_map_page_to_spf(page, flags, ss_mask_to_map_to); + } + + return rc; +} + +int32_t gsl_shmem_map_allocation(const struct gsl_shmem_alloc_data *alloc_data, + uint32_t flags, uint32_t ss_mask_to_map_to, uint32_t master_proc_id) +{ + int32_t rc = AR_EBADPARAM; + struct gsl_shmem_page *page = NULL; + + if (!ctxt[master_proc_id] || !alloc_data) + return AR_EUNSUPPORTED; + + page = (struct gsl_shmem_page *)alloc_data->handle; + rc = ar_shmem_map(&page->shmem_info); + if (rc) { + GSL_ERR("shmem_map is failed %d", rc); + return rc; + } + rc = gsl_shmem_map_page_to_spf(page, flags, ss_mask_to_map_to); + if (rc) { + GSL_ERR("gsl_shmem_map_page_to_spf is failed %d", rc); + ar_shmem_unmap(&page->shmem_info); + } + return rc; +} + +int32_t gsl_shmem_map_dynamic_pd(struct gsl_shmem_alloc_data *alloc_data, + uint32_t flags, uint32_t ss_mask, uint32_t master_proc_id) +{ + int32_t rc = 0; + uint32_t dyn_ss_mask = 0; + uint32_t num_sys_id = 0, sys_id = AR_SUB_SYS_ID_FIRST; + uint32_t dyn_pd_list[AR_SUB_SYS_ID_LAST], dyn_pd_cnt = 0; + ar_shmem_proc_info ss_id_list[AR_SUB_SYS_ID_LAST]; + struct gsl_shmem_page *page = NULL; + + if (!ctxt[master_proc_id] || !alloc_data) + return AR_EBADPARAM; + + page = alloc_data->handle; + /* + * The page spf_ss_mask contains the mapped pds, + * check and skip mapping for those. + */ + ss_mask &= ~GSL_GET_SPF_SS_MASK(master_proc_id); + ss_mask &= ~page->spf_ss_mask; + if (!ss_mask) + return rc; + + /* back up ss_id_list to restore after mapping dynamic pd */ + gsl_memcpy(ss_id_list, sizeof(ss_id_list), page->ss_id_list, + page->shmem_info.num_sys_id * sizeof(ar_shmem_proc_info)); + num_sys_id = page->shmem_info.num_sys_id; + page->shmem_info.num_sys_id = 0; + dyn_pd_cnt = 0; + dyn_ss_mask = ss_mask; + while (dyn_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(ss_mask, sys_id)) { + page->ss_id_list[page->shmem_info.num_sys_id].proc_id = + sys_id; + page->ss_id_list[page->shmem_info.num_sys_id].proc_type = + DYNAMIC_PD; + page->ss_id_list[page->shmem_info.num_sys_id++].is_active = + TRUE; + dyn_pd_list[dyn_pd_cnt++] = sys_id; + } + ++sys_id; + dyn_ss_mask >>= 1; + } + + rc = gsl_shmem_map_allocation(alloc_data, flags, ss_mask, master_proc_id); + if (rc != AR_EOK) { + GSL_ERR("dynamic pd mapping failed %d", rc); + /* restore page ss_id_list */ + page->shmem_info.num_sys_id = num_sys_id; + gsl_memcpy(page->ss_id_list, sizeof(page->ss_id_list), ss_id_list, + num_sys_id * sizeof(ar_shmem_proc_info)); + return rc; + } + /* + * ss_id_list contains only static PDs as the dynamic PDs + * are skipped during boot up. So, add the dynamic PDs + * to the list after memory is mapped for dynamic PDs. + */ + page->shmem_info.num_sys_id = num_sys_id; + gsl_memcpy(page->ss_id_list, sizeof(page->ss_id_list), ss_id_list, + num_sys_id * sizeof(ar_shmem_proc_info)); + while (dyn_pd_cnt) { + --dyn_pd_cnt; + page->ss_id_list[page->shmem_info.num_sys_id].proc_id = + dyn_pd_list[dyn_pd_cnt]; + page->ss_id_list[page->shmem_info.num_sys_id++].proc_type = + DYNAMIC_PD; + } + page->spf_ss_mask |= ss_mask; + return rc; +} + +int32_t gsl_shmem_unmap_dynamic_pd(struct gsl_shmem_alloc_data *alloc_data, + uint32_t ss_mask, uint32_t master_proc_id) +{ + int32_t rc = 0; + uint32_t tmp_ss_mask = 0; + uint32_t num_sys_id = 0, sys_id = AR_SUB_SYS_ID_FIRST; + ar_shmem_proc_info ss_id_list[AR_SUB_SYS_ID_LAST]; + struct gsl_shmem_page *page = NULL; + + if (!ctxt[master_proc_id] || !alloc_data) + return AR_EBADPARAM; + + /* Back up page ss_id_list to preserve other pds. */ + page = alloc_data->handle; + gsl_memcpy(ss_id_list, sizeof(ss_id_list), page->ss_id_list, + page->shmem_info.num_sys_id * sizeof(ar_shmem_proc_info)); + num_sys_id = page->shmem_info.num_sys_id; + page->shmem_info.num_sys_id = 0; + ss_mask &= ~GSL_GET_SPF_SS_MASK(master_proc_id); + tmp_ss_mask = ss_mask; + while (tmp_ss_mask) { + if (GSL_TEST_SPF_SS_BIT(ss_mask, sys_id)) { + page->ss_id_list[page->shmem_info.num_sys_id].proc_id = + sys_id; + page->ss_id_list[page->shmem_info.num_sys_id].proc_type = + DYNAMIC_PD; + /* Skip unmap command to DSP if proc is down */ + if ((gsl_spf_ss_state_get(page->master_proc) & ss_mask) != ss_mask) + page->ss_id_list[page->shmem_info.num_sys_id].is_active = FALSE; + ++page->shmem_info.num_sys_id; + } + ++sys_id; + tmp_ss_mask >>= 1; + } + /* + * ss_mask contains only dynamic pd, so unmap + * happens only for dynamic pd. + */ + rc = gsl_shmem_unmap_allocation(alloc_data, ss_mask); + if (rc != AR_EOK) + GSL_ERR("dynamic pd unmap failed %d", rc); + /* + * Restore page ss_id_list by removing unmapped + * dynamic pds. + */ + page->shmem_info.num_sys_id = 0; + for (int j = 0; j < num_sys_id; j++) { + if ((ss_id_list[j].proc_type == DYNAMIC_PD) && + (GSL_TEST_SPF_SS_BIT(ss_mask, + ss_id_list[j].proc_id))) + continue; + page->ss_id_list[page->shmem_info.num_sys_id].proc_id = + ss_id_list[j].proc_id; + page->ss_id_list[page->shmem_info.num_sys_id++].proc_type = + ss_id_list[j].proc_type; + } + page->spf_ss_mask &= ~ss_mask; + return rc; +} + +int32_t gsl_shmem_get_mapped_ss_mask( + const struct gsl_shmem_alloc_data *alloc_data) +{ + if (alloc_data && alloc_data->handle) + return alloc_data->handle->spf_ss_mask; + return 0; +} + +uint64_t gsl_shmem_get_metadata( + const struct gsl_shmem_alloc_data *alloc_data) +{ + return (alloc_data->handle)->shmem_info.metadata; +} + +int32_t gsl_shmem_hyp_assign(gsl_shmem_handle_t alloc_handle, + uint64_t dest_sys, uint64_t src_sys) +{ + int32_t rc = AR_EOK; + ar_shmem_hyp_assign_phys_info hyp_assn_info = { 0 }; + ar_shmem_hyp_assign_phys_addr hyp_phys_addr; + ar_shmem_hyp_assign_dest_sys_info hyp_dst_sys; + + hyp_phys_addr.phys_addr = + ((uint64_t)alloc_handle->shmem_info.ipa_msw << 32) + + alloc_handle->shmem_info.ipa_lsw; + hyp_phys_addr.size = alloc_handle->shmem_info.buf_size; + hyp_dst_sys.dest_sys_id = dest_sys; + hyp_dst_sys.dest_perm = DEST_SYS_PERM_WRITE_READ; + + hyp_assn_info.phys_addr_list = &hyp_phys_addr; + hyp_assn_info.dest_sys_list = &hyp_dst_sys; + hyp_assn_info.src_sys_list = &src_sys; + hyp_assn_info.phys_addr_list_size = + sizeof(hyp_phys_addr) / sizeof(ar_shmem_hyp_assign_phys_addr); + hyp_assn_info.dest_sys_list_size = + sizeof(hyp_dst_sys) / sizeof(ar_shmem_hyp_assign_dest_sys_info); + hyp_assn_info.src_sys_list_size = 1; + hyp_assn_info.metadata = alloc_handle->shmem_info.metadata; + + rc = ar_shmem_hyp_assign_phys(&hyp_assn_info); + if (rc) + GSL_ERR("ar hyp_assign_phys failed %d", rc); + + return rc; +} + +int32_t gsl_shmem_init(uint32_t num_master_procs, uint32_t *master_procs) +{ + int32_t rc = AR_EOK; + uint32_t i = 0, j = 0; + struct gsl_shmem_page *page = NULL; + bool_t is_shmem_supported = FALSE; + uint32_t bin_idx = 0; + + /* register with GPR */ + rc = __gpr_cmd_register(GSL_SHMEM_SRC_PORT, + gsl_shmem_gpr_callback, ctxt); + if (rc) { + GSL_ERR("Registering shmem src port failed"); + return rc; + } + /* TODO: This ar_shmem_init() API call will be removed in a future update. */ + rc = ar_shmem_init(); + if (rc) + goto deregister; + + rc = ar_shmem_init_v2(num_master_procs, master_procs); + if (rc) + goto deregister; + + for (; i < num_master_procs; i++) { + __gpr_cmd_is_shared_mem_supported(master_procs[i], + &is_shmem_supported); + if (!is_shmem_supported) + continue; + + ctxt[master_procs[i]] = + gsl_mem_zalloc(sizeof(struct gsl_shmem_mgr_ctxt)); + + if (!ctxt[master_procs[i]]) { + GSL_ERR("Unable to allocate memory"); + rc = AR_ENOMEMORY; + goto free_ctxt; + } + + for (bin_idx = 0; bin_idx < GSL_SHMEM_MGR_NUM_BINS; ++bin_idx) { + rc = ar_list_init(&(ctxt[master_procs[i]]->bins[bin_idx].page_list), + NULL, NULL); + if (rc) { + GSL_ERR("ar init list failed %d", rc); + goto free_ctxt; + } + ctxt[master_procs[i]]->bins[bin_idx].num_pages = 0; + } + } + + for (i = 0; i < num_master_procs; i++) { + if (!ctxt[master_procs[i]]) + continue; + + rc = ar_osal_mutex_create(&ctxt[master_procs[i]]->mutex); + if (rc) { + GSL_ERR("ar mutex create failed %d", rc); + goto cleanup; + } + rc = ar_osal_mutex_create(&ctxt[master_procs[i]]->sig_lock); + if (rc) { + GSL_ERR("ar mutex create failed %d", rc); + goto cleanup_mutex; + } + rc = gsl_signal_create(&ctxt[master_procs[i]]->sig, + &ctxt[master_procs[i]]->sig_lock); + if (rc) { + GSL_ERR("ar signal create failed %d", rc); + goto cleanup_sig_lock; + } + +#ifdef GSL_SHMEM_MGR_STATS_ENABLE + stats.curr_bytes_mapped = 0; + stats.curr_bytes_requested = 0; + stats.curr_bytes_allocated = 0; + stats.max_bytes_mapped = 0; + stats.max_bytes_requested = 0; + stats.max_bytes_allocated = 0; +#endif + /* + * allocate a page and keep it mapped till de-init, this is to somewhat + * reduce the amount of mapping/unmapping that takes place + */ + allocate_page(GSL_SHMEM_PRE_ALLOC_SIZE, + GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH, + GSL_GET_SPF_SS_MASK(master_procs[i]), 0, 0, + GSL_EXT_MEM_HDL_NOT_ALLOCD, + master_procs[i], &page); + } + + goto exit; + +cleanup_sig_lock: + if (ctxt[master_procs[i]]) + ar_osal_mutex_destroy(ctxt[master_procs[i]]->sig_lock); +cleanup_mutex: + if (ctxt[master_procs[i]]) + ar_osal_mutex_destroy(ctxt[master_procs[i]]->mutex); +cleanup: + for (j = 0; j < i; j++) { + if (ctxt[master_procs[j]]) { + ar_osal_mutex_destroy(ctxt[master_procs[j]]->sig_lock); + ar_osal_mutex_destroy(ctxt[master_procs[j]]->mutex); + } + } +free_ctxt: + for (j = 0; j < num_master_procs; j++) { + if (ctxt[master_procs[j]]) { + gsl_mem_free(ctxt[master_procs[j]]); + ctxt[master_procs[j]] = NULL; + } + } +deregister: + __gpr_cmd_deregister(GSL_SHMEM_SRC_PORT); +exit: + return rc; +} + +int32_t gsl_shmem_deinit(void) +{ + int32_t rc1 = AR_EOK, rc = AR_EOK; + ar_list_node_t *iter = NULL, *iter_look_ahead = NULL; + struct gsl_shmem_page *page = NULL; + uint32_t bin_idx = GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH; + uint32_t i = 0; + + for (; i <= AR_SUB_SYS_ID_LAST; i++) { + if (ctxt[i] == NULL) + continue; + + /* free all pages that were allocated at init time */ + iter = ctxt[i]->bins[GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH] + .page_list.dummy.next; + while (iter != &ctxt[i]->bins[bin_idx].page_list.dummy) { + /* + * below look ahead logic is needed because we are deleting + * nodes as we traverse the list + */ + iter_look_ahead = iter->next; + page = get_container_base(iter, struct gsl_shmem_page, node); + free_page(GSL_SHMEM_MGR_BIN_IDX_PRE_ALLOC_SCRATCH, page, 0); + iter = iter_look_ahead; + } + + rc = gsl_signal_destroy(&ctxt[i]->sig); + if (rc) + rc1 = rc; + + rc = ar_osal_mutex_destroy(ctxt[i]->sig_lock); + if (rc && !rc1) + rc1 = rc; + + rc = ar_osal_mutex_destroy(ctxt[i]->mutex); + if (rc && !rc1) + rc1 = rc; + + gsl_mem_free(ctxt[i]); + ctxt[i] = NULL; + } + + rc = ar_shmem_deinit(); + if (rc && !rc1) + rc1 = rc; + + rc = __gpr_cmd_deregister(GSL_SHMEM_SRC_PORT); + if (rc && !rc1) + rc1 = AR_EFAILED; + + return rc1; +} diff --git a/gsl/src/gsl_spf_ss_state.c b/gsl/src/gsl_spf_ss_state.c new file mode 100644 index 0000000..7961395 --- /dev/null +++ b/gsl/src/gsl_spf_ss_state.c @@ -0,0 +1,404 @@ +/** + * \file gsl_spf_ss_state.c + * + * \brief + * Maintains the state of Spf framework across all subsystems. With MDF + * (Multi-DSP framework) capabilities there will be a Spf master service that + * runs in a certain subsystem (typically ADSP) and Spf satelite services + * run in other subsystems suchs as MDSP or CDSP. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_spf_ss_state.h" +#include "gsl_common.h" +#include "gsl_intf.h" +#include "ar_osal_types.h" +#include "ar_osal_error.h" +#include "ar_osal_mutex.h" +#include "ar_osal_servreg.h" +#include "ar_osal_shmem.h" +#include "ar_util_err_detection.h" +#include "gsl_mdf_utils.h" + +#define GSL_AUDIO_PD_DOMAIN_STR "msm/adsp/audio_pd" +#define GSL_COMPUTE_PD_DOMAIN_STR "msm/cdsp/audio_pd" +#define GSL_COMPUTE_ROOT_PD_DOMAIN_STR "msm/cdsp/root_pd" +#define GSL_MODEM_PD_DOMAIN_STR "msm/mdsp/audio_pd" +#define GSL_SENSOR_PD_DOMAIN_STR "msm/sdsp/audio_pd" +#define GSL_AUDIO_PD_SERVICE_STR "avs/audio" + +struct gsl_spf_ss_state { + /* + * bit mask that represents which subsystems are supported + */ + uint32_t ss_supported_flags; + /* + * bit mask representing the state of each subsystem + */ + uint32_t ss_state_flags; + /* + * Used to sychronize accesses to the global subsystem state + */ + ar_osal_mutex_t lock; + /* + * callback invoked whenever there is an SSR up or down event + */ + gsl_spf_ss_cb_t ssr_cb; +}; + +/* + * A cluster has 1 master and N satellites + * This array stores state information for all the masters and corresponding + * satellites. + */ +struct gsl_spf_ss_state *_spf_cluster_ss_state[AR_SUB_SYS_ID_LAST + 1] = {NULL}; + +static uint32_t spf_cluster_ref_count; + +/* + * Store servreg handles from registration for re-use + */ + +struct gsl_servreg_handle_list *servreg_handle_list; + +static uint32_t gsl_find_proc_id_from_name(char_t *name) +{ + uint32_t proc_id = AR_SUB_SYS_ID_INVALID; + + if (!strcmp(name, GSL_AUDIO_PD_DOMAIN_STR)) + proc_id = AR_AUDIO_DSP; + else if (!strcmp(name, GSL_COMPUTE_PD_DOMAIN_STR) || + !strcmp(name, GSL_COMPUTE_ROOT_PD_DOMAIN_STR)) + proc_id = AR_COMPUTE_DSP; + else if (!strcmp(name, GSL_MODEM_PD_DOMAIN_STR)) + proc_id = AR_MODEM_DSP; + else if (!strcmp(name, GSL_SENSOR_PD_DOMAIN_STR)) + proc_id = AR_SENSOR_DSP; + + return proc_id; +} + +static void servreg_callback(ar_osal_servreg_t servreg_handle, + ar_osal_servreg_cb_event_type event_id, void *cb_context, void *payload, + uint32_t payload_size) +{ + uint32_t ss_mask = 0; + uint32_t master_proc = AR_SUB_SYS_ID_INVALID; + uint32_t proc_id = AR_SUB_SYS_ID_INVALID; + uint32_t sys_id = AR_SUB_SYS_ID_FIRST; + uint32_t supported_ss_mask = 0, tmp_ss_mask = 0; + /* + * reference unused variables to make compiler happy. Can't change function + * signature because it needs to match what OSAL expects. + */ + (void)servreg_handle; + (void)cb_context; + (void)payload_size; + + ar_osal_servreg_state_notify_payload_type *serv_ntfy_pld = + (ar_osal_servreg_state_notify_payload_type *)payload; + + if (event_id == AR_OSAL_SERVICE_STATE_NOTIFY) { + proc_id = gsl_find_proc_id_from_name(serv_ntfy_pld->domain.name); + if (proc_id != AR_SUB_SYS_ID_INVALID) { + ss_mask = GSL_GET_SPF_SS_MASK(proc_id); + } else { + GSL_ERR("could not recognize domain %s", + serv_ntfy_pld->domain.name); + return; + } + + master_proc = gsl_mdf_utils_get_master_proc_id(ss_mask); + if (master_proc == 0) { + GSL_ERR("Invalid proc id %d", master_proc); + return; + } + if (serv_ntfy_pld->service_state == AR_OSAL_SERVICE_STATE_DOWN) { + GSL_INFO("AR_OSAL_SERVICE_STATE_DOWN proc_id %d", proc_id); + /* + * For dynamic PD down notification, restart master proc. + * PD down notification can also be sent for normal PD close + * as part of PD deinitialization. Check and ignore notification + * for such case. + */ + if (gsl_mdf_utils_is_dynamic_pd(proc_id)) { + if (gsl_mdf_utils_get_dynamic_pd_state(proc_id)) { + gsl_spf_ss_state_set(master_proc, ss_mask, GSL_SPF_SS_STATE_DN); + GSL_INFO("Restart master proc %d for dynamic pd %d crash", + master_proc, proc_id); + ar_osal_servreg_restart_service( + servreg_handle_list->handles[master_proc]); + } + return; + } + gsl_spf_ss_state_set(master_proc, ss_mask, GSL_SPF_SS_STATE_DN); + /* + * For dynamic PD down notification, restart master proc. + * PD down notification can also be sent for normal PD close + * as part of PD deinitialization. Check and ignore notification + * for such case. + */ + /* notify gsl_main */ + _spf_cluster_ss_state[master_proc]->ssr_cb(GSL_SPF_SS_STATE_DN, + ss_mask); + } else if (serv_ntfy_pld->service_state == AR_OSAL_SERVICE_STATE_UP) { + GSL_INFO("AR_OSAL_SERVICE_STATE_UP proc_id %d", proc_id); + if (gsl_mdf_utils_is_dynamic_pd(proc_id)) { + /* PD up notification can also be sent when PD is loaded part of + * normal pd initialization. Skip SSR callback notification. + */ + gsl_spf_ss_state_set(master_proc, ss_mask, GSL_SPF_SS_STATE_UP); + return; + } + if (gsl_mdf_utils_is_master_proc(ss_mask)) { + /* + * If there is an associated dynamic PD satellite add it to + * ss_mask as up, since dynamic PD crash would have forced this + * master proc restart. + */ + gsl_mdf_utils_get_supported_ss_info_from_master_proc(master_proc, + &supported_ss_mask); + tmp_ss_mask = supported_ss_mask; + while (tmp_ss_mask && (sys_id <= AR_SUB_SYS_ID_LAST)) { + if (GSL_TEST_SPF_SS_BIT(supported_ss_mask, sys_id) && + gsl_mdf_utils_is_dynamic_pd(sys_id)) { + ss_mask |= GSL_GET_SPF_SS_MASK(sys_id); + } + ++sys_id; + tmp_ss_mask >>= 1; + } + } + /* update the global Spf SS state */ + GSL_DBG("set ss state with ss_mask 0x%x", ss_mask); + gsl_spf_ss_state_set(master_proc, ss_mask, GSL_SPF_SS_STATE_UP); + /* notify gsl_main */ + _spf_cluster_ss_state[master_proc]->ssr_cb(GSL_SPF_SS_STATE_UP, + ss_mask); + } + } +} + +static uint32_t gsl_servreg_setup(void) +{ + int32_t rc = AR_EOK; + ar_osal_servreg_entry_type service = { GSL_AUDIO_PD_SERVICE_STR, 0 }; + ar_osal_servreg_entry_type *domain_list = NULL; + uint32_t i = 0, domain_list_size = 0, proc_id; + ar_osal_servreg_t servreg_handle; + + rc = ar_osal_servreg_init(); + if (rc) { + GSL_ERR("failed to initialize ar_osal state notifier %d", rc); + goto exit; + } + + /* first we query for number of entries in domain list */ + rc = ar_osal_servreg_get_domainlist(&service, NULL, &domain_list_size); + if (rc != AR_ENOMEMORY) { + GSL_ERR("failed to get num domains with ar_osal state notifier %d", + rc); + goto deinit_state_notify; + } + + /* next we query for actual list */ + domain_list = gsl_mem_zalloc(domain_list_size * + sizeof(ar_osal_servreg_entry_type)); + if (!domain_list) { + rc = AR_ENOMEMORY; + goto deinit_state_notify; + } + rc = ar_osal_servreg_get_domainlist(&service, domain_list, + &domain_list_size); + if (rc) { + GSL_ERR("failed to get domains with ar_osal state notifier %d", rc); + goto free_domain_list; + } + + /* add 1 to num handles since domain 0 is invalid */ + servreg_handle_list = + gsl_mem_zalloc(sizeof(struct gsl_servreg_handle_list) + + (AR_SUB_SYS_ID_LAST + 1) * sizeof(ar_osal_servreg_t)); + if (!servreg_handle_list) { + rc = AR_ENOMEMORY; + goto free_domain_list; + } + servreg_handle_list->num_handles = domain_list_size + 1; + + /* add 1 for offset since domain 0 is invalid */ + /* scan through domain list and register for notification */ + for (i = 0; i < domain_list_size; ++i) { + proc_id = gsl_find_proc_id_from_name(domain_list[i].name); + if (proc_id == AR_SUB_SYS_ID_INVALID) + continue; + servreg_handle = ar_osal_servreg_register(AR_OSAL_CLIENT_LISTENER, + servreg_callback, _spf_cluster_ss_state[proc_id], + domain_list + i, &service); + /* + * On some platform variants, the proc may not be present. Ideally the servereg + * domain list could indicate this, but it may not be possible due to cross platform + * build dependencies. So, ignore the error to avoid failing to initialize GSL. + */ + if (!servreg_handle) + GSL_ERR("failed to register for %s : %s, continue", domain_list[i].name, service.name); + + servreg_handle_list->handles[proc_id] = servreg_handle; + } + + gsl_mem_free(domain_list); + return rc; + +free_domain_list: + gsl_mem_free(domain_list); +deinit_state_notify: + ar_osal_servreg_deinit(); +exit: + return rc; +} + +static int32_t gsl_register_err_det_ctxt(uint32_t master_proc) +{ + struct gsl_spf_ss_state *cluster; + int32_t rc = AR_EOK; + uint32_t i = 0, j = 0, num_handles = 0; + struct gsl_servreg_handle_list *input_handle_list; + + cluster = _spf_cluster_ss_state[master_proc]; + + if (!cluster) + return AR_EBADPARAM; + + for (i = AR_SUB_SYS_ID_FIRST; i <= AR_SUB_SYS_ID_LAST; ++i) { + if (gsl_spf_ss_state_is_ss_supported(master_proc, i)) + ++num_handles; + } + + input_handle_list = + (struct gsl_servreg_handle_list *)gsl_mem_zalloc( + sizeof(struct gsl_servreg_handle_list) + + (num_handles) * sizeof(ar_osal_servreg_t)); + if (!input_handle_list) + return AR_ENOMEMORY; + + for (i = AR_SUB_SYS_ID_FIRST; i <= AR_SUB_SYS_ID_LAST; ++i) { + if (gsl_spf_ss_state_is_ss_supported(master_proc, i) && + servreg_handle_list->handles[i] != NULL) { + input_handle_list->handles[j] = servreg_handle_list->handles[i]; + ++j; + } + } + + input_handle_list->num_handles = j; + + rc = ar_err_det_init_ctxt(master_proc, input_handle_list); + + return rc; +} + +bool_t gsl_spf_ss_state_is_ss_supported(uint32_t master_proc, uint32_t proc_id) +{ + uint32_t ss_mask = 0; + + if (_spf_cluster_ss_state[master_proc] != NULL) { + ss_mask = _spf_cluster_ss_state[master_proc]->ss_supported_flags; + if (GSL_TEST_SPF_SS_BIT(ss_mask, proc_id)) + return TRUE; + } + + return FALSE; +} + +int32_t gsl_spf_ss_state_init(uint32_t master_proc, uint32_t supported_ss_mask, + gsl_spf_ss_cb_t cb) +{ + int32_t rc = AR_EOK; + + if (master_proc <= AR_SUB_SYS_ID_INVALID || + master_proc > AR_SUB_SYS_ID_LAST) + return AR_EBADPARAM; + _spf_cluster_ss_state[master_proc] = + gsl_mem_zalloc(sizeof(struct gsl_spf_ss_state)); + + rc = ar_osal_mutex_create(&_spf_cluster_ss_state[master_proc]->lock); + if (rc) + goto exit; + + if (spf_cluster_ref_count == 0) { + rc = gsl_servreg_setup(); + if (rc) + goto cleanup; + } + _spf_cluster_ss_state[master_proc]->ss_supported_flags = supported_ss_mask; + _spf_cluster_ss_state[master_proc]->ssr_cb = cb; + ++spf_cluster_ref_count; + + rc = gsl_register_err_det_ctxt(master_proc); + + return rc; +cleanup: + ar_osal_mutex_destroy(_spf_cluster_ss_state[master_proc]->lock); +exit: + gsl_mem_free(_spf_cluster_ss_state[master_proc]); + _spf_cluster_ss_state[master_proc] = NULL; + return rc; +} + +void gsl_spf_ss_state_deinit(uint32_t master_proc) +{ + if (master_proc <= AR_SUB_SYS_ID_INVALID || + master_proc > AR_SUB_SYS_ID_LAST) + return; + + if (_spf_cluster_ss_state[master_proc] != NULL) { + _spf_cluster_ss_state[master_proc]->ss_supported_flags = 0; + _spf_cluster_ss_state[master_proc]->ssr_cb = NULL; + ar_osal_mutex_destroy(_spf_cluster_ss_state[master_proc]->lock); + gsl_mem_free(_spf_cluster_ss_state[master_proc]); + _spf_cluster_ss_state[master_proc] = NULL; + --spf_cluster_ref_count; + + ar_err_det_destroy_ctxt(master_proc); + } + + if (spf_cluster_ref_count == 0) { + ar_osal_servreg_deinit(); + gsl_mem_free(servreg_handle_list); + } +} + +uint32_t gsl_spf_ss_state_set(uint32_t master_proc, uint32_t ss_mask, + enum spf_ss_state_t state) +{ + uint32_t updated_ss_state = 0; + + if (master_proc <= AR_SUB_SYS_ID_INVALID || + master_proc > AR_SUB_SYS_ID_LAST) + return AR_EBADPARAM; + if (_spf_cluster_ss_state[master_proc] == NULL) + return AR_EBADPARAM; + GSL_MUTEX_LOCK(_spf_cluster_ss_state[master_proc]->lock); + if ((ss_mask & _spf_cluster_ss_state[master_proc]->ss_supported_flags) && + (state == GSL_SPF_SS_STATE_UP)) + _spf_cluster_ss_state[master_proc]->ss_state_flags |= ss_mask; + else if ((ss_mask & + _spf_cluster_ss_state[master_proc]->ss_supported_flags) && + (state == GSL_SPF_SS_STATE_DN)) { + _spf_cluster_ss_state[master_proc]->ss_state_flags &= ~ss_mask; + /* @TODO free mdf shared mem for proc_ids that went down */ + } + updated_ss_state = _spf_cluster_ss_state[master_proc]->ss_state_flags; + GSL_MUTEX_UNLOCK(_spf_cluster_ss_state[master_proc]->lock); + + return updated_ss_state; +} + +uint32_t gsl_spf_ss_state_get(uint32_t master_proc) +{ + if (master_proc <= AR_SUB_SYS_ID_INVALID || + master_proc > AR_SUB_SYS_ID_LAST) + return AR_EBADPARAM; + if (_spf_cluster_ss_state[master_proc] != NULL) + return _spf_cluster_ss_state[master_proc]->ss_state_flags; + return AR_EOK; +} + diff --git a/gsl/src/gsl_spf_timeout.c b/gsl/src/gsl_spf_timeout.c new file mode 100644 index 0000000..3d4e037 --- /dev/null +++ b/gsl/src/gsl_spf_timeout.c @@ -0,0 +1,118 @@ +/** + * \file gsl_spf_timeout.c + * + * \brief + * Represents GSL SPF timeouts + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_common.h" +#include "ar_osal_error.h" +#include "acdb.h" + +#define SET_TIMEOUT_IF_VALID(val, max, target) \ + do { if ((val) > 0 && (val) <= (max)) (target) = (val); } while (0) + +uint32_t GSL_SPF_TIMEOUT_MS = GSL_SPF_TIMEOUT_MS_DEFAULT; +uint32_t GSL_GRAPH_OPEN_TIMEOUT_MS = GSL_GRAPH_OPEN_TIMEOUT_MS_DEFAULT; +uint32_t GSL_GRAPH_PREPARE_TIMEOUT_MS = GSL_GRAPH_PREPARE_TIMEOUT_MS_DEFAULT; +uint32_t GSL_GRAPH_START_STOP_TIMEOUT_MS = GSL_GRAPH_START_STOP_TIMEOUT_MS_DEFAULT; +uint32_t GSL_SPF_READ_WRITE_TIMEOUT_MS = GSL_SPF_READ_WRITE_TIMEOUT_MS_DEFAULT; + +int32_t gsl_spf_timeouts_get_timeouts_from_acdb(void) +{ + AcdbDriverData acdb_req = { 0, }; + AcdbBlob acdb_rsp = { 0, }; + struct spf_timeouts_value *sv = NULL; + int32_t rc = AR_EOK; + uint32_t i = 0, *tmp_p = NULL, *tmp_pos = NULL; + + GSL_INFO("Enter"); + + /* first query for size */ + acdb_req.key_vector.num_keys = 0; + acdb_req.module_id = GSL_SPF_TIMEOUTS; + acdb_rsp.buf = NULL; + acdb_rsp.buf_size = 0; + rc = acdb_ioctl(ACDB_CMD_GET_DRIVER_DATA, &acdb_req, sizeof(acdb_req), + &acdb_rsp, sizeof(acdb_rsp)); + if (rc != AR_EOK && rc != AR_ENOTEXIST) { + GSL_ERR("acdb query ACDB_CMD_GET_DRIVER_DATA failed %d", rc); + return rc; + } + + acdb_rsp.buf = gsl_mem_zalloc(acdb_rsp.buf_size); + if (!acdb_rsp.buf) { + rc = AR_ENOMEMORY; + return rc; + } + + rc = acdb_ioctl(ACDB_CMD_GET_DRIVER_DATA, &acdb_req, sizeof(acdb_req), + &acdb_rsp, sizeof(acdb_rsp)); + if (rc != AR_EOK) { + GSL_ERR("acdb query ACDB_CMD_GET_DRIVER_DATA failed %d", rc); + goto exit; + } + + tmp_p = (uint32_t *)acdb_rsp.buf; + /* MID */ + if (*tmp_p++ != GSL_SPF_TIMEOUTS) { + GSL_ERR("got incorrect SPF_TIMEOUTS from ACDB %d", *((uint32_t *)acdb_rsp.buf)); + rc = AR_EFAILED; + goto exit; + } + + acdb_rsp.buf_size -= 4; /* PARAM ID GSL_SPF_TIMEOUTS size */ + while (acdb_rsp.buf_size > 0) { + if (*tmp_p == PARAM_ID_SPF_TIMEOUTS) { + GSL_INFO("Get the spf timeout value success"); + tmp_pos = tmp_p; + ++tmp_p; /* Skip Param ID */ + ++tmp_p; /* Skip Size */ + sv = (struct spf_timeouts_value *)tmp_p; + SET_TIMEOUT_IF_VALID(sv->spf_timeout, + GSL_SPF_TIMEOUT_MS_DEFAULT, GSL_SPF_TIMEOUT_MS); + SET_TIMEOUT_IF_VALID(sv->graph_open_timeout, + GSL_GRAPH_OPEN_TIMEOUT_MS_DEFAULT, GSL_GRAPH_OPEN_TIMEOUT_MS); + SET_TIMEOUT_IF_VALID(sv->graph_prepare_timeout, + GSL_GRAPH_PREPARE_TIMEOUT_MS_DEFAULT, GSL_GRAPH_PREPARE_TIMEOUT_MS); + SET_TIMEOUT_IF_VALID(sv->graph_start_stop_timeout, + GSL_GRAPH_START_STOP_TIMEOUT_MS_DEFAULT, GSL_GRAPH_START_STOP_TIMEOUT_MS); + SET_TIMEOUT_IF_VALID(sv->spf_read_write_timeout, + GSL_SPF_READ_WRITE_TIMEOUT_MS_DEFAULT, GSL_SPF_READ_WRITE_TIMEOUT_MS); + ++sv; + acdb_rsp.buf_size -= ((void *)sv - (void *)tmp_pos); + tmp_p = (uint32_t *)sv; + } else { + GSL_ERR("got incorrect PID from ACDB %d", *((uint32_t *)acdb_rsp.buf)); + goto exit; + } + } + +exit: + if(acdb_rsp.buf) + gsl_mem_free(acdb_rsp.buf); + return rc; +} + +int32_t gsl_spf_timeouts_init(void) +{ + int32_t rc = AR_EOK; + rc = gsl_spf_timeouts_get_timeouts_from_acdb(); + if (rc) { + GSL_ERR("get spf timeouts data failed rc %d, use the default value", rc); + GSL_SPF_TIMEOUT_MS = GSL_SPF_TIMEOUT_MS_DEFAULT; + GSL_GRAPH_OPEN_TIMEOUT_MS = GSL_GRAPH_OPEN_TIMEOUT_MS_DEFAULT; + GSL_GRAPH_PREPARE_TIMEOUT_MS = GSL_GRAPH_PREPARE_TIMEOUT_MS_DEFAULT; + GSL_GRAPH_START_STOP_TIMEOUT_MS = GSL_GRAPH_START_STOP_TIMEOUT_MS_DEFAULT; + GSL_SPF_READ_WRITE_TIMEOUT_MS = GSL_SPF_READ_WRITE_TIMEOUT_MS_DEFAULT; + } + GSL_INFO("GSL_SPF_TIMEOUT_MS[%d] GSL_GRAPH_OPEN_TIMEOUT_MS[%d]", GSL_SPF_TIMEOUT_MS, + GSL_GRAPH_OPEN_TIMEOUT_MS); + GSL_INFO("GSL_GRAPH_PREPARE_TIMEOUT_MS[%d] GSL_GRAPH_START_STOP_TIMEOUT_MS[%d]", + GSL_GRAPH_PREPARE_TIMEOUT_MS, GSL_GRAPH_OPEN_TIMEOUT_MS); + GSL_INFO("GSL_SPF_READ_WRITE_TIMEOUT_MS[%d]", GSL_SPF_READ_WRITE_TIMEOUT_MS); + return AR_EOK; +} diff --git a/gsl/src/gsl_subgraph.c b/gsl/src/gsl_subgraph.c new file mode 100644 index 0000000..fff7fd8 --- /dev/null +++ b/gsl/src/gsl_subgraph.c @@ -0,0 +1,340 @@ +/** + * \file gsl_subgraph.c + * + * \brief + * Represents a single sub-graph + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_subgraph.h" +#include "ar_osal_error.h" +#include "ar_util_list.h" +#include "gsl_common.h" +#include "gsl_intf.h" +#include "gsl_shmem_mgr.h" +#include "gsl_mdf_utils.h" + +uint32_t gsl_subgraph_init(struct gsl_subgraph *sg, uint32_t sg_id) +{ + uint32_t rc = AR_EOK; + + if (sg == NULL) + return AR_EBADPARAM; + + rc = ar_list_init_node(&sg->node); + if (rc) { + GSL_ERR("ar init list failed %d", rc); + goto exit; + } + + sg->open_ref_cnt = 0; + sg->start_ref_cnt = 0; + sg->stop_ref_cnt = 0; + sg->sg_id = sg_id; + + for (int i = 0; i < AR_SUB_SYS_ID_LAST; i++) { + gsl_memset(&sg->persist_cal_data_per_proc[i].persist_cal_data, 0, sizeof(sg->persist_cal_data_per_proc[i].persist_cal_data)); + } + gsl_memset(&sg->user_persist_cfg_data, 0, + sizeof(sg->user_persist_cfg_data)); + + rc = ar_list_init(&sg->children, NULL, NULL); + +exit: + return rc; +} + +uint32_t gsl_subgraph_add_children(struct gsl_subgraph *sg, + AcdbSubgraph *child_sgids, AcdbSubgraph *pruned_child_sgids, + AcdbSubgraph *existing_child_sgids) +{ + uint32_t i = 0, is_found = 0; + struct gsl_child_sg *child = NULL; + struct ar_list_node_t *itr = NULL; + + if (!sg || !child_sgids) + return AR_EBADPARAM; + + /* initialize number of sgids to 0 */ + if (pruned_child_sgids) { + pruned_child_sgids->sg_id = child_sgids->sg_id; + pruned_child_sgids->num_dst_sgids = 0; + } + if (existing_child_sgids) { + existing_child_sgids->sg_id = child_sgids->sg_id; + existing_child_sgids->num_dst_sgids = 0; + } + + for (; i < child_sgids->num_dst_sgids; ++i) { + /* check if child already exists */ + is_found = 0; + ar_list_for_each_entry(itr, &sg->children) { + child = get_container_base(itr, struct gsl_child_sg, node); + if (!child) { + GSL_ERR("null returned for child\n"); + return AR_EBADPARAM; + } + if (child->sg_id == child_sgids->dst_sg_ids[i]) { + /* child already exists */ + ++child->ref_cnt; + is_found = 1; + break; + } + } + if (!is_found) { + child = gsl_mem_zalloc(sizeof(struct gsl_child_sg)); + if (!child) + return AR_ENOMEMORY; + + child->sg_id = child_sgids->dst_sg_ids[i]; + child->ref_cnt = 1; + ar_list_init_node((struct ar_list_node_t *)child); + ar_list_add_tail(&sg->children, &child->node); + if (pruned_child_sgids) { + /* add child to pruned list */ + pruned_child_sgids->dst_sg_ids[ + pruned_child_sgids->num_dst_sgids] = child->sg_id; + /* increment number of pruned sgids */ + ++pruned_child_sgids->num_dst_sgids; + } + } else if (existing_child_sgids) { + /* child was found, so add child to exitsting list */ + existing_child_sgids->dst_sg_ids[ + existing_child_sgids->num_dst_sgids] = child->sg_id; + ++existing_child_sgids->num_dst_sgids; + } + + } + return AR_EOK; +} + +uint32_t gsl_subgraph_remove_children(struct gsl_subgraph *sg, + AcdbSubgraph *child_sgids, struct gsl_cmd_properties *props, + AcdbSubgraph *pruned_child_sgids) +{ + uint32_t i = 0; + struct gsl_child_sg *child = NULL; + struct ar_list_node_t *itr = NULL; + + if (!sg || !child_sgids) + return AR_EBADPARAM; + + if (pruned_child_sgids) { + pruned_child_sgids->sg_id = child_sgids->sg_id; + pruned_child_sgids->num_dst_sgids = 0; + } + + /* + * in case the parent matches the properties we remove all of its + * children this is the same behavior as if props was set to NULL + */ + if (props && is_matching_sg_property(sg, props)) + props = NULL; + + for (; i < child_sgids->num_dst_sgids; ++i) { + /* check if child already exists */ + ar_list_for_each_entry(itr, &sg->children) { + child = get_container_base(itr, struct gsl_child_sg, node); + if (!child) { + GSL_ERR("null returned for child\n"); + return AR_EBADPARAM; + } + if (child->sg_id != child_sgids->dst_sg_ids[i]) + continue; + /* + * found child, only remove it if no properties are passed or + * if the child matched the properties + */ + if (!props || is_matching_sg_property(child->sg_obj, props)) { + if (--child->ref_cnt == 0) { + /* update pruned list */ + if (pruned_child_sgids) { + /* add sgid to list */ + pruned_child_sgids->dst_sg_ids[ + pruned_child_sgids->num_dst_sgids] = + child->sg_id; + /* increment count */ + ++(pruned_child_sgids->num_dst_sgids); + } + /* remove child */ + ar_list_delete(&sg->children, itr); + gsl_mem_free(child); + break; + } + } + } + } + + return AR_EOK; +} + +int32_t gsl_subgraph_query_persist_cal_by_mem(struct gsl_subgraph *sg_obj, + const struct gsl_key_vector *ckv, const AcdbHwAccelMemType mem_type, + uint32_t master_proc, uint32_t persist_cal_idx) +{ + /* used for grabbing data differentiated on hw accel/not */ + AcdbProcSubgraphPersistCalReq cmd_struct; + AcdbSgIdPersistCalData rsp_struct; + int32_t rc = AR_EOK; + uint32_t sg_ss_mask = 0; + AcdbSubgraphProcPair sg_pair; + + if (!sg_obj || !ckv) + return AR_EBADPARAM; + + if (persist_cal_idx < 0 || persist_cal_idx > sg_obj->num_proc_ids) + return AR_EBADPARAM; + + sg_pair.subgraph_id = sg_obj->sg_id; + sg_pair.proc_id = ACDB_HW_ACCEL_MEM_TYPE_MASK( + sg_obj->persist_cal_data_per_proc[persist_cal_idx].proc_id, mem_type); + /* actual proc_id where persist_cal needs to be applied. */ + + cmd_struct.num_subgraphs = 1; + cmd_struct.subgraph_list = &sg_pair; + + /* + * always query with empty prior CKV for persist cal as we want to get + * the full set of parameters so we can replace entire cal blob + */ + cmd_struct.cal_key_vector_prior.num_keys = 0; + cmd_struct.cal_key_vector_prior.graph_key_vector = NULL; + cmd_struct.cal_key_vector_new.num_keys = ckv->num_kvps; + cmd_struct.cal_key_vector_new.graph_key_vector = + (AcdbKeyValuePair *)ckv->kvp; + + rsp_struct.cal_data = NULL; + rsp_struct.num_sg_ids = 0; + rsp_struct.cal_data_size = 0; + + rc = acdb_ioctl(ACDB_CMD_GET_PROC_SUBGRAPH_CAL_DATA_PERSIST, + &cmd_struct, sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc == AR_ENOTEXIST) { + /* + * avoid printing error log for the case where a subgraph does not have + * any persistent data + */ + GSL_DBG("get proc persist cal size failed %d", rc); + return rc; + } else if (rc) { + GSL_ERR("get proc persist cal size failed %d", rc); + return rc; + } + + if (rsp_struct.num_sg_ids == 0) { /**< no persist cal data for memtype */ + return AR_ENOTEXIST; + } + + rc = gsl_mdf_utils_query_graph_ss_mask(&sg_obj->sg_id, 1, &sg_ss_mask); + if (rc) { + GSL_ERR("query ss mask for sg_id 0x%x failed %d", sg_obj->sg_id, rc); + goto exit; + } + + if (mem_type == ACDB_HW_ACCEL_MEM_DEFAULT) { + /* reuse existing allocation if at all possible */ + if (sg_obj->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr == NULL || + sg_obj->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data_size != rsp_struct.cal_data_size) { + + if (sg_obj->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr != NULL) + gsl_shmem_free(&sg_obj->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data); + + rc = gsl_shmem_alloc_ext(rsp_struct.cal_data_size, sg_ss_mask, 0, 0, + master_proc, &sg_obj->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data); + if (rc) { + GSL_ERR("shmem alloc failed %d", rc); + goto exit; + } + } + sg_obj->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data_size = rsp_struct.cal_data_size; + rsp_struct.cal_data = sg_obj->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr; + } else { + /* do not re-use cma allocations */ + if (sg_obj->cma_persist_cfg_data.v_addr != NULL) { + gsl_shmem_free(&sg_obj->cma_persist_cfg_data); + sg_obj->cma_persist_cfg_data.v_addr = NULL; + } + + rc = gsl_shmem_alloc_ext(rsp_struct.cal_data_size, sg_ss_mask, + GSL_SHMEM_CMA, 0, master_proc, &sg_obj->cma_persist_cfg_data); + if (rc) { + GSL_ERR("shmem alloc failed %d", rc); + goto exit; + } + + sg_obj->cma_cal_data_size = rsp_struct.cal_data_size; + rsp_struct.cal_data = sg_obj->cma_persist_cfg_data.v_addr; + } + + rc = acdb_ioctl(ACDB_CMD_GET_PROC_SUBGRAPH_CAL_DATA_PERSIST, + &cmd_struct, sizeof(cmd_struct), &rsp_struct, sizeof(rsp_struct)); + if (rc) { + GSL_ERR("get persist cal failed %d", rc); + goto exit; + } + +exit: + return rc; +} + +int32_t gsl_subgraph_set_persist_cal(struct gsl_subgraph *sg, + uint8_t *persistent_cal, uint32_t persistent_cal_sz, + uint32_t master_proc, uint32_t persist_cal_idx) +{ + int32_t rc = AR_EOK; + uint32_t sg_ss_mask; + + if (!sg || !persistent_cal) + return AR_EBADPARAM; + + if (persist_cal_idx < 0 || persist_cal_idx > sg->num_proc_ids) + return AR_EBADPARAM; + + + rc = gsl_mdf_utils_query_graph_ss_mask(&sg->sg_id, 1, &sg_ss_mask); + if (rc) { + GSL_ERR("query ss mask for sg_id 0x%x failed %d", sg->sg_id, rc); + goto exit; + } + + /* try to use existing allocation if at all possible */ + if (sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr != NULL && + sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data_size < persistent_cal_sz) { + gsl_shmem_free(&sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data); + + rc = gsl_shmem_alloc_ext(persistent_cal_sz + + sizeof(AcdbSgIdPersistData), sg_ss_mask, 0, 0, + master_proc, &sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data); + if (rc) { + GSL_ERR("shmem alloc failed %d", rc); + goto exit; + } + } + + sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data_size = persistent_cal_sz + + sizeof(AcdbSgIdPersistData); + gsl_memcpy((uint8_t *)sg->persist_cal_data_per_proc[persist_cal_idx].persist_cal_data.v_addr + + sizeof(AcdbSgIdPersistData), persistent_cal_sz, persistent_cal, + persistent_cal_sz); + +exit: + return rc; +} + +bool_t is_matching_sg_property(struct gsl_subgraph *sg, + struct gsl_cmd_properties *props) +{ + uint32_t n; + + switch (props->property_id) { + case SUB_GRAPH_PROP_ID_SG_TYPE: + for (n = 0; n < props->num_property_values; ++n) { + if (props->property_values[n] == sg->sg_type_data.sg_type) + return TRUE; + } + break; + } + return FALSE; +} + diff --git a/gsl/src/gsl_subgraph_pool.c b/gsl/src/gsl_subgraph_pool.c new file mode 100644 index 0000000..b540103 --- /dev/null +++ b/gsl/src/gsl_subgraph_pool.c @@ -0,0 +1,184 @@ +/** + * \file gsl_subgraph_pool.c + * + * \brief + * Implements a store for all subgraphs active in Spf, note this is a + * singleton. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "gsl_subgraph_pool.h" +#include "ar_util_list.h" +#include "ar_osal_error.h" +#include "ar_osal_log.h" +#include "gsl_subgraph.h" +#include "gsl_common.h" +#include "ar_osal_mutex.h" +#include +#include + + +struct gsl_sg_pool { + ar_list_t sg_list; /**< list of all subgraphs in the system */ + uint32_t num_subgraphs; /**< number of entries in subgraph pool */ + ar_osal_mutex_t lock; /**< used to serialize operations on pool */ +} sg_pool; + +int32_t gsl_sg_pool_init(void) +{ + int32_t rc = AR_EOK; + + gsl_memset(&sg_pool, 0, sizeof(sg_pool)); + rc = ar_osal_mutex_create(&sg_pool.lock); + if (rc) { + GSL_ERR("ar_osal_mutex_create failed %d", rc); + goto exit; + } + + rc = ar_list_init(&sg_pool.sg_list, NULL, NULL); + if (rc) + GSL_ERR("ar_list_init failed %d", rc); +exit: + return rc; +} + +int32_t gsl_sg_pool_deinit(void) +{ + ar_osal_mutex_destroy(sg_pool.lock); + ar_list_clear(&sg_pool.sg_list); + return AR_EOK; +} + +/* todo find SG from graph SG list */ +struct gsl_subgraph *gsl_sg_pool_find(uint32_t sgid) +{ + ar_list_node_t *curr = NULL; + struct gsl_subgraph *curr_sg = NULL; + + ar_list_for_each_entry(curr, &sg_pool.sg_list) { + curr_sg = get_container_base(curr, struct gsl_subgraph, node); + if (curr_sg->sg_id == sgid) + goto exit; + } + curr_sg = NULL; +exit: + return curr_sg; +} + +struct gsl_subgraph *gsl_sg_pool_add(uint32_t sg_id, bool_t preload_only) +{ + struct gsl_subgraph *curr_sg = NULL; + + GSL_MUTEX_LOCK(sg_pool.lock); + + /* check if sg_id already exists in the pool */ + curr_sg = gsl_sg_pool_find(sg_id); + + if (!curr_sg) { + /* subgraph does not exist, so add it to pool */ + curr_sg = gsl_mem_zalloc(sizeof(struct gsl_subgraph)); + if (curr_sg == NULL) + goto exit; + if (gsl_subgraph_init(curr_sg, sg_id) != AR_EOK) { + /* GSL_ERR("gsl_subgraph_init failed %d", rc); */ + goto cleanup; + } + + if (ar_list_add_tail(&sg_pool.sg_list, &curr_sg->node) + != AR_EOK) { + /* GSL_ERR("ar_list_add_tail failed %d", rc); */ + goto cleanup; + } + ++sg_pool.num_subgraphs; + } + if (preload_only == FALSE) + ++curr_sg->open_ref_cnt; + goto exit; + +cleanup: + gsl_mem_free(curr_sg); + curr_sg = NULL; +exit: + GSL_MUTEX_UNLOCK(sg_pool.lock); + return curr_sg; +} + + +int32_t gsl_sg_pool_remove(struct gsl_subgraph *sg, bool_t unload_only) +{ + int32_t rc = AR_EOK; + + if (sg == NULL) + return AR_EBADPARAM; + + GSL_MUTEX_LOCK(sg_pool.lock); + if (sg->open_ref_cnt > 0 && (unload_only == FALSE)) + sg->open_ref_cnt--; + + if (sg->open_ref_cnt == 0) { + rc = ar_list_delete(&sg_pool.sg_list, &sg->node); + if (rc) { + GSL_ERR("ar list delete failed %d", rc); + goto exit; + } + --sg_pool.num_subgraphs; + /* + * Do not free if we fail to remove from list, to preserve the + * integrity of the linked list + */ + gsl_mem_free(sg); + } +exit: + GSL_MUTEX_UNLOCK(sg_pool.lock); + return rc; +} + +uint32_t gsl_sg_pool_prune_sg_list(struct gsl_subgraph **subgraphs, + uint32_t num_sgs, struct gsl_cmd_properties *props, + struct gsl_sgid_list *pruned_sgids, struct gsl_sgid_list *existing_sgids) +{ + uint32_t i = 0; + + if (!subgraphs || !pruned_sgids) + return AR_EBADPARAM; + + pruned_sgids->len = 0; + if (existing_sgids) + existing_sgids->len = 0; + + GSL_MUTEX_LOCK(sg_pool.lock); + for (; i < num_sgs; ++i) { + if (subgraphs[i]->open_ref_cnt == 1 && + (!props || is_matching_sg_property(subgraphs[i], props))) + pruned_sgids->sg_ids[pruned_sgids->len++] = subgraphs[i]->sg_id; + else if (existing_sgids) + existing_sgids->sg_ids[existing_sgids->len++] = subgraphs[i]->sg_id; + } + GSL_MUTEX_UNLOCK(sg_pool.lock); + + return AR_EOK; +} + +void gsl_sg_pool_update_child_refs(void) +{ + ar_list_node_t *parent = NULL; + ar_list_node_t *child = NULL; + struct gsl_subgraph *parent_sg = NULL; + struct gsl_child_sg *child_entry = NULL; + + /* scan through the children of every subgraph in the pool */ + ar_list_for_each_entry(parent, &sg_pool.sg_list) { + parent_sg = get_container_base(parent, struct gsl_subgraph, node); + ar_list_for_each_entry(child, &parent_sg->children) { + /* + * update the sg_obj for this child only if not already set, + * gsl_sg_pool_find does a linear search through the entire pool + * so we only want to call it when necessary + */ + child_entry = get_container_base(child, struct gsl_child_sg, node); + if (!child_entry->sg_obj) + child_entry->sg_obj = gsl_sg_pool_find(child_entry->sg_id); + } + } +} diff --git a/public_headers/config.yml b/public_headers/config.yml new file mode 100644 index 0000000..daf616d --- /dev/null +++ b/public_headers/config.yml @@ -0,0 +1,28 @@ +project: https://github.com/AudioReach/audioreach-graphservices + +branches: + master: + modes: + blocking: + headers: + - ar_osal/api/*.h + - ar_util/api/*.h + - gpr/api/*.h + - gsl/dls_client_api/*.h + - gsl/hw_rsc_api/*.h + - gsl/api/*.h + - gsl/rtc_api/*.h + - acdb/api/*.h + - acdb/ats/api/*.h + - spf/api/apm/*.h + - spf/api/asps/*.h + - spf/api/modules/*.h + - spf/api/vcpm/*.h + - spf/api/ar_utils/*.h + - spf/api/ar_utils/generic/*.h +abi_checks: + - path: build/usr/lib/libar-gsl.so + - path: build/usr/lib/libar-gpr.so + - path: build/usr/lib/libar-util.so + - path: build/usr/lib/libar-osal.so + - path: build/usr/lib/libar-acdb.so diff --git a/spf/Android.bp b/spf/Android.bp new file mode 100644 index 0000000..70c5688 --- /dev/null +++ b/spf/Android.bp @@ -0,0 +1,14 @@ +cc_library_headers { + name: "libspf-headers", + cflags: ["-D__H2XML__"], + + export_include_dirs: [ + "api", + "api/apm", + "api/ar_utils", + "api/modules", + "api/vcpm", + ], + + proprietary: true, +} diff --git a/spf/LICENSE b/spf/LICENSE new file mode 100644 index 0000000..0569a78 --- /dev/null +++ b/spf/LICENSE @@ -0,0 +1,180 @@ +This text file is provided to comply with the attribution requirements of +the licenses herein, but see NOTICE for license terms of this software. +The Apache 2.0 license can be found at http://www.apache.org/licenses/LICENSE-2.0.html + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/spf/Makefile.am b/spf/Makefile.am new file mode 100644 index 0000000..5b51abf --- /dev/null +++ b/spf/Makefile.am @@ -0,0 +1,163 @@ +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = spf.pc +EXTRA_DIST = $(pkgconfig_DATA) + +AM_CFLAGS = -Wall -Werror +AM_CFLAGS += -I ./api +AM_CFLAGS += -I ./api/apm +AM_CFLAGS += -I ./api/ar_utils +AM_CFLAGS += -I ./api/modules +AM_CFLAGS += -I ./api/vcpm + +spf_sources = ./api/apm/apm_api.h \ + ./api/apm/apm_api_version.h \ + ./api/apm/apm_container_api.h \ + ./api/apm/apm_graph_properties.h \ + ./api/apm/apm_memmap_api.h \ + ./api/apm/apm_module_api.h \ + ./api/apm/apm_sub_graph_api.h \ + ./api/ar_utils/spf_begin_pack.h \ + ./api/ar_utils/spf_begin_pragma.h \ + ./api/ar_utils/spf_end_pack.h \ + ./api/ar_utils/spf_end_pragma.h \ + ./api/ar_utils/ar_error_codes.h \ + ./api/ar_utils/ar_guids.h \ + ./api/ar_utils/ar_ids.h \ + ./api/ar_utils/ar_defs.h \ + ./api/asps/asps_ads_usecase_api.h \ + ./api/asps/asps_upd_usecase_api.h \ + ./api/asps/asps_asr_usecase_api.h \ + ./api/asps/asps_acd_usecase_api.h \ + ./api/asps/asps_acm_api.h \ + ./api/modules/aac_decoder_api.h \ + ./api/modules/aac_encoder_api.h \ + ./api/modules/acd_api.h \ + ./api/modules/alac_decoder_api.h \ + ./api/modules/amdb_api.h \ + ./api/modules/amrwb_decoder_api.h \ + ./api/modules/amrwb_encoder_api.h \ + ./api/modules/amrwbplus_decoder_api.h \ + ./api/modules/ape_decoder_api.h \ + ./api/modules/aptx-adaptive3-ble-encoder-api.h \ + ./api/modules/aptx_adaptive_encoder_api.h \ + ./api/modules/aptx_adaptive_swb_decoder_api.h \ + ./api/modules/aptx_adaptive_swb_encoder_api.h \ + ./api/modules/aptx_classic_decoder_api.h \ + ./api/modules/aptx_classic_encoder_api.h \ + ./api/modules/aptx_hd_decoder_api.h \ + ./api/modules/aptx_hd_encoder_api.h \ + ./api/modules/audio_dam_buffer_api.h \ + ./api/modules/audio_hw_clk_api.h \ + ./api/modules/audio_hw_dma_api.h \ + ./api/modules/audio_hw_lpm_api.h \ + ./api/modules/audio_if_api.h \ + ./api/modules/celt_enc_api.h \ + ./api/modules/codec_dma_api.h \ + ./api/modules/codec_metadata_api.h \ + ./api/modules/common_enc_dec_api.h \ + ./api/modules/contexts_api.h \ + ./api/modules/cop_packetizer_cmn_api.h \ + ./api/modules/cop_packetizer_v0_api.h \ + ./api/modules/cop_v2_depacketizer_api.h \ + ./api/modules/cop_v2_packetizer_api.h \ + ./api/modules/cps_data_router.h \ + ./api/modules/data_logging_api.h \ + ./api/modules/data_marker_api.h \ + ./api/modules/detection_cmn_api.h \ + ./api/modules/history_buffer_api.h \ + ./api/modules/display_port_api.h \ + ./api/modules/dls_api.h \ + ./api/modules/dls_log_pkt_hdr_api.h \ + ./api/modules/dtmf_detection_api.h \ + ./api/modules/flac_decoder_api.h \ + ./api/modules/fluence_ffv_common_calibration.h \ + ./api/modules/gapless_api.h \ + ./api/modules/gate_api.h \ + ./api/modules/hw_core_api.h \ + ./api/modules/hw_intf_cmn_api.h \ + ./api/modules/i2s_api.h \ + ./api/modules/imcl_fwk_intent_api.h \ + ./api/modules/imcl_spm_intent_api.h \ + ./api/modules/irm_api.h \ + ./api/modules/lc3_decoder_api.h \ + ./api/modules/lc3_encoder_api.h \ + ./api/modules/ldac_encoder_api.h \ + ./api/modules/lpass_core_api.h \ + ./api/modules/mailbox_api.h \ + ./api/modules/media_fmt_api_basic.h \ + ./api/modules/media_fmt_api_ext.h \ + ./api/modules/media_fmt_api.h \ + ./api/modules/metadata_api.h \ + ./api/modules/module_cmn_api.h \ + ./api/modules/mp2_decoder_api.h \ + ./api/modules/mp3_decoder_api.h \ + ./api/modules/mspp_module_calibration_api.h \ + ./api/modules/mux_demux_api.h \ + ./api/modules/opus_decoder_api.h \ + ./api/modules/pcm_decoder_api.h \ + ./api/modules/pcm_encoder_api.h \ + ./api/modules/pcm_tdm_api.h \ + ./api/modules/pop_suppressor_api.h \ + ./api/modules/priority_sync_api.h \ + ./api/modules/prm_api.h \ + ./api/modules/rate_adapted_timer_api.h \ + ./api/modules/rd_sh_mem_client_api.h \ + ./api/modules/rd_sh_mem_ep_api.h \ + ./api/modules/rtm_logging_api.h \ + ./api/modules/rt_proxy_api.h \ + ./api/modules/rx_haptics_api.h \ + ./api/modules/sa_hdt_api.h \ + ./api/modules/sbc_decoder_api.h \ + ./api/modules/sbc_encoder_api.h \ + ./api/modules/sh_mem_pull_push_mode_api.h \ + ./api/modules/slimbus_api.h \ + ./api/modules/smart_sync_api.h \ + ./api/modules/sp_dc_api.h \ + ./api/modules/splitter_api.h \ + ./api/modules/spr_api.h \ + ./api/modules/sp_rx.h \ + ./api/modules/sp_vi.h \ + ./api/modules/sync_api.h \ + ./api/modules/test_module_api.h \ + ./api/modules/trm_api.h \ + ./api/modules/tsm_module_api.h \ + ./api/modules/tty_cmn_api.h \ + ./api/modules/usb_api.h \ + ./api/modules/us_detect_api.h \ + ./api/modules/us_gen_api.h \ + ./api/modules/vocoder_cmn_api.h \ + ./api/modules/vorbis_decoder_api.h \ + ./api/modules/wr_sh_mem_client_api.h \ + ./api/modules/wr_sh_mem_ep_api.h \ + ./api/modules/wsa_haptics_vi_api.h \ + ./api/modules/congestion_buf_api.h \ + ./api/modules/jitter_buf_api.h \ + ./api/vcpm/vcpm_api.h \ + ./api/modules/asr_module_calibration_api.h \ + ./api/modules/tts_module_calibration_api.h \ + ./api/modules/nmt_module_calibration_api.h \ + ./api/modules/us_tone_renderer_api.h \ + ./api/modules/mma_api.h \ + ./api/modules/sound_dose_api.h \ + ./api/modules/sdz_api.h + +asps_sources = ./api/asps/asps_ads_usecase_api.h \ + ./api/asps/asps_upd_usecase_api.h \ + ./api/asps/asps_acd_usecase_api.h \ + ./api/asps/asps_acm_api.h \ + ./api/asps/asps_asr_usecase_api.h \ + ./api/asps/asps_sdz_usecase_api.h \ + ./api/asps/asps_us_rendering_usecase_api.h + +spf_includedir = $(includedir)/spf +spf_include_HEADERS = $(spf_sources) + +asps_includedir = $(includedir)/spf/asps +asps_include_HEADERS = $(asps_sources) + +#LIBRARY for LE apps +lib_LTLIBRARIES = libar-spfhdrs.la +libar_spfhdrs_la_CC = @CC@ +libar_spfhdrs_la_SOURCES = $(spf_sources) $(asps_sources) +libar_spfhdrs_la_CFLAGS = $(AM_CFLAGS) +libar_spfhdrs_la_LDFLAGS = -shared -version-number @LT_VERSION_NUMBER@ diff --git a/spf/api/apm/apm_api.h b/spf/api/apm/apm_api.h new file mode 100644 index 0000000..010a299 --- /dev/null +++ b/spf/api/apm/apm_api.h @@ -0,0 +1,1245 @@ +#ifndef _APM_API_H_ +#define _APM_API_H_ +/** + * \file apm_api.h + * \brief + * This file contains Audio Processing Manager Commands Data Structures + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/*------------------------------------------------------------------------------ + * Module ID Definitions + *----------------------------------------------------------------------------*/ + + +#include "spf_begin_pack.h" + +/** + In-band : + This structure is followed by an in-band payload of type, + apm_module_param_data_t + Out-of-band : + Out of band payload can be extracted from the mem_map_handle, + payload_address_lsw and payload_address_msw using the + posal api posal_memorymap_get_virtual_addr_from_shmm_handle. + Out of band payload of apm_cmd_header_t can be of 2 types. + 1. apm_module_param_data_t + 2. apm_module_param_shared_data_t - This payload should only be used + for the following apm commands + a. APM_CMD_REGISTER_SHARED_CFG + b. APM_CMD_DEREGISTER_SHARED_CFG + */ +struct apm_cmd_header_t +{ + uint32_t payload_address_lsw; + /**< Lower 32 bits of the payload address. */ + + uint32_t payload_address_msw; + /**< Upper 32 bits of the payload address. + + The 64-bit number formed by payload_address_lsw and + payload_address_msw must be aligned to a 32-byte boundary and be in + contiguous memory. + + @values + - For a 32-bit shared memory address, this field must be set to 0. + - For a 36-bit shared memory address, bits 31 to 4 of this field must + be set to 0. @tablebulletend */ + + uint32_t mem_map_handle; + /**< Unique identifier for a shared memory address. + + @values + - NULL -- The message is in the payload (in-band). + - Non-NULL -- The parameter data payload begins at the address + specified by a pointer to the physical address of the payload in + shared memory (out-of-band). + + @contcell + The aDSP returns this memory map handle through + #apm_CMD_SHARED_MEM_MAP_REGIONS. + + An optional field is available if parameter data is in-band: + %afe_port_param_data_v2_t param_data[...]. + See Parameter data variable payload. */ + + uint32_t payload_size; + /**< Actual size of the variable payload accompanying the message or in + shared memory. This field is used for parsing both in-band and + out-of-band data. + + @values > 0 bytes, in multiples of 4 bytes */ +} +#include "spf_end_pack.h" +; + +typedef struct apm_cmd_header_t apm_cmd_header_t; + +/** + Payload of the module parameter data structure. + Immediately following this structure are param_size bytes of + calibration data. The structure and size depend on the + module_instace_id/param_id combination. +*/ + + +#include "spf_begin_pack.h" + +struct apm_module_param_data_t +{ + uint32_t module_instance_id; + /**< Valid instance ID of module + @values */ + + uint32_t param_id; + /**< Valid ID of the parameter. + + @values See Chapter */ + + uint32_t param_size; + /**< Size of the parameter data based upon the + module_instance_id/param_id combination. + @values > 0 bytes, in multiples of + 4 bytes at least */ + + uint32_t error_code; + /**< Error code populated by the entity hosting the module. + Applicable only for out-of-band command mode */ +} +#include "spf_end_pack.h" +; + +typedef struct apm_module_param_data_t apm_module_param_data_t; + + +/** + Payload of the shared persistent module parameter data structure. + Immediately following this structure are param_size bytes of + calibration data. The structure and size depend on the param_id. +*/ + + +#include "spf_begin_pack.h" + +struct apm_module_param_shared_data_t +{ + uint32_t param_id; + /**< Valid ID of the parameter. + + @values See Chapter */ + + uint32_t param_size; + /**< Size of the parameter data based upon the + module_instance_id/param_id combination. + @values > 0 bytes, in multiples of + 4 bytes at least */ +} +#include "spf_end_pack.h" +; + +typedef struct apm_module_param_shared_data_t apm_module_param_shared_data_t; + + +/** + Payload of the property data structure. This + structure applies to container, sub-graph and module + properties. Immediately following this structure are + prop_size bytes of property data. + Property payload size must be at least 4 bytes. +*/ + +#include "spf_begin_pack.h" + +struct apm_prop_data_t +{ + uint32_t prop_id; + /**< Property ID + @values */ + + uint32_t prop_size; + /**< Size of the property ID structure */ + +} +#include "spf_end_pack.h" +; + +typedef struct apm_prop_data_t apm_prop_data_t; + + +/** + Payload of the register events data structure. This + structure is preceded by apm_cmd_header_t structure +*/ + +#include "spf_begin_pack.h" + +struct apm_module_register_events_t +{ + uint32_t module_instance_id; + /**< Valid instance ID of module */ + + uint32_t event_id; + /**< Valid event ID of the module */ + + uint32_t is_register; + /**< 1 - to register the event + * 0 - to de-register the event + */ + + uint32_t error_code; + /**< Error code populated by the entity hosting the module. + Applicable only for out-of-band command mode */ + + uint32_t event_config_payload_size; + /**< Size of the event config data based upon the + module_instance_id/event_id combination. + @values > 0 bytes, in multiples of + 4 bytes at least */ + + uint32_t reserved; + /**< reserved must be set to zero. + For 8 byte alignment */ +} +#include "spf_end_pack.h" +; +typedef struct apm_module_register_events_t apm_module_register_events_t; + +/** + Payload of the module event data structure. This + structure is preceeded by apm_cmd_header_t structure + and followed by event payload +*/ + +#include "spf_begin_pack.h" + +struct apm_module_event_t +{ + uint32_t event_id; + /**< Valid event ID of the module */ + + uint32_t event_payload_size; + /**< Size of the event data based upon the + module_instance_id/eveny_id combination. + @values > 0 bytes, in multiples of + 4 bytes at least */ +} +#include "spf_end_pack.h" +; + +typedef struct apm_module_event_t apm_module_event_t; + +/** + Instance ID of the Audio Processing Manager module + + This module instance supports the following parameter IDs: + - #APM_PARAM_ID_SUB_GRAPH_CFG + - #APM_PARAM_ID_CONTAINER_CFG + - #APM_PARAM_ID_MODULES_LIST + - #APM_PARAM_ID_MODULE_PROP + - #APM_PARAM_ID_MODULE_CONN + - #APM_PARAM_ID_MODULE_CTRL_LINK_CFG + + @calibration_hdr_field + module_id -- APM_MODULE_INSTANCE_ID +*/ + +/** + h2xml_title1 {Audio Processing Manager (APM) Module API} + h2xml_title_agile_rev {Audio Processing Manager (APM) Module API} + h2xml_title_date {June 27, 2019} + */ +#define APM_MODULE_INSTANCE_ID 0x00000001 + +/** h2xmlm_module {"APM_MODULE_INSTANCE_ID",APM_MODULE_INSTANCE_ID} + h2xmlm_displayName {"Audio Processing Manager"} + h2xmlm_description {Audio Processing Manager (APM).\n + + This module supports the following parameter IDs: \n + - #APM_PARAM_ID_SUB_GRAPH_CONFIG \n + - #APM_PARAM_ID_CONTAINER_CONFIG \n + - #APM_PARAM_ID_MODULES_LIST \n + - #APM_PARAM_ID_MODULE_PROP \n + - #APM_PARAM_ID_MODULE_CONN \n + - #APM_PARAM_ID_MODULE_CTRL_LINK_CFG \n + - #APM_PARAM_ID_IMCL_PEER_DOMAIN_INFO \n + - #APM_PARAM_ID_PATH_DELAY \n + - #APM_PARAM_ID_SUB_GRAPH_LIST \n + +} + h2xmlm_dataMaxInputPorts {0} + h2xmlm_dataMaxOutputPorts {0} + h2xmlm_stackSize {0} + h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module -->*/ + +/** @} <-- End of the Module --> */ + + + + + + + + + + +/** @ingroup apm_cmd_graph_open + Opens a list of one or more sub-graphs. Graph open command is + issued against APM module instance iD. Graph open command + consists of following parameter ID's. + + - #APM_PARAM_ID_SUB_GRAPH_CFG + - #APM_PARAM_ID_CONTAINER_CFG + - #APM_PARAM_ID_MODULES_LIST + - #APM_PARAM_ID_MODULE_PROP + - #APM_PARAM_ID_MODULE_CONN + - #APM_PARAM_ID_MODULE_CTRL_LINK_CFG + + In the overall graph open command payload, parameter ID + #APM_PARAM_ID_SUB_GRAPH_CFG and #APM_PARAM_ID_CONTAINER_CFG + should be populated first before any other parameter ID's. The + sub-graph and container ID's need to be configured first + before configuring the rest of the parameter ID's. + + Parameter ID #APM_PARAM_ID_MODULES_LIST must be configured + after configuring the #APM_PARAM_ID_SUB_GRAPH_CFG and + #APM_PARAM_ID_CONTAINER_CFG. + + Parameter ID #APM_PARAM_ID_MODULE_PROP, + #APM_PARAM_ID_MODULE_CONN and #APM_PARAM_ID_MODULE_CTRL_LINK_CFG, + must be configured after configuring the + #APM_PARAM_ID_MODULES_LIST. + + Overall payload for this command is of variable length. + Payload length depends upon the number of sub-graphs, + container, modules being configured as part of this command. + + @gpr_hdr_fields + Opcode -- APM_CMD_GRAPH_OPEN + + Payload struct + + apm_cmd_header_t + apm_module_param_data_t + apm_param_id_sub_graph_cfg_t (Contains number of sub-graphs) + (List of structures below is repeated for each sub-graph ID + being configured) + apm_sub_graph_cfg_t + apm_prop_data_t + apm_sg_prop_id_perf_mode_t + apm_prop_data_t + apm_sg_prop_id_direction_t + apm_prop_data_t + apm_sg_prop_id_scenario_id_t + <8 byte alignment if any> + + apm_module_param_data_t + apm_param_id_container_cfg_t (Contains number of containers) + (List of structures below is repeated for each container ID + being configured) + apm_container_cfg_t + apm_prop_data_t + apm_cont_prop_id_type_t + apm_container_type_t + apm_prop_data_t + apm_cont_prop_id_graph_pos_t + apm_prop_data_t + apm_cont_prop_id_stack_size_t + apm_prop_data_t + apm_cont_prop_id_proc_domain_t + apm_prop_data_t + apm_cont_prop_id_parent_container_t + <8 byte alignment if any> + + apm_module_param_data_t + apm_param_id_modules_list_t (Contains number of module lists) + (List of structures below is repeated for each module list per + sub-graph / container ID pair being configured + being configured) + apm_modules_list_t (Number of modules in the list) + (Structure below is repeated for each module instance + being configured) + apm_module_cfg_t + <8 byte alignment if any> + + apm_module_param_data_t + apm_param_id_module_prop_t (Contains number of module property object) + (List of structures below is repeated for each module + property configuration object) + apm_module_prop_cfg_t (Contains number of properties per module instance) + (Structure below is repeated for each module instance + property being configured) + apm_prop_data_t + apm_module_prop_id_port_info_t + + <8 byte alignment if any> + apm_module_param_data_t + apm_param_id_module_conn_t (Contains number of data connections) + (Structure below is repeated for each data link being configured) + apm_module_conn_cfg_t + + <8 byte alignment if any> + apm_module_param_data_t + apm_param_id_module_ctrl_link_cfg_t (Contains number of control links) + (Structure below is repeated for each control link being configured) + apm_module_ctrl_link_cfg_t (Contains number of control link intents) + (List of structure below is repeated for each control link properties) + apm_prop_data_t + apm_module_ctrl_link_prop_id_intent_list_t + + (any non-APM module calibration payloads follow below) + <8 byte alignment if any> + apm_module_param_data_t + <>Param ID payload<> + <8 byte alignment if any> + apm_module_param_data_t + <>Param ID payload <> + <8 byte alignment if any, but not mandatory at the end> + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + None. + */ +#define APM_CMD_GRAPH_OPEN 0x01001000 + +/** @ingroup apm_cmd_graph_prepare + Prepares one or more sub-graph ID's that have been configured + Graph prepare command is issued against APM module instance + iD. Graph prepare command consists of following parameter + ID's. + + - #APM_PARAM_ID_SUB_GRAPH_LIST + + This command may be issued after the following commands: + - #APM_CMD_GRAPH_OPEN + + If this command is issued to more than 1 sub-graph ID's, the + command is executed in a sequential manner for each sub-graph. + + @gpr_hdr_fields + Opcode -- APM_CMD_GRAPH_PREPARE + + @Payload struct + + apm_cmd_header_t + apm_module_param_data_t + apm_param_id_sub_graph_list_t (Contains number of sub-graph + ID) + apm_sub_graph_id_t (array of sub-graph ID's) + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Sub-graph ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_GRAPH_PREPARE 0x01001001 + +/** @ingroup apm_cmd_graph_start + Starts one or more sub-graph ID's that have been configured + using the #APM_CMD_GRAPH_OPEN. + Graph start command is issued against APM module instance + iD. Graph start command consists of following parameter + ID's. + + - #APM_PARAM_ID_SUB_GRAPH_LIST + + This command may be issued after the following commands: + - #APM_CMD_GRAPH_OPEN + - #APM_CMD_GRAPH_PREPARE + - #APM_CMD_GRAPH_STOP + - #APM_CMD_GRAPH_SUSPEND + + If this command is issued to more than 1 sub-graph ID's, the + command is executed in a sequential manner for each sub-graph. + + @gpr_hdr_fields + Opcode -- APM_CMD_GRAPH_START + + @Payload struct + + apm_cmd_header_t + apm_module_param_data_t + apm_param_id_sub_graph_list_t (Contains number of sub-graph + ID) + apm_sub_graph_id_t (array of sub-graph ID's) + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Sub-graph ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_GRAPH_START 0x01001002 + +/** @ingroup apm_cmd_graph_stop + Stops one or more sub-graph ID's that have been configured + using the #APM_CMD_GRAPH_OPEN. + Graph stop command is issued against APM module instance iD. + Graph start command consists of following parameter ID's. + + - #APM_PARAM_ID_SUB_GRAPH_LIST + + This command may be issued after the following commands: + - #APM_CMD_GRAPH_START + + If this command is issued to more than 1 sub-graph ID's, the + command is executed in a sequential manner for each sub-graph. + + @gpr_hdr_fields + Opcode -- APM_CMD_GRAPH_STOP + + @Payload struct + + apm_cmd_header_t + apm_module_param_data_t + apm_param_id_sub_graph_list_t (Contains number of sub-graph + ID) + apm_sub_graph_id_t (array of sub-graph ID's) + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Sub-graph ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_GRAPH_STOP 0x01001003 + +/** @ingroup apm_cmd_graph_close + Closes one or more sub-graph ID's, data and control links that + have been configured using the #APM_CMD_GRAPH_OPEN command. + Graph close command is issued against APM module instance iD. + Graph close command consists of following parameter ID's. + Any combination of below parameter ID's can be sent as part of + the close command. + + - #APM_PARAM_ID_SUB_GRAPH_LIST + - #APM_PARAM_ID_MODULE_CONN + - #APM_PARAM_ID_MODULE_CTRL_LINK_CFG + + This command may be issued after the following commands: + - #APM_CMD_GRAPH_OPEN + - #APM_CMD_GRAPH_PREPARE + - #APM_CMD_GRAPH_START + - #APM_CMD_GRAPH_STOP + - #APM_CMD_GRAPH_FLUSH + - #APM_CMD_GRAPH_SUSPEND + + If this command is issued to more than 1 sub-graph ID's, the + command is executed in a sequential manner for each sub-graph. + + @gpr_hdr_fields + Opcode -- APM_CMD_GRAPH_CLOSE + + @Payload struct + + apm_cmd_header_t + apm_module_param_data_t + apm_param_id_sub_graph_list_t (Contains number of sub-graph + ID) + apm_sub_graph_id_t (array of sub-graph ID's) + <8 byte alignment if any> + + apm_module_param_data_t + apm_param_id_module_conn_t (Contains number of data connections) + (Structure below is repeated for each data link being configured) + apm_module_conn_cfg_t + <8 byte alignment if any> + + apm_module_param_data_t + apm_param_id_module_ctrl_link_cfg_t (Contains number of control links) + (Structure below is repeated for each control link being configured) + apm_module_ctrl_link_cfg_t (Contains number of control link intents) + (List of structure below is repeated for each control link properties) + apm_prop_data_t + apm_module_ctrl_link_prop_id_intent_list_t + <8 byte alignment if any, but not mandatory at the end> + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Sub-graph ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_GRAPH_CLOSE 0x01001004 + +/** @ingroup apm_cmd_close_all + * This command is used by the client for cleaning up all the + * allocated resources within the framework including + * - Closing all the opened sub-graphs, containers and modules. + * Sub-graphs will be closed regardless of state. + * - For multi DSP framework, this includes + * sub-graphs/containers/modules on all the satellites + * processors. + * - All the mapped memories for master and satellite processor + * at the time of receiving this command are unmapped. + * - Modules registered and loaded via AMDB API's are unloaded + * and de-registered. + * One or more resources listed above at the time of receiving this + * command will be de-allocated. Client need not send the list of + * all those resources explicitly. + + @gpr_hdr_fields + Opcode -- APM_CMD_CLOSE_ALL + + @Payload struct + None + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + */ +#define APM_CMD_CLOSE_ALL 0x01001013 + +/** @ingroup apm_cmd_graph_flush + Flushes one or more sub-graph ID's that have been configured + Graph flush command is issued against APM module instance + iD. Graph flush command consists of following parameter + ID's. + + - #APM_PARAM_ID_SUB_GRAPH_LIST + + This command can be issued for the sub-graphs which have been + started at least once and are in pause state. Pause state is + configured using #APM_CMD_SET_CFG on a specific module within + a sub-graph. + + If this command is issued to more than 1 sub-graph ID's, the + command is executed in a sequential manner for each sub-graph. + + @gpr_hdr_fields + Opcode -- APM_CMD_GRAPH_FLUSH + + @Payload struct + + apm_cmd_header_t + apm_module_param_data_t + apm_param_id_sub_graph_list_t (Contains number of sub-graph + ID) + apm_sub_graph_id_t (array of sub-graph ID's) + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Sub-graph ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_GRAPH_FLUSH 0x01001005 + +/** @ingroup apm_cmd_set_cfg + Configures one or more parameter ID's for one more module + instances present in the graph. Module instances may include + APM module instance or any other data and control processing + module present within the graph. + + This command can be issued for all the module instance ID that + have been configured at least once using the + #APM_CMD_GRAPH_OPEN + + @gpr_hdr_fields + Opcode -- APM_CMD_SET_CFG + + @Payload struct + + apm_cmd_header_t + (List of structures below is repeated for each module + instance parameter ID ) + apm_module_param_data_t + <>Param ID payload<> + <8 byte alignment if any> + apm_module_param_data_t + <>Param ID payload <> + <8 byte alignment if any> + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Module ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_SET_CFG 0x01001006 + +/** @ingroup apm_cmd_get_cfg + This parameter is used for querying one or more + configuration/calibration parameter ID corresponding to any + module instance ID. Module instances may any control + processing module present within the graph. This command is + currently not supported for APM module instance parameter + ID's. + + This command can be issued for all the module instance ID that + have been configured at least once using the #APM_CMD_GRAPH_OPEN + + @gpr_hdr_fields + Opcode -- APM_CMD_GET_CFG + + @Payload struct + + apm_cmd_header_t + (List of strucures below is repeated for each module + instance parameter ID ) + apm_module_param_data_t + <>Param ID empty payload<> + <8 byte alignment if any> + apm_module_param_data_t + <>Param ID empty payload <> + <8 byte alignment if any, but not mandatory at the end> + + @return + Response code -- #APM_CMD_RSP_GET_CFG + + @dependencies + Module ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_GET_CFG 0x01001007 + +/** @ingroup apm_cmd_rsp_get_cfg + The response code returned as an acknowledgment for the + #APM_CMD_GET_CFG command. + + The response payload starts with status field which indicates + the overall status of the #APM_CMD_GET_CFG command. + + Immediately following the status field is variable length + payload consisting the parameter data for the module ID's + which are queried as part of the #APM_CMD_GET_CFG command. + Each PID data uses the header structure + #apm_module_param_data_t followed by the actual param ID data. + + Client is responsible for specifying sufficiently large + payload size to accommodate configuration/calibration data + corresponding to each parameter ID data being queried. + + Status field is populated with success code (#AR_EOK) if all + the parameter ID's being queried returns success code. + + Status field is populated with failure code (#AR_EFAILED) if + at least one param ID results failure error code. + + @gpr_hdr_fields + Opcode -- APM_CMD_RSP_GET_CFG + + @Payload struct + + apm_cmd_rsp_get_cfg_t + (List of strucures below is repeated for each module + instance parameter ID ) + apm_module_param_data_t + <>Param ID payload<> + <8 byte alignment if any> + apm_module_param_data_t + <>Param ID payload <> + <8 byte alignment if any, but not mandatory at the end> + + @return + None + + @dependencies + None + + */ +#define APM_CMD_RSP_GET_CFG 0x02001000 + +#include "spf_begin_pack.h" + +struct apm_cmd_rsp_get_cfg_t +{ + uint32_t status; +} +#include "spf_end_pack.h" +; + +typedef struct apm_cmd_rsp_get_cfg_t apm_cmd_rsp_get_cfg_t; + + +/** @ingroup apm_cmd_register_cfg + This command is used for registering persistent + calibration/configuration data corresponding to one or more + parameter ID's for one ore more data/control processing + modules. This command is applicable for the module instances + supporting persistent calibration/configuration data. + + This command can be issued for all the module instance ID that + have been configured at least once using the #APM_CMD_GRAPH_OPEN + + @gpr_hdr_fields + Opcode -- APM_CMD_REGISTER_CFG + + @Payload struct + + apm_cmd_header_t + (List of strucures below is repeated for each module + instance parameter ID ) + apm_module_param_data_t + <>Param ID payload<> + <8 byte alignment if any> + apm_module_param_data_t + <>Param ID payload <> + <8 byte alignment if any, but not mandatory at the end> + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Module ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_REGISTER_CFG 0x01001008 + +/** @ingroup apm_cmd_deregister_cfg + This command is used for de-registering persistent + calibration/configuration data corresponding to one or more + parameter ID's for one or more data/control processing + modules. This command is applicable for the module instances + supporting persistent calibration/configuration data. + + This command can be issued for all the module instance ID that + have been configured at least once using the #APM_CMD_GRAPH_OPEN + + This command may be issued after the following commands: + - #APM_CMD_REGISTER_CFG + + @gpr_hdr_fields + Opcode -- APM_CMD_DEREGISTER_CFG + + @Payload struct + + apm_cmd_header_t + (List of strucures below is repeated for each module + instance parameter ID ) + apm_module_param_data_t + <>Param ID payload<> + <8 byte alignment if any> + apm_module_param_data_t + <>Param ID payload <> + <8 byte alignment if any, but not mandatory at the end> + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Module ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + The de-register command must be sent for the parameter ID's + after issuing successful register command. + + */ +#define APM_CMD_DEREGISTER_CFG 0x01001009 + +/** @ingroup apm_cmd_register_shared_cfg + This command is used for registering shared persistent + calibration/configuration data corresponding to one + parameter ID's for any data/control processing modules. This + command is applicable for the module instances supporting + shared persistent calibration/configuration data. + + This command can be issued for all the module instance ID that + have been configured at least once using the #APM_CMD_GRAPH_OPEN + payload struct -- apm_cmd_header_t, which in turn has + apm_module_param_shared_data_t as out of band payload + + @gpr_hdr_fields + Opcode -- APM_CMD_REGISTER_SHARED_CFG + + @Payload struct + + apm_cmd_header_t + (List of strucures below is repeated for each module + instance parameter ID ) + apm_module_param_shared_data_t + <>Param ID payload<> + <8 byte alignment if any> + apm_module_param_shared_data_t + <>Param ID payload<> + <8 byte alignment if any, but not mandatory at the end> + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Module ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_REGISTER_SHARED_CFG 0x0100100A + +/** @ingroup apm_cmd_deregister_shared_cfg + This command is used for registering shared persistent + calibration/configuration data corresponding to one + parameter ID's for any data/control processing modules. This + command is applicable for the module instances supporting + shared persistent calibration/configuration data. + + This command can be issued for all the module instance ID that + have been configured at least once using the #APM_CMD_GRAPH_OPEN + + payload struct -- apm_cmd_header_t, which in turn has + apm_module_param_shared_data_t as out of band payload + + This command may be issued after the following commands: + - #APM_CMD_REGISTER_SHARED_CFG + + + @gpr_hdr_fields + Opcode -- APM_CMD_DEREGISTER_SHARED_CFG + + @Payload struct + + apm_cmd_header_t + (List of strucures below is repeated for each module + instance parameter ID ) + apm_module_param_shared_data_t + <>Param ID payload<> + <8 byte alignment if any> + apm_module_param_shared_data_t + <>Param ID payload<> + <8 byte alignment if any, but not mandatory at the end> + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Module ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + The de-register command must be sent for the parameter ID's + only after issuing successful register command. + + */ +#define APM_CMD_DEREGISTER_SHARED_CFG 0x0100100B + +/** @ingroup APM_CMD_REGISTER_MODULE_EVENTS + Registers/de-registers one or more event ID's for one or more + module instances present in the graph. This command can be only sent + to modules present in an opened graph. This command + cannot be sent to APM_MODULE_INSTANCE_ID. + + This command can be issued for all the module instance ID that + have been configured at least once using the + #APM_CMD_GRAPH_OPEN + + @Payload struct + apm_cmd_header_t + apm_module_register_events_t + + <8 byte alignment if any> + apm_module_register_events_t + + <8 byte alignment if any, but not mandatory at the end> + + When there are multiple events different + apm_module_register_events_t must be 8 byte aligned. + + @gpr_hdr_fields + Opcode -- APM_CMD_REGISTER_MODULE_EVENTS + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Module ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command or else and + error code is returned by APM. + + */ +#define APM_CMD_REGISTER_MODULE_EVENTS 0x0100100E + + +/** @ingroup apm_cmd_get_spf_status_t + This parameter is used for querying SPF status. If the + command can reach the APM, means that SPF is ready. + + @gpr_hdr_fields + Opcode -- APM_CMD_GET_SPF_STATE + + @return + Response code -- #APM_CMD_RSP_GET_SPF_STATE + + @dependencies + None + + */ +#define APM_CMD_GET_SPF_STATE 0x01001021 + + +/** Definition for the spf Not-Ready State */ +#define APM_SPF_STATE_NOT_READY 0 + +/** Definition for the spf Ready State */ +#define APM_SPF_STATE_READY 1 + + +/** @ingroup apm_cmd_rsp_get_spf_status_t + The response code returned as an acknowledgment for the + #APM_CMD_GET_SPF_STATE command. + + The response payload starts with status field which indicates + the overall status of the #APM_CMD_GET_SPF_STATE command. + + @gpr_hdr_fields + Opcode -- APM_CMD_RSP_GET_SPF_STATE + + @return + None + + @dependencies + None + + */ +#define APM_CMD_RSP_GET_SPF_STATE 0x02001007 + +#include "spf_begin_pack.h" + +struct apm_cmd_rsp_get_spf_status_t +{ + uint32_t status; + /**< spf status. + + @values + - #APM_SPF_STATE_NOT_READY + - #APM_SPF_STATE_READY + @tablebulletend */ +} + +#include "spf_end_pack.h" +; + +typedef struct apm_cmd_rsp_get_spf_status_t apm_cmd_rsp_get_spf_status_t; + + +/** @ingroup APM_EVENT_MODULE_TO_CLIENT + Event raised by module to client, if the event is registered + by the client + + This event can be raised by all module instances that + have been configured at least once using the + #APM_CMD_GRAPH_OPEN + + Payload struct -- apm_module_event_t + + @gpr_hdr_fields + Opcode -- APM_EVENT_MODULE_TO_CLIENT + + @return + Error code -- #GPR_BASIC_RSP_RESULT + */ +#define APM_EVENT_MODULE_TO_CLIENT 0x03001000 + +/** + * Parameter ID for getting path delay from APM + * + * The graphs corresponding to the modules mentioned in the + * payload of this command must be opened using #APM_CMD_GRAPH_OPEN + * + * This param is used with APM_CMD_GET_CFG. + * Usually APM_CMD_GET_CFG doesn't carry any parameter specific payload, however, + * this command contains payload to specify the path. + * + * For the delay to be accurate calibration should already be done for the path. + * Media format must have been propagated. Typically, all subgraphs must be in PREPARE state. + * + * Maximum possible delay from source to destination is returned. + * In some cases, delay may not be exactly same as returned. For example, in FTRT paths, or + * processing time is smaller than expected. Also, delay can be obtained only for PCM or packetized data paths. + * If raw compressed data is involved, then delay cannot be known correctly for the portion that's compressed. + * Query however, won't fail as delay of the rest of the path (if any) can be determined. + * + * Under split-merge scenarios, if there are multiple paths from source to destination, + * first path will be chosen arbitrarily. + * + * If path is not complete, error is returned. + * Delay is >= 0. + * + * Client can leave the port-ids zeros to be autofilled by spf. + * When port-ids are zero src and dst module's delay may or may not be included as explained below + * + * - If src has only outputs and max input ports = 0, then it's delay is included. + * Since src has no input ports, this is the only way to account for its delay. + * - If dst has only input ports and max output ports = 0, then it's delay is included. + * Since dst has no output ports, this is the only way to account for its delay. + * - For all other cases, delay is from the output port of src to output port of dst. + * This way of defining helps in concatenation. E.g., A -> B -> C can be obtained as A to B + B to C + * and delay of B is not considered twice. + * When dst has multiple outputs, an output will be selected arbitrarily. + * + * Payload struct -- apm_module_event_t + * + */ +#define APM_PARAM_ID_PATH_DELAY 0x08001119 + +#include "spf_begin_pack.h" +/** + * This struct defines the start and end of path for which delay is queried. + * + */ +struct apm_path_defn_for_delay_t +{ + uint32_t src_module_instance_id; + /**< Source module instance ID + * input parameter. */ + uint32_t src_port_id; + /**< Source port-ID. Set to zero if port-id is not known. + * Knowing port-id helps reduce the complexity of graph search. + * Also, if specific path delays are needed in split-merge scenarios, port-id helps + * (E.g. module A's port 1 & 2 ends up in port 1 & 2 of end point B. Since there are 2 paths from A to B + * having port-id helps). + * + * + * If port-id is zero at the time of query, it will be populated with proper port-id when APM responds. + * This is an input & output parameter. */ + uint32_t dst_module_instance_id; + /**< Destination module instance ID. + * This is an input parameter. */ + uint32_t dst_port_id; + /**< Destination port-ID. Set to zero if port-id is not known. + * If port-id is zero at the time of query, it will be populated with proper port-id when APM responds. + * This is an input & output parameter. */ + uint32_t delay_us; + /**< Microsecond delay + * This is an output parameter.*/ +} +#include "spf_end_pack.h" +; + + +typedef struct apm_path_defn_for_delay_t apm_path_defn_for_delay_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** + * defines the main payload for the APM_PARAM_ID_PATH_DELAY query + */ +struct apm_param_id_path_delay_t +{ + uint32_t num_paths; + /** number of paths to be queried */ + + apm_path_defn_for_delay_t paths[0]; + /** definition of each path */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct apm_param_id_path_delay_t apm_param_id_path_delay_t; + +/* @ingroup apm_cmd_graph_suspend + Suspends one or more sub-graph ID's that have been configured + Graph suspend command is issued against APM module instance + iD. Graph suspend command consists of following parameter + ID's. + + - #APM_PARAM_ID_SUB_GRAPH_LIST + + This command can be issued for the sub-graphs which have been + started at least once. + + If this command is issued to more than 1 sub-graph ID's, the + command is executed in a sequential manner for each sub-graph. + + @gpr_hdr_fields + Opcode -- APM_CMD_GRAPH_SUSPEND + + @Payload struct + + apm_cmd_header_t + apm_module_param_data_t + apm_param_id_sub_graph_list_t (Contains number of sub-graph + ID) + apm_sub_graph_id_t (array of sub-graph ID's) + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + Sub-graph ID's listed as part of this command must be + configured using the #APM_CMD_GRAPH_OPEN command and + started using the #APM_CMD_GRAPH_START. + For the sub-graphs in STOPPED or PREPARED state suspend + command is not applied. + + */ +#define APM_CMD_GRAPH_SUSPEND 0x01001043 + +/** @ingroup apm_param_id_satellite_pd_info_t + This parameter is used for setting + satellite proc domain info to the master APM. + + This param is used with APM_CMD_SET_CFG. + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + @dependencies + None + +*/ +#define APM_PARAM_ID_SATELLITE_PD_INFO 0x08001251 + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct apm_param_id_satellite_pd_info_t +{ + uint32_t num_proc_domain_ids; + /**< Number of satellite proc domain ids */ + + + uint32_t proc_domain_id_list[0]; + /**< List of atellite proc domain IDs. + @values { "DONT_CARE"=0xFFFFFFFF, + "MDSP"=#APM_PROC_DOMAIN_ID_MDSP, + "ADSP"=#APM_PROC_DOMAIN_ID_ADSP, + "SDSP"=#APM_PROC_DOMAIN_ID_SDSP, + "CDSP"=#APM_PROC_DOMAIN_ID_CDSP} + Number of elements = num_proc_domain_ids */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct apm_param_id_satellite_pd_info_t apm_param_id_satellite_pd_info_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + + +#endif /* _APM_API_H_ */ diff --git a/spf/api/apm/apm_api_version.h b/spf/api/apm/apm_api_version.h new file mode 100644 index 0000000..266e3f1 --- /dev/null +++ b/spf/api/apm/apm_api_version.h @@ -0,0 +1,25 @@ +#ifndef _APM_API_VERSION_H_ +#define _APM_API_VERSION_H_ +/** + * \file apm_api_version.h + * \brief + * This file contains the version information for Audio Procesing Manager API + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define APM_API_VERSION 1 + +/** API branch version of the Audio Processing Manager + + @versiontable{0.3,4.7, + 0 & Mainline version @tblendline} + */ +#define APM_API_BRANCH_VERSION 0 + +/** @} */ /* end_addtogroup aapm_api_version */ + + +#endif /* _APM_API_VERSION_H_ */ diff --git a/spf/api/apm/apm_container_api.h b/spf/api/apm/apm_container_api.h new file mode 100644 index 0000000..788cd3a --- /dev/null +++ b/spf/api/apm/apm_container_api.h @@ -0,0 +1,251 @@ +#ifndef _APM_CONTAINER_API_H_ +#define _APM_CONTAINER_API_H_ +/** + * \file apm_container_api.h + * \brief + * This file contains APM container commands and events structures definitions. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "apm_graph_properties.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/*====================================================================================================================*/ +/*====================================================================================================================*/ + +#define APM_PARAM_ID_CONTAINER_CONFIG 0x08001000 +/** h2xmlp_parameter {"Container Configuration", APM_PARAM_ID_CONTAINER_CONFIG} + h2xmlp_description {ID of the parameter to configure the container properties.\n } + h2xmlp_toolPolicy {RTC; Calibration}*/ + + +/* Immediately following this structure is a variable length array of structure objects corresponding to each container + configuration and properties. Length of the array is determined by number of containers being configured */ +#include "spf_begin_pack.h" +struct apm_param_id_container_cfg_t +{ + uint32_t num_container; + /**< h2xmle_description {Number of containers being configured} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_param_id_container_cfg_t apm_param_id_container_cfg_t; + +/* Immediately following this structure is a variable length array of container property structure. Length of the array + is determined by number of properties being configured */ +#include "spf_begin_pack.h" +struct apm_container_cfg_t +{ + uint32_t container_id; + /**< h2xmle_description {Valid ID of the container} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t num_prop; + /**< h2xmle_description {Number of properties for this sub-graph} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_container_cfg_t apm_container_cfg_t; + + + +#include "spf_begin_pack.h" +struct apm_container_type_t +{ + uint32_t type; + /**< @h2xmle_rangeEnum {containerCap} + @h2xmle_default {APM_PROP_ID_INVALID} + @h2xmle_description {Container type} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_container_type_t apm_container_type_t; + +/** h2xmlgp_configType {"CONT_CFG"} + @h2xmlgp_config {"CONT_CFG", "APM_PARAM_ID_CONTAINER_CONFIG", APM_PARAM_ID_CONTAINER_CONFIG} + @h2xmlgp_description {ID of the parameter to configure the container properties} + @{ <-- Start of container_cfg --> */ +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_CONTAINER_PROP_ID_CONTAINER_TYPE 0x08001011 +/** @h2xmlp_property {"Container Type", APM_CONTAINER_PROP_ID_CONTAINER_TYPE} + @h2xmlp_description {Container type} */ + +/** + @h2xmlp_insertSubStruct{apm_container_type_t} +*/ + +/* Immediately following this structure is the container type struct (only once). */ +#include "spf_begin_pack.h" +struct apm_cont_prop_id_type_t +{ + uint32_t version; + /**< @h2xmle_range {1..0xFFFFFFFF} + @h2xmle_default {1} + version can never be incremented to 2 because it will change below var length array. + @h2xmle_description {Version number} */ + + apm_container_type_t type_id; + /**< @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {APM_PROP_ID_INVALID} + @h2xmle_description {Container type} + This is not meant to be a variable size array, but due to backward compatibility + with previous struct, which based based on container capability ID, we had to do this. + @h2xmle_variableArraySize {version}*/ +} +#include "spf_end_pack.h" +; +typedef struct apm_cont_prop_id_type_t apm_cont_prop_id_type_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_CONTAINER_PROP_ID_GRAPH_POS 0x08001012 +/** @h2xmlp_property {"Graph Position", APM_CONTAINER_PROP_ID_GRAPH_POS} + @h2xmlp_description {Container property ID for Graph Position} */ +/**< Enumeration for container graph position Stream */ +#define APM_CONT_GRAPH_POS_STREAM 0x1 + +/**< Enumeration for container graph position Per Stream Per Device*/ +#define APM_CONT_GRAPH_POS_PER_STR_PER_DEV 0x2 + +/**< Enumeration for container graph position Stream-Device */ +#define APM_CONT_GRAPH_POS_STR_DEV 0x3 + +/**< Enumeration for container graph position Global Device */ +#define APM_CONT_GRAPH_POS_GLOBAL_DEV 0x4 + +#include "spf_begin_pack.h" +struct apm_cont_prop_id_graph_pos_t +{ + uint32_t graph_pos; + /**< @h2xmle_rangeList {"DONT_CARE"=0xFFFFFFFF, + "STREAM"=APM_CONT_GRAPH_POS_STREAM, + "PSPD"=APM_CONT_GRAPH_POS_PER_STR_PER_DEV, + "STR_DEV"=APM_CONT_GRAPH_POS_STR_DEV, + "GLOBAL DEV"=APM_CONT_GRAPH_POS_GLOBAL_DEV} + @h2xmle_default {0xFFFFFFFF} + @h2xmle_description {Container position in the graph.} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_cont_prop_id_graph_pos_t apm_cont_prop_id_graph_pos_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_CONTAINER_PROP_ID_STACK_SIZE 0x08001013 +/** @h2xmlp_property {"Stack Size", APM_CONTAINER_PROP_ID_STACK_SIZE} + @h2xmlp_description {Container property ID for Stack Size } */ + +#include "spf_begin_pack.h" +struct apm_cont_prop_id_stack_size_t +{ + uint32_t stack_size; + /**< @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0xFFFFFFFF} + @h2xmle_description {Stack size for this container.} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_cont_prop_id_stack_size_t apm_cont_prop_id_stack_size_t; + + +/*--------------------------------------------------------------------------------------------------------------------*/ +/**< Enumeration for container property ID Processor Domain */ +#define APM_CONTAINER_PROP_ID_PROC_DOMAIN 0x08001014 +/** @h2xmlp_property {"Proc Domain", APM_CONTAINER_PROP_ID_PROC_DOMAIN} + @h2xmlp_description {Container property ID for Processor Domain } */ + +#include "spf_begin_pack.h" +struct apm_cont_prop_id_proc_domain_t +{ + uint32_t proc_domain; + /**< @h2xmle_rangeList {"DONT_CARE"=0xFFFFFFFF, + "MDSP"=APM_PROC_DOMAIN_ID_MDSP, + "ADSP"=APM_PROC_DOMAIN_ID_ADSP, + "SDSP"=APM_PROC_DOMAIN_ID_SDSP, + "CDSP"=APM_PROC_DOMAIN_ID_CDSP} + @h2xmle_default {0xFFFFFFFF} + @h2xmle_description {Container processor domain.} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_cont_prop_id_proc_domain_t apm_cont_prop_id_proc_domain_t; +/*--------------------------------------------------------------------------------------------------------------------*/ +/**< Enumeration for parent container property ID */ +#define APM_CONTAINER_PROP_ID_PARENT_CONTAINER_ID 0x080010CB +/** @h2xmlp_property {"Parent Container ID", APM_CONTAINER_PROP_ID_PARENT_CONTAINER_ID} + @h2xmlp_description {Container property ID for parent container property ID} */ + +#include "spf_begin_pack.h" +struct apm_cont_prop_id_parent_container_t +{ + uint32_t parent_container_id; + /**< @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0xFFFFFFFF} + @h2xmle_description {ID of the Offload Container in Master DSP to which + the containers in the Satellite DSP are associated.} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_cont_prop_id_parent_container_t apm_cont_prop_id_parent_container_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/**< Enumeration for container property Heap ID */ +#define APM_CONTAINER_PROP_ID_HEAP_ID 0x08001174 +/** @h2xmlp_property {"Container Heap", APM_CONTAINER_PROP_ID_HEAP_ID} + @h2xmlp_description {Container property ID for the Heap ID} */ +/**< Enumeration for container Default Heap ID */ +#define APM_CONT_HEAP_DEFAULT 0x1 + +/**< Enumeration for container Low Power Island (LPI) Heap ID */ +#define APM_CONT_HEAP_LOW_POWER 0x2 + +#include "spf_begin_pack.h" +struct apm_cont_prop_id_heap_id_t +{ + uint32_t heap_id; + /**< @h2xmle_rangeList {"Default"=APM_CONT_HEAP_DEFAULT, + "Low Power"=APM_CONT_HEAP_LOW_POWER} + @h2xmle_default {APM_CONT_HEAP_DEFAULT} + @h2xmle_description {Informs the container about the heap it needs to use. + The container re-maps this id to the actual heap id} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_cont_prop_id_heap_id_t apm_cont_prop_id_heap_id_t; + +/**< Enumeration for container property Peer-Heap ID */ +#define APM_CONTAINER_PROP_ID_PEER_HEAP_ID 0x0800124D + +#include "spf_begin_pack.h" +struct apm_cont_prop_id_peer_heap_id_t +{ + uint32_t heap_id; + /**< @h2xmle_rangeList {"Default"=APM_CONT_HEAP_DEFAULT, + "Low Power"=APM_CONT_HEAP_LOW_POWER} + @h2xmle_default {APM_CONT_HEAP_DEFAULT} + @h2xmle_description {Informs the container about its peer container's heap id.} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_cont_prop_id_peer_heap_id_t apm_cont_prop_id_peer_heap_id_t; +/*--------------------------------------------------------------------------------------------------------------------*/ +/** @} <-- End of container_cfg -->*/ +/*====================================================================================================================*/ +/*====================================================================================================================*/ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _APM_CONTAINER_API_H_ */ diff --git a/spf/api/apm/apm_graph_properties.h b/spf/api/apm/apm_graph_properties.h new file mode 100644 index 0000000..126288f --- /dev/null +++ b/spf/api/apm/apm_graph_properties.h @@ -0,0 +1,224 @@ +#ifndef _APM_GRAPH_PROPERTIES_H_ +#define _APM_GRAPH_PROPERTIES_H_ +/** + * \file apm_graph_properties.h + * \brief + * This file contains APM graph property definitions. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + + +/* Legacy container capability IDs */ +/* To be removed. */ + +/** @ingroup spf_apm_graph_props + Legacy capability identifier for pre/postprocessing. */ +#define APM_CONTAINER_CAP_ID_PP 0x1 + +/** @ingroup spf_apm_graph_props + Legacy capability identifier for compression/decompression. */ +#define APM_CONTAINER_CAP_ID_CD 0x2 + +/** @ingroup spf_apm_graph_props + Legacy capability identifier for an endpoint. */ +#define APM_CONTAINER_CAP_ID_EP 0x3 + +/** @ingroup spf_apm_graph_props + Capability identifier for an offload container. */ +#define APM_CONTAINER_CAP_ID_OLC 0x4 + + +/** @ingroup spf_apm_graph_props + Container type identifier for a specialized container. */ +#define APM_CONTAINER_TYPE_ID_SC 0x0B001000 + +/** @ingroup spf_apm_graph_props + Container type identifier for a generic container. */ +#define APM_CONTAINER_TYPE_ID_GC 0x0B001001 + +/** @ingroup spf_apm_graph_props + Container type identifier for an offload container. */ +#define APM_CONTAINER_TYPE_ID_OLC 0x0B001002 + +/** @ingroup spf_apm_graph_props + Container type identifier for a wear container. */ +#define APM_CONTAINER_TYPE_ID_WC 0x0B001003 + + +/////////////////DOMAIN IDs////////////////////////// + +/* THESE HAVE TO BE SAME AS GPR IDs + refer gpr_ids_domains.h */ + +/** @ingroup spf_apm_graph_props + Processor domain identifier is invalid or unknown. */ +#define APM_PROC_DOMAIN_ID_INVALID 0x0 + +/** @ingroup spf_apm_graph_props + Processor domain identifier for the modem DSP. */ +#define APM_PROC_DOMAIN_ID_MDSP 0x1 + +/** @ingroup spf_apm_graph_props + Processor domain identifier for the audio DSP. */ +#define APM_PROC_DOMAIN_ID_ADSP 0x2 + +/** @ingroup spf_apm_graph_props + Processor domain identifier for the sensors DSP. */ +#define APM_PROC_DOMAIN_ID_SDSP 0x4 + +/** @ingroup spf_apm_graph_props + Processor domain identifier for the Hexagon Tensor Processor (previously + called the compute DSP). */ +#define APM_PROC_DOMAIN_ID_CDSP 0x5 + +/** @ingroup spf_apm_graph_props + Processor domain identifier for the Companion Chip DSP. */ +#define APM_PROC_DOMAIN_ID_CC_DSP 0x6 + +//////////////////////////////////////////////////////// + +/** @ingroup spf_apm_graph_props + Property identifier is invalid or unknown. */ +#define APM_PROP_ID_INVALID 0x0 + +/** @ingroup spf_apm_graph_props + Property identifier for the don't care value. @newpage*/ +#define APM_PROP_ID_DONT_CARE AR_NON_GUID(0xFFFFFFFF) + + +#ifdef __H2XML__ +// Enums required for module H2XML generation. + +enum processors { + PROC_DOMAIN_ADSP = APM_PROC_DOMAIN_ID_ADSP, + /*#< @h2xmle_name {aDSP} */ + + PROC_DOMAIN_MDSP = APM_PROC_DOMAIN_ID_MDSP, + /*#< @h2xmle_name {mDSP} */ + + PROC_DOMAIN_SDSP = APM_PROC_DOMAIN_ID_SDSP, + /*#< @h2xmle_name {sDSP} */ + + PROC_DOMAIN_CDSP = APM_PROC_DOMAIN_ID_CDSP, + /*#< @h2xmle_name {cDSP} */ + + PROC_DOMAIN_CC_DSP = APM_PROC_DOMAIN_ID_CC_DSP + /*#< @h2xmle_name {CC_DSP} */ +}; + +enum containerCapOld { + APM_CONTAINER_CAP_INVALID_OLD = APM_PROP_ID_INVALID, + /*#< @h2xmle_name {INVALID} */ + + APM_CONTAINER_CAP_PP = APM_CONTAINER_CAP_ID_PP, + /*#< @h2xmle_name {PP} */ + + APM_CONTAINER_CAP_CD = APM_CONTAINER_CAP_ID_CD, + /*#< @h2xmle_name {CD} */ + + APM_CONTAINER_CAP_EP = APM_CONTAINER_CAP_ID_EP, + /*#< @h2xmle_name {EP} */ + + APM_CONTAINER_CAP_OLC = APM_CONTAINER_CAP_ID_OLC, + /*#< @h2xmle_name {OLC} */ +}; + +enum containerCap { + APM_CONTAINER_TYPE_INVALID = APM_PROP_ID_INVALID, + /*#< @h2xmle_name {Invalid} */ + + APM_CONTAINER_TYPE_SC = APM_CONTAINER_TYPE_ID_SC, + /*#< @h2xmle_name {Specialized} + @h2xmle_replace {APM_CONTAINER_CAP_ID_PP} */ + + APM_CONTAINER_TYPE_GC = APM_CONTAINER_TYPE_ID_GC, + /*#< @h2xmle_name {Generic} + @h2xmle_replace {APM_CONTAINER_CAP_ID_CD, APM_CONTAINER_CAP_ID_EP} */ + + APM_CONTAINER_TYPE_OLC = APM_CONTAINER_TYPE_ID_OLC, + /*#< @h2xmle_name {Offload} + @h2xmle_replace {APM_CONTAINER_CAP_ID_OLC} */ + + APM_CONTAINER_TYPE_WC = APM_CONTAINER_TYPE_ID_WC, + /*#< @h2xmle_name {Wear} */ +}; + +#else +/** @ingroup spf_apm_graph_props + Valid processor domain IDs. +*/ +enum processors { + PROC_DOMAIN_ADSP = APM_PROC_DOMAIN_ID_ADSP, + /**< Audio DSP. */ + + PROC_DOMAIN_MDSP = APM_PROC_DOMAIN_ID_MDSP, + /**< Modem DSP. */ + + PROC_DOMAIN_SDSP = APM_PROC_DOMAIN_ID_SDSP, + /**< Sensors DSP. */ + + PROC_DOMAIN_CDSP = APM_PROC_DOMAIN_ID_CDSP, + /**< Hexagon Tensor Processor (previously called the compute DSP). */ + + PROC_DOMAIN_CC_DSP = APM_PROC_DOMAIN_ID_CC_DSP + /**< Companion chip DSP */ +}; + +/** @ingroup spf_apm_graph_props + Valid container capabilities. +*/ +enum containerCapOld { + APM_CONTAINER_CAP_INVALID_OLD = APM_PROP_ID_INVALID, + /**< Invalid capability ID. */ + + APM_CONTAINER_CAP_PP = APM_CONTAINER_CAP_ID_PP, + /**< Pre/postprocessing. */ + + APM_CONTAINER_CAP_CD = APM_CONTAINER_CAP_ID_CD, + /**< Compression or decompression. */ + + APM_CONTAINER_CAP_EP = APM_CONTAINER_CAP_ID_EP, + /**< Endpoint. */ + + APM_CONTAINER_CAP_OLC = APM_CONTAINER_CAP_ID_OLC, + /**< Offload container. */ +}; + +/** @ingroup spf_apm_graph_props + Valid types of containers. +*/ +enum containerCap { + APM_CONTAINER_TYPE_INVALID = APM_PROP_ID_INVALID, + /**< Invalid property ID. */ + + APM_CONTAINER_TYPE_SC = APM_CONTAINER_TYPE_ID_SC, + /**< Specialized container. */ + + APM_CONTAINER_TYPE_GC = APM_CONTAINER_TYPE_ID_GC, + /**< Generic container. */ + + APM_CONTAINER_TYPE_OLC = APM_CONTAINER_TYPE_ID_OLC, + /**< Offload container. */ + + APM_CONTAINER_TYPE_WC = APM_CONTAINER_TYPE_ID_WC, + /**< Wear container. */ +}; + +#endif /* __H2XML__*/ + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _APM_GRAPH_PROPERTIES_H_ */ diff --git a/spf/api/apm/apm_memmap_api.h b/spf/api/apm/apm_memmap_api.h new file mode 100644 index 0000000..e85bdc5 --- /dev/null +++ b/spf/api/apm/apm_memmap_api.h @@ -0,0 +1,900 @@ +/** + * \file apm_memmap_api.h + * \brief + * This file contains the structure definitions for the memory map commands + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _APM_MEMMAP_API_H_ +#define _APM_MEMMAP_API_H_ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** @addtogroup spf_apm_memory_map +@{ */ + +/** Commands the APM to map multiple shared memory regions. + All the mapped regions must be from the same memory pool. + + @gpr_hdr_fields + Opcode -- APM_CMD_SHARED_MEM_MAP_REGIONS + + @msgpayload{apm_cmd_shared_mem_map_regions_t} + @tablens{weak__apm__cmd__shared__mem__map__regions__t} + + @par Memory region configuration (apm_shared_map_region_payload_t) + @table{weak__apm__shared__map__region__payload__t} + + @return + #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. + + @dependencies + None. @newpage +*/ +#define APM_CMD_SHARED_MEM_MAP_REGIONS 0x0100100C + +/** Commands the APM to map multiple shared memory regions from + a memory pool and associate it with the specified shmem_id. + SPF-client is expected to map these memory regions with other SPF instances + if needed. + + @gpr_hdr_fields + Opcode -- APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS + + @msgpayload{apm_cmd_global_shared_mem_map_regions_t} + @tablens{weak__apm__cmd__global_shared__mem__map__regions__t} + + @par Memory region configuration (apm_shared_map_region_payload_t) + @table{weak__apm__shared__map__region__payload__t} + + @return + GPR_IBASIC_RSP_RESULT (see AudioReach SPF Generic Packet Router (GPR) API Reference). + + @dependencies + None. @newpage + */ +#define APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS 0x01001059 + +/** Identifier for the shared memory 8_4K pool. + @inputfile{group__weakb__property__flag__values.tex} +*/ +#define APM_MEMORY_MAP_SHMEM8_4K_POOL 3 + +/** Commands the APM to map multiple MDF shared memory regions. + All the mapped regions must be from the same memory pool. + + @gpr_hdr_fields + Opcode -- APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS + + @msgpayload{apm_cmd_shared_satellite_mem_map_regions_t} + @tablens{weak__apm__cmd__shared__satellite__mem__map__regions__t} + + @par Memory region configuration (apm_shared_map_region_payload_t) + @table{weak__apm__shared__map__region__payload__t} + + @return + #APM_CMD_RSP_SHARED_SATELLITE_MEM_MAP_REGIONS. + + @dependencies + None. @newpage +*/ +#define APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS 0x01001026 + +/** @weakgroup weakb_property_flag_values +@{ */ + +/** Definition of the IsVirtual flag shift value. */ +#define APM_MEMORY_MAP_SHIFT_IS_VIRTUAL 0 + +/** Definition of the IsVirtual flag bitmask. */ +#define APM_MEMORY_MAP_BIT_MASK_IS_VIRTUAL (0x00000001UL) + +/** Definition of the physical memory flag. */ +#define APM_MEMORY_MAP_PHYSICAL_MEMORY 0 + +/** Definition of the virtual memory flag. */ +#define APM_MEMORY_MAP_VIRTUAL_MEMORY 1 + +/** Definition of the is_uncached flag shift value. */ +#define APM_MEMORY_MAP_SHIFT_IS_UNCACHED 1 + +/** Definition of the is_uncached flag bitmask. */ +#define APM_MEMORY_MAP_BIT_MASK_IS_UNCACHED (0x00000002UL) + +/** Definition of the is_offset_mode flag shift value. */ +#define APM_MEMORY_MAP_SHIFT_IS_OFFSET_MODE 2 + +/** Definition of the is_offset_mode flag bitmask. */ +#define APM_MEMORY_MAP_BIT_MASK_IS_OFFSET_MODE (0x00000004UL) + +/** Definition of the is_client_loaned_memory flag shift value. */ +#define APM_MEMORY_MAP_SHIFT_IS_MEM_LOANED 3 + +/** Definition of the is_client_loaned_memory flag bitmask. */ +#define APM_MEMORY_MAP_BIT_MASK_IS_MEM_LOANED (0x00000008UL) + +/** Definition of the loaned_memory_heap_manager_type flag shift value. */ +#define APM_MEMORY_MAP_SHIFT_LOANED_MEMORY_HEAP_MNGR_TYPE 4 + +/** Definition of the loaned_memory_heap_manager_type flag bitmask. */ +#define APM_MEMORY_MAP_BIT_MASK_LOANED_MEMORY_HEAP_MNGR_TYPE (0x00000030UL) + +/** Definition of the Loaned memory Default Heap Manager. */ +#define APM_MEMORY_MAP_LOANED_MEMORY_HEAP_MNGR_TYPE_DEFAULT 0 + +/** Definition of the Loaned memory Safe Heap Manager. */ +#define APM_MEMORY_MAP_LOANED_MEMORY_HEAP_MNGR_TYPE_SAFE_HEAP 1 + +/** Definition of the Loaned memory Heap Manager type value reserved. */ +#define APM_MEMORY_MAP_LOANED_MEMORY_HEAP_MNGR_TYPE_RESERVED1 2 +#define APM_MEMORY_MAP_LOANED_MEMORY_HEAP_MNGR_TYPE_RESERVED2 3 + +/** Definition of the memory address type flag shift value. */ +#define APM_MEMORY_MAP_SHIFT_MEMORY_ADDRESS_TYPE 6 + +/** Definition of the memory address type flag bitmask. */ +#define APM_MEMORY_MAP_BIT_MASK_MEMORY_ADDRESS_TYPE (0x000001C0UL) + +/** Definition of the memory address type default - physical address (PA) */ +#define APM_MEMORY_MAP_MEMORY_ADDRESS_TYPE_PA_OR_VA 0 + +/** Definition of the memory address type - file descriptor(FD) . */ +#define APM_MEMORY_MAP_MEMORY_ADDRESS_TYPE_FD 1 + +/** Definition of the memory address type - max value. */ +#define APM_MEMORY_MAP_MEMORY_ADDRESS_TYPE_MAX 7 + +/** @} */ /* end_weakgroup weakb_property_flag_values */ + +/** @weakgroup weak_apm_cmd_global_shared_mem_map_regions_t + @{ */ +/** Immediately following this structure are num_regions of + #apm_shared_map_region_payload_t. + */ +#include "spf_begin_pack.h" +struct apm_cmd_global_shared_mem_map_regions_t +{ + uint32_t shmem_id; + /**< A unique ID assigned by the client for these memory regions. + All subsequent commands #AR_SPF_MSG_GLOBAL_SH_MEM will use + this unique ID to refer these shared memory regions. + */ + + uint16_t mem_pool_id; + /**< Type of memory on which this memory region is mapped. + + @valuesbul + - #APM_MEMORY_MAP_SHMEM8_4K_POOL + - Other values are reserved + + The memory ID implicitly defines the characteristics of the memory. + Characteristics can include alignment type, permissions, and so on. + + APM_MEMORY_MAP_SHMEM8_4K_POOL is shared memory, byte addressable, and + 4 KB aligned. */ + + uint16_t num_regions; + /**< Number of physical regions to map. + * Immediately following this structure are num_regions of + #apm_shared_map_region_payload_t. + + @values > 0 + + If the is_offset_mode bit in the property_flag is set, num_regions can + only be set to 1.*/ + + uint32_t property_flag; + /**< Configures one common property for all regions in the payload. No + two regions in the same command can have different properties. + + @values 0x00000000 through 0x00000003 + + @contcell + @subhead{Bit 0 -- IsVirtual flag} + + Indicates physical or virtual mapping: + - 0 -- The shared memory address provided in + #apm_shared_map_region_payload_t is a physical address. The + shared memory must be mapped (a hardware TLB entry), and a + software entry must be added for internal bookkeeping. + - 1 -- The shared memory address provided in the map + payload [usRegions] is a virtual address. The shared memory + must not be mapped (because the hardware TLB entry is already + available). But a software entry must be added for internal + bookkeeping. \n @vertspace{2} + This bit value (1) is useful if two services within the aDSP + are communicating via the GPR. They can directly communicate + via the virtual address instead of the physical address. The + virtual regions must be contiguous. + + @subhead{Bit 1 -- is\_uncached flag} + + Indicates whether the memory is mapped as cached memory or uncached: + - 0 -- Cached + - 1 -- Uncached + + Most memories must be mapped as cached. Some special cases require + uncached memory. + + @subhead{Bit 2 -- is\_offset\_mode flag} + + Indicates whether the memory will be subsequently referred to with + offsets: + - 0 -- Subsequent commands using this mapped regions + will use physical or virtual addresses.\n + @vertspace{2} + For example, buf_addr_lsw and buf_addr_msw in + apm_cmd_loan_global_shared_mem_t or ar_spf_msg_global_sh_mem_t + will be physical or virtual addresses. + - 1 -- Subsequent commands using this mapped regions + will use offsets.\n + @vertspace{2} + For example, buf_addr_lsw and buf_addr_msw in + apm_cmd_loan_global_shared_mem_t or ar_spf_msg_global_sh_mem_t + will be offsets. The offset is from the base address, which is + defined as the address given by apm_shared_map_region_payload_t. + + @subhead{Bits 31 to 3} + + Reserved and must be set to 0. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_global_shared_mem_map_regions_t */ +typedef struct apm_cmd_global_shared_mem_map_regions_t apm_cmd_global_shared_mem_map_regions_t; + +/** @weakgroup weak_apm_cmd_shared_mem_map_regions_t +@{ */ +/** Immediately following this structure are num_regions of + #apm_shared_map_region_payload_t. +*/ +#include "spf_begin_pack.h" +struct apm_cmd_shared_mem_map_regions_t +{ + uint16_t mem_pool_id; + /**< Type of memory on which this memory region is mapped. + + @valuesbul + - #APM_MEMORY_MAP_SHMEM8_4K_POOL + - Other values are reserved + + The memory ID implicitly defines the characteristics of the memory. + Characteristics can include alignment type, permissions, and so on. + + APM_MEMORY_MAP_SHMEM8_4K_POOL is shared memory, byte addressable, and + 4 KB aligned. */ + + uint16_t num_regions; + /**< Number of regions to map. + + @values > 0 + + If the is_offset_mode bit in the property_flag is set, num_regions can + only be set to 1.*/ + + uint32_t property_flag; + /**< Configures one common property for all regions in the payload. No + two regions in the same command can have different properties. + + @values 0x00000000 through 0x00000007 + + @contcell + @subhead{Bit 0 -- IsVirtual flag} + + Indicates physical or virtual mapping: + - 0 -- The shared memory address provided in + #apm_shared_map_region_payload_t is a physical address. The + shared memory must be mapped (a hardware TLB entry), and a + software entry must be added for internal bookkeeping. + - 1 -- The shared memory address provided in the map + payload [usRegions] is a virtual address. The shared memory + must not be mapped (because the hardware TLB entry is already + available). But a software entry must be added for internal + bookkeeping. \n @vertspace{2} + This bit value (1) is useful if two services within the aDSP + are communicating via the APR. They can directly communicate + via the virtual address instead of the physical address. The + virtual regions must be contiguous. + + @subhead{Bit 1 -- is\_uncached flag} + + Indicates whether the memory is mapped as cached memory or uncached: + - 0 -- Cached + - 1 -- Uncached + + Most memories must be mapped as cached. Some special cases require + uncached memory. + + @subhead{Bit 2 -- is\_offset\_mode flag} + + Indicates whether the memory will be subsequently referred to with + offsets: + - 0 -- Subsequent commands using mem_map_handle returned by + #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS will use physical or + virtual addresses. \n @vertspace{2} + For example, buf_addr_lsw and buf_addr_msw in + data_cmd_wr_sh_mem_ep_data_buffer_t will be physical or + virtual addresses. + - 1 -- Subsequent commands using mem_map_handle returned by + APM_CMD_RSP_SHARED_MEM_MAP_REGIONS will use offsets. \n + @vertspace{2} + For example, buf_addr_lsw and buf_addr_msw in + data_cmd_wr_sh_mem_ep_data_buffer_t will be offsets. The + offset is from the base address, which is defined as the + address given by apm_shared_map_region_payload_t. + + After mapping a physical region using this command, a mem_map_handle is + returned. Subsequently, the client uses mem_map_handle in any command + using addresses or offsets that belong to a memory region mapped in + this command. + + @contcell + @subhead{Bit 3 -- is\_client\_loaned\_memory flag} + + Specifies whether the client manages the memory or allows the APM to + manage the memory: + - 0 -- Client owned memory (the shared memory is managed by the + client). @vertspace{3} + - 1 -- Client loaned memory (the shared memory is mapped by the + client and managed by the APM). + + For loaned memory, the client must relinquish the memory access + permissions for multi-DSP framework (MDF) use cases. + + @contcell + @subhead{Bit 4-5 -- loaned\_memory\_heap\_configuration} + + Specifies the heap configuration for the memory loaned by client and + managed by APM ( .i.e., this configuration is valid only when Bit_3 is SET) + - 0 -- Default Heap ( Regular heap, functionally backward compatible ) + - 1 -- Safe Heap ( When the satellite is considered as un-secure + Process Domain, configuring as Safe Heap is + recommended ) + - 2/3 -- Values reserved for future use + + -It is recommended to use the same heap configuration for all the MDF memory maps + for a pair for the master-satellite combination. + -If multiple Satellite Process Domains (PD's) are present in a product + with same loaned shared memory mapped to all the satellite PD's, + and one of the satellite PD is termed as un-secure PD, + configuring as Safe Heap is recommended. + -In general, configuration as Default Heap is recommended. + + @contcell + @subhead{Bit 6-8 -- memory\_address\_type} + + Specifies the memory address type. In the Default configuration (0), would ensure backward compatibility. + - 0 – Physical/Virtual Address + - 1 – File descriptor + - 2-7 – Values reserved for Future + + It is important to note, the Signal Processing Framework (a.k.a AudioReach SPF) would not have any + mechanism to convert the memory address type or validate the same. + This configuration would enable the HLOS system, specifically GSL in userspace and the audio packet + driver with kernel space access, to determine if FD (file descriptor) to PA (physical address) + conversion is required in the audio packet driver. This determination is based on the actual needs + of the underlying process domain, which requires memory addresses accordingly. + + + @subhead{Bits 31 to 9} + + Reserved and must be set to 0. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_shared_mem_map_regions_t */ +typedef struct apm_cmd_shared_mem_map_regions_t apm_cmd_shared_mem_map_regions_t; + +/** @weakgroup weak_apm_cmd_shared_satellite_mem_map_regions_t +@{ */ +/** Immediately following this structure are num_regions of + %apm_shared_map_region_payload_t. +*/ +#include "spf_begin_pack.h" +struct apm_cmd_shared_satellite_mem_map_regions_t +{ + uint32_t master_mem_handle; + /**< Specifies the memory handle of the master processor that corresponds to + the shared memory region being mapped to the satellite process domain. + + This handle must have been sent in the response after mapping the + memory to the master processor. */ + + uint32_t satellite_proc_domain_id; + /**< Specifies the satellite process domain ID to which the memory is + mapped. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_APPS + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROC_DOMAIN_ID_GDSP_0 + - #APM_PROC_DOMAIN_ID_GDSP_1 + - #APM_PROC_DOMAIN_ID_APPS_2 @tablebulletend */ + + uint16_t mem_pool_id; + /**< Type of memory on which this memory region is mapped. + + @valuesbul + - #APM_MEMORY_MAP_SHMEM8_4K_POOL + - Other values are reserved + + The memory ID implicitly defines the characteristics of the memory. + Characteristics can include alignment type, permissions, etc. + + APM_MEMORY_MAP_SHMEM8_4K_POOL is shared memory, byte addressable, and + 4 KB aligned. */ + + uint16_t num_regions; + /**< Number of regions to map. + + @values 1 + + @note1 If the is_offset_mode bit in the property_flag is set, + num_regions can only be 1.*/ + + uint32_t property_flag; + /**< Configures one common property for all regions in the payload. No + two regions in the same command can have different properties. + + @values 0x00000000 through 0x00000007 + + @contcell + @subhead{Bit 0 -- IsVirtual flag} + Indicates physical or virtual mapping: + - 0 -- The shared memory address provided in + %apm_shared_map_region_payload_t is a physical address. The + shared memory must be mapped (a hardware TLB entry), and a + software entry must be added for internal bookkeeping. + - 1 -- The shared memory address provided in the map + payload [usRegions] is a virtual address. The shared memory + must not be mapped (because the hardware TLB entry is already + available). But a software entry must be added for internal + bookkeeping. \n @vertspace{2} + This bit value is useful if two services within the aDSP + are communicating via the APR. They can directly communicate + via the virtual address instead of the physical address. The + virtual regions must be contiguous. + + @subhead{Bit 1 -- is\_uncached flag} + Indicates whether the memory is mapped as cached memory or uncached: + - 0 -- Cached + - 1 -- Uncached + + Most memories must be mapped as cached. Some special cases require + uncached memory. + + @subhead{Bit 2 -- is\_offset\_mode flag} + Indicates whether the memory is subsequently referred to with offsets: + - 0 -- Subsequent commands using mem_map_handle returned by + #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS will use physical or + virtual addresses. \n @vertspace{2} + For example, buf_addr_lsw and buf_addr_msw in + data_cmd_wr_sh_mem_ep_data_buffer_t are physical or virtual + addresses. + - 1 -- Subsequent commands using mem_map_handle returned by + APM_CMD_RSP_SHARED_MEM_MAP_REGIONS will use offsets. \n + @vertspace{2} + For example, buf_addr_lsw and buf_addr_msw in + data_cmd_wr_sh_mem_ep_data_buffer_t are offsets. The offset + is from the base address, which is defined as the address + given by %apm_shared_map_region_payload_t. + + After mapping a physical region using this command, a mem_map_handle is + returned. Subsequently, the client uses mem_map_handle in any command + using addresses or offsets that belong to a memory region mapped in + this command. + + @contcell + @subhead{Bit 3 -- is\_client\_loaned\_memory flag} + Specifies whether the client manages the memory or allows the APM to + manage the memory: + - 0 -- Client owned memory (the shared memory is managed by the + client) + - 1 -- Client loaned memory (the shared memory is mapped by the + client and managed by the APM) + + For loaned memory, the client must relinquish the memory access + permissions for MDF use cases. + + @contcell + @subhead{Bit 4-5 -- loaned\_memory\_heap\_configuration} + + Specifies the heap configuration for the memory loaned by client and + managed by APM ( .i.e., this configuration is valid only when Bit_3 is SET) + - 0 -- Default Heap ( Regular heap, functionally backward compatible ) + - 1 -- Safe Heap ( When the satellite is considered as un-secure + Process Domain, configuring as Safe Heap is + recommended ) + - 2/3 -- Values reserved for future use + + -It is recommended to use the same heap configuration for all the MDF memory maps + for a pair for the master-satellite combination. + -If multiple Satellite Process Domains (PD's) are present in a product + with same loaned shared memory mapped to all the satellite PD's, + and one of the satellite PD is termed as un-secure PD, + configuring as Safe Heap is recommended. + -In general, configuration as Default Heap is recommended. + + @contcell + @subhead{Bit 6-8 -- memory\_address\_type} + + Specifies the memory address type. In the Default configuration (0), would ensure backward compatibility. + - 0 – Physical/virtual Address + - 1 – File descriptor + - 2-7 – Values reserved for Future + + It is important to note, the Signal Processing Framework (a.k.a AudioReach SPF) would not have any + mechanism to convert the memory address type or validate the same. + This configuration would enable the HLOS system, specifically GSL in userspace and the audio packet + driver with kernel space access, to determine if FD (file descriptor) to PA (physical address) + conversion is required in the audio packet driver. This determination is based on the actual needs + of the underlying process domain, which requires memory addresses accordingly. + + + @subhead{Bits 31 to 9} + Reserved and must be set to 0. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_shared_satellite_mem_map_regions_t */ +typedef struct apm_cmd_shared_satellite_mem_map_regions_t apm_cmd_shared_satellite_mem_map_regions_t; + +/** @weakgroup weak_apm_shared_map_region_payload_t +@{ */ +/* Payload of the map region: used by the + apm_cmd_shared_mem_map_regions_t structure. +*/ +#include "spf_begin_pack.h" +struct apm_shared_map_region_payload_t +{ + uint32_t shm_addr_lsw; + /**< Lower 32 bits of the shared memory address of the memory region to + map. This word must be contiguous memory, and it must be + 4 KB aligned. + + @values Non-zero 32-bit value */ + + uint32_t shm_addr_msw; + /**< Upper 32 bits of the shared memory address of the memory region to + map. This word must be contiguous memory, and it must be + 4 KB aligned. + + @valuesbul + - For a 32-bit shared memory address, this field must be set to 0. + - For a 36-bit address, bits 31 to 4 must be set to 0. + - For a 64-bit shared memory address, non-zero 32-bit value. + @tablebulletend */ + + uint32_t mem_size_bytes; + /**< Number of bytes in the region. + + @values Multiples of 4 KB + + The APM always maps the regions as virtual contiguous memory, but + the memory size must be in multiples of 4 KB to avoid gaps in the + virtually contiguous mapped memory. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_shared_map_region_payload_t */ +typedef struct apm_shared_map_region_payload_t apm_shared_map_region_payload_t; + +/** Returns the memory map handle in response to an + #APM_CMD_SHARED_MEM_MAP_REGIONS command. + + @gpr_hdr_fields + Opcode -- APM_CMD_RSP_SHARED_MEM_MAP_REGIONS + + @msgpayload{apm_cmd_rsp_shared_mem_map_regions_t} + @table{weak__apm__cmd__rsp__shared__mem__map__regions__t} + + @return + None. + + @dependencies + An #APM_CMD_SHARED_MEM_MAP_REGIONS command must have been issued. @newpage +*/ +#define APM_CMD_RSP_SHARED_MEM_MAP_REGIONS 0x02001001 + +/** @weakgroup weak_apm_cmd_rsp_shared_mem_map_regions_t +@{ */ +#include "spf_begin_pack.h" +struct apm_cmd_rsp_shared_mem_map_regions_t +{ + uint32_t mem_map_handle; + /**< Unique identifier for the shared memory address. + The APM returns this handle through #APM_CMD_SHARED_MEM_MAP_REGIONS. + + @values Any 32-bit value + + The APM uses this handle to retrieve the shared memory attributes. + This handle can be an abstract representation of the shared memory + regions that are being mapped. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_rsp_shared_mem_map_regions_t */ +typedef struct apm_cmd_rsp_shared_mem_map_regions_t apm_cmd_rsp_shared_mem_map_regions_t; + +/** Returns the memory map handle in response to an + #APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS command. + + @gpr_hdr_fields + Opcode -- APM_CMD_RSP_SHARED_SATELLITE_MEM_MAP_REGIONS + + @msgpayload{apm_cmd_rsp_shared_satellite_mem_map_regions_t} + @table{weak__apm__cmd__rsp__shared__satellite__mem__map__regions__t} + + @return + None. + + @dependencies + An #APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS command must have been + issued. @newpage +*/ +#define APM_CMD_RSP_SHARED_SATELLITE_MEM_MAP_REGIONS 0x02001009 + +/** @weakgroup weak_apm_cmd_rsp_shared_satellite_mem_map_regions_t +@{ */ +#include "spf_begin_pack.h" +struct apm_cmd_rsp_shared_satellite_mem_map_regions_t +{ + uint32_t mem_map_handle; + /**< Unique identifier for the shared memory address. + + The satellite process domain uses this handle to retrieve the + shared memory attributes. This handle can be an abstract + representation of the shared memory regions that are being mapped. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_rsp_shared_satellite_mem_map_regions_t */ +typedef struct apm_cmd_rsp_shared_satellite_mem_map_regions_t apm_cmd_rsp_shared_satellite_mem_map_regions_t; + +/** Commands the APM to unmap global shared memory regions that were + previously mapped via #APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS. + + Client is expected to send this unmap command only when the use case is ended. + This is to ensure no module is actively using the global shared memory. + + @gpr_hdr_fields + Opcode -- APM_CMD_GLOBAL_SHARED_MEM_UNMAP_REGIONS + + @msgpayload{apm_cmd_global_shared_mem_unmap_regions_t} + @table{weak__apm__cmd__global__shared__mem__unmap__regions__t} + + @return + GPR_IBASIC_RSP_RESULT (see AudioReach SPF Generic Packet Router (GPR) API Reference). + + @dependencies + An #APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS command must have been issued. @newpage + */ +#define APM_CMD_GLOBAL_SHARED_MEM_UNMAP_REGIONS 0x0100105A + +/** @weakgroup weak_apm_cmd_global_shared_mem_unmap_regions_t + @{ */ +#include "spf_begin_pack.h" +struct apm_cmd_global_shared_mem_unmap_regions_t +{ + uint32_t shmem_id; + /**< Unique identifier for the global shared memory. + This is the same ID which was sent in #APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS. + + @values Any 32-bit value + + The APM uses this handle to retrieve the associated shared + memory regions and unmap them. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_global_shared_mem_unmap_regions_t */ +typedef struct apm_cmd_global_shared_mem_unmap_regions_t apm_cmd_global_shared_mem_unmap_regions_t; + +/** Commands the APM to unmap multiple shared memory regions that were + previously mapped via #APM_CMD_SHARED_MEM_MAP_REGIONS. + + @gpr_hdr_fields + Opcode -- APM_CMD_SHARED_MEM_UNMAP_REGIONS + + @msgpayload{apm_cmd_shared_mem_unmap_regions_t} + @table{weak__apm__cmd__shared__mem__unmap__regions__t} + + @return + GPR_IBASIC_RSP_RESULT (see AudioReach SPF Generic Packet Router (GPR) API Reference). + + @dependencies + An #APM_CMD_SHARED_MEM_MAP_REGIONS command must have been issued. @newpage +*/ +#define APM_CMD_SHARED_MEM_UNMAP_REGIONS 0x0100100D + +/** @weakgroup weak_apm_cmd_shared_mem_unmap_regions_t +@{ */ +#include "spf_begin_pack.h" +struct apm_cmd_shared_mem_unmap_regions_t +{ + uint32_t mem_map_handle; + /**< Unique identifier for the shared memory address. + The APM returns this handle through #APM_CMD_SHARED_MEM_MAP_REGIONS. + + @values Any 32-bit value + + The APM uses this handle to retrieve the associated shared + memory regions and unmap them. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_shared_mem_unmap_regions_t */ +typedef struct apm_cmd_shared_mem_unmap_regions_t apm_cmd_shared_mem_unmap_regions_t; + +/** Commands the APM to unmap multiple shared memory regions + that were previously mapped via #APM_CMD_SHARED_MEM_MAP_REGIONS. + + @gpr_hdr_fields + Opcode -- APM_CMD_SHARED_SATELLITE_MEM_UNMAP_REGIONS + + @msgpayload{apm_cmd_shared_satellite_mem_unmap_regions_t} + @table{weak__apm__cmd__shared__satellite__mem__unmap__regions__t} + + @return + GPR_IBASIC_RSP_RESULT (see AudioReach SPF Generic Packet Router (GPR) API Reference). + + @dependencies + An #APM_CMD_SHARED_MEM_MAP_REGIONS command must have been issued. +*/ +#define APM_CMD_SHARED_SATELLITE_MEM_UNMAP_REGIONS 0x01001027 + +/** @weakgroup weak_apm_cmd_shared_satellite_mem_unmap_regions_t +@{ */ +#include "spf_begin_pack.h" +struct apm_cmd_shared_satellite_mem_unmap_regions_t +{ + uint32_t satellite_proc_domain_id; + /**< Specifies the satellite process domain ID whose memory must be + unmapped. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_APPS + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROC_DOMAIN_ID_GDSP_0 + - #APM_PROC_DOMAIN_ID_GDSP_1 + - #APM_PROC_DOMAIN_ID_APPS_2 @tablebulletend */ + + uint32_t master_mem_handle; + /**< Unique identifier for the shared memory address. + + @values Any 32-bit value + + The satellite process domain uses this handle to retrieve the + associated shared memory regions and unmap them. The APM returns this + handle through #APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS. */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_shared_satellite_mem_unmap_regions_t */ +typedef struct apm_cmd_shared_satellite_mem_unmap_regions_t apm_cmd_shared_satellite_mem_unmap_regions_t; + +#if 0 +/** This Command specifies memory block loaned to the SPF instance from the specified global + shared memory which is previously mapped with command #APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS. + This memory can be used by the SPF modules to communicate within the specified global + shared memory use case. + + @gpr_hdr_fields + Opcode -- APM_CMD_LOAN_GLOBAL_SHARED_MEM + + @msgpayload{apm_cmd_loan_global_shared_mem_t} + @tablens{weak__apm__cmd__loan__global_shared__mem__t} + + @return + GPR_IBASIC_RSP_RESULT (see AudioReach SPF Generic Packet Router (GPR) API Reference). + + @dependencies + None. @newpage + */ +#define APM_CMD_LOAN_GLOBAL_SHARED_MEM 0x0100105C + +/** @weakgroup weak_apm_cmd_loan_global_shared_mem_t +@{ */ +#include "spf_begin_pack.h" +struct apm_cmd_loan_global_shared_mem_t +{ + uint32_t shmem_id; + /**< Unique identifier for the global shared memory. + This is the same ID which was sent in #APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS. + + @values Any 32-bit value + */ + + uint32_t loaned_mem_addr_lsw; + /**< Lower 32 bits of the physical/Virtual/byte-offset address value. + + This refers to the loaned memory for SPF from the specified global shared memory. + + If global shared memory was mapped with offset property (Bit 2 is set) + then this value is a byte offset from the base virtual address of + global shared memory. + + If global shared memory was not mapped with offset property (Bit 2 is unset) + then this value either refers to a physical or a virtual address depending on the + Bit 0 configuration in the global shared memory map property. + + This memory can be used by the SPF for sending any out of band + command/event from SPF back to the client or another SPF instance. + + @values Non-zero 32-bit value */ + + uint32_t loaned_mem_addr_msw; + /**< Upper 32 bits of the physical/Virtual address value. + + @valuesbul + - For offset based addressing, this field must be set to 0. + - For a 32-bit shared memory address, this field must be set to 0. + - For a 36-bit address, bits 31 to 4 must be set to 0. + - For a 64-bit shared memory address, non-zero 32-bit value. + @tablebulletend */ + + uint32_t loaned_mem_block_size; + /**< Number of bytes loaned to the SPF from the specified global shared memory. + Base virtual address of this memory block will be retrieved from the + physical/virtual/byte-offset address value specified in this payload. + */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_loan_global_shared_mem_t */ +typedef struct apm_cmd_loan_global_shared_mem_t apm_cmd_loan_global_shared_mem_t; + +/** This Command specifies memory block(s) which was previously loaned to the SPF instance + from the specified global shared memory will no longer be available. + + @gpr_hdr_fields + Opcode -- APM_CMD_UNLOAN_GLOBAL_SHARED_MEM + + @msgpayload{apm_cmd_unloan_global_shared_mem_t} + @tablens{weak__apm__cmd__unloan__global_shared__mem__t} + + @return + GPR_IBASIC_RSP_RESULT (see AudioReach SPF Generic Packet Router (GPR) API Reference). + + @dependencies + None. @newpage + */ +#define APM_CMD_UNLOAN_GLOBAL_SHARED_MEM 0x0100105D + +/** @weakgroup weak_apm_cmd_unloan_global_shared_mem_t +@{ */ +#include "spf_begin_pack.h" +struct apm_cmd_unloan_global_shared_mem_t +{ + uint32_t shmem_id; + /**< Unique identifier for the global shared memory. + This is the same ID which was sent in #APM_CMD_LOAN_GLOBAL_SHARED_MEM. + + @values Any 32-bit value + */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_apm_cmd_unloan_global_shared_mem_t*/ +typedef struct apm_cmd_unloan_global_shared_mem_t apm_cmd_unloan_global_shared_mem_t; + +#endif + +/** @} */ /* end_addtogroup spf_apm_memory_map */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _APM_MEMMAP_API_H_ */ diff --git a/spf/api/apm/apm_module_api.h b/spf/api/apm/apm_module_api.h new file mode 100644 index 0000000..da4b166 --- /dev/null +++ b/spf/api/apm/apm_module_api.h @@ -0,0 +1,295 @@ +#ifndef _APM_MODULE_API_H_ +#define _APM_MODULE_API_H_ +/** + * \file apm_module_api.h + * \brief + * This file contains APM module related commands and events structures definitions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_PARAM_ID_MODULES_LIST 0x08001002 +/** h2xmlp_parameter {"APM_PARAM_ID_MODULES_LIST", APM_PARAM_ID_MODULES_LIST} + h2xmlp_description { ID of the parameter to configure the modules list for a given \n + combination of sub-graph and container ID's. \n } + h2xmlp_toolPolicy {RTC; Calibration}*/ + +/* Immediately following this structure is a variable length array apm_modules_list_t */ +#include "spf_begin_pack.h" +struct apm_param_id_modules_list_t +{ + uint32_t num_modules_list; + /**< h2xmle_description {Number of sub-graphs being configured} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_param_id_modules_list_t apm_param_id_modules_list_t; + + +/* Immediately following this structure is a variable length array apm_modules_list_t */ + +#include "spf_begin_pack.h" +struct apm_modules_list_t +{ + uint32_t sub_graph_id; + /**< h2xmle_description {Sub-graph ID being configured} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t container_id; + /**< h2xmle_description {Container ID being configured } + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t num_modules; + /**< h2xmle_description {Number of modules being configured} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_modules_list_t apm_modules_list_t; + + +#include "spf_begin_pack.h" +struct apm_module_cfg_t +{ + uint32_t module_id; + /**< h2xmle_description {Valid ID of the module} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t instance_id; + /**< h2xmle_description {Instance ID for this module} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_module_cfg_t apm_module_cfg_t; + + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_PARAM_ID_MODULE_PROP 0x08001003 +/** h2xmlp_parameter {"APM_PARAM_ID_SUB_GRAPH_CONFIG", APM_PARAM_ID_SUB_GRAPH_CONFIG} + h2xmlp_description {ID of the parameter to configure the module properties. } + h2xmlp_toolPolicy {RTC; Calibration} */ + +#include "spf_begin_pack.h" +struct apm_param_id_module_prop_t +{ + uint32_t num_module_prop_cfg; + /**< h2xmle_description {Number of module property configuration objects} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + +} +#include "spf_end_pack.h" +; +typedef struct apm_param_id_module_prop_t apm_param_id_module_prop_t; + +/* Immediately following this structure is a variable length + array of structure objects corresponding to each module + properties. Length of the array is determined by number of + module properties being configured. */ + +#include "spf_begin_pack.h" +struct apm_module_prop_cfg_t +{ + uint32_t instance_id; + /**< h2xmle_description {Valid ID of the module.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t num_props; + /**< h2xmle_description {Number of properties for the module.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; + +typedef struct apm_module_prop_cfg_t apm_module_prop_cfg_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_MODULE_PROP_ID_PORT_INFO 0x08001015 +/** h2xmlp_parameter {"APM_MODULE_PROP_ID_PORT_INFO", APM_MODULE_PROP_ID_PORT_INFO} + h2xmlp_description {Enumeration for module property ID Port Info. } + h2xmlp_toolPolicy {RTC; Calibration} */ + +#include "spf_begin_pack.h" +struct apm_module_prop_id_port_info_t +{ + uint32_t max_ip_port; + /**< h2xmle_description {Max number of input ports.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t max_op_port; + /**< h2xmle_description {Max number of output ports.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_module_prop_id_port_info_t apm_module_prop_id_port_info_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_PARAM_ID_MODULE_CONN 0x08001004 +/** h2xmlp_parameter {"APM_PARAM_ID_MODULE_CONN", APM_PARAM_ID_MODULE_CONN} + h2xmlp_description { ID of the parameter to configure the connection between module ports.\n + This parameter ID must be used under command APM_CMD_GRAPH_OPEN. \n + + Configure connection links between each of the input and \n + output ports of modules present in the sub-graph. \n + Connection between source and destination module ports is \n + 1:1 i.e. the source module's output cannot be routed to \n + multiple input ports of 1 or more destination modules. \n + Similarly, destination module's input port cannot accept \n + data from more than 1 output ports of one or more source \n + modules. Any such connection is treated as invalid \n + configuration and will be flagged as error to the client. \n } + h2xmlp_toolPolicy {RTC; Calibration} */ + +/* Immediately following this structure is a variable length array of connection objects. + Length of the array is determined using the number of connections configuration parameter. */ +#include "spf_begin_pack.h" +struct apm_param_id_module_conn_t +{ + uint32_t num_connections; + /**< h2xmle_description {Number of connections.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_param_id_module_conn_t apm_param_id_module_conn_t; + + +#include "spf_begin_pack.h" +struct apm_module_conn_cfg_t +{ + uint32_t src_mod_inst_id; + /**< h2xmle_description {Source module instance ID.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t src_mod_op_port_id; + /**< h2xmle_description {Source module output port ID.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t dst_mod_inst_id; + /**< h2xmle_description {Destination module instance ID.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t dst_mod_ip_port_id; + /**< h2xmle_description {Destination module input port ID.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_module_conn_cfg_t apm_module_conn_cfg_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_PARAM_ID_MODULE_CTRL_LINK_CFG 0x08001061 +/** h2xmlp_parameter {"APM_PARAM_ID_MODULE_CTRL_LINK_CFG", APM_PARAM_ID_MODULE_CTRL_LINK_CFG} + h2xmlp_description {ID of the parameter to configure the list of control links across module control ports. } + h2xmlp_toolPolicy {RTC; Calibration} */ + +/* Immediately following this structure is a variable length array of structure objects corresponding to module control + port link configuration. Length of the array is determined by number of control links being configured. */ +#include "spf_begin_pack.h" +struct apm_param_id_module_ctrl_link_cfg_t +{ + uint32_t num_ctrl_link_cfg; + /**< h2xmle_description {Number of module control link configuration objects.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_param_id_module_ctrl_link_cfg_t apm_param_id_module_ctrl_link_cfg_t; + + +/* Immediately following this structure is a variable length array of structure objects corresponding to each module + control link properties. Length of the array is determined by number of module properties being configured. */ +#include "spf_begin_pack.h" +struct apm_module_ctrl_link_cfg_t +{ + uint32_t peer_1_mod_iid; + /**< h2xmle_description {Module instance ID for first peer module.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t peer_1_mod_ctrl_port_id; + /**< h2xmle_description {Control port ID for the first peer module.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t peer_2_mod_iid; + /**< h2xmle_description {Module instance ID for second peer module.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t peer_2_mod_ctrl_port_id; + /**< h2xmle_description {Control port ID for the second peer module.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t num_props; + /**< h2xmle_description {Number of link properties.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_module_ctrl_link_cfg_t apm_module_ctrl_link_cfg_t; + + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_MODULE_PROP_ID_CTRL_LINK_INTENT_LIST 0x08001062 +/** h2xmlp_parameter {"APM_MODULE_PROP_ID_CTRL_LINK_INTENT_LIST", APM_MODULE_PROP_ID_CTRL_LINK_INTENT_LIST} + h2xmlp_description {Enumeration for control link property ID Port Info. } + h2xmlp_toolPolicy {RTC; Calibration} */ + +/* Immediately following this structure is a variable length array of control link intent id list for each control link. + Length of the array is determined by number of control link properties being configured. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct apm_module_ctrl_link_prop_id_intent_list_t +{ + uint32_t num_intents; + /**< h2xmle_description {Number of intents associated with a control link.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t intent_id_list[0]; + /**< h2xmle_description {Number of intents associated with a control link.} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct apm_module_ctrl_link_prop_id_intent_list_t apm_module_ctrl_link_prop_id_intent_list_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _APM_MODULE_API_H_ */ diff --git a/spf/api/apm/apm_sub_graph_api.h b/spf/api/apm/apm_sub_graph_api.h new file mode 100644 index 0000000..f23dcb3 --- /dev/null +++ b/spf/api/apm/apm_sub_graph_api.h @@ -0,0 +1,226 @@ +#ifndef _APM_SUB_GRAPH_API_H_ +#define _APM_SUB_GRAPH_API_H_ +/** + * \file apm_sub_graph_api.h + * \brief + * This file contains APM sub-graph related commands and events data structures definitions + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "apm_graph_properties.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/*====================================================================================================================*/ +/*====================================================================================================================*/ +#define APM_PARAM_ID_SUB_GRAPH_CONFIG 0x08001001 +/** h2xmlp_parameter {"Sub Graph Config", APM_PARAM_ID_SUB_GRAPH_CONFIG} + h2xmlp_description { ID of the parameter to configure the sub-graph properties.\n + This parameter ID must be used under command APM_CMD_GRAPH_OPEN \n } + h2xmlp_toolPolicy {RTC; Calibration} */ + +/* Immediately following this structure is a variable length array of structure objects corresponding to each sub-graph + configuration and properties. Length of the array is determined by number of sub-graphs being configured */ +#include "spf_begin_pack.h" +struct apm_param_id_sub_graph_cfg_t +{ + uint32_t num_sub_graphs; + /**< h2xmle_description {Number of sub-graphs being configured} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_param_id_sub_graph_cfg_t apm_param_id_sub_graph_cfg_t; + + +/* Immediately following this structure is a variable length array of sub-graph property structure. + Length of the array is determined by number of properties being configured */ +#include "spf_begin_pack.h" +struct apm_sub_graph_cfg_t +{ + uint32_t sub_graph_id; + /**< h2xmle_description {Valid ID of the sub-graph} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ + + uint32_t num_sub_graph_prop; + /**< h2xmle_description {Number of properties for this sub-graph } + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_sub_graph_cfg_t apm_sub_graph_cfg_t; + +/** @h2xmlgp_config {"SG_CFG", "APM_PARAM_ID_SUB_GRAPH_CONFIG", APM_PARAM_ID_SUB_GRAPH_CONFIG} + @h2xmlgp_description {Properties supported by APM_PARAM_ID_SUB_GRAPH_CONFIG} + @{ <-- Start of subgraph_cfg --> */ +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_SUB_GRAPH_PROP_ID_PERF_MODE 0x0800100E +/** @h2xmlp_property {"Performance Mode", APM_SUB_GRAPH_PROP_ID_PERF_MODE} + @h2xmlp_description {Sub-graph property ID Performance Mode} */ +/**< Enumeration for low power performance mode of subgraph */ +#define APM_SG_PERF_MODE_LOW_POWER 0x1 + +/**< Enumeration for low latency performance mode of subgraph */ +#define APM_SG_PERF_MODE_LOW_LATENCY 0x2 + +#include "spf_begin_pack.h" +struct apm_sg_prop_id_perf_mode_t +{ + uint32_t perf_mode; + /**< @h2xmle_rangeList {"Low Power"=APM_SG_PERF_MODE_LOW_POWER, + "Low Latency"=APM_SG_PERF_MODE_LOW_LATENCY} + @h2xmle_default {APM_SG_PERF_MODE_LOW_POWER} + @h2xmle_description {Performance Mode} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_sg_prop_id_perf_mode_t apm_sg_prop_id_perf_mode_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_SUB_GRAPH_PROP_ID_DIRECTION 0x0800100F +/** @h2xmlp_property {"SG Direction", APM_SUB_GRAPH_PROP_ID_DIRECTION} + @h2xmlp_description {Sub-graph property ID Direction} */ +/**< Enumeration for sub-graph direction Tx */ +#define APM_SUB_GRAPH_DIRECTION_TX 0x1 + +/**< Enumeration for sub-graph direction Rx */ +#define APM_SUB_GRAPH_DIRECTION_RX 0x2 + +#include "spf_begin_pack.h" +struct apm_sg_prop_id_direction_t +{ + uint32_t direction; + /**< @h2xmle_rangeList {"DONT_CARE"=0xFFFFFFFF, + "TX"=APM_SUB_GRAPH_DIRECTION_TX, + "RX"=APM_SUB_GRAPH_DIRECTION_RX} + @h2xmle_default {0xFFFFFFFF} + @h2xmle_description {Data flow direction for this sub-graph} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_sg_prop_id_direction_t apm_sg_prop_id_direction_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +#define APM_SUB_GRAPH_PROP_ID_SCENARIO_ID 0x08001010 +/** @h2xmlp_property {"Scenario ID", APM_SUB_GRAPH_PROP_ID_SCENARIO_ID} + @h2xmlp_description {Sub-graph property ID Scenario ID} */ + +/**< Enumeration for Scenario ID Audio Playback */ +#define APM_SUB_GRAPH_SID_AUDIO_PLAYBACK 0x1 + +/**< Enumeration for Scenario ID Audio Record */ +#define APM_SUB_GRAPH_SID_AUDIO_RECORD 0x2 + +/**< Enumeration for Scenario ID Voice call. */ +#define APM_SUB_GRAPH_SID_VOICE_CALL 0x3 + +#include "spf_begin_pack.h" +struct apm_sg_prop_id_scenario_id_t +{ + uint32_t scenario_id; + /**< @h2xmle_rangeList {"DONT_CARE"=0xFFFFFFFF, + "Audio Playback"=APM_SUB_GRAPH_SID_AUDIO_PLAYBACK, + "Audio Record"=APM_SUB_GRAPH_SID_AUDIO_RECORD, + "Voice Call"=APM_SUB_GRAPH_SID_VOICE_CALL} + @h2xmle_default {0xFFFFFFFF} + @h2xmle_description {Scenario ID for this sub-grpah} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_sg_prop_id_scenario_id_t apm_sg_prop_id_scenario_id_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ + +#define APM_SUB_GRAPH_PROP_ID_VSID 0x080010CC +/** @h2xmlp_property {"PROP_ID_VSID", APM_SUB_GRAPH_PROP_ID_VSID} + * @h2xmlp_description {Sub-graph property ID VSID} + * @h2xmlp_isVoice (true) */ + +/**< Enumeration for VSID Voice call with Subscription 1 and VSID 0x11C05000 */ +#define APM_SUB_GRAPH_VSID_SUB1 AR_NON_GUID(0x11C05000) + +/**< Enumeration for VSID Voice call with Subscription 2 and VSID 0x11DC5000 */ +#define APM_SUB_GRAPH_VSID_SUB2 AR_NON_GUID(0x11DC5000) + +/** Apps only mode with vocoder loopback on SUB1 */ +#define APM_SUB_GRAPH_VSID_VOC_LB_SUB1 AR_NON_GUID(0x12006000) + +/** Apps only mode with vocoder loopback on SUB2 */ +#define APM_SUB_GRAPH_VSID_VOC_LB_SUB2 AR_NON_GUID(0x121C6000) + +/**< Dont care value for VSID, which shall be enumerated by HLOS client at a later time. */ +#define APM_SUB_GRAPH_VSID_DONT_CARE AR_NON_GUID(0xFFFFFFFF) + +#include "spf_begin_pack.h" +struct apm_sg_prop_id_vsid_t +{ + uint32_t vsid; + /**< @h2xmle_rangeList {"VSID_DONT_CARE"=0xFFFFFFFF, + "VSID_SUB1"=0x11C05000; + "VSID_SUB2"=0x11DC5000} + @h2xmle_default {0xFFFFFFFF} + @h2xmle_description {VSID for this sub-grpah} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_sg_prop_id_vsid_t apm_sg_prop_id_vsid_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/** @} <-- End of subgraph_cfg -->*/ + +/*====================================================================================================================*/ +/*====================================================================================================================*/ +#define APM_PARAM_ID_SUB_GRAPH_LIST 0x08001005 +/** h2xmlp_parameter {"Sub Graph List", APM_PARAM_ID_SUB_GRAPH_LIST} + h2xmlp_description {IID of the parameter to configure the sub-graph list. \n + This parameter ID must be used under command APM_CMD_GRAPH_OPEN \n } + h2xmlp_toolPolicy {RTC; Calibration} */ + +/** + Immediately following this structure is a variable length array of structure objects corresponding to each sub-graph + configuration and properties. Length of the array is determined by number of sub-graphs being configured +*/ +#include "spf_begin_pack.h" +struct apm_param_id_sub_graph_list_t +{ + uint32_t num_sub_graphs; + /**< h2xmle_description {Number of sub-graphs being configured} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_param_id_sub_graph_list_t apm_param_id_sub_graph_list_t; + + +#include "spf_begin_pack.h" +struct apm_sub_graph_id_t +{ + uint32_t sub_graph_id; + /**< h2xmle_description {Sub-graph ID} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct apm_sub_graph_id_t apm_sub_graph_id_t; + +/*====================================================================================================================*/ +/*====================================================================================================================*/ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _APM_SUB_GRAPH_API_H_ */ diff --git a/spf/api/ar_utils/ar_defs.h b/spf/api/ar_utils/ar_defs.h new file mode 100644 index 0000000..2ec9a7d --- /dev/null +++ b/spf/api/ar_utils/ar_defs.h @@ -0,0 +1,17 @@ +#ifndef _ARDEFS_H +#define _ARDEFS_H +/** + * \file ar_defs.h + * \brief + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_osal_types.h" + + +#endif /* _ARDEFS_H */ + diff --git a/spf/api/ar_utils/ar_error_codes.h b/spf/api/ar_utils/ar_error_codes.h new file mode 100644 index 0000000..a9fbb31 --- /dev/null +++ b/spf/api/ar_utils/ar_error_codes.h @@ -0,0 +1,31 @@ +#ifndef _AR_ERROR_CODES_H_ +#define _AR_ERROR_CODES_H_ +/** + * \file ar_error_codes.h + * \brief + * This file contains common error code definitions to be used across multimedia code bases + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +#include "ar_defs.h" +#include "ar_osal_error.h" +/** @addtogroup ar_error_codes +@{ */ + +/** Status messages (error codes) returned by command responses. */ +typedef uint32_t ar_result_t; + +#define AR_DID_FAIL(x) ( AR_EOK != (x) ) + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _AR_ERROR_CODES_H_ */ diff --git a/spf/api/ar_utils/ar_guids.h b/spf/api/ar_utils/ar_guids.h new file mode 100644 index 0000000..a701a17 --- /dev/null +++ b/spf/api/ar_utils/ar_guids.h @@ -0,0 +1,129 @@ +#ifndef AR_GUIDS_H_ +#define AR_GUIDS_H_ +/** + * \file ar_guids.h + * \brief + * GUID interpretation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/** + * GUIDs are 32 bit numbers. + * +*/ + +/** + * An empty macro to mark non-GUIDs so that GUID script doesn't mistake the ID for a GUID + * + */ + +#define AR_NON_GUID(x) x + +/** + * GUID Owners + */ +/** + * GUID owner is Qualcomm. + */ +#define AR_GUID_OWNER_QC 0x0 +/** + * GUID owner is not-Qualcomm. + * All ISVs, OEMs & Customers must use this range. + */ +#define AR_GUID_OWNER_NON_QC 0x1 + /** Rest are reserved */ + +/** + * Mask for Owner + */ +#define AR_GUID_OWNER_MASK AR_NON_GUID(0xF0000000) +/** + * Shift for Owner + */ +#define AR_GUID_OWNER_SHIFT 28 + +/** + * GUID types + */ +/** + * Reserved GUID type. Used for legacy IDs. + */ +#define AR_GUID_TYPE_RESERVED 0x0 + +/** + * GUID type for Control commands. + */ +#define AR_GUID_TYPE_CONTROL_CMD 0x1 +/** + * GUID type for command responses of control commands. + */ +#define AR_GUID_TYPE_CONTROL_CMD_RSP 0x2 +/** + * GUID type for control events. + */ +#define AR_GUID_TYPE_CONTROL_EVENT 0x3 +/** + * GUID type for data commands + */ +#define AR_GUID_TYPE_DATA_CMD 0x4 +/** + * GUID type for data command responses. + */ +#define AR_GUID_TYPE_DATA_CMD_RSP 0x5 +/** + * GUID type for data events + */ +#define AR_GUID_TYPE_DATA_EVENT 0x6 +/** + * GUID type for module-id + */ +#define AR_GUID_TYPE_MODULE_ID 0x7 +/** + * GUID type for module's param & event-id + */ +#define AR_GUID_TYPE_PARAM_EVENT_ID 0x8 +/** + * GUID type for media format-id. + */ +#define AR_GUID_TYPE_FORMAT_ID 0x9 +/** + * GUID type is CAPI. + * All CAPI framework extensions, interface extensions + * their events, params use this. + * + * All module params & events must use AR_GUID_TYPE_PARAM_EVENT_ID + */ +#define AR_GUID_TYPE_CAPI 0xA + +/** + * GUID Type is miscellaneous. Used for container types etc + * + */ +#define AR_GUID_TYPE_MISC 0xB + +/** Rest are reserved */ + +/** + * Mask for GUID type + */ +#define AR_GUID_TYPE_MASK AR_NON_GUID(0x0F000000) +/** + * Shift for GUID type + */ +#define AR_GUID_TYPE_SHIFT 24 + +/** + * Zero is an invalid ID. + * To be used like NULL value for pointers. + */ +#define AR_GUID_INVALID 0 + + + +#endif /* AR_GUIDS_H_ */ + diff --git a/spf/api/ar_utils/ar_ids.h b/spf/api/ar_utils/ar_ids.h new file mode 100644 index 0000000..1e30f5b --- /dev/null +++ b/spf/api/ar_utils/ar_ids.h @@ -0,0 +1,85 @@ +#ifndef AR_IDS_H_ +#define AR_IDS_H_ +/** + * \file ar_ids.h + * \brief + * GUID interpretation + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_guids.h" +/** + * Zero is an invalid instance ID. + * + * It cannot be used for a container, subgraph or a module-instance. + */ +#define AR_INVALID_INSTANCE_ID 0 + +/** + * spf static instance ID range is from 1-0x2000 (including both ends) + * E.g. 1 is APM_MODULE_INSTANCE_ID + * + * + * Module instance ID, container (instance) ID, subgraph (instance) ID must all be unique. + * i.e. a number used for module-instance-ID cannot be used for container-ID and so on. + * + * The below ranges are applicable for module-instance-ID, subgraph ID, and container ID. + * + */ +#define AR_SPF_STATIC_INSTANCE_ID_RANGE_BEGIN 1 +#define AR_SPF_STATIC_INSTANCE_ID_RANGE_END AR_NON_GUID(0x2000) + +/** + * Static instance ID range for platform driver 0x2001-0x4000 (including both ends) + */ +#define AR_PLATFORM_DRIVER_STATIC_INSTANCE_ID_RANGE_BEGIN AR_NON_GUID(0x2001) +#define AR_PLATFORM_DRIVER_STATIC_INSTANCE_ID_RANGE_END AR_NON_GUID(0x4000) + +/** + * Dynamic instance IDs starts from 0x4001. ARCT uses this range to assign instance IDs. + * The range includes this number. + * + */ +#define AR_DYNAMIC_INSTANCE_ID_RANGE_BEGIN AR_NON_GUID(0x4001) + + +/** + * Following masks apply to Port-IDs + * + * Port-ID has to be unique for the module. + * Two modules can have same port-ID + * + * Port-ID cannot be zero. + */ + +#define AR_PORT_ID_INVALID 0 +/** + * Control ports have MSB set. Data ports have MSB clear. + * Static Control Ports have 2 Most significant bits set + */ +#define AR_PORT_DATA_TYPE_MASK AR_NON_GUID(0x80000000) +#define AR_PORT_DATA_TYPE_SHIFT 31 +#define AR_PORT_DATA_TYPE_DATA 0 +#define AR_PORT_DATA_TYPE_CONTROL 1 + +#define AR_CONTROL_PORT_TYPE_MASK AR_NON_GUID(0x40000000) +#define AR_CONTROL_PORT_TYPE_SHIFT 30 +#define AR_CONTROL_PORT_TYPE_STATIC 1 +#define AR_CONTROL_PORT_TYPE_DYNAMIC 0 + +/** + * LSB determines if a port id input (0) or output (1) + * input - even + * output - odd + */ +#define AR_PORT_DIR_TYPE_MASK AR_NON_GUID(0x00000001) +#define AR_PORT_DIR_TYPE_SHIFT 0 +#define AR_PORT_DIR_TYPE_INPUT 0 +#define AR_PORT_DIR_TYPE_OUTPUT 1 + +#endif /* AR_IDS_H_ */ + diff --git a/spf/api/ar_utils/ar_spf_cmd_api.h b/spf/api/ar_utils/ar_spf_cmd_api.h new file mode 100644 index 0000000..144a48b --- /dev/null +++ b/spf/api/ar_utils/ar_spf_cmd_api.h @@ -0,0 +1,128 @@ +/** + * \file ar_spf_cmd.h + * \brief + * This file contains the API definitions for the commands related to the global shared memory + * used between client<->module and module<->module + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +#ifndef _AR_SPF_CMD_API_H_ +#define _AR_SPF_CMD_API_H_ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** @ingroup spf_apm_commands + This command carries an OOB payload from global shared memory (#APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS) + and used by the client to signal module to read the payload and handle accordingly. + + OOB payload structure and the communication protocol is private to client and module. + + @gpr_hdr_fields + Opcode -- AR_SPF_MSG_GLOBAL_SH_MEM + + @msgpayload + ar_spf_msg_global_sh_mem_t + + @par + This command can be issued for all the module instance IDs that were + configured at least once using #APM_CMD_GRAPH_OPEN. + + @return + GPR_IBASIC_RSP_RESULT + */ +#define AR_SPF_MSG_GLOBAL_SH_MEM 0x0100105B + +/** Definition of the is_ack_required flag bitmask. */ +#define AR_SPF_MSG_GLOBAL_SH_MEM_BIT_MASK_IS_ACK_NOT_REQUIRED (0x00000001UL) + +/** Definition of the is_memory_release flag bitmask. */ +#define AR_SPF_MSG_GLOBAL_SH_MEM_BIT_MASK_IS_MEM_RELEASE (0x00000002UL) + +/** @ingroup spf_apm_commands + Payload for #AR_SPF_MSG_GLOBAL_SH_MEM. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct ar_spf_msg_global_sh_mem_t +{ + uint32_t shmem_id; + /**< A unique ID used by the client to map the global memory regions using + command #APM_CMD_GLOBAL_SHARED_MEM_MAP_REGIONS. + */ + + uint32_t property_flag; + /**< Configures property for this command. + + @values 0x00000000 through 0x00000001 + + @contcell + @subhead{Bit 0 -- is_ack_not_required flag} + + Indicates if acknowledgment is needed for this command: + - 1 -- Ack is not needed. This is useful if client only want to send the information and not waiting for the + response. Client may still receive #GPR_IBASIC_RSP_RESULT in response to this command if command fails to reach the + destination. + + - 0 -- Ack is needed. This is a common case where client wants to wait for the response. + + @subhead{Bit 1 -- is_release_memory flag} + + Indicates if client/HLOS wants module to release the specified shared memory. This can be used for cleanup or during + error handling. + - 1 -- release; used when client/HLOS wants module to stop reading/writing from/into the specified shared memory. + If shmem_size is zero then client/HLOS wants module to stop using the entire shared memory region. This can be used + just before shared memory is going to be unmapped. + If shmem_size is non zero then client/HLOs wants module to stop using the memory block specified with msw,lsw. + + - 0 -- Default value; used when client wants module to read/use the specified shared memory. + + @subhead{Bits 31 to 2} + + Reserved and must be set to 0. */ + uint32_t shmem_addr_lsw; + /**< Lower 32 bits of the physical/Virtual/byte-offset address value. + + This refers to the memory which is used by client/module to communicate. + + If global shared memory was mapped with offset property (Bit 2 is set) + then this value is a byte offset from the base virtual address of + global shared memory. + + If global shared memory was not mapped with offset property (Bit 2 is unset) + then this value either refers to a physical or a virtual address depending on the + Bit 0 configuration in the global shared memory map property. + + @values Non-zero 32-bit value */ + + uint32_t shmem_addr_msw; + /**< Upper 32 bits of the physical/Virtual address value. + + @valuesbul + - For offset based addressing, this field must be set to 0. + - For a 32-bit shared memory address, this field must be set to 0. + - For a 36-bit address, bits 31 to 4 must be set to 0. + - For a 64-bit shared memory address, non-zero 32-bit value. + @tablebulletend */ + + uint32_t shmem_size; + /**< Number of bytes in the shared memory used by the client/modules to communicate. + Base virtual address of this memory will be retrieved from the + physical/virtual/byte-offset address value specified in this payload. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct ar_spf_msg_global_sh_mem_t ar_spf_msg_global_sh_mem_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _AR_SPF_CMD_API_H_ */ diff --git a/spf/api/ar_utils/generic/ar_msg.h b/spf/api/ar_utils/generic/ar_msg.h new file mode 100644 index 0000000..db4e2da --- /dev/null +++ b/spf/api/ar_utils/generic/ar_msg.h @@ -0,0 +1,111 @@ +/** + * \file ar_msg.h + * \brief + * This file contains a utility for generating diagnostic messages. + * This file defines macros for printing debug messages on the target or in simulation. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _AR_MSG_H +#define _AR_MSG_H + +#include "ar_defs.h" +#include "ar_guids.h" +#include + +/** Enable (1) or disable (0) the debug messagef */ +#define ar_log_debugmsg_enable 1 + +// use ar osal for non diag usecases +#include "ar_osal_log.h" + +// Undefine earlier definitions of diag declerations +#undef MSG +#undef MSG_1 +#undef MSG_2 +#undef MSG_3 +#undef MSG_4 +#undef MSG_5 +#undef MSG_6 +#undef MSG_7 +#undef MSG_8 +#undef MSG_9 +#undef MSG_FATAL +#undef AR_MSG_ISLAND +#undef AR_MSG + +// Undefine priority messages +#undef DBG_LOW_PRIO +#undef DBG_MED_PRIO +#undef DBG_HIGH_PRIO +#undef DBG_ERROR_PRIO +#undef DBG_FATAL_PRIO +#undef MSG_LEGACY_ERROR +#undef MSG_LEGACY_HIGH +#undef MSG_LEGACY_MED +#undef MSG_LEGACY_LOW + + +// Legacy debug priority messages +#define DBG_LOW_PRIO AR_LOW_PRIO /**< Low priority debug message. */ +#define DBG_MED_PRIO AR_MED_PRIO /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO AR_HIGH_PRIO /**< High priority debug message. */ +#define DBG_ERROR_PRIO AR_ERROR_PRIO /**< Error priority debug message. */ +#define DBG_FATAL_PRIO AR_FATAL_PRIO /**< Fatal priority debug message. */ +#define MSG_LEGACY_ERROR DBG_ERROR_PRIO +#define MSG_LEGACY_HIGH DBG_HIGH_PRIO +#define MSG_LEGACY_MED DBG_MED_PRIO +#define MSG_LEGACY_LOW DBG_LOW_PRIO + + +#define AR_MSG_ISLAND AR_MSG + +/* Undefine earlier definitions of MSG macros, and define for SIM */ +#define MSG AR_MSG_LOG +#define MSG_1 AR_MSG_LOG +#define MSG_2 AR_MSG_LOG +#define MSG_3 AR_MSG_LOG +#define MSG_4 AR_MSG_LOG +#define MSG_5 AR_MSG_LOG +#define MSG_6 AR_MSG_LOG +#define MSG_7 AR_MSG_LOG +#define MSG_8 AR_MSG_LOG +#define MSG_9 AR_MSG_LOG +#define MSG_FATAL AR_MSG_LOG + +#undef AR_MSG_TAG +#define AR_MSG_TAG ( NULL ) + +#ifdef __FILENAME__ +#define LOCAL_FILE_NAME AR_NON_GUID(__FILENAME__) +#elif __FILE__ +#define LOCAL_FILE_NAME AR_NON_GUID(__FILE__) +#endif + +#undef AR_MSG_LOG +#define AR_MSG_LOG( xx_ss_sid, xx_ss_mask, xx_fmt, ...) \ + do { \ + if (ar_log_debugmsg_enable) \ + { \ + static const char *msg_tag = AR_MSG_TAG; \ + static const char filename[] = LOCAL_FILE_NAME; \ + static const uint32_t line_no = __LINE__; \ + ar_log( xx_ss_mask, msg_tag, filename, line_no, xx_fmt, ##__VA_ARGS__); \ + if (DBG_FATAL_PRIO == (xx_ss_mask)) \ + { \ + assert(0); \ + } \ + } \ + } while(0) + +#define AR_MSG_DFLT_MSG_SSID MSG_SSID_QDSP6 + +/* This Logging macro supports variable arguments*/ +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + AR_MSG_LOG( AR_MSG_DFLT_MSG_SSID, xx_ss_mask, xx_fmt, ##__VA_ARGS__ ) + + +#endif // #ifndef _AR_MSG_H diff --git a/spf/api/ar_utils/hexagon/sim/ar_msg.h b/spf/api/ar_utils/hexagon/sim/ar_msg.h new file mode 100644 index 0000000..d907dd8 --- /dev/null +++ b/spf/api/ar_utils/hexagon/sim/ar_msg.h @@ -0,0 +1,364 @@ +/** + * \file ar_msg.h + * \brief + * This file contains a utility for generating diagnostic messages. + * This file defines macros for printing debug messages on the target or in simulation + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _AR_MSG_H +#define _AR_MSG_H + +#include "ar_defs.h" +#include "ar_guids.h" +#include +#include "msg.h" +#include "msgcfg.h" + +// user pd +#if !defined(ROOTPD_AVS_INTEGRATION) +#include "cosim_log_island_i.h" +#else // root pd +#include "cosim_log_rpd_island_i.h" +#endif + +/** Enable (1) or disable (0) the debug messagef */ +#define ar_log_debugmsg_enable 1 + +/** Variable for setting priority threshold for the debug message in simulator. */ +extern uint8_t ar_logs_debugmsg_lowest_prio; + +// use ar osal for non diag usecases +#include "ar_osal_log.h" + +// Undefine earlier definitions of diag declerations +#undef MSG +#undef MSG_1 +#undef MSG_2 +#undef MSG_3 +#undef MSG_4 +#undef MSG_5 +#undef MSG_6 +#undef MSG_7 +#undef MSG_8 +#undef MSG_9 +#undef MSG_FATAL +#undef AR_MSG_ISLAND +#undef AR_MSG + +// Undefine priority messages +#undef DBG_LOW_PRIO +#undef DBG_MED_PRIO +#undef DBG_HIGH_PRIO +#undef DBG_ERROR_PRIO +#undef DBG_FATAL_PRIO + + +// Legacy debug priority messages +#define DBG_LOW_PRIO MSG_LEGACY_LOW /**< Low priority debug message. */ +#define DBG_MED_PRIO MSG_LEGACY_MED /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO MSG_LEGACY_HIGH /**< High priority debug message. */ +#define DBG_ERROR_PRIO MSG_LEGACY_ERROR /**< Error priority debug message. */ +#define DBG_FATAL_PRIO MSG_LEGACY_FATAL /**< Fatal priority debug message. */ + +#ifdef __FILENAME__ +#define LOCAL_FILE_NAME AR_NON_GUID(__FILENAME__) +#elif __FILE__ +#define LOCAL_FILE_NAME AR_NON_GUID(__FILE__) +#endif + +#ifndef LOCAL_FILE_NAME +#define LOCAL_FILE_NAME AR_NON_GUID("") +#endif + +// user pd +#if !defined(ROOTPD_AVS_INTEGRATION) + +#define AR_MSG_DOMAIN_ID 2 +#define PROC_DOMAIN " ADSP: " + +#undef AR_MSG_LOG +#define AR_MSG_LOG(num_args, priority, xx_fmt, ...) \ + do \ + { \ + if (ar_log_debugmsg_enable && (priority >= ar_logs_debugmsg_lowest_prio)) \ + { \ + static const char xx_ar_log_format[] = (xx_fmt); \ + static const char xx_ar_log_file[] = LOCAL_FILE_NAME; \ + \ + static const ar_dbg_log_msg_t xx_ar_log_msg = {.msg_header.b.msg_line = __LINE__, \ + .msg_header.b.msg_priority = priority, \ + .msg_header.b.domain_id = AR_MSG_DOMAIN_ID, \ + .msg_header.b.num_words = 2 + num_args, \ + .msg_format_ptr = (char *)xx_ar_log_format, \ + .msg_filename_ptr = xx_ar_log_file }; \ + uint32_t cycles = (uint32_t)(hexagon_sim_read_pcycles() >> AR_DBG_LOG_CYCLES_SHIFT); \ + ar_dbg_log(&xx_ar_log_msg, cycles, ##__VA_ARGS__); \ + if (DBG_FATAL_PRIO == (priority)) \ + { \ + assert(0); \ + } \ + } \ + } while (0) + +#undef AR_MSG_ISLAND_LOG +#define AR_MSG_ISLAND_LOG(num_args, priority, xx_fmt, ...) \ + do \ + { \ + if (ar_log_debugmsg_enable && (priority >= ar_logs_debugmsg_lowest_prio)) \ + { \ + static const char xx_ar_log_format[] = (xx_fmt); \ + static const char xx_ar_log_file[] = LOCAL_FILE_NAME; \ + \ + static const ar_dbg_log_msg_t xx_ar_log_msg = {.msg_header.b.msg_line = __LINE__, \ + .msg_header.b.msg_priority = priority, \ + .msg_header.b.domain_id = AR_MSG_DOMAIN_ID, \ + .msg_header.b.num_words = 2 + num_args, \ + .msg_format_ptr = (char *)xx_ar_log_format, \ + .msg_filename_ptr = xx_ar_log_file }; \ + uint32_t cycles = 0; \ + ar_dbg_log(&xx_ar_log_msg, cycles, ##__VA_ARGS__); \ + if (DBG_FATAL_PRIO == (priority)) \ + { \ + assert(0); \ + } \ + } \ + } while (0) + +#endif + +// rootpd +#if defined(ROOTPD_AVS_INTEGRATION) + +#define AR_MSG_DOMAIN_ID 1 +#define PROC_DOMAIN " MDSP: " + +#undef AR_MSG_LOG +#define AR_MSG_LOG(num_args, priority, xx_fmt, ...) \ + do \ + { \ + if (ar_log_debugmsg_enable && (priority >= ar_logs_debugmsg_lowest_prio)) \ + { \ + static const char xx_ar_log_format[] QSR_ATTR = (xx_fmt); \ + static const char xx_ar_log_file[] QSR_ATTR = LOCAL_FILE_NAME; \ + static const ar_rpd_dbg_log_msg_t xx_ar_log_msg QSR_ATTR = { .msg_header.b.msg_line = __LINE__, \ + .msg_header.b.msg_priority = priority, \ + .msg_header.b.domain_id = AR_MSG_DOMAIN_ID, \ + .msg_header.b.num_words = 2 + num_args, \ + .msg_format_ptr = (char *)xx_ar_log_format, \ + .msg_filename_ptr = xx_ar_log_file }; \ + uint32_t cycles = (uint32_t)(hexagon_sim_read_pcycles() >> AR_DBG_LOG_CYCLES_SHIFT); \ + ar_rpd_dbg_log(&xx_ar_log_msg, cycles, ##__VA_ARGS__); \ + if (DBG_FATAL_PRIO == (priority)) \ + { \ + assert(0); \ + } \ + } \ + } while (0) + +#endif + +#undef DBG_MSG_CAST +#define DBG_MSG_CAST (uint32_t) + +#define MSG(xx_ss_id, xx_ss_mask, xx_fmt) AR_MSG_LOG(0, xx_ss_mask, xx_fmt) + +#define MSG_1(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1) AR_MSG_LOG(1, xx_ss_mask, xx_fmt, DBG_MSG_CAST xx_arg1) + +#define MSG_2(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2) \ + AR_MSG_LOG(2, xx_ss_mask, xx_fmt, DBG_MSG_CAST xx_arg1, DBG_MSG_CAST xx_arg2) + +#define MSG_3(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3) \ + AR_MSG_LOG(3, xx_ss_mask, xx_fmt, DBG_MSG_CAST xx_arg1, DBG_MSG_CAST xx_arg2, DBG_MSG_CAST xx_arg3) + +#define MSG_4(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4) \ + AR_MSG_LOG(4, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4) + +#define MSG_5(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5) \ + AR_MSG_LOG(5, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5) + +#define MSG_6(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5, xx_arg6) \ + AR_MSG_LOG(6, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5, \ + DBG_MSG_CAST xx_arg6) + +#define MSG_7(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5, xx_arg6, xx_arg7) \ + AR_MSG_LOG(7, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5, \ + DBG_MSG_CAST xx_arg6, \ + DBG_MSG_CAST xx_arg7) + +#define MSG_8(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5, xx_arg6, xx_arg7, xx_arg8) \ + AR_MSG_LOG(8, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5, \ + DBG_MSG_CAST xx_arg6, \ + DBG_MSG_CAST xx_arg7, \ + DBG_MSG_CAST xx_arg8) + +#define MSG_9( \ + xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5, xx_arg6, xx_arg7, xx_arg8, xx_arg9) \ + AR_MSG_LOG(9, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5, \ + DBG_MSG_CAST xx_arg6, \ + DBG_MSG_CAST xx_arg7, \ + DBG_MSG_CAST xx_arg8, \ + DBG_MSG_CAST xx_arg9) + +#define ISLAND_MSG(xx_ss_id, xx_ss_mask, xx_fmt) AR_MSG_ISLAND_LOG(0, xx_ss_mask, xx_fmt) + +#define ISLAND_MSG_1(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1) \ + AR_MSG_ISLAND_LOG(1, xx_ss_mask, xx_fmt, DBG_MSG_CAST xx_arg1) + +#define ISLAND_MSG_2(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2) \ + AR_MSG_ISLAND_LOG(2, xx_ss_mask, xx_fmt, DBG_MSG_CAST xx_arg1, DBG_MSG_CAST xx_arg2) + +#define ISLAND_MSG_3(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3) \ + AR_MSG_ISLAND_LOG(3, xx_ss_mask, xx_fmt, DBG_MSG_CAST xx_arg1, DBG_MSG_CAST xx_arg2, DBG_MSG_CAST xx_arg3) + +#define ISLAND_MSG_4(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4) \ + AR_MSG_ISLAND_LOG(4, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4) + +#define ISLAND_MSG_5(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5) \ + AR_MSG_ISLAND_LOG(5, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5) + +#define ISLAND_MSG_6(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5, xx_arg6) \ + AR_MSG_ISLAND_LOG(6, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5, \ + DBG_MSG_CAST xx_arg6) + +#define ISLAND_MSG_7(xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5, xx_arg6, xx_arg7) \ + AR_MSG_ISLAND_LOG(7, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5, \ + DBG_MSG_CAST xx_arg6, \ + DBG_MSG_CAST xx_arg7) + +#define ISLAND_MSG_8( \ + xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5, xx_arg6, xx_arg7, xx_arg8) \ + AR_MSG_ISLAND_LOG(8, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5, \ + DBG_MSG_CAST xx_arg6, \ + DBG_MSG_CAST xx_arg7, \ + DBG_MSG_CAST xx_arg8) + +#define ISLAND_MSG_9( \ + xx_ss_id, xx_ss_mask, xx_fmt, xx_arg1, xx_arg2, xx_arg3, xx_arg4, xx_arg5, xx_arg6, xx_arg7, xx_arg8, xx_arg9) \ + AR_MSG_ISLAND_LOG(9, \ + xx_ss_mask, \ + xx_fmt, \ + DBG_MSG_CAST xx_arg1, \ + DBG_MSG_CAST xx_arg2, \ + DBG_MSG_CAST xx_arg3, \ + DBG_MSG_CAST xx_arg4, \ + DBG_MSG_CAST xx_arg5, \ + DBG_MSG_CAST xx_arg6, \ + DBG_MSG_CAST xx_arg7, \ + DBG_MSG_CAST xx_arg8, \ + DBG_MSG_CAST xx_arg9) + +/* Supporting macros for MM_MSG() logging utility. + * MM_MSG is supported on both target and simulation builds. */ + +/* Utility to get variable argument + * Slide the variable arguments to get the string '_N' to be appended */ +#define AR_VA_NUM_ARGS_IMPL(a, b, c, d, e, f, g, h, i, j, _N, ...) _N +#define AR_VA_NUM_ARGS(...) AR_VA_NUM_ARGS_IMPL(, ##__VA_ARGS__, _9, _8, _7, _6, _5, _4, _3, _2, _1, ) +/* Concatenates string x with y*/ +#define AR_TOKENPASTE(x, y) x##y + +/*Macro parses the text to MSG with _N as suffix, where N = {1, 2, 3, .... ,9} */ +#define AR_MSG_x(_N) AR_TOKENPASTE(MSG, _N) + +/*Macro parses the text to MSG with _N as suffix, where N = {1, 2, 3, .... ,9} */ +#define AR_MSG_ISLAND_x(_N) AR_TOKENPASTE(ISLAND_MSG, _N) + +#ifndef MSG_SSID_QDSP6 +#define MSG_SSID_QDSP6 +#endif // AR_MSG_DFLT_MSG_SSID + +#if defined(ISLAND_TEST) +#undef AR_MSG_ISLAND +#define AR_MSG_ISLAND AR_NON_GUID(_AR_MSG_ISLAND_) +#else +#undef AR_MSG_ISLAND +#define AR_MSG_ISLAND AR_NON_GUID(AR_MSG) +#endif + +/* This Logging macro supports variable arguments*/ +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + AR_MSG_x(AR_VA_NUM_ARGS(__VA_ARGS__))(MSG_SSID_QDSP6, xx_ss_mask, PROC_DOMAIN xx_fmt, ##__VA_ARGS__) + +/* This Logging macro supports variable arguments*/ +#define _AR_MSG_ISLAND_(xx_ss_mask, xx_fmt, ...) \ + AR_MSG_ISLAND_x(AR_VA_NUM_ARGS(__VA_ARGS__))(MSG_SSID_QDSP6, xx_ss_mask, PROC_DOMAIN xx_fmt, ##__VA_ARGS__) +#endif // #ifndef _AR_MSG_H diff --git a/spf/api/ar_utils/hexagon/tgt/shared/ar_msg.h b/spf/api/ar_utils/hexagon/tgt/shared/ar_msg.h new file mode 100644 index 0000000..0f93a03 --- /dev/null +++ b/spf/api/ar_utils/hexagon/tgt/shared/ar_msg.h @@ -0,0 +1,158 @@ +/** + * \file ar_msg.h + * \brief + * This file contains a utility for generating diagnostic messages. + * This file defines macros for printing debug messages on the target or in simulation. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _AR_MSG_H +#define _AR_MSG_H + +#include "ar_guids.h" +#include "HAP_farf.h" + +/** MSG to FARF converter & Diag utilities needed only for .so files.*/ +/* Include Diag message utitlity headers */ +#include "msg.h" +#include "msgcfg.h" + + +//map elite to Diag mask +#define DBG_LOW_PRIO MSG_LEGACY_LOW /**< Low priority debug message. */ +#define DBG_MED_PRIO MSG_LEGACY_MED /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO MSG_LEGACY_HIGH /**< High priority debug message. */ +#define DBG_ERROR_PRIO MSG_LEGACY_ERROR /**< Error priority debug message. */ +#define DBG_FATAL_PRIO MSG_LEGACY_FATAL /**< Fatal priority debug message. */ + +#ifdef __FILENAME__ +#define LOCAL_FILE_NAME AR_NON_GUID(__FILENAME__) +#elif __FILE__ +#define LOCAL_FILE_NAME AR_NON_GUID(__FILE__) +#endif + +#define AR_MSG_ISLAND AR_MSG //for now - pending discussion to add hap_debug_v2_uimage + +static inline uint16 diag_to_farf_mask_map(uint16 xx_ss_mask) { + switch(xx_ss_mask) { + case MSG_LEGACY_LOW: + return HAP_LEVEL_LOW; + case MSG_LEGACY_MED: + return HAP_LEVEL_MEDIUM; + case MSG_LEGACY_HIGH: + return HAP_LEVEL_HIGH; + case MSG_LEGACY_ERROR: + return HAP_LEVEL_ERROR; + case MSG_LEGACY_FATAL: + return HAP_LEVEL_FATAL; + default: + return HAP_LEVEL_ERROR; + } +} + +#define MSG_FARF(xx_ss_mask, xx_fmt...) \ + do { \ + if(0 == (HAP_debug_v2)) { \ + _HAP_debug_v2( \ + diag_to_farf_mask_map(xx_ss_mask), \ + LOCAL_FILE_NAME, \ + __LINE__, \ + xx_fmt); \ + } else { \ + HAP_debug_v2( \ + diag_to_farf_mask_map(xx_ss_mask), \ + LOCAL_FILE_NAME, \ + __LINE__, \ + xx_fmt); \ + } \ + } while (0) + +#undef MSG +#undef MSG_1 +#undef MSG_2 +#undef MSG_3 +#undef MSG_4 +#undef MSG_5 +#undef MSG_6 +#undef MSG_7 +#undef MSG_8 +#undef MSG_9 +#undef MSG_FATAL +#undef MSG_SPRINTF_1 +#undef MSG_SPRINTF_2 +#undef MSG_SPRINTF_3 +#undef MSG_SPRINTF_4 +#undef MSG_SPRINTF_5 +#undef MSG_SPRINTF_6 +#undef MSG_SPRINTF_7 +#undef MSG_SPRINTF_8 +#undef MSG_SPRINTF_FMT_VAR_3 + +// MSG APIs +#define MSG(xx_ss_id, xx_ss_mask, xx_fmt) \ + MSG_FARF(xx_ss_mask,xx_fmt) +#define MSG_1(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_2(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_3(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_4(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_5(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_6(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_7(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_8(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_9(xx_ss_id, xx_ss_mask, xx_fmt,...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) + +// MSG_sprintf APIs +#define MSG_SPRINTF_1(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_SPRINTF_2(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_SPRINTF_3(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_SPRINTF_4(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_SPRINTF_5(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_SPRINTF_6(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_SPRINTF_7(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) +#define MSG_SPRINTF_8(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) + +#define MSG_SPRINTF_FMT_VAR_3(xx_ss_id, xx_ss_mask, xx_fmt, ...) \ + MSG_FARF(xx_ss_mask,xx_fmt,##__VA_ARGS__) + +/* Supporting macros for AR_MSG() logging utility. + * AR_MSG is supported on both target and simulation builds. */ + +/* Utility to get variable argument + * Slide the variable arguments to get the string '_N' to be appended */ +#define AR_VA_NUM_ARGS_IMPL(a, b, c, d, e, f, g, h, i, j, _N, ...) _N +#define AR_VA_NUM_ARGS(...) AR_VA_NUM_ARGS_IMPL(, ##__VA_ARGS__, _9, _8, _7, _6, _5, _4, _3, _2, _1, ) +/* Concatenates string x with y*/ +#define AR_TOKENPASTE(x, y) x##y + +/*Macro parses the text to MSG with _N as suffix, where N = {1, 2, 3, .... ,9} */ +#define AR_MSG_x(_N) AR_TOKENPASTE(MSG, _N) + +#ifndef MSG_SSID_DFLT +#define MSG_SSID_DFLT MSG_SSID_QDSP6 +#endif // MSG_SSID_DFLT + +/* This Logging macro supports variable arguments*/ +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + AR_MSG_x(AR_VA_NUM_ARGS(__VA_ARGS__))(MSG_SSID_DFLT, xx_ss_mask, xx_fmt, ##__VA_ARGS__) + +#endif // #ifndef _AR_MSG_H diff --git a/spf/api/ar_utils/hexagon/tgt/static/ar_msg.h b/spf/api/ar_utils/hexagon/tgt/static/ar_msg.h new file mode 100644 index 0000000..3a82fa0 --- /dev/null +++ b/spf/api/ar_utils/hexagon/tgt/static/ar_msg.h @@ -0,0 +1,101 @@ +/** + * \file ar_msg.h + * \brief + * This file contains a utility for generating diagnostic messages. + * This file defines macros for printing debug messages on the target or in simulation. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _AR_MSG_H +#define _AR_MSG_H + +#include "ar_defs.h" +#include + +//*************************************************************************** +// Debug message enable flags +//*************************************************************************** + + +//*************************************************************************** +// Define MSG() macros +//*************************************************************************** + +/** If the target supports diag logging use diag msg utils. Currently only hexagon targets support diag. + * + * If the target doesn't support diag logging use ar logging. Casa logging utils + * can be used on sim/arm/win32. ar logging also has support for cosim depending + * upon the compiler flags. + * + * NOTE: + * Techinically diag logging can also be featurized under platform specific ar osal source files but + * the downside is Qshrink will not work. Because the Qshrink compresses the messages at compile + * time by looking for MSG_1, MSG_2 .. tags and it will not compress the ar_osal_log() prints. + * In future, if Qshrink supports ar_osal_log() then diag utils can be featurized in ar_osal_log.c + * itself. + * + */ + +/** + * Maps AR_MSG -> Diag macros MSG(), MSG_!, MSG_2 .. + */ +#include "msg.h" +#include "msgcfg.h" + +// Legacy debug priority messages +#define DBG_LOW_PRIO MSG_LEGACY_LOW /**< Low priority debug message. */ +#define DBG_MED_PRIO MSG_LEGACY_MED /**< Medium priority debug message. */ +#define DBG_HIGH_PRIO MSG_LEGACY_HIGH /**< High priority debug message. */ +#define DBG_ERROR_PRIO MSG_LEGACY_ERROR /**< Error priority debug message. */ +#define DBG_FATAL_PRIO MSG_LEGACY_FATAL /**< Fatal priority debug message. */ + +#if defined(USES_AUDIO_IN_ISLAND) +#define AR_MSG_ISLAND(xx_ss_mask, xx_fmt, ...) MICRO_MSG(MSG_SSID_QDSP6, xx_ss_mask, xx_fmt, ##__VA_ARGS__) +#else +#define AR_MSG_ISLAND AR_MSG +#endif + + +// determining the process domain based on the DSP mode information in the build env +#ifdef MDSPMODE +#define PROC_DOMAIN " MDSP: " +#endif + +#ifdef ADSPMODE +#define PROC_DOMAIN " ADSP: " +#endif + +#ifdef CDSPMODE +#define PROC_DOMAIN " CDSP: " +#endif + +#ifdef SDSPMODE +#define PROC_DOMAIN " SDSP: " +#endif + +#ifndef PROC_DOMAIN +#define PROC_DOMAIN " ADSP: " +#endif + +/* Utility to get variable argument + * Slide the variable arguments to get the string '_N' to be appended */ +#define AR_VA_NUM_ARGS_IMPL(a, b, c, d, e, f, g, h, i, j, _N, ...) _N +#define AR_VA_NUM_ARGS(...) AR_VA_NUM_ARGS_IMPL(, ##__VA_ARGS__, _9, _8, _7, _6, _5, _4, _3, _2, _1, ) +/* Concatenates string x with y*/ +#define AR_TOKENPASTE(x, y) x##y + +/*Macro parses the text to MSG with _N as suffix, where N = {1, 2, 3, .... ,9} */ +#define AR_MSG_x(_N) AR_TOKENPASTE(MSG, _N) + +#ifndef MSG_SSID_DFLT +#define MSG_SSID_DFLT MSG_SSID_QDSP6 +#endif // MSG_SSID_DFLT + +/* This Logging macro supports variable arguments*/ +#define AR_MSG(xx_ss_mask, xx_fmt, ...) \ + AR_MSG_x(AR_VA_NUM_ARGS(__VA_ARGS__))(MSG_SSID_QDSP6, xx_ss_mask, PROC_DOMAIN xx_fmt, ##__VA_ARGS__) + +#endif // _AR_MSG_H diff --git a/spf/api/ar_utils/spf_begin_pack.h b/spf/api/ar_utils/spf_begin_pack.h new file mode 100644 index 0000000..c3716ee --- /dev/null +++ b/spf/api/ar_utils/spf_begin_pack.h @@ -0,0 +1,23 @@ +/** + * \file spf_begin_pack.h + * \brief + * This file defines pack attributes for different compilers to be used to pack spf API data structures + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#if defined( __qdsp6__ ) +/* No packing atrributes for Q6 compiler; all structs manually packed */ +#elif defined( __GNUC__ ) +#elif defined( __arm__ ) + __packed +#elif defined( _MSC_VER ) + #pragma warning( disable:4103 ) /* Another header changing "pack". */ + #pragma pack( push, 1 ) +#elif defined( __H2XML__) +#else + #error "Unsupported compiler." +#endif /* __GNUC__ */ diff --git a/spf/api/ar_utils/spf_begin_pragma.h b/spf/api/ar_utils/spf_begin_pragma.h new file mode 100644 index 0000000..8f7e4ba --- /dev/null +++ b/spf/api/ar_utils/spf_begin_pragma.h @@ -0,0 +1,23 @@ +/** + * \file spf_begin_pragma.h + * \brief + * This file defines pragma to ignore zero length array warnings for different compilers + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#if defined( __qdsp6__ ) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wzero-length-array" +#elif defined( __GNUC__ ) +#elif defined( __arm__ ) +#elif defined( _MSC_VER ) + #pragma warning( push ) + #pragma warning( disable:4200 ) +#elif defined( __H2XML__) +#else + #error "Unsupported compiler." +#endif diff --git a/spf/api/ar_utils/spf_end_pack.h b/spf/api/ar_utils/spf_end_pack.h new file mode 100644 index 0000000..538ee4e --- /dev/null +++ b/spf/api/ar_utils/spf_end_pack.h @@ -0,0 +1,25 @@ +/** + * \file spf_end_pack.h + * \brief + * This file defines pack attributes for different compilers to be used to pack spf API data structures + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#if defined( __qdsp6__ ) +/* No packing atrributes for Q6 compiler; all structs manually packed */ +#elif defined( __XTENSA__) +#elif defined( __GNUC__ ) + __attribute__((packed)); +#elif defined( __arm__ ) +#elif defined( _MSC_VER ) + #pragma pack( pop ) +#elif defined (__H2XML__) + __attribute__((packed)) +#else + #error "Unsupported compiler." +#endif /* __GNUC__ */ + diff --git a/spf/api/ar_utils/spf_end_pragma.h b/spf/api/ar_utils/spf_end_pragma.h new file mode 100644 index 0000000..87300c1 --- /dev/null +++ b/spf/api/ar_utils/spf_end_pragma.h @@ -0,0 +1,21 @@ +/** + * \file spf_end_pragma.h + * \brief + * This file defines pragma to ignore zero length array warnings for different compilers + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#if defined( __qdsp6__ ) + #pragma GCC diagnostic pop +#elif defined( __GNUC__ ) +#elif defined( __arm__ ) +#elif defined( _MSC_VER ) + #pragma warning( pop ) +#elif defined (__H2XML__) +#else + #error "Unsupported compiler." +#endif /* __GNUC__ */ + diff --git a/spf/api/asps/asps_acd_usecase_api.h b/spf/api/asps/asps_acd_usecase_api.h new file mode 100644 index 0000000..d92092b --- /dev/null +++ b/spf/api/asps/asps_acd_usecase_api.h @@ -0,0 +1,88 @@ +#ifndef _ASPS_ACD_USECASE_API_H_ +#define _ASPS_ACD_USECASE_API_H_ +/** + * \file asps_acd_useacase_api.h + * \brief + * This file contains ACD Usecase ID specific APIs. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +/*------------------------------------------------------------------------------ + * Usecase ID definition + *----------------------------------------------------------------------------*/ + +/*ACD usecase ID */ +#define ASPS_USECASE_ID_ACD 0x0B001004 + +/*------------------------------------------------------------------------------ + * Register request payload specific for ACD usecase. It contains list of context + * ids that sensors wants to setup. + * + * 1. This payload structure is populated in the register request event rasied + * by ASPS to Apps client i.e EVENT_ID_ASPS_SENSOR_REGISTER_REQUEST. + * + * 2. This same payload structure is used for the ACD usecase register requests + * orignating from sensors i.e PARAM_ID_ASPS_SENSOR_USECASE_REGISTER. + *----------------------------------------------------------------------------*/ + +/** ACD usecase(ASPS_USECASE_ID_ACD) specific payload. This contians the list of + * context ids necessary to calibrate the ACD module. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asps_acd_usecase_register_payload_t +{ + uint32_t num_contexts; + /**< Number of context ids. */ + + uint32_t context_ids[0]; + /**< Variable length array of context ids. Length of the array is "num_contexts" */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct asps_acd_usecase_register_payload_t asps_acd_usecase_register_payload_t; + +/*------------------------------------------------------------------------------ + * Register ACK payload specific for ACD usecase. It contains the module iid + * and list of context ids configured for the instance. This can be cascaded + * payload if there are multiple ACD module instance IDs. + * + * 1. This payload structure is used for the register ACK set cfg by + * Apps client to ASPS i.e PARAM_ID_ASPS_SENSOR_REGISTER_ACK + * + * 2. This payload structure is also used in the Usecase info event payload raised + * by ASPS to sensors i.e EVENT_ID_ASPS_SENSOR_USECASE_INFO + *----------------------------------------------------------------------------*/ + +/** ACD usecase (ASPS_USECASE_ID_ACD) specific ACK Payload structure. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asps_acd_usecase_register_ack_payload_t +{ + uint32_t module_instance_id; + /**< Module instance ID of which is configured with the following contexts ids. */ + + uint32_t num_contexts; + /**< Number of context ids */ + + uint32_t context_ids[0]; + /**< Variable length array of context ids. Length of the array is "num_contexts" */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct asps_acd_usecase_register_ack_payload_t asps_acd_usecase_register_ack_payload_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif /* _ASPS_ACD_USECASE_API_H_ */ diff --git a/spf/api/asps/asps_acm_api.h b/spf/api/asps/asps_acm_api.h new file mode 100644 index 0000000..67c84f8 --- /dev/null +++ b/spf/api/asps/asps_acm_api.h @@ -0,0 +1,382 @@ +#ifndef _ASPS_ACM_API_H_ +#define _ASPS_ACM_API_H_ +/** + * \file asps_api.h + * \brief + * This file contains Audio-Sensor Proxy Service Commands Data Structures + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +/*------------------------------------------------------------------------------ + * Usecase ID API includes + *----------------------------------------------------------------------------*/ +#include "asps_acd_usecase_api.h" +#include "asps_upd_usecase_api.h" +#include "asps_ads_usecase_api.h" +#include "asps_us_rendering_usecase_api.h" +#include "asps_sdz_usecase_api.h" +#include "asps_asr_usecase_api.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +/*------------------------------------------------------------------------------ + * API Definitions + *----------------------------------------------------------------------------*/ + +/*ASPS module instance ID. Used for GPR communication */ +#define ASPS_MODULE_INSTANCE_ID 0x00000007 + +/*------------------------------------------------------------------------------ + * EVENT_ID_ASPS_SENSOR_REGISTER_REQUEST + *----------------------------------------------------------------------------*/ + +/** + Event raised by ASPS to setup a given usecase for a given sensor instance. + + The event has a variable payload which is specific to usecase id. For example, + ACD usecase will contain list of context ids. + + @Payload struct + apm_cmd_header_t + apm_module_event_t + event_id_asps_sensor_register_request_t + + <8 byte alignment if any, but not mandatory at the end> + + @gpr_hdr_fields + Opcode -- APM_MODULE_EVENT_TO_CLIENT + + @return + Error code -- #PARAM_ID_ASPS_SENSOR_REGISTER_ACK + */ +#define EVENT_ID_ASPS_SENSOR_REGISTER_REQUEST 0x080012EB + +/** + Payload of the EVENT_ID_ASPS_SENSOR_REGISTER_REQUEST data structure. This + structure is preceeded by apm_module_event_t structure and followed by + usecase specific payload if any. +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_asps_sensor_register_request_t +{ + uint32_t see_sensor_iid; + /**< Unique identifier for the audio sensor instance in SEE framework. + Valid non-zero value. */ + + uint32_t usecase_id; + /**< Indicates the usecase which a given sensor instance is trying to + register. + + Supported usecase ids: + 1. ASPS_USECASE_ID_ACD + 2. ASPS_USECASE_ID_UPD + 3. ASPS_USECASE_ID_PCM_DATA + 4. ASPS_USECASE_ID_ULTRASOUND_RENDERING + 5. ASPS_USECASE_ID_SDZ */ + + uint32_t payload_size; + /**< Size of the "usecase_id" specific payload if any. */ + + uint32_t payload[0]; + /**< Points to "usecase_id" specific paylod if any. + 1. ASPS_USECASE_ID_ACD - Payload required - struct asps_acd_usecase_register_request_payload_t + 2. ASPS_USECASE_ID_UPD - Payload not required. + 3. ASPS_USECASE_ID_PCM_DATA - Payload required - struct asps_pcm_data_usecase_register_payload_t */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_asps_sensor_register_request_t event_id_asps_sensor_register_request_t; + +/*------------------------------------------------------------------------------ + * PARAM_ID_ASPS_SENSOR_REGISTER_ACK + *----------------------------------------------------------------------------*/ + +/** + This parameter is set as an ACK to the event EVENT_ID_ASPS_SENSOR_REGISTER_REQUEST. + It contains the + + @Payload struct + apm_cmd_header_t + apm_module_param_data_t + param_id_asps_sensor_register_ack_t + + <8 byte alignment if any, but not mandatory at the end> + + @gpr_hdr_fields + Opcode -- APM_CMD_SET_CFG + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + */ +#define PARAM_ID_ASPS_SENSOR_REGISTER_ACK 0x080012ED + +/** + Payload of the PARAM_ID_ASPS_SENSOR_REGISTER_ACK data structure. This + structure is preceeded by apm_module_param_data_t structure. +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_asps_sensor_register_ack_t +{ + uint32_t see_sensor_iid; + /**< Sensor instance iid which was passed as part of the ASPS event. */ + + uint32_t usecase_id; + /**< Indicates the usecase which a given sensor instance is trying to + register. + + Supported usecase ids: + 1. ASPS_USECASE_ID_ACD + 2. ASPS_USECASE_ID_UPD + 3. ASPS_USECASE_ID_PCM_DATA */ + + uint32_t payload_size; + /**< Size of the usecase_id specific ACK payload following this structure. + + In case of ACD usecase, the ACK payload contains list of context ids for + each of the ACD module instance IDs that. */ + + uint32_t payload[0]; + /**< Points to "usecase_id" specific paylod if any. + + 1. ASPS_USECASE_ID_ACD - Payload struct asps_acd_usecase_register_ack_payload_t + This can be a cascaded payload, if there are multiple ACD module instance ids. + < acd_sensor_register_ack_payload_t > list of context ids for module instance 1 + < acd_sensor_register_ack_payload_t > list of context ids for module instance 2 + + 2. ASPS_USECASE_ID_UPD - Payload struct asps_upd_usecase_register_ack_payload_t + + 3. ASPS_USECASE_ID_PCM_DATA - Payload struct asps_audio_data_usecase_register_ack_payload_t */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct param_id_asps_sensor_register_ack_t param_id_asps_sensor_register_ack_t; + +/*------------------------------------------------------------------------------ + * EVENT_ID_ASPS_SENSOR_DEREGISTER_REQUEST + *----------------------------------------------------------------------------*/ + +/** + De-registers request event ID. This is the sensor de-register request event. + + @Payload struct + apm_cmd_header_t + apm_module_event_t + event_id_asps_sensor_deregister_request_t + <8 byte alignment if any, but not mandatory at the end> + + @gpr_hdr_fields + Opcode -- APM_MODULE_EVENT_TO_CLIENT + + @return + Error code -- #PARAM_ID_ASPS_BASIC_ACK + + */ +#define EVENT_ID_ASPS_SENSOR_DEREGISTER_REQUEST 0x080012EC + +/** + Payload of the EVENT_ID_ASPS_SENSOR_DEREGISTER_REQUEST data structure. This + structure is preceeded by apm_module_event_t structure. +*/ +#include "spf_begin_pack.h" + +struct event_id_asps_sensor_deregister_request_t +{ + uint32_t see_sensor_iid; + /**< Unique identifier for the audio sensor instance in SEE framework. + Valid non-zero value. */ + + uint32_t usecase_id; + /**< Module event ID for which sensor instance wants to de-register from. + Valid non-zero value. + + Supported usecase ids: + 1. ASPS_USECASE_ID_ACD + 2. ASPS_USECASE_ID_UPD + 3. ASPS_USECASE_ID_PCM_DATA */ +} +#include "spf_end_pack.h" +; + +typedef struct event_id_asps_sensor_deregister_request_t event_id_asps_sensor_deregister_request_t; + +/*------------------------------------------------------------------------------ + * EVENT_ID_ASPS_GET_SUPPORTED_CONTEXT_IDS + *----------------------------------------------------------------------------*/ + +/** + Event raised by ASPS to get list of supported instance IDS. + + @Payload struct + apm_cmd_header_t + apm_module_event_t + event_id_asps_get_supported_context_ids_t + <8 byte alignment if any, but not mandatory at the end> + + @gpr_hdr_fields + Opcode -- APM_MODULE_EVENT_TO_CLIENT + + @return + Response set config -- #PARAM_ID_ASPS_SUPPORTED_CONTEXT_IDS + + */ +#define EVENT_ID_ASPS_GET_SUPPORTED_CONTEXT_IDS 0x08001302 + +/** + Payload of the EVENT_ID_ASPS_GET_SUPPORTED_CONTEXT_IDS data structure. This + structure is preceded by apm_module_event_t structure. +*/ +#include "spf_begin_pack.h" + +struct event_id_asps_get_supported_context_ids_t +{ + uint32_t see_sensor_iid; + /**< Unique identifier for the audio sensor instance in SEE framework thats + requesting for the list of supported context ids. + + Valid non-zero value. */ +} +#include "spf_end_pack.h" +; + +typedef struct event_id_asps_get_supported_context_ids_t event_id_asps_get_supported_context_ids_t; + +/*------------------------------------------------------------------------------ + * PARAM_ID_ASPS_SUPPORTED_CONTEXT_IDS + *----------------------------------------------------------------------------*/ + +/** + Set param to inform list of supported context ids to ASPS. + This param is through APM_CMD_SET_CFG. + + sizeof of the param payload = sizeof(param_id_asps_supported_context_ids_t) + + (num_supported_context * sizeof(uint32_t) ); + + @Payload struct + apm_cmd_header_t + apm_module_param_data_t + param_id_asps_supported_context_ids_t + <8 byte alignment if any, but not mandatory at the end> + + @gpr_hdr_fields + Opcode -- APM_CMD_SET_CFG + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + */ +#define PARAM_ID_ASPS_SUPPORTED_CONTEXT_IDS 0x08001303 + +/** + Payload of the PARAM_ID_ASPS_SUPPORTED_CONTEXT_IDS data structure. This + structure is preceeded by apm_module_param_data_t structure. +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_asps_supported_context_ids_t +{ + uint32_t see_sensor_iid; + /**< Unique identifier for the audio sensor instance in SEE framework that + requested for the list of supported context ids. + Valid non-zero value. */ + + uint32_t num_supported_contexts; + /**< Number of supported context ids */ + + uint32_t supported_context_ids[0]; + /**< Variable length array of supported context ids. + Length of the array is "num_supported_context" */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_asps_supported_context_ids_t param_id_asps_supported_context_ids_t; + +/*------------------------------------------------------------------------------ + * EVENT_ID_ASPS_CLOSE_ALL + *----------------------------------------------------------------------------*/ + +/** + Event raised by ASPS to close all the sessions corresponding to earlier register + requests. + + There is no payload for this event. + + @Payload struct + apm_cmd_header_t + apm_module_event_t + <8 byte alignment if any, but not mandatory at the end> + + @gpr_hdr_fields + Opcode -- APM_MODULE_EVENT_TO_CLIENT + + @return + ACK is not required. + + */ +#define EVENT_ID_ASPS_CLOSE_ALL 0x0800133E + + +/*------------------------------------------------------------------------------ + * PARAM_ID_ASPS_BASIC_ACK + *----------------------------------------------------------------------------*/ + +/** + Sets the error code corresponding to the request event raised by ASPS. + This param is through APM_CMD_SET_CFG. + + @Payload struct + apm_cmd_header_t + apm_module_param_data_t + param_id_asps_basic_ack_t + <8 byte alignment if any, but not mandatory at the end> + + @gpr_hdr_fields + Opcode -- APM_CMD_SET_CFG + + @return + Error code -- #GPR_BASIC_RSP_RESULT + + */ +#define PARAM_ID_ASPS_BASIC_ACK 0x08001304 + +/** + Payload of the PARAM_ID_ASPS_BASIC_ACK data structure. This + structure is preceeded by apm_module_param_data_t structure. +*/ +#include "spf_begin_pack.h" + +struct param_id_asps_basic_ack_t +{ + uint32_t error_code; + /**< Audio reach error code. */ + + uint32_t asps_event_id; + /**< ASPS event ID to which this response is being returned. */ + + uint32_t see_sensor_iid; + /**< Sensor instance iid which was passed as part of the ASPS event. */ + + uint32_t usecase_id; + /**< Usecase ID for which the response is being returned.*/ +} +#include "spf_end_pack.h" +; +typedef struct param_id_asps_basic_ack_t param_id_asps_basic_ack_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif //_ASPS_API_H_ diff --git a/spf/api/asps/asps_ads_usecase_api.h b/spf/api/asps/asps_ads_usecase_api.h new file mode 100644 index 0000000..9aca01d --- /dev/null +++ b/spf/api/asps/asps_ads_usecase_api.h @@ -0,0 +1,115 @@ +#ifndef _ASPS_ADS_USECASE_API_H_ +#define _ASPS_ADS_USECASE_API_H_ +/** + * \file asps_ads_useacase_api.h + * \brief + * This file contains PCM DATA Usecase ID specific APIs. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +/*------------------------------------------------------------------------------ + * Usecase ID definition + *----------------------------------------------------------------------------*/ + +/*ADS usecase ID */ +#define ASPS_USECASE_ID_PCM_DATA 0x0B00100A + +#ifdef ASPS_USECASE_ID_PCM_DATA /* definitions specific to PCM DATA usecase */ + +/** + PCM DATA usecase(ASPS_USECASE_ID_PCM_DATA) specific payload. This payload contains the + type of the stream required by the sensor. + This structure is proceeded by param_id_asps_sensor_usecase_register_t structure. */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asps_pcm_data_usecase_register_payload_t +{ + //stream type for pcm data takes values {0,1,2} + // 0 : INVALID, 1 : STREAM_TYPE_PCM_RAW, 2 : STREAM_TYPE_PCM_NS + uint32_t stream_type; +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct asps_pcm_data_usecase_register_payload_t asps_pcm_data_usecase_register_payload_t; + +#endif /* ASPS_USECASE_ID_PCM_DATA */ + +/*ADS usecase ID */ +#define ASPS_USECASE_ID_PCM_DATA_V2 0x0B00100C + +/** + PCM DATA usecase(ASPS_USECASE_ID_PCM_DATA_V2) specific payload. This payload contains the + type of the stream required by the sensor. + This structure is proceeded by param_id_asps_sensor_usecase_register_t structure. */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asps_pcm_data_v2_usecase_register_payload_t +{ + uint32_t stream_type; + /* stream type for pcm data takes values {0,1,2} + * 0 : INVALID, 1 : STREAM_TYPE_PCM_RAW, 2 : STREAM_TYPE_PCM_NS */ + + uint32_t requires_buffering; + /* indicates whether the capture use case requires a buffering module + * in the chain */ + + uint32_t sample_rate; + /* sampling rate of pcm data at end point */ + + uint32_t bit_width; + /* bit width of pcm data at end point + * currently supports only 16 bit */ + + uint32_t num_channels; + /* number of channels takes values from {0..32} */ + +#if 0 + uint8_t channel_type[0]; + /* channel type for each channel in num_channels + * variable array of size num_channels elements + * takes values from {0..63} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct asps_pcm_data_v2_usecase_register_payload_t asps_pcm_data_v2_usecase_register_payload_t; + +/** PCM DATA usecase (ASPS_USECASE_ID_PCM_DATA/V2) specific Payload structure. This structure is proceeded + by event_id_asps_sensor_usecase_info_t. */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct asps_audio_data_usecase_register_ack_payload_t +{ + uint32_t sns_rd_ep_miid; + /**< Module instance ID of SNS read end point module. */ + + uint32_t mfc_miid; + /**< Module instance ID of MFC module. */ + + uint32_t pcm_cnv_miid; + /**< Module instance ID of PCM_CNV module. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct asps_audio_data_usecase_register_ack_payload_t asps_audio_data_usecase_register_ack_payload_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif /* _ASPS_ADS_USECASE_API_H_ */ diff --git a/spf/api/asps/asps_asr_usecase_api.h b/spf/api/asps/asps_asr_usecase_api.h new file mode 100644 index 0000000..2c2c5d5 --- /dev/null +++ b/spf/api/asps/asps_asr_usecase_api.h @@ -0,0 +1,90 @@ +#ifndef _ASPS_ASR_USECASE_API_H_ +#define _ASPS_ASR_USECASE_API_H_ +/** + * \file asps_asr_usecase_api.h + * \brief + * This file contains ASR Usecase ID specific APIs. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/*------------------------------------------------------------------------------ + * Usecase ID definition + *----------------------------------------------------------------------------*/ + +/*ASR usecase ID */ +#define ASPS_USECASE_ID_ASR 0x0B001011 + +/*------------------------------------------------------------------------------ + * Register request payload specific for ASR usecase. It contains ASR + * configuration parameters that sensors wants to setup. + * + * 1. This payload structure is populated in the register request event raised + * by ASPS to Apps client i.e EVENT_ID_ASPS_SENSOR_REGISTER_REQUEST. + * + * 2. This same payload structure is used for the ASR usecase register requests + * originating from sensors i.e PARAM_ID_ASPS_SENSOR_USECASE_REGISTER. + *----------------------------------------------------------------------------*/ + +/** ASR usecase(ASPS_USECASE_ID_ASR) specific payload. This contains the + * ASR configuration necessary to calibrate the ASR module. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asps_asr_usecase_register_payload_t +{ + uint32_t frame_length_ms; + /**< Frame length in milliseconds for ASR processing + Range: 100..20000, Default: 3000 */ + + uint32_t language_code; + /**< Language code for ASR output + Range: Language enum values, Default: ASPS_ASR_LANG_EN_US (0) */ + + uint32_t enable_sdz; + /**< Flag to enable Speaker Diarization along with ASR + Range: 0..1, Default: 0 */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct asps_asr_usecase_register_payload_t asps_asr_usecase_register_payload_t; + +/*------------------------------------------------------------------------------ + * Register ACK payload specific for ASR usecase. It contains the module iid + * and ASR configuration status. + * + * 1. This payload structure is used for the register ACK set cfg by + * Apps client to ASPS i.e PARAM_ID_ASPS_SENSOR_REGISTER_ACK + * + * 2. This payload structure is also used in the Usecase info event payload raised + * by ASPS to sensors i.e EVENT_ID_ASPS_SENSOR_USECASE_INFO + *----------------------------------------------------------------------------*/ + +/** ASR usecase (ASPS_USECASE_ID_ASR) specific ACK Payload structure. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asps_asr_usecase_register_ack_payload_t +{ + uint32_t asr_module_instance_id; + /**< ASR Module instance ID which is configured with the ASR settings. */ + + uint32_t sdz_module_instance_id; + /**< SDZ Module instance ID (valid only if SDZ is enabled) + Set to 0 if SDZ is not enabled */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct asps_asr_usecase_register_ack_payload_t asps_asr_usecase_register_ack_payload_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif /* _ASPS_ASR_USECASE_API_H_ */ diff --git a/spf/api/asps/asps_sdz_usecase_api.h b/spf/api/asps/asps_sdz_usecase_api.h new file mode 100644 index 0000000..d848bc8 --- /dev/null +++ b/spf/api/asps/asps_sdz_usecase_api.h @@ -0,0 +1,51 @@ +#ifndef _ASPS_SDZ_USECASE_API_H_ +#define _ASPS_SDZ_USECASE_API_H_ +/** + * \file asps_sdz_useacase_api.h + * \brief + * This file contains Speaker Diarization Usecase ID specific APIs. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +/*------------------------------------------------------------------------------ + * Usecase ID definition + *----------------------------------------------------------------------------*/ + +/* SDZ usecase ID */ +#define ASPS_USECASE_ID_SDZ 0x0B001010 + +/*------------------------------------------------------------------------------ + * Register ACK payload specific for SDZ usecase. It contains SDZ module iid. + * + * 1. This payload structure is used for the register ACK set cfg by + * Apps client to ASPS i.e PARAM_ID_ASPS_SENSOR_REGISTER_ACK + * + * 2. This payload structure is also used in the Usecase info event payload raised + * by ASPS to sensors i.e EVENT_ID_ASPS_SENSOR_USECASE_INFO + *----------------------------------------------------------------------------*/ + +#include "spf_begin_pack.h" + +struct asps_sdz_usecase_register_ack_payload_t +{ + uint32_t module_instance_id; + /**< SDZ Module instance ID */ +} +#include "spf_end_pack.h" +; +typedef struct asps_sdz_usecase_register_ack_payload_t asps_sdz_usecase_register_ack_payload_t; + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif /* _ASPS_SDZ_USECASE_API_H_ */ diff --git a/spf/api/asps/asps_upd_usecase_api.h b/spf/api/asps/asps_upd_usecase_api.h new file mode 100644 index 0000000..290ef61 --- /dev/null +++ b/spf/api/asps/asps_upd_usecase_api.h @@ -0,0 +1,50 @@ +#ifndef _ASPS_UPD_USECASE_API_H_ +#define _ASPS_UPD_USECASE_API_H_ +/** + * \file asps_upd_useacase_api.h + * \brief + * This file contains Ultrasound Usecase ID specific APIs. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +/*------------------------------------------------------------------------------ + * Usecase ID definition + *----------------------------------------------------------------------------*/ + +/* UPD usecase ID */ +#define ASPS_USECASE_ID_UPD 0x0B001005 + +/*------------------------------------------------------------------------------ + * Register ACK payload specific for UPD usecase. It contains UPD module iid. + * + * 1. This payload structure is used for the register ACK set cfg by + * Apps client to ASPS i.e PARAM_ID_ASPS_SENSOR_REGISTER_ACK + * + * 2. This payload structure is also used in the Usecase info event payload raised + * by ASPS to sensors i.e EVENT_ID_ASPS_SENSOR_USECASE_INFO + *----------------------------------------------------------------------------*/ + +#include "spf_begin_pack.h" + +struct asps_upd_usecase_register_ack_payload_t +{ + uint32_t module_instance_id; + /**< UPD Module instance ID */ +} +#include "spf_end_pack.h" +; +typedef struct asps_upd_usecase_register_ack_payload_t asps_upd_usecase_register_ack_payload_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif /* _ASPS_UPD_USECASE_API_H_ */ diff --git a/spf/api/asps/asps_us_rendering_usecase_api.h b/spf/api/asps/asps_us_rendering_usecase_api.h new file mode 100644 index 0000000..919bc65 --- /dev/null +++ b/spf/api/asps/asps_us_rendering_usecase_api.h @@ -0,0 +1,76 @@ +#ifndef _ASPS_US_RENDERER_USECASE_API_H_ +#define _ASPS_US_RENDERER_USECASE_API_H_ +/** + * \file asps_us_renderer_useacase_api.h + * \brief + * This file contains US Renderer Usecase ID specific APIs. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +/*------------------------------------------------------------------------------ + * Usecase ID definition + *----------------------------------------------------------------------------*/ +#define ASPS_USECASE_ID_ULTRASOUND_RENDERING 0x0B00100B + +/** + Ultrasound Renderer sepcific payload. This payload contains the + end point configuration requested by the sensor. + This structure is preceeded by param_id_asps_sensor_usecase_register_t structure. */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asps_ultrasound_rendering_usecase_register_payload_t +{ + uint32_t sampling_rate; + /* sampling rate of pcm data at end point */ + + uint32_t bit_width; + /* bit width of pcm data + * currently supports only 16 bit */ + + uint32_t num_channels; + /* number of channels takes values from {0..32} */ + +#if 0 + uint8_t channel_type[0]; + /* channel type for each channel in num_channels + * variable array of size num_channels elements + * takes values from {0..63} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct asps_ultrasound_rendering_usecase_register_payload_t asps_ultrasound_rendering_usecase_register_payload_t; + +/** Ultrasound Renderer usecase specific information */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asps_ultrasound_rendering_usecase_register_ack_payload_t +{ + uint32_t module_iid_us_tone_renderer; + /* miid for sending set params to the audio renderer + * which will be received as ack for US gen proxy + * usecase registration */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct asps_ultrasound_rendering_usecase_register_ack_payload_t asps_ultrasound_rendering_usecase_register_ack_payload_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ +#endif /* _ASPS_US_RENDERER_USECASE_API_H_ */ diff --git a/spf/api/modules/aac_decoder_api.h b/spf/api/modules/aac_decoder_api.h new file mode 100644 index 0000000..b77a5f5 --- /dev/null +++ b/spf/api/modules/aac_decoder_api.h @@ -0,0 +1,300 @@ +#ifndef AAC_DECODER_API_H_ +#define AAC_DECODER_API_H_ +/*============================================================================== + @file aac_decoder_api.h + @brief This file contains AAC decoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of AAC module */ +#define AAC_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of AAC module */ +#define AAC_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of AAC module */ +#define AAC_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of AAC module */ +#define AAC_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of AAC module */ +#define AAC_DEC_MODULE_STACK_SIZE 4096 + +/** Flag to turn off both SBR and PS processing, if they are present in the + bit stream */ +#define AAC_SBR_OFF_PS_OFF (2) + +/** Flag to turn on SBR but turn off PS processing,if they are present in the + bit stream */ +#define AAC_SBR_ON_PS_OFF (1) + +/** Flag to turn on both SBR and PS processing, if they are present in the + bit stream (default behavior) */ +#define AAC_SBR_ON_PS_ON (0) + +/** First single channel element in a dual mono bit stream */ +#define AAC_DUAL_MONO_MAP_SCE_1 (1) + +/** Second single channel element in a dual mono bit stream */ +#define AAC_DUAL_MONO_MAP_SCE_2 (2) + +/** AAC extension audio object type is Low Complexity (LC) */ +#define AAC_EXTENSION_AOT_LC 2 + +/** AAC extension audio object type is SBR */ +#define AAC_EXTENSION_AOT_SBR 5 + +/** AAC extension audio object type is PS */ +#define AAC_EXTENSION_AOT_PS 29 + +/** Use AAC stereo mix coefficients defined in ISO/IEC */ +#define AAC_STEREO_MIX_COEFF_ISO (0) + +/** Use AAC stereo mix coefficients defined in ARIB */ +#define AAC_STEREO_MIX_COEFF_ARIB (1) + +/*============================================================================== + Param ID +==============================================================================*/ + +/** Parameter ID of the AAC decoder SBR/PS Enable flag */ +#define PARAM_ID_AAC_SBR_PS_FLAG 0x08001054 + +/** @h2xmlp_parameter {"PARAM_ID_AAC_SBR_PS_FLAG", PARAM_ID_AAC_SBR_PS_FLAG} + @h2xmlp_description {Parameter for configuring AAC SBR PS processing flag } + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_aac_sbr_ps_flag_t +{ + uint32_t sbr_ps_flag; + /**< @h2xmle_description {Control parameter that enables or disables SBR/PS processing in the + AAC bit stream. Changes are applied to the next decoded frame} + @h2xmle_default {0} + @h2xmle_rangeList {"AAC_SBR_OFF_PS_OFF"=2, + "AAC_SBR_ON_PS_OFF"=1, + "AAC_SBR_ON_PS_ON"=0} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_aac_sbr_ps_flag_t param_id_aac_sbr_ps_flag_t; + +/*============================================================================== + Param ID +==============================================================================*/ + +/** ID of parameter for configuring AAC decoder dual mono mapping */ +#define PARAM_ID_AAC_DUAL_MONO_MAPPING 0x08001055 + +/** @h2xmlp_parameter {"PARAM_ID_AAC_DUAL_MONO_MAPPING", PARAM_ID_AAC_DUAL_MONO_MAPPING} + @h2xmlp_description {Parameter for configuring AAC decoder dual mono channel mapping. + This parameter applies only to AAC dual mono bit stream decoding. The + command can be sent any time after opening a write or read/write stream, + and the changes take effect from the next decoded frame. + + The same SCE can be routed to both he left and right channels. The + following table shows the message payload for AAC dual mono channel + mapping, where all the channels are valid.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_aac_dual_mono_mapping_t +{ + uint16_t left_channel_sce; + /**< @h2xmle_description {Specifies which SCE is connected to the left channel} + @h2xmle_default {1} + @h2xmle_rangeList {"AAC_DUAL_MONO_MAP_SCE_1"=1, + "AAC_DUAL_MONO_MAP_SCE_2"=2} + @h2xmle_policy {Basic} */ + + uint16_t right_channel_sce; + /**< @h2xmle_description {Specifies which SCE is connected to the right channel} + @h2xmle_default {1} + @h2xmle_rangeList {"AAC_DUAL_MONO_MAP_SCE_1"=1, + "AAC_DUAL_MONO_MAP_SCE_2"=2} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct aac_dual_mono_mapping_param_t aac_dual_mono_mapping_param_t; + +/*============================================================================== + Param ID +==============================================================================*/ + +/** ID of parameter for configuring AAC decoder SBR signalling */ +#define PARAM_ID_AAC_SBR_SIGNALLING 0x08001056 + +/** @h2xmlp_parameter {"PARAM_ID_AAC_SBR_SIGNALLING", PARAM_ID_AAC_SBR_SIGNALLING} + @h2xmlp_description {Parameter for configuring AAC decoder SBR signaling. + This parameter applies only to AAC bit stream decoding. The command is sent + after opening a write or read/write stream and before actual decoding + begins. The parameter is used to select the stereo mix coefficients + between the ISO/IEC and ARIB standards. + Do not send this command during decoding. Such a change can cause + glitches in the stereo output.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_aac_sbr_signalling_t +{ + uint32_t extension_aot; + /**< @h2xmle_description {The extension audio object type in a stream. + If this value is set as AAC_EXTENSION_AOT_LC, all remaining fields + are ignored and the decoder operates in implicit signaling mode.} + @h2xmle_default {2} + @h2xmle_rangeList {"AAC_EXTENSION_AOT_LC"=2, + "AAC_EXTENSION_AOT_SBR"=5, + "AAC_EXTENSION_AOT_PS"=29} + @h2xmle_policy {Basic} */ + + uint32_t extension_sampling_rate; + /**< @h2xmle_description {The extension sampling rate} + @h2xmle_default {0} + @h2xmle_rangeList {INVALID_VALUE=0,8000, 11025, 12000, 16000, 22050, 24000, 32000, + 44100, 48000, 64000, 88200, 96000} + @h2xmle_policy {Basic} */ + + uint32_t sbr_present; + /**< @h2xmle_description {Specifies whether to explicitly assume the presence or absence of the + SBR payload in the stream.} + @h2xmle_rangeList {"SBR payload is absent"=0; + "SBR payload is present"=1} + @h2xmle_policy {Basic} */ + + uint32_t ps_present; + /**< @h2xmle_description {Specifies whether to explicitly assume the presence or absence of the + PS payload in the stream.} + @h2xmle_rangeList {"PS payload is absent"=0; + "PS payload is present"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_aac_sbr_signalling_t param_id_aac_sbr_signalling_t; + +/*============================================================================== + Param ID +==============================================================================*/ + +/** ID of the AAC decoder Stereo Mixing parameter */ +#define PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG 0x08001057 + +/** @h2xmlp_parameter {"PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG", PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG} + @h2xmlp_description {Parameter for configuring AAC decoder Stereo Mixing. + This parameter applies only to AAC bit stream decoding. The command is sent + after opening a write or read/write stream and before actual decoding + begins. The parameter is used to select the stereo mix coefficients + between the ISO/IEC and ARIB standards. + Do not send this command during decoding. Such a change can cause + glitches in the stereo output.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_aac_stereo_mix_coeff_selection_t +{ + uint32_t aac_stereo_mix_coeff_flag; + /**< @h2xmle_description {Specifies which standard is used for AAC stereo mix.} + @h2xmle_rangeList {"AAC_STEREO_MIX_COEFF_ISO"=0; + "AAC_STEREO_MIX_COEFF_ARIB"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_aac_stereo_mix_coeff_selection_t param_id_aac_stereo_mix_coeff_selection_t; + +/*============================================================================== + Module +==============================================================================*/ + +/** @h2xml_title1 {AAC Decoder Module API} + @h2xml_title_agile_rev {AAC Decoder Module API} + @h2xml_title_date {April 15, 2019} */ + +/** + * Module ID for AAC decoder. + * Decodes data of format-id = MEDIA_FMT_ID_AAC + */ +#define MODULE_ID_AAC_DEC 0x0700101F + +/** + @h2xmlm_module {"MODULE_ID_AAC_DEC", MODULE_ID_AAC_DEC} + @h2xmlm_displayName {"AAC Decoder"} + @h2xmlm_description {This module is used as the decoder for AAC use cases.\n + - This module has only one input and one output port.\n + - Payload for media_format_t: payload_media_fmt_aac_t\n + - Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_AAC\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + -- PARAM_ID_AAC_SBR_PS_FLAG\n + -- PARAM_ID_AAC_DUAL_MONO_MAPPING\n + -- PARAM_ID_AAC_SBR_SIGNALLING\n + -- PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG\n + -- PARAM_ID_REMOVE_INITIAL_SILENCE\n + -- PARAM_ID_REMOVE_TRAILING_SILENCE\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_AAC\n + -- payload : payload_media_fmt_aac_t\n + } + @h2xmlm_dataMaxInputPorts {AAC_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {AAC_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=AAC_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=AAC_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {AAC_DEC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"media_format_t"} + @h2xmlm_InsertParameter + @h2xml_Select {media_format_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_RAW_COMPRESSED"=6} + @h2xmle_default {0} + @h2xml_Select {media_format_t::fmt_id} + @h2xmle_rangeList {"Media format ID of AAC"=MEDIA_FMT_ID_AAC} + @h2xmle_default {0} + @h2xml_Select {"payload_media_fmt_aac_t"} + @h2xmlm_InsertStructure + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @h2xml_Select {"param_id_aac_sbr_ps_flag_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aac_dual_mono_mapping_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aac_sbr_signalling_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aac_stereo_mix_coeff_selection_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif // AAC_DECODER_API_H_ diff --git a/spf/api/modules/aac_encoder_api.h b/spf/api/modules/aac_encoder_api.h new file mode 100644 index 0000000..1f97f45 --- /dev/null +++ b/spf/api/modules/aac_encoder_api.h @@ -0,0 +1,327 @@ +#ifndef _AAC_ENCODER_API_H_ +#define _AAC_ENCODER_API_H_ +/*============================================================================== + @file aac_encoder_api.h + @brief This file contains AAC encoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "imcl_fwk_intent_api.h" +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of AAC module */ +#define AAC_ENC_DATA_INPUT_PORT 0x2 + +/* Output port ID of AAC module */ +#define AAC_ENC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of AAC module */ +#define AAC_ENC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of AAC module */ +#define AAC_ENC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of AAC module */ +#define AAC_ENC_MODULE_STACK_SIZE 4096 + +/* Max size of cutoff table */ +#define MAX_NUM_CUTOFF_LEVELS 6 + +/* Control port for receiving br info*/ +#define COP_ENCODER_FEEDBACK_IN AR_NON_GUID(0xC0000001) + +/*============================================================================== + Parameters +==============================================================================*/ +/** ID of the encoder Bit Rate level map parameter.This parameter can be set at run time.*/ +#define PARAM_ID_AAC_BIT_RATE_LEVEL_MAP 0x08001312 +/* Structure payload for: PARAM_ID_AAC_BIT_RATE_LEVEL_MAP*/ +/** @h2xmlp_parameter {"PARAM_ID_AAC_BIT_RATE_LEVEL_MAP", PARAM_ID_AAC_BIT_RATE_LEVEL_MAP} + @h2xmlp_description {- Configures the table which maps each bitrate level received to the actual bitrate value \n + -> Quality levels are always in ascending order of bit rate + - (even if we add a new level at the bottom in the future) \n + - i.e. a lower quality level always refers to a lower bit rate \n + -> For a given bit rate level, the encoder will never encode at a + - bit rate higher than that defined by the corresponding mapping \n + -> The mapping table can be sent multiple times on the fly and each time, + - the new table received will be cached and used to set the bitrate for the next frame.} + @h2xmlp_toolPolicy {Calibration}*/ + +/** ID of the encoder cutoff configuration parameter.This parameter can be set at run time.*/ +#define PARAM_ID_AAC_CUTOFF_FREQ_CONFIG 0x08001A5C +/* Structure payload for: PARAM_ID_AAC_CUTOFF_FREQ_CONFIG*/ +/** @h2xmlp_parameter {"PARAM_ID_AAC_CUTOFF_FREQ_CONFIG", PARAM_ID_AAC_CUTOFF_FREQ_CONFIG} + @h2xmlp_description {- Configures the cutoff frequency configuration.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct aac_bitrate_level_map_t +{ + uint32_t level; + /**< @h2xmle_description {Index of each quality level, since maximum levels supported is 5 this index ranges from 0 to 5} + @h2xmle_range {0..5} + @h2xmle_default {0} + */ + uint32_t bitrate; + /**< @h2xmle_description {Bitrate quality levels determined for ABR for 165kbps peak bitrate} + @h2xmle_rangeList {"BIT_RATE_33000" = 33000; + "BIT_RATE_66000" = 66000; + "BIT_RATE_99000" = 99000; + "BIT_RATE_132000" = 132000; + "BIT_RATE_165000" = 165000} + @h2xmle_default {165000} + + */ +} +#include "spf_end_pack.h" +; + +typedef struct aac_bitrate_level_map_t aac_bitrate_level_map_t; + +#include "spf_begin_pack.h" +struct param_id_aac_bitrate_level_map_payload_t +{ + uint32_t num_levels; + /**< @h2xmle_description {Number of bitrate quality levels} + @h2xmle_range {0..5} + @h2xmle_default {0} + */ +#if 0 + aac_bitrate_level_map_t br_lev_tbl[num_levels]; +#endif +} +#include "spf_end_pack.h" +; + +typedef struct param_id_aac_bitrate_level_map_payload_t param_id_aac_bitrate_level_map_payload_t; + +/** @h2xmlp_subStruct */ +#include "spf_begin_pack.h" +struct cutoff_freq_level_info_t +{ + uint32_t cutoff_bitrate_low; + /**< @h2xmle_description {low range of bitrate for a cutoff frequency} + @h2xmle_range {0x1F40..0x5DC00} + @h2xmle_default {0} + */ + uint32_t cutoff_bitrate_high; + /**< @h2xmle_description {higher range of bitrate for a cutoff frequency} + @h2xmle_range {0x1F40..0x5DC00} + @h2xmle_default {0} + */ + int32_t cutoff_freq_value; + /**< @h2xmle_description {Cutoff frequency value for a bitrate of range [cutoff_bitrate_low, cutoff_bitrate_high] + NOTE : Any cutoff frequency above max cutoff frequency will be limited to max cutoff frequency(SR/2).} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0} + */ +} +#include "spf_end_pack.h" +; +typedef struct cutoff_freq_level_info_t cutoff_freq_level_info_t; + +#include "spf_begin_pack.h" +struct param_id_aac_enc_cutoff_freq_config_t +{ + uint32_t freq_cutoff_mode; + /**< @h2xmle_description {Frequency cutoff mode. + Mode0 – use to retain existing logic in encoder w.r.t cutoff frequency handling. + Mode1 – Use to enable a global cutoff frequency. + For example, for usecases with requirement to limit cutoff frequency to a + particular level irrespective of configuration(sampling rate, bit rate etc.,) + Mode2 – Use to enable a cutoff frequency table based on bitrate range. + For example, user can choose to configure different cutoff frequencies for different + bitrate ranges, with upto 6 levels. + Mode3 – Use to disable cutoff frequency logic in the encoder. + This will pick max cutoff frequency as default, i.e., half the sampling rate. + All other values are reserved. } + @h2xmle_range {0x0..0x2} + @h2xmle_default {0} + */ + uint32_t global_cutoff_freq; + /**< @h2xmle_description {Value of the global cutoff frequency in Hz. This value will be picked as global cutoff + frequency when 'freq_cutoff_mode' field is set to 'mode1'. + NOTE : Any value above maximum cutoff frequency will be discarded and cutoff frequency + will be set to max cutoff frequency.} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0} + */ + uint32_t num_cutoff_levels; + /**< @h2xmle_description {Number of cutoff frequency levels mapped to bitrate ranges. This value and immediately + following variable size array based on num_cutoff_levels will be chosen for cutoff frequency + configuration when 'freq_cutoff_mode' field is set to ‘mode2’.} + @h2xmle_range {0..MAX_NUM_CUTOFF_LEVELS} + @h2xmle_default {0} + */ +#ifdef __H2XML__ + cutoff_freq_level_info_t cutoff_freq_level_table[0]; + /**< @h2xmle_description {Cutoff frequency level table of size num_cutoff_levels} + */ +#endif //__H2XML__ +} +#include "spf_end_pack.h" +; + +typedef struct param_id_aac_enc_cutoff_freq_config_t param_id_aac_enc_cutoff_freq_config_t; + +/*============================================================================== + Module +==============================================================================*/ +/** @h2xml_title1 {AAC Encoder Module API} + @h2xml_title_agile_rev {AAC Encoder Module API} + @h2xml_title_date {April 15, 2019} */ + +/** + * Module ID for AAC encoder. + * Encodes to data of format-id = MEDIA_FMT_ID_AAC + */ +#define MODULE_ID_AAC_ENC 0x0700101E + +/** + @h2xmlm_module {"MODULE_ID_AAC_ENC", MODULE_ID_AAC_ENC} + @h2xmlm_displayName {"AAC Encoder"} + @h2xmlm_modSearchKeys {Audio, Bluetooth} + @h2xmlm_description {This module is used as the encoder for AAC use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : aac_enc_cfg_t\n + - Encodes data to format-id = MEDIA_FMT_ID_AAC\n + - Supports following params:\n + -- PARAM_ID_ENCODER_OUTPUT_CONFIG\n + -- PARAM_ID_ENC_BITRATE\n + -- PARAM_ID_ENC_FRAME_SIZE_CONTROL\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: \n + -- AAC-LC mono, stereo: 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48 kHz\n + -- AAC+ mono, stereo: 24, 32, 44.1, 48 kHz\n + -- eAAC+ : 24, 32, 44.1, 48 kHz\n + -- Number of channels : 2\n + -- Bit Width : 16\n + -- Bits Per Sample : 16\n + -- Q format : Q15\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- minimum bit rates in bps:\n + --- AAC-LC mono : 4000\n + --- AAC-LC stereo : 8000\n + --- AAC+ mono : 10000 for 24/32 kHz. 12000 for 44.1/48kHz\n + --- AAC+ stereo : 18000 for 24/32 kHz. 24000 for 44.1/48kHz\n + --- eAAC+ : 10000 for 24/32 kHz. 12000 for 44.1/48kHz\n + -- maximum bit rates in bps:\n + --- AAC-LC mono : min(192000, 6*fs)\n + --- AAC-LC stereo : min(384000, 12*fs)\n + --- AAC+ mono : min(192000, 6*fs)\n + --- AAC+ stereo : min(192000, 12*fs)\n + --- eAAC+ : min(192000, 6*fs)\n} + @h2xmlm_dataMaxInputPorts {AAC_ENC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {AAC_ENC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=AAC_ENC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=AAC_ENC_DATA_OUTPUT_PORT} + @h2xmlm_ctrlStaticPort {"COP_ENCODER_FEEDBACK_IN" = 0xC0000001, + "Bit rate level encoder feedback intent" = INTENT_ID_BT_ENCODER_FEEDBACK} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {AAC_ENC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_encoder_output_config_t"} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_encoder_output_config_t::fmt_id} + @h2xmle_rangeList {"Media format ID of AAC"=MEDIA_FMT_ID_AAC} + @h2xmle_default {0} + @h2xml_Select {"aac_enc_cfg_t"} + @h2xmlm_InsertStructure + @h2xml_Select {"param_id_enc_bitrate_param_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aac_bitrate_level_map_payload_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aac_enc_cutoff_freq_config_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_enc_frame_size_control_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ +/*============================================================================== + Module +==============================================================================*/ +/** @h2xml_title1 {AAC_LC Encoder Module API} + @h2xml_title_agile_rev {AAC_LC Encoder Module API} + @h2xml_title_date {JULY 02 2021} */ + +/** + * Module ID for AAC_LC encoder. + * Encodes to data of format-id = MEDIA_FMT_ID_AAC + */ +#define MODULE_ID_AAC_LC_ENC 0x070010DF + +/** + @h2xmlm_module {"MODULE_ID_AAC_LC_ENC", MODULE_ID_AAC_LC_ENC} + @h2xmlm_displayName {"AAC_LC Encoder"} + @h2xmlm_modSearchKeys {Bluetooth} + @h2xmlm_description {This module is used as the encoder for AAC_LC use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : aac_enc_cfg_t\n + - Encodes data to format-id = MEDIA_FMT_ID_AAC\n + - Supports following params:\n + -- PARAM_ID_ENCODER_OUTPUT_CONFIG\n + -- PARAM_ID_ENC_BITRATE\n + -- PARAM_ID_ENC_FRAME_SIZE_CONTROL\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: \n + -- AAC-LC mono, stereo: 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48 kHz\n + -- Number of channels : 2\n + -- Bit Width : 16\n + -- Bits Per Sample : 16\n + -- Q format : Q15\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- minimum bit rates in bps:\n + --- AAC-LC mono : 4000\n + --- AAC-LC stereo : 8000\n + -- maximum bit rates in bps:\n + --- AAC-LC mono : min(192000, 6*fs)\n + --- AAC-LC stereo : min(384000, 12*fs)\n} + @h2xmlm_dataMaxInputPorts {AAC_ENC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {AAC_ENC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=AAC_ENC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=AAC_ENC_DATA_OUTPUT_PORT} + @h2xmlm_ctrlStaticPort {"COP_ENCODER_FEEDBACK_IN" = 0xC0000001, + "Bit rate level encoder feedback intent" = INTENT_ID_BT_ENCODER_FEEDBACK} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {AAC_ENC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_encoder_output_config_t"} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_encoder_output_config_t::fmt_id} + @h2xmle_rangeList {"Media format ID of AAC"=MEDIA_FMT_ID_AAC} + @h2xmle_default {0} + @h2xml_Select {"aac_enc_cfg_t"} + @h2xmlm_InsertStructure + @h2xml_Select {"param_id_enc_bitrate_param_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aac_bitrate_level_map_payload_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aac_enc_cutoff_freq_config_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_enc_frame_size_control_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif //_AAC_ENCODER_API_H_ diff --git a/spf/api/modules/acd_api.h b/spf/api/modules/acd_api.h new file mode 100644 index 0000000..d4d21a2 --- /dev/null +++ b/spf/api/modules/acd_api.h @@ -0,0 +1,420 @@ +#ifndef _ACD_API_H_ +#define _ACD_API_H_ + +/*============================================================================== + @file acd_api.h + @brief This file contains Public APIs for Audio Context Detection Engine Module + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "detection_cmn_api.h" +#include "contexts_api.h" +/** + @h2xml_title1 {ACD API} + @h2xml_title_agile_rev {ACD API} + @h2xml_title_date {Dec 12, 2020} + */ + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ +/* maximum number of ports on either side, supported by algorithm */ +#define CAPI_ACD_MAX_PORTS 1 +/* maximum number of Detection Clients, supported by algorithm */ +#define CAPI_ACD_MAX_DETECTION_EVENT_CLIENTS 4 +/* Stack Size requirement of this Algo*/ +#define CAPI_ACD_STACK_SIZE 8192 +/* Global unique Module ID definition. + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_ACD 0x070010CC + +/* Unique Paramter id */ +#define PARAM_ID_ACD_STATIC_CFG 0x0800133B + +/* Structure definition for Parameter */ +/** @h2xmlp_parameter {"PARAM_ID_ACD_STATIC_CFG",PARAM_ID_ACD_STATIC_CFG} + @h2xmlp_description {Defines the static configuration needed by the ACD module \n + -# This helps configure required processing blocks in the algorithm} + @h2xmlp_toolPolicy {Calibration}*/ +#include "spf_begin_pack.h" +struct param_id_acd_static_cfg_t +{ + uint32_t env_process_required; + /**< @h2xmle_description {flag to control if ACD should process environment contexts} + @h2xmle_default {1} + @h2xmle_range {0..1} */ + + uint32_t event_process_required; + /**< @h2xmle_description {flag to control if ACD should process event contexts} + @h2xmle_default {1} + @h2xmle_range {0..1}*/ + + uint32_t ambience_process_required; + /**< @h2xmle_description {flag to control if ACD should process ambience contexts} + @h2xmle_default {1} + @h2xmle_range {0..1}*/ + + uint32_t ambience_class_bitmask; + /**< @h2xmle_description {Bitmask to Enable or disable individual ambience classes} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {Speech} + @h2xmle_description {Enable/Disable Speech Ambience} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {Music} + @h2xmle_description {Enable/Disable Music Ambience} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000004} + @h2xmle_bitName {Noise} + @h2xmle_description {Enable/Disable Noise Ambience} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000008} + @h2xmle_bitName {Silence} + @h2xmle_description {Enable/Disable Silence Ambience} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_default {0xF} + @h2xmle_range {0..0xF}*/ + + + uint32_t num_noise_smoothing_frames; + /**< @h2xmle_description {Number of frames to take into account for averaging Noise Levels} + @h2xmle_default {1} + @h2xmle_range {0..100}*/ + +} +#include "spf_end_pack.h" +; +typedef struct param_id_acd_static_cfg_t param_id_acd_static_cfg_t; + +#define PARAM_ID_ACD_AMBIENCE_DYNAMIC_CFG 0x0800133C + +/* Structure definition for Parameter */ +/** @h2xmlp_parameter {"PARAM_ID_ACD_AMBIENCE_DYNAMIC_CFG",PARAM_ID_ACD_AMBIENCE_DYNAMIC_CFG} + @h2xmlp_description {Defines the dynamic configuration needed by the ACD's Ambience sub-module} + @h2xmlp_toolPolicy {Calibration}*/ +#include "spf_begin_pack.h" +struct param_id_acd_ambience_dynamic_cfg_t +{ + uint16_t speech_hangover_num_frames; + /**< @h2xmle_description {Number of frames of no detected speech before vad classification goes to 0} + @h2xmle_default {10} + @h2xmle_range {0..0xFFFF}*/ + + uint16_t music_hangover_num_frames; + /**< @h2xmle_description {Number of frames of no detected music before mad classification goes to 0} + @h2xmle_default {10} + @h2xmle_range {0..0xFFFF}*/ + + uint32_t max_conf_frames_speech; + /**< @h2xmle_description {Number of frames for capping speech confidence frames} + @h2xmle_default {300} + @h2xmle_range {0..0xFFFFFFFF}*/ + + uint32_t min_conf_frames_speech; + /**< @h2xmle_description {Minimum confidence frames for speech detection} + @h2xmle_default {30} + @h2xmle_range {0..0xFFFFFFFF}*/ + + uint32_t max_conf_frames_music; + /**< @h2xmle_description {Number of frames for capping music confidence frames} + @h2xmle_default {300} + @h2xmle_range {0..0xFFFFFFFF}*/ + + uint32_t min_conf_frames_music; + /**< @h2xmle_description {Minimum confidence frames for music detection} + @h2xmle_default {30} + @h2xmle_range {0..0xFFFFFFFF}*/ +} +#include "spf_end_pack.h" +; +typedef struct param_id_acd_ambience_dynamic_cfg_t param_id_acd_ambience_dynamic_cfg_t; + + + +#define EVENT_ID_ACD_DETECTION_EVENT 0x0800133D +/* Structure definition for Parameter */ +/** @parameter {"EVENT_ID_ACD_DETECTION_EVENT",EVENT_ID_ACD_DETECTION_EVENT} + @description {Event raised by ACD to the clients; registration and event have differnt payload types} + @toolPolicy {NO_SUPPORT}*/ + +/** IDs that determine the type of context_specific_payload use to configure + the acd during event register payload. + */ +enum acd_event_cfg_key_id_t +{ + ACD_KEY_ID_GENERIC_INFO = 0, /**< reg: acd_generic_key_id_reg_cfg_t; event: acd_generic_key_id_event_t */ + ACD_MAX_KEYS_SUPPORTED /**< Maxium supported value for acd_event_cfg_key_id_t */ +}; + +typedef enum acd_event_cfg_key_id_t acd_event_cfg_key_id_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct acd_key_info_t +{ + uint32_t key_id; + /**< @description {ID that Indicates the information/payload type that will follow} + @rangeEnum {acd_event_cfg_key_id_t} + @default {ACD_KEY_ID_GENERIC_INFO} */ + + uint32_t key_payload_size; + /**< @description {Size of the key specific payload that follows -has to be 4 byte multiple + This is followed by the key specific payload based on the key ID}*/ +#if defined(__H2XML__) + uint8_t key_specific_payload[0]; + /*@variableArraySize {key_payload_size} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct acd_key_info_t acd_key_info_t; +/** ################################ Struct definitions for event registration################### */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_acd_detection_cfg_t +{ + uint32_t num_keys; + /**< @description {number of keys and related structures in the payload that follows}*/ +#if defined(__H2XML__) + acd_key_info_t key_payload_arr[0]; + /**< @description {event config array of size num_keys.} + @variableArraySize {num_keys} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct event_id_acd_detection_cfg_t event_id_acd_detection_cfg_t; + +/** @description {This is the context specific payload to configure the + detection events for contexts with the generic event key id} */ +#include "spf_begin_pack.h" +struct acd_context_specific_generic_reg_info_t +{ + uint32_t context_id; + /**< @description {context ID} + @rangeList {"ENV_HOME"=MODULE_CMN_CONTEXT_ID_ENV_HOME; + "ENV_OFFICE"=MODULE_CMN_CONTEXT_ID_ENV_OFFICE; + "ENV_RESTAURANT"=MODULE_CMN_CONTEXT_ID_ENV_RESTAURANT; + "ENV_INDOOR"=MODULE_CMN_CONTEXT_ID_ENV_INDOOR; + "ENV_INSTREET"=MODULE_CMN_CONTEXT_ID_ENV_INSTREET; + "ENV_OUTDOOR"=MODULE_CMN_CONTEXT_ID_ENV_OUTDOOR; + "ENV_INCAR"=MODULE_CMN_CONTEXT_ID_ENV_INCAR; + "ENV_INTRAIN"=MODULE_CMN_CONTEXT_ID_ENV_INTRAIN; + "ENV_UNKNOWN"=MODULE_CMN_CONTEXT_ID_ENV_UNKNOWN; + "EVENT_ALARM"=MODULE_CMN_CONTEXT_ID_EVENT_ALARM; + "EVENT_BABYCRYING"=MODULE_CMN_CONTEXT_ID_EVENT_BABYCRYING; + "EVENT_DOGBARKING"=MODULE_CMN_CONTEXT_ID_EVENT_DOGBARKING; + "EVENT_DOORBELL"=MODULE_CMN_CONTEXT_ID_EVENT_DOORBELL; + "EVENT_DOORCLOSE"=MODULE_CMN_CONTEXT_ID_EVENT_DOORCLOSE; + "EVENT_DOOROPEN"=MODULE_CMN_CONTEXT_ID_EVENT_DOOROPEN; + "EVENT_GLASSBREAKING"=MODULE_CMN_CONTEXT_ID_EVENT_GLASSBREAKING; + "EVENT_SIREN"=MODULE_CMN_CONTEXT_ID_EVENT_SIREN; + "AMBIENCE_SPEECH"=MODULE_CMN_CONTEXT_ID_AMBIENCE_SPEECH; + "AMBIENCE_MUSIC"=MODULE_CMN_CONTEXT_ID_AMBIENCE_MUSIC; + "AMBIENCE_NOISY_SPL"=MODULE_CMN_CONTEXT_ID_AMBIENCE_NOISY_SPL; + "AMBIENCE_SILENT_SPL"=MODULE_CMN_CONTEXT_ID_AMBIENCE_SILENT_SPL; + "AMBIENCE_NOISY_SFLUX"=MODULE_CMN_CONTEXT_ID_AMBIENCE_NOISY_SFLUX; + "AMBIENCE_SILENT_SFLUX"=MODULE_CMN_CONTEXT_ID_AMBIENCE_SILENT_SFLUX} + @default {MODULE_CMN_CONTEXT_ID_ENV_HOME} */ + + uint32_t confidence_threshold; + /**< @description {Threshold for context detection} + @range {0..100} + @default {50} */ + + uint32_t step_size; + /**< @description {This denotes the step size in confidence i.e, event + should only be raised if the confidence score changes by this much} + @range {0..100} + @default {10} */ +} +#include "spf_end_pack.h" +; + +typedef struct acd_context_specific_generic_reg_info_t acd_context_specific_generic_reg_info_t; + +/* Event register/config payload associated with the generic context IDs + Corresponding to ACD_KEY_ID_GENERIC_INFO +*/ + +#include "spf_begin_pack.h" +struct acd_generic_key_id_reg_cfg_t +{ + uint32_t num_contexts; + /**< @description {number of contexts required by the client} */ +#if defined (__H2XML__) + acd_context_specific_generic_reg_info_t context_cfg_arr[0]; + /**< @description {context config payloads specific to generic key} + @variableArraySize {num_contexts} */ +#endif +} +#include "spf_end_pack.h" +; + +typedef struct acd_generic_key_id_reg_cfg_t acd_generic_key_id_reg_cfg_t; +/** ################################ Struct definitions for raised event################### */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_acd_detection_event_t +{ + uint32_t event_timestamp_lsw; + /**< @description {This denotes the buffer timestamp (lsw) in us when the event is raised} + @range {0..0xFFFFFFFF} */ + + uint32_t event_timestamp_msw; + /**< @description {This denotes the buffer timestamp (msw) in us when the event is raised} + @range {0..0xFFFFFFFF} */ + + uint32_t num_keys; + /**< @description {number of keys and related structures in the payload that follows} + @rangeEnum {acd_event_cfg_key_id_t} + @default {ACD_KEY_ID_GENERIC_INFO} */ + +#if defined(__H2XML__) + acd_key_info_t key_payload_arr[0]; + /**< @description {key array} + @variableArraySize {num_keys} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_acd_detection_event_t event_id_acd_detection_event_t; + +#include "spf_begin_pack.h" +struct acd_context_specific_generic_event_t +{ + uint32_t context_id; + /**< @description {context ID} + @rangeList {"ENV_HOME"=MODULE_CMN_CONTEXT_ID_ENV_HOME; + "ENV_OFFICE"=MODULE_CMN_CONTEXT_ID_ENV_OFFICE; + "ENV_RESTAURANT"=MODULE_CMN_CONTEXT_ID_ENV_RESTAURANT; + "ENV_INDOOR"=MODULE_CMN_CONTEXT_ID_ENV_INDOOR; + "ENV_INSTREET"=MODULE_CMN_CONTEXT_ID_ENV_INSTREET; + "ENV_OUTDOOR"=MODULE_CMN_CONTEXT_ID_ENV_OUTDOOR; + "ENV_INCAR"=MODULE_CMN_CONTEXT_ID_ENV_INCAR; + "ENV_INTRAIN"=MODULE_CMN_CONTEXT_ID_ENV_INTRAIN; + "ENV_UNKNOWN"=MODULE_CMN_CONTEXT_ID_ENV_UNKNOWN; + "EVENT_ALARM"=MODULE_CMN_CONTEXT_ID_EVENT_ALARM; + "EVENT_BABYCRYING"=MODULE_CMN_CONTEXT_ID_EVENT_BABYCRYING; + "EVENT_DOGBARKING"=MODULE_CMN_CONTEXT_ID_EVENT_DOGBARKING; + "EVENT_DOORBELL"=MODULE_CMN_CONTEXT_ID_EVENT_DOORBELL; + "EVENT_DOORCLOSE"=MODULE_CMN_CONTEXT_ID_EVENT_DOORCLOSE; + "EVENT_DOOROPEN"=MODULE_CMN_CONTEXT_ID_EVENT_DOOROPEN; + "EVENT_GLASSBREAKING"=MODULE_CMN_CONTEXT_ID_EVENT_GLASSBREAKING; + "EVENT_SIREN"=MODULE_CMN_CONTEXT_ID_EVENT_SIREN; + "AMBIENCE_SPEECH"=MODULE_CMN_CONTEXT_ID_AMBIENCE_SPEECH; + "AMBIENCE_MUSIC"=MODULE_CMN_CONTEXT_ID_AMBIENCE_MUSIC; + "AMBIENCE_NOISY_SPL"=MODULE_CMN_CONTEXT_ID_AMBIENCE_NOISY_SPL; + "AMBIENCE_SILENT_SPL"=MODULE_CMN_CONTEXT_ID_AMBIENCE_SILENT_SPL; + "AMBIENCE_NOISY_SFLUX"=MODULE_CMN_CONTEXT_ID_AMBIENCE_NOISY_SFLUX; + "AMBIENCE_SILENT_SFLUX"=MODULE_CMN_CONTEXT_ID_AMBIENCE_SILENT_SFLUX} + @default {MODULE_CMN_CONTEXT_ID_ENV_HOME} */ + + uint32_t event_type; + /**< @description {Defines whether the Context Detected is Started, Stopped or Ongoing} + @rangeList {"ACD_TYPE_STOPPED" = 0; + "ACD_TYPE_STARTED" = 1; + "ACD_TYPE_DETECTED" = 2}*/ + uint32_t confidence_score; + /**< @description {Confidence Score for the detection} + @range {0..100} */ + + uint32_t detection_timestamp_lsw; + /**< @description {This denotes the timestamp (lsw) in us when the context was first detected (event type started)} + @range {0..0xFFFFFFFF} */ + + uint32_t detection_timestamp_msw; + /**< @description {This denotes the timestamp (msw) in us when the context was first detected (event type started)} + @range {0..0xFFFFFFFF} */ +} +#include "spf_end_pack.h" +; +typedef struct acd_context_specific_generic_event_t acd_context_specific_generic_event_t; + +/* Event Payload associated with the generic context IDs + Corresponding to ACD_KEY_ID_GENERIC_INFO*/ + +#include "spf_begin_pack.h" +struct acd_generic_key_id_event_t +{ + uint32_t num_contexts; + /**< @description {number of client's contexts detected by the algo} */ +#if defined (__H2XML__) + acd_context_specific_generic_event_t context_event_arr[0]; + /**< @description {context config for the required events array} + @variableArraySize {num_contexts} */ +#endif +} +#include "spf_end_pack.h" +; + +typedef struct acd_generic_key_id_event_t acd_generic_key_id_event_t; +/*============================================================================== + Module definition +==============================================================================*/ + +/** @h2xmlm_module {"MODULE_ID_ACD",MODULE_ID_ACD} + @h2xmlm_displayName {"Audio Context Detection"} + @h2xmlm_description {Supports the Audio Context Detection (environments, events, ambiences) \n + This module supports the following parameter IDs: \n + * PARAM_ID_ACD_STATIC_CFG \n + * PARAM_ID_ACD_AMBIENCE_DYNAMIC_CFG \n + * PARAM_ID_DETECTION_ENGINE_REGISTER_MULTI_SOUND_MODEL \n + * PARAM_ID_MLA_ENABLE \n + * Supported Input Media Format: \n + * - Data Format : FIXED_POINT \n + * - fmt_id : Don't care \n + * - Sample Rates : 16Khz \n + * - Number of channels : any, but algo uses only the first channel \n + * - Channel type : 1 to 63 \n + * - Bits per sample : 16 \n + * - Q format : 15 \n + * - Interleaving : Deinterleaved Unpacked \n + * - Signed/unsigned : Any } + @h2xmlm_dataMaxInputPorts {CAPI_ACD_MAX_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {CAPI_ACD_MAX_PORTS} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {CAPI_ACD_STACK_SIZE} + + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {param_id_acd_static_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_acd_ambience_dynamic_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_detection_engine_register_multi_sound_model_t} + @h2xmlm_InsertParameter + @h2xml_Select {"mla_enable_t"} + @h2xmlm_InsertParameter + +@} <-- End of the Module --> +*/ +#endif //_ACD_API_H \ No newline at end of file diff --git a/spf/api/modules/alac_decoder_api.h b/spf/api/modules/alac_decoder_api.h new file mode 100644 index 0000000..1427439 --- /dev/null +++ b/spf/api/modules/alac_decoder_api.h @@ -0,0 +1,112 @@ +#ifndef _ALAC_DECODER_API_H_ +#define _ALAC_DECODER_API_H_ + +/*============================================================================== + @file alac_decoder_api.h + @brief This file contains ALAC decoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {ALAC Decoder Module API} + @h2xml_title_agile_rev {ALAC Decoder Module API} + @h2xml_title_date {February 22, 2019} */ + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of ALAC module */ +#define ALAC_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of ALAC module */ +#define ALAC_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of ALAC module */ +#define ALAC_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of ALAC module */ +#define ALAC_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of ALAC module */ +#define ALAC_DEC_MODULE_STACK_SIZE 1024 + +/*============================================================================== + Module +==============================================================================*/ + +/** @ingroup MEDIA_FMT_ID_ALAC + Media format ID for the Apple Lossless Audio Codec (ALAC). + + @par ALAC format block (payload_media_fmt_alac_t) + @table{weak__payload__alac__fmt__blk__t} @newpage* + + @par channelLayoutTag constants + The following constants are extracted when channel layout information is + present in the bit stream. These constants describe the channel layout + (for more information, refer to @xhyperref{S4,ISO/IEC 13818-7}). + @verbatim + enum + { + kALACChannelLayoutTag_Mono = (100<<16) | 1, // C + kALACChannelLayoutTag_Stereo = (101<<16) | 2, // L R + kALACChannelLayoutTag_MPEG_3_0_B = (113<<16) | 3, // C L R + kALACChannelLayoutTag_MPEG_4_0_B = (116<<16) | 4, // C L R Cs + kALACChannelLayoutTag_MPEG_5_0_D = (120<<16) | 5, // C L R Ls Rs + kALACChannelLayoutTag_MPEG_5_1_D = (124<<16) | 6, // C L R Ls Rs LFE + kALACChannelLayoutTag_AAC_6_1 = (142<<16) | 7, // C L R Ls Rs Cs LFE + kALACChannelLayoutTag_MPEG_7_1_B = (127<<16) | 8 // C Lc Rc L R Ls Rs LFE + }; + @endverbatim +*/ + +/** + * Module ID for ALAC decoder. + * Decodes data of format-id = MEDIA_FMT_ID_ALAC + */ + +#define MODULE_ID_ALAC_DEC 0x0700102B +/** + @h2xmlm_module {"MODULE_ID_ALAC_DEC", MODULE_ID_ALAC_DEC} + @h2xmlm_displayName {"ALAC Decoder"} + @h2xmlm_description {This module is used as the decoder for ALAC use cases.\n + - This module has only one input and one output port.\n + - Payload for media_format_t: payload_media_fmt_alac_t\n + - Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_ALAC\n + - Supports following params:\n + -- PARAM_ID_REMOVE_INITIAL_SILENCE\n + -- PARAM_ID_REMOVE_TRAILING_SILENCE\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_ALAC\n + -- payload : payload_media_fmt_alac_t\n + } + @h2xmlm_dataMaxInputPorts {ALAC_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {ALAC_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=ALAC_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=ALAC_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {ALAC_DEC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> + */ + +#endif // _ALAC_DECODER_H_ diff --git a/spf/api/modules/amdb_api.h b/spf/api/modules/amdb_api.h new file mode 100644 index 0000000..e15a712 --- /dev/null +++ b/spf/api/modules/amdb_api.h @@ -0,0 +1,522 @@ +/** + * \file amdb_api.h + * \brief + * API header for AMDB. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _AMDB_API_H_ +#define _AMDB_API_H_ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" + +/*# @h2xml_title1 {Audio Module Data Base (AMDB) APIs} + @h2xml_title_agile_rev {Audio Module Data Base (AMDB) APIs} + @h2xml_title_date {October 31, 2018} */ + +/*# @h2xmlx_xmlNumberFormat {int} */ + + +#define AMDB_MODULE_REG_STRUCT_V1 1 + +/** @ingroup spf_mods_amdb + Interface type is the Common Audio Processor Interface. */ +#define AMDB_INTERFACE_TYPE_CAPI 2 + +/** @ingroup spf_mods_amdb + Interface version is the Common Audio Processor Interface version 3. */ +#define AMDB_INTERFACE_VERSION_CAPI_V3 3 + +/** @ingroup spf_mods_amdb + Module is generic, such as a preprocessor, postprocessor, and so on. */ +#define AMDB_MODULE_TYPE_GENERIC 2 + +/** @ingroup spf_mods_amdb + Module is a decoder. */ +#define AMDB_MODULE_TYPE_DECODER 3 + +/** @ingroup spf_mods_amdb + Module is an encoder. */ +#define AMDB_MODULE_TYPE_ENCODER 4 + +/** @ingroup spf_mods_amdb + Module is a converter. */ +#define AMDB_MODULE_TYPE_CONVERTER 5 + +/** @ingroup spf_mods_amdb + Module is a packetizer. */ +#define AMDB_MODULE_TYPE_PACKETIZER 6 + +/** @ingroup spf_mods_amdb + Module is a de-packetizer. @newpage */ +#define AMDB_MODULE_TYPE_DEPACKETIZER 7 + +/** @ingroup spf_mods_amdb + Module is a detector (such as DTMF, VoiceUI). @newpage */ +#define AMDB_MODULE_TYPE_DETECTOR 8 + +/** @ingroup spf_mods_amdb + Module is a generator (such as DTMF, Ultrasound). @newpage */ +#define AMDB_MODULE_TYPE_GENERATOR 9 + +/** @ingroup spf_mods_amdb + Module is a pre or post-processor (such as filters). @newpage */ +#define AMDB_MODULE_TYPE_PP 10 + +/** @ingroup spf_mods_amdb + Module is a an end point (software or hardware end point, such as I2S source or sink). @newpage */ +#define AMDB_MODULE_TYPE_END_POINT 11 + + +/** @ingroup spf_mods_amdb + Payload for #AMDB_CMD_REGISTER_MODULES. + This structure contains module-specific registration. + + When interface_type = CAPI and interface_version = 3, immediately + following this structure is %amdb_capi_module_reg_info_t. + */ +#include "spf_begin_pack.h" +struct amdb_module_reg_info_t +{ + uint16_t interface_type; + /**< Type of the module interface. + + @values #AMDB_INTERFACE_TYPE_CAPI */ + + uint16_t interface_version; + /**< Version of the module interface. + + @values #AMDB_INTERFACE_VERSION_CAPI_V3 */ +} +#include "spf_end_pack.h" +; +typedef struct amdb_module_reg_info_t amdb_module_reg_info_t; + + +/** @ingroup spf_mods_amdb + Payload for #AMDB_CMD_REGISTER_MODULES. + This structure contains CAPI-specific registration data. +*/ +#include "spf_begin_pack.h" +struct amdb_capi_module_reg_info_t +{ + uint32_t module_type; + /**< Type of module. + + @valuesbul + - #AMDB_MODULE_TYPE_GENERIC + - #AMDB_MODULE_TYPE_DECODER + - #AMDB_MODULE_TYPE_ENCODER + - #AMDB_MODULE_TYPE_CONVERTER + - #AMDB_MODULE_TYPE_PACKETIZER + - #AMDB_MODULE_TYPE_DEPACKETIZER + - #AMDB_MODULE_TYPE_DETECTOR + - #AMDB_MODULE_TYPE_GENERATOR + - #AMDB_MODULE_TYPE_PP + - #AMDB_MODULE_TYPE_END_POINT + @tablebulletend */ + + uint32_t module_id; + /**< ID for the module. */ + + uint16_t file_name_len; + /**< Length of the SO filename (in bytes). + + The file_name element in the structure is of length file_name_len. */ + + uint16_t tag_len; + /**< Length of tag in bytes. This tag identifies the entry point function. + + The tag element in the structure is of length tag_len bytes. */ + + uint32_t error_code; + /**< Result of the module registration. + + The SPF must be able to write to this memory. Memory is populated only + for out-of-band data. @newpagetable */ +} +#include "spf_end_pack.h" +; +typedef struct amdb_capi_module_reg_info_t amdb_capi_module_reg_info_t; + + +/** @ingroup spf_mods_amdb + Instance ID for the AMDB module. This module supports the following command + IDs: + - #AMDB_CMD_REGISTER_MODULES + - #AMDB_CMD_DEREGISTER_MODULES + - #AMDB_CMD_LOAD_MODULES + - #AMDB_CMD_UNLOAD_MODULES + + @par Calibration header field + Opcode -- AMDB_MODULE_INSTANCE_ID + */ +#define AMDB_MODULE_INSTANCE_ID 0x00000003 + +/** @ingroup spf_mods_amdb + Registers a module with the AMDB to enable the module for dynamic loading. + + @msgpayload + amdb_module_registration_t \n + @indent{12pt} amdb_module_reg_info_t \n + @indent{12pt} amdb_capi_module_reg_info_t + + @detdesc + When amdb_capi_module_reg_info_t follows amdb_module_reg_info_t, the + following variable-size arrays are present. Their size depends upon the + variables present in %amdb_capi_module_reg_info_t. + - @codeinline{uint8_t file_name[0];} @vertspace{-6} + - Name of the SO file of length file_name_len bytes @vertspace{-4} + - Total size of this variable array is file_name_len * sizeof (uint8_t) + @vertspace{-3} + - @codeinline{uint8_t tag[0];} @vertspace{-6} + - Tag name of length tag_len @vertspace{-4} + - For CAPIv2, the tag is a prefix for the entry point functions: + @vertspace{-6} + - tag + _get_static_properties @vertspace{-4} + - tag + _init @vertspace{-3} + - Total size of this variable array is tag_len * sizeof (uint8_t) + @vertspace{-3} + - @codeinline{uint8_t alignment[0];} @vertspace{-6} + - For 4-byte alignment @vertspace{-2} + + @returns + GPR_IBASIC_RSP_RESULT (see @xhyperref{80VN50010,80-VN500-10}). + + @dependencies + When registering offloaded modules on a satellite DSP using the out-of-band + command, the client must have used + #APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS to perform memory mapping for the + satellite. + */ +#define AMDB_CMD_REGISTER_MODULES 0x0100101E + +/** @ingroup spf_mods_amdb + Payload for #AMDB_CMD_REGISTER_MODULES. + The overall payload can be both in-band and out-of-band. +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct amdb_module_registration_t +{ + uint32_t proc_domain; + /**< ID for the processor domain in which the AMDB is running. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROC_DOMAIN_ID_GDSP_0 + - #APM_PROC_DOMAIN_ID_GDSP_1 + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + + uint32_t num_modules; + /**< Number of modules being registered. */ + + uint32_t struct_version; + /**< Version of the %amdb_module_reg_info_t structure. */ + + amdb_module_reg_info_t reg_info[0]; + /**< Array of registration information for num_modules (of type + reg_info[num_modules]). + + Each element in the array (including filename and tag) must be 4-byte + aligned. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct amdb_module_registration_t amdb_module_registration_t; + + +/** @ingroup spf_mods_amdb + Deregisters one or more registered modules. + + @msgpayload + amdb_module_deregistration_t + + @returns + GPR_IBASIC_RSP_RESULT (see @xhyperref{80VN50010,80-VN500-10}). + + @dependencies + Modules must have been previous registered with #AMDB_CMD_REGISTER_MODULES. + @par + When deregistering offloaded modules from a satellite DSP using the + out-of-band command, the client must have used + #APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS to perform memory mapping for the + satellite. + */ +#define AMDB_CMD_DEREGISTER_MODULES 0x0100101F + +/** @ingroup spf_mods_amdb + Payload for #AMDB_CMD_DEREGISTER_MODULES. + This payload can be both in-band and out-of-band. +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct amdb_module_deregistration_t +{ + uint32_t proc_domain; + /**< ID for the processor domain in which the AMDB is running. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROC_DOMAIN_ID_GDSP_0 + - #APM_PROC_DOMAIN_ID_GDSP_1 + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + + uint32_t num_modules; + /**< Number of modules being registered. */ + + uint32_t module_id[0]; + /**< Array of module IDs for num_modules (module_id[num_modules]). */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct amdb_module_deregistration_t amdb_module_deregistration_t; + +/** @ingroup spf_mods_amdb + Payload for #AMDB_CMD_LOAD_MODULES, #AMDB_CMD_RSP_LOAD_MODULES, and + #AMDB_CMD_UNLOAD_MODULES. + This structure contains module-specific information for loading and + unloading modules. + */ +#include "spf_begin_pack.h" +struct amdb_load_unload_info_t +{ + uint32_t module_id; + /**< ID for the module. */ + + uint32_t handle_lsw; + /**< Lower 32 bits of the 64-bit handle to the module. */ + + uint32_t handle_msw; + /**< Upper 32 bits of the 64-bit handle to the module. */ +} +#include "spf_end_pack.h" +; +typedef struct amdb_load_unload_info_t amdb_load_unload_info_t; + + +/** @ingroup spf_mods_amdb + Loads one or more modules if they were successfully registered with the + AMDB. + + @msgpayload + amdb_module_load_unload_t \n + @indent{12pt} amdb_load_unload_info_t + + @returns + #AMDB_CMD_RSP_LOAD_MODULES + + @dependencies + A module must have been registered before loading. + @par + For loading offloaded modules on a satellite DSP using an + out-of-band command, the client must have used + #APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS to perform memory mapping for the + satellite. @newpage + */ +#define AMDB_CMD_LOAD_MODULES 0x01001020 + +/** @ingroup spf_mods_amdb + Payload for #AMDB_CMD_LOAD_MODULES, #AMDB_CMD_RSP_LOAD_MODULES, and + #AMDB_CMD_UNLOAD_MODULES. + + The overall payload can be for both in-band and out-of-band data. + - For an in-band payload, the incoming payload is copied, modified (if + necessary), and sent in the response. + - For an out-of-band payload, the incoming payload is sent in the response. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct amdb_module_load_unload_t +{ + uint32_t proc_domain; + /**< ID for the processor domain in which the AMDB is running. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROC_DOMAIN_ID_GDSP_0 + - #APM_PROC_DOMAIN_ID_GDSP_1 + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + + uint32_t error_code; + /**< Result of module loading. For an out-of-band payload, this block + is updated directly. */ + + uint32_t num_modules; + /**< Number of modules being registered. */ + + amdb_load_unload_info_t load_unload_info[0]; + /**< Array of load or unload information for num_modules (of type + load_unload_info[num_modules]). */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct amdb_module_load_unload_t amdb_module_load_unload_t; + + +/** @ingroup spf_mods_amdb + Sent in response to an #AMDB_CMD_LOAD_MODULES command. + + If a module was not registered with the AMDB, handle_lsw and handle_msw + is populated with 0 in the response payload for that module. + + @msgpayload + amdb_module_load_unload_t \n + @indent{12pt} amdb_load_unload_info_t + + @returns + None. + */ +#define AMDB_CMD_RSP_LOAD_MODULES 0x02001008 + +/** @ingroup spf_mods_amdb + Unloads a module that was loaded via the #AMDB_CMD_LOAD_MODULES command. + + @msgpayload + amdb_module_load_unload_t \n + @indent{12pt} amdb_load_unload_info_t + + @returns + GPR_IBASIC_RSP_RESULT (see @xhyperref{80VN50010,80-VN500-10}). + + @dependencies + For unloading offloaded modules on a satellite DSP using an out-of-band + command, the client must have used + #APM_CMD_SHARED_SATELLITE_MEM_MAP_REGIONS to perform memory mapping for the + satellite. @newpage + */ +#define AMDB_CMD_UNLOAD_MODULES 0x01001022 + + + +/** @ingroup spf_mods_amdb + Identifier for the parameter that gets the module version info. + + @msgpayload + amdb_param_id_amdb_module_version_info_t \n + @indent{12pt} amdb_param_id_amdb_module_version_info_t + + @returns + GPR_IBASIC_RSP_RESULT (see @xhyperref{80VN50010,80-VN500-10}). + + @newpage + +*/ +#define AMDB_PARAM_ID_MODULE_VERSION_INFO 0x080013D6 + +#define AMDB_MODULE_INFO_OK 0 +#define AMDB_MODULE_INFO_ERR_FILE_NOT_FOUND 1 +#define AMDB_MODULE_INFO_ERR_DYNAMIC_LINK 2 +#define AMDB_MODULE_INFO_ERR_GENERAL 0xFFFFFFFF + +/** @ingroup spf_mods_amdb +Payload for #AMDB_PARAM_ID_MODULE_VERSION_INFO + +The client is reponsible for filling out the proc_domain, num_modules, and module_id fields. Please note that +since only one proc_domain is given it is the responsibility of the CLIENT to iterate through all of the PDs to +look for the module of intrest. +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct amdb_param_id_module_version_info_t +{ + uint32_t proc_domain; + /**< ID for the processor domain. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + uint32_t num_modules; + /**< Number of modules in the array. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct amdb_param_id_module_version_info_t amdb_param_id_module_version_info_t; + + + +/** @ingroup spf_mods_amdb +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct amdb_module_build_ts_info_t +{ + uint16_t year; + /**< Year that the build was produced */ + uint16_t month; + /**< month the build was produced + @h2xmle_range {0..12} */ + uint16_t day; + /**< day the build was produced + @h2xmle_range {0..31} */ + uint16_t hour; + /**< hour the build was produced + @h2xmle_range {0..24} */ + uint16_t minute; + /**< minute the build was produced + @h2xmle_range {0..60} */ + uint16_t second; + /**< second the build was produced + @h2xmle_range {0..60} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct amdb_module_build_ts_info_t amdb_module_build_ts_info_t; + +/** @ingroup spf_mods_amdb +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct amdb_module_version_info_payload_t +{ + uint32_t module_id; + /**< Requested module id, to be filled in by the client. */ + uint32_t error_code; + /**< Indicates whether an error has occurred loading the module + + @valuesbul + - #AMDB_MODULE_INFO_OK + - #AMDB_MODULE_INFO_ERR_FILE_NOT_FOUND + - #AMDB_MODULE_INFO_ERR_DYNAMIC_LINK + - #AMDB_MODULE_INFO_ERR_GENERAL @tablebulletend */ + uint32_t is_present; + /**< 1 if and only if the module is present and not stubbed in the AMDB. */ + uint32_t module_version_major; + /**< Major version of the requested module. 0 indicates unknown version */ + uint32_t module_version_minor; + /**< Minor version of the requested module. 0 indicates unknown version */ + + amdb_module_build_ts_info_t build_ts; + /**< Indicates the time at which the build for the given module was created. */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct amdb_module_version_info_payload_t amdb_module_version_info_payload_t; + + +#endif //_AMDB_API_H_ diff --git a/spf/api/modules/amrwb_decoder_api.h b/spf/api/modules/amrwb_decoder_api.h new file mode 100644 index 0000000..d9cd65e --- /dev/null +++ b/spf/api/modules/amrwb_decoder_api.h @@ -0,0 +1,76 @@ +#ifndef AMRWB_DECODER_API_H_ +#define AMRWB_DECODER_API_H_ +/*============================================================================== + @file amwrb_decoder_api.h + @brief This file contains AMRWB decoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/** @h2xml_title1 {AMRWB Decoder Module API} + @h2xml_title_agile_rev {AMRWB Decoder Module API} + @h2xml_title_date {May 28, 2019} */ + +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "vocoder_cmn_api.h" +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of AMRWB module */ +#define AMRWB_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of AMRWB module */ +#define AMRWB_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of AMRWB module */ +#define AMRWB_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of AMRWB module */ +#define AMRWB_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of AMRWB module */ +#define AMRWB_DEC_MODULE_STACK_SIZE 8192 + +/*============================================================================== + Module +==============================================================================*/ + +/* Module ID of AMRWB decoder module */ +#define MODULE_ID_AMRWB_DEC 0x07001078 + +/** + @h2xmlm_module {"MODULE_ID_AMRWB_DEC", MODULE_ID_AMRWB_DEC} + @h2xmlm_displayName {"AMRWB Decoder"} + @h2xmlm_description {This module is used as the decoder for AMRWB use cases.\n + - This module has only one input and one output port.\n + - Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id : + -MEDIA_FMT_ID_AMRWB\n + -MEDIA_FMT_ID_AMRWB_FS\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : + -MEDIA_FMT_ID_AMRWB\n + -MEDIA_FMT_ID_AMRWB_FS\n + } + @h2xmlm_dataMaxInputPorts {AMRWB_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {AMRWB_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=AMRWB_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=AMRWB_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {AMRWB_DEC_MODULE_STACK_SIZE} + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + +#endif //_AMRWB_DECODER_API_H_ diff --git a/spf/api/modules/amrwb_encoder_api.h b/spf/api/modules/amrwb_encoder_api.h new file mode 100644 index 0000000..74171ca --- /dev/null +++ b/spf/api/modules/amrwb_encoder_api.h @@ -0,0 +1,99 @@ +#ifndef _AMRWB_ENCODER_API_H_ +#define _AMRWB_ENCODER_API_H_ +/*============================================================================== + @file amrwb_encoder_api.h + @brief This file contains AMRWB encoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/** @h2xml_title1 {AMRWB Encoder Module API} + @h2xml_title_agile_rev {AMRWB Encoder Module API} + @h2xml_title_date {May 28, 2019} */ + +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "vocoder_cmn_api.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of AMRWB module */ +#define AMRWB_ENC_DATA_INPUT_PORT 0x2 + +/* Output port ID of AMRWB module */ +#define AMRWB_ENC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of AMRWB module */ +#define AMRWB_ENC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of AMRWB module */ +#define AMRWB_ENC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of AMRWB module */ +#define AMRWB_ENC_MODULE_STACK_SIZE 16384 + +/*============================================================================== + Module +==============================================================================*/ + +/** + * Module ID for AMRWB encoder. + * Encodes to data of format-id = MEDIA_FMT_ID_AMRWB + */ +#define MODULE_ID_AMRWB_ENC 0x07001079 +/** + @h2xmlm_module {"MODULE_ID_AMRWB_ENC", MODULE_ID_AMRWB_ENC} + @h2xmlm_displayName {"AMRWB Encoder"} + @h2xmlm_description {This module is used as the encoder for AMRWB use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : amrwb_enc_cfg_t\n + - Encodes data to format-id:\n + - MEDIA_FMT_ID_AMRWB - for voice use cases\n + - MEDIA_FMT_ID_AMRWB_FS - for audio use cases\n + - Supports following params:\n + -- PARAM_ID_ENCODER_OUTPUT_CONFIG\n + -- PARAM_ID_ENC_BITRATE\n + -- PARAM_ID_VOCODER_ENABLE_DTX_MODE\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 16000 Hz\n + -- Number of channels : 1\n + -- Bit Width : 16\n + -- Bits Per Sample : 16\n + -- Q format : Q15\n + -- Interleaving : de-interleaved unpacked\n + - Supported bit rates in kbps\n + -- 6.60, 8.85, 12.65, 14.25, 15.85, 18.25, 19.85, 23.05, 23.85 + } + @h2xmlm_dataMaxInputPorts {AMRWB_ENC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {AMRWB_ENC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=AMRWB_ENC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=AMRWB_ENC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {AMRWB_ENC_MODULE_STACK_SIZE} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_encoder_output_config_t"} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_encoder_output_config_t::fmt_id} + @h2xmle_rangeList {"Media format ID of AMRWB"=MEDIA_FMT_ID_AMRWB} + @h2xmle_default {MEDIA_FMT_ID_AMRWB} + @h2xml_Select {"amrwb_enc_cfg_t"} + @h2xmlm_InsertStructure + @h2xml_Select {"param_id_enc_bitrate_param_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_vocoder_enable_dtx_mode_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif //_AMRWB_ENCODER_API_H_ diff --git a/spf/api/modules/amrwbplus_decoder_api.h b/spf/api/modules/amrwbplus_decoder_api.h new file mode 100644 index 0000000..2c56092 --- /dev/null +++ b/spf/api/modules/amrwbplus_decoder_api.h @@ -0,0 +1,88 @@ +#ifndef _AMRWBPLUS_DECODER_H_ +#define _AMRWBPLUS_DECODER_H_ +/*============================================================================== + @file amrwbplus_api.h + @brief This file contains AMRWBPLUS APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + Export of this technology or + software is regulated by the U.S. Government, Diversion contrary to U.S. + law prohibited. + ==============================================================================*/ +// clang-format off + +/*============================================================================== + * Include files + ==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {AMRWBPLUS Decoder Module API} + @h2xml_title_agile_rev {AMRWBPLUS Decoder Module API} + @h2xml_title_date {April 15, 2019} */ + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of AMRWBPLUS module */ +#define AMRWBPLUS_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of AMRWBPLUS module */ +#define AMRWBPLUS_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of AMRWBPLUS module */ +#define AMRWBPLUS_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of AMRWBPLUS module */ +#define AMRWBPLUS_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of AMRWBPLUS module */ +#define AMRWBPLUS_DEC_MODULE_STACK_SIZE 8192 + + +#define MODULE_ID_AMRWBPLUS_DEC 0x07001012 + +/** + @h2xmlm_module {"MODULE_ID_AMRWBPLUS_DEC", MODULE_ID_AMRWBPLUS_DEC} + @h2xmlm_displayName {"AMRWBPlus Decoder"} + @h2xmlm_description { + This module is used as the decoder for AMRWBPLUS use cases. + This module has only one input and one output port. + Payload for media_format_t: payload_media_fmt_amrwbplus_t + Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_AMRWBPLUS\n + - Supports following params:\n + -- PARAM_ID_REMOVE_INITIAL_SILENCE\n + -- PARAM_ID_REMOVE_TRAILING_SILENCE\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_AMRWBPLUS\n + } + @h2xmlm_dataMaxInputPorts {AMRWBPLUS_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {AMRWBPLUS_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=AMRWBPLUS_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=AMRWBPLUS_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {AMRWBPLUS_DEC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> + */ + + + #endif // _AMRWBPLUS_DECODER_API_H_ + + + + + diff --git a/spf/api/modules/ape_decoder_api.h b/spf/api/modules/ape_decoder_api.h new file mode 100644 index 0000000..43343db --- /dev/null +++ b/spf/api/modules/ape_decoder_api.h @@ -0,0 +1,87 @@ +#ifndef _APE_DECODER_API_H_ +#define _APE_DECODER_API_H_ + +/*============================================================================== + @file ape_decoder_api.h + @brief This file contains APE decoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {APE Decoder Module API} + @h2xml_title_agile_rev {APE Decoder Module API} + @h2xml_title_date {February 22, 2019} */ + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of APE module */ +#define APE_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of APE module */ +#define APE_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of APE module */ +#define APE_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of APE module */ +#define APE_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of APE module */ +#define APE_DEC_MODULE_STACK_SIZE 20480 + +/*============================================================================== + Module +==============================================================================*/ + +/** + * Module ID for APE decoder. + * Decodes data of format-id = MEDIA_FMT_ID_APE + */ + +#define MODULE_ID_APE_DEC 0x0700102C +/** + @h2xmlm_module {"MODULE_ID_APE_DEC", MODULE_ID_APE_DEC} + @h2xmlm_displayName {"APE Decoder"} + @h2xmlm_description {This module is used as the decoder for APE use cases.\n + - This module has only one input and one output port.\n + - Payload for media_format_t: payload_media_fmt_ape_t\n + - Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_APE\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + -- PARAM_ID_REMOVE_INITIAL_SILENCE\n + -- PARAM_ID_REMOVE_TRAILING_SILENCE\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_APE\n + -- payload : payload_media_fmt_ape_t\n + } + @h2xmlm_dataMaxInputPorts {APE_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {APE_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=APE_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=APE_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {APE_DEC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> + */ + +#endif // _APE_DECODER_H_ diff --git a/spf/api/modules/aptx-adaptive3-ble-encoder-api.h b/spf/api/modules/aptx-adaptive3-ble-encoder-api.h new file mode 100644 index 0000000..8c8c3a7 --- /dev/null +++ b/spf/api/modules/aptx-adaptive3-ble-encoder-api.h @@ -0,0 +1,134 @@ +/*============================================================================== + @file aptx-adaptive3-ble-encoder-api.h + @brief This file contains aptX Adaptive 3.0 LE encoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _APTX_ADAPTIVE3_BLE_ENCODER_API_H_ +#define _APTX_ADAPTIVE3_BLE_ENCODER_API_H_ + +#define SKIP_LC3_XML 1 +#define MASQERADE_AS_LC3 0 + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "imcl_spm_intent_api.h" +#include "lc3_encoder_api.h" + +/*============================================================================== + Parameters +==============================================================================*/ + + + +/*============================================================================== + Module +==============================================================================*/ + +#if !MASQERADE_AS_LC3 +/** @h2xml_title1 {aptX Adaptive QLEA 3.0 Encoder} + @h2xml_title_agile_rev {aptX Adaptive QLEA 3.0 Encoder} + @h2xml_title_date {October 8th, 2021} +*/ +#define MODULE_ID_APTX_ADAPTIVE_QLEA_ENC 0x070010C3 +/** + @h2xmlm_module {"MODULE_ID_APTX_ADAPTIVE_QLEA_ENC", MODULE_ID_APTX_ADAPTIVE_QLEA_ENC} + @h2xmlm_displayName {"aptX Adaptive QLEA 3.0 Encoder"} + @h2xmlm_description {This module encodes 24-bit PCM audio into aptX Adaptive QLEA 3.0 encoded stream(s)\n + - The output media format is Deinterleaved Raw Compressed\n + - This module should be used in the same subgraph as the CoPv2 Packetizer\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following mandatory params:\n + -- PARAM_ID_LC3_ENC_INIT - configures the aptX Adaptive QLEA 3.0 Encoder parameters\n + -- Supports following optional params:\n + -- PARAM_ID_LC3_ENC_DOWNMIX_2_MONO - downmixes stereo PCM input to mono before encoding\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 96, 48\n + -- Number of channels : 2\n + -- PCM Bits Per Sample : 24\n + -- input PCM Q format : Q31\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- stereo : depends on selected aptX Adaptive QLEA 3.0 frame duration and sample rate \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_ctrlStaticPort {"COP_ENCODER_FEEDBACK_IN" = 0xC0000001, + "Bit rate level encoder feedback intent" = INTENT_ID_BT_ENCODER_FEEDBACK} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {lc3_config_t} + @h2xmlm_InsertParameter + @h2xml_Select {stream_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_lc3_encoder_config_payload_t} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_lc3_encoder_switch_enc_pcm_input_payload_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ +#else + +// MASQERADE AS LC3 + +/** @h2xml_title1 {LC3 Encoder} + @h2xml_title_agile_rev {LC3 Encoder} + @h2xml_title_date {November 4th, 2020} +*/ +#define MODULE_ID_LC3_ENC 0x07001085 +/** + @h2xmlm_module {"MODULE_ID_LC3_ENC", MODULE_ID_LC3_ENC} + @h2xmlm_displayName {"LC3 1.0 Encoder"} + @h2xmlm_description {This module encodes 24-bit PCM audio into LC3-encoded stream(s)\n + - The output media format is Deinterleaved Raw Compressed\n + - This module should be used in the same subgraph as the CoPv2 Packetizer\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following mandatory params:\n + -- PARAM_ID_LC3_ENC_INIT - configures the LC3 Encoder parameters\n + -- Supports following optional params:\n + -- PARAM_ID_LC3_ENC_DOWNMIX_2_MONO - downmixes stereo PCM input to mono before encoding\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 48, 44.1, 32, 24, 16, 8 \n + -- Number of channels : 1, 2\n + -- PCM Bits Per Sample : 24\n + -- input PCM Q format : Q31\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- mono : depends on selected LC3 frame duration and sample rate \n + -- stereo : depends on selected LC3 frame duration and sample rate \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_ctrlStaticPort {"COP_ENCODER_FEEDBACK_IN" = 0xC0000001, + "Bit rate level encoder feedback intent" = INTENT_ID_BT_ENCODER_FEEDBACK} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {lc3_config_t} + @h2xmlm_InsertParameter + @h2xml_Select {stream_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_lc3_encoder_config_payload_t} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_lc3_encoder_switch_enc_pcm_input_payload_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> + +*/ + +#endif + +#endif //_APTX_ADAPTIVE3_BLE_ENCODER_API_H_ diff --git a/spf/api/modules/aptx_adaptive_encoder_api.h b/spf/api/modules/aptx_adaptive_encoder_api.h new file mode 100644 index 0000000..ff73844 --- /dev/null +++ b/spf/api/modules/aptx_adaptive_encoder_api.h @@ -0,0 +1,320 @@ +/*============================================================================== + @file aptx_adaptive_encoder_api.h + @brief This file contains aptx Adaptive encoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _APTX_ADAPTIVE_ENCODER_API_H_ +#define _APTX_ADAPTIVE_ENCODER_API_H_ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "imcl_spm_intent_api.h" + + +/* Control port for receiving br info*/ +#define COP_ENCODER_FEEDBACK_IN AR_NON_GUID(0xC0000001) + +#define SINK_CAPABILITIES_LEN 11 //sink capability bytes + +/*============================================================================== + Parameters +==============================================================================*/ + +/** ID of the aptx adaptive encoder initialization parameter. This parameter should be set at init time.*/ +#define PARAM_ID_APTX_ADAPTIVE_ENC_INIT 0x08001183 +/* Structure payload for: PARAM_ID_APTX_ADAPTIVE_ENC_INIT*/ +/** @h2xmlp_parameter {"PARAM_ID_APTX_ADAPTIVE_ENC_INIT", PARAM_ID_APTX_ADAPTIVE_ENC_INIT} + @h2xmlp_description {- Configures the init parameters of the aptX Adaptive R2 Encoder. \n + - Configures a number of adaptive encoder parameters after adaptive module is instantiated \n + -} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct param_id_aptx_adaptive_enc_init_t +{ + uint32_t sampleRate; + /**< @h2xmle_description { Configures sample rate of incoming PCM audio} + @h2xmle_rangeList {"unchanged" = 0; + "SRATE_48K" = 1; + "SRATE_44K" = 2; + "SRATE_96K" = 3} + @h2xmle_default {1} */ + + uint32_t mtulink0; + /**< @h2xmle_description {Configures MTU size in bytes. A value of 0 means "do not change"} + @h2xmle_range {0..1500} + @h2xmle_default {675} */ + + int32_t channelMode0; + /**< @h2xmle_description { Configures the channel mode of the aptX Kernel lib} + @h2xmle_rangeList {"APTX_CHANNEL_UNCHANGED" = -1; + "APTX_CHANNEL_STEREO" = 0; + "APTX_CHANNEL_MONO" = 1; + "APTX_CHANNEL_DUAL_MONO" = 2; + "APTX_CHANNEL_STEROO_TWS" = 4; + "APTX_CHANNEL_EARBUD" = 8} + + @h2xmle_default {0} */ + + + + uint32_t minsinkBufLL; + uint32_t maxsinkBufLL; + uint32_t minsinkBufHQ; + uint32_t maxsinkBufHQ; + uint32_t minsinkBufTws; + uint32_t maxsinkBufTws; + + /**< @h2xmle_description {Informs the aptX adaptive Encoder of the minimum & maximum buffering,in mS, that \n + the A2DP Sink can accept. \n + These are the minimum/maximum buffering needed from reception of the packet by the sink to the rendering of the first audio sample of that packet \n + For minsinkBufxx, each bit represents 1 mS of audio \n + For maxsinkBufxx, each bit represents 4 mS of audio \n + minsinkBufxx values default to 20 (20mS) \n + maxsinkBufxx values default to 50 (200mS) \n + A value of 0 means "unchanged". } + + @h2xmle_range {0..256} + @h2xmle_default {20} */ + + + uint32_t profile; + /**< @h2xmle_description {Configures aptX Adaptive Primary Profile at initialization time"} + @h2xmle_rangeList {"High Quality" = 4096; + "Low Latency" = 8192 } + @h2xmle_default {4096} */ + + + uint32_t twsplusDualMonoMode; + /**< @h2xmle_description {Configures startup mode for TWS Plus Adaptive"} + @h2xmle_rangeList {"Start in dual mono mode" = 1; + "Start in stero mode" = 0 } + @h2xmle_default {0} */ + + + uint32_t twsplusFadeDuration; + /**< @h2xmle_description {Configures fade duration between stereo and dual mono input PCM for TWS Plus Adaptive} + + @h2xmle_range {1..256} + @h2xmle_default {255} */ + + + uint8_t sinkCapability[SINK_CAPABILITIES_LEN]; + /**< @h2xmle_description {Array of SINK_CAPABILITIES_LEN bytes, containing supported decoder configurations, from capability exchange. \n } + + @h2xmle_range {0..255} + @h2xmle_default {0} */ + + +} + +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_adaptive_enc_init_t param_id_aptx_adaptive_enc_init_t; + + + + +/** ID of the aptx adaptive encoder profile parameter. This parameter should be set at init time.*/ +#define PARAM_ID_APTX_ADAPTIVE_ENC_PROFILE 0x08001184 +/* Structure payload for: PARAM_ID_APTX_ADAPTIVE_ENC_PROFILE*/ +/** @h2xmlp_parameter {"PARAM_ID_APTX_ADAPTIVE_ENC_PROFILE", PARAM_ID_APTX_ADAPTIVE_ENC_PROFILE} + @h2xmlp_description {- Configures the Primary & Secondary profiles of aptX Adaptive R2 Encoder. \n + - Also configures TTP offsets for LL and HQ profiles. \n + -} + @h2xmlp_toolPolicy {Calibration}*/ + + +#include "spf_begin_pack.h" + +struct param_id_aptx_adaptive_enc_profile_t +{ + uint32_t primprofile; + /**< @h2xmle_description {Configures Primary Profile of Adaptive Encoder"} + @h2xmle_rangeList {"APTX_PPROFILE_UNCHANGED" = 0; + "APTX_PPROFILE_HIGH_QUALITY_0" = 1; + "APTX_PPROFILE_LOW_LATENCY_0" = 2; + "APTX_PPROFILE_LOW_LATENCY_1" = 4; + "APTX_PPROFILE_HIGH_QUALITY_1" = 5 } + + @h2xmle_default {1} */ + + uint32_t secprofile; + /**< @h2xmle_description {Configures Secondary Profile of Adaptive Encoder"} + @h2xmle_rangeList {"APTX_SPROFILE_UNCHANGED" = 0; + "APTX_SPROFILE_NONE" = 1 } + + @h2xmle_default {1} */ + + + uint32_t LLModeLatTarget0; + + /**< @h2xmle_description {Configures ttp offset for Profile LL-0.\n + Each bit represents 1mS of audio. \n + A value of 0 means 'do not change'} + @h2xmle_range {1..255} + @h2xmle_default {60} */ + + + uint32_t LLModeLatTarget1; + /**< @h2xmle_description {Configures ttp offset for Profile LL-1.\n + Each bit represents 1mS of audio. \n + A value of 0 means 'do not change'} + @h2xmle_range {1..255} + @h2xmle_default {80} */ + + + uint32_t hQLatTarget0; + /**< @h2xmle_description {Configures ttp offset for Profile HQ-0.\n + Each bit represents 4mS of audio. \n + A value of 0 means 'do not change'} + @h2xmle_range {1..255} + @h2xmle_default {50} */ + + + uint32_t hQLatTarget1; + /**< @h2xmle_description {Configures ttp offset for Profile HQ-1.\n + Each bit represents 4mS of audio. \n + A value of 0 means 'do not change'} + @h2xmle_range {1..255} + @h2xmle_default {50} */ + + + +} + +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_adaptive_enc_profile_t param_id_aptx_adaptive_enc_profile_t; + + + +/** ID of the aptx adaptive encoder Source Audio sample rate parameter. This parameter should be set at init time.*/ +#define PARAM_ID_APTX_ADAPTIVE_ENC_AUDIOSRC_INFO 0x08001186 +/* Structure payload for: PARAM_ID_APTX_ADAPTIVE_ENC_AUDIOSRC_INFO*/ +/** @h2xmlp_parameter {"PARAM_ID_APTX_ADAPTIVE_ENC_AUDIOSRC_INFO", PARAM_ID_APTX_ADAPTIVE_ENC_AUDIOSRC_INFO} + @h2xmlp_description {- Informs R2 Encoder what the sample rate of the original audio being encoded was.\n + - + -} + @h2xmlp_toolPolicy {Calibration}*/ + + +#include "spf_begin_pack.h" + +struct param_id_aptx_adaptive_enc_original_samplerate_t +{ + + uint16_t original_sample_rate; + /**< @h2xmle_description { Informs aptX Adaptive Encoder what sample rate the presented audio originally used.} + @h2xmle_rangeList {"No change (same as system setting)" = 0; + "44.1KHz" = 1; + "48kHz" = 2; + "88.2kHz" = 4; + "96kHz" = 8; + "192kHz" = 16} + + @h2xmle_default {0} */ + +} + +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_adaptive_enc_original_samplerate_t param_id_aptx_adaptive_enc_original_samplerate_t; + + + + +/** ID of the aptx adaptive encoder Source Audio sample rate parameter. This parameter can be set at run time.*/ +#define PARAM_ID_APTX_ADAPTIVE_ENC_SWITCH_TO_MONO 0x08001187 +/* Structure payload for: PARAM_ID_APTX_ADAPTIVE_ENC_SWITCH_TO_MONO*/ +/** @h2xmlp_parameter {"PARAM_ID_APTX_ADAPTIVE_ENC_SWITCH_TO_MONO", PARAM_ID_APTX_ADAPTIVE_ENC_SWITCH_TO_MONO} + @h2xmlp_description {- Switches the PCM mix at the input to the R2 Adaptive Encoder.\n + - + -} + @h2xmlp_toolPolicy {Calibration}*/ + + +#include "spf_begin_pack.h" + +struct param_id_aptx_adaptive_enc_switch_to_mono_t +{ + + uint32_t switch_between_mono_and_stereo; + /**< @h2xmle_description { Informs aptX Adaptive Encoder what sample rate the presented audio originally used.} + @h2xmle_rangeList {"switch from stereo to double mono" = 1; + "switch from double mono to stereo" = 2} + + @h2xmle_default {2} */ + +} + +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_adaptive_enc_switch_to_mono_t param_id_aptx_adaptive_enc_switch_to_mono_t; + + + +/*============================================================================== + Module +==============================================================================*/ + + +/** @h2xml_title1 {aptX Adaptive R2 Encoder} + @h2xml_title_agile_rev {aptX Adaptive R2 Encoder} + @h2xml_title_date {Oct 31, 2019} +*/ +#define MODULE_ID_APTX_ADAPTIVE_ENC 0x07001082 +/** + @h2xmlm_module {"MODULE_ID_APTX_ADAPTIVE_ENC", MODULE_ID_APTX_ADAPTIVE_ENC} + @h2xmlm_displayName {"aptX Adaptive R2 Encoder"} + @h2xmlm_description {This module is used as the encoder for aptX Adaptive R2 use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : xxx_enc_cfg_t\n + - Encodes data to format-id = 0x00013204\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following params:\n + -- PARAM_ID_ENCODER_OUTPUT_CONFIG\n + -- PARAM_ID_ENC_BITRATE\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 44.1, 48 \n + -- Number of channels : 2\n + -- Bit Width : 32\n + -- Bits Per Sample : 24\n + -- Q format : Q4.27\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- maximum bit rates in bps:\n + --- mono : n\a \n + --- stereo : xxxkbps \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_ctrlStaticPort {"COP_ENCODER_FEEDBACK_IN" = 0xC0000001, + "Bit rate level encoder feedback intent" = INTENT_ID_BT_ENCODER_FEEDBACK} + @h2xmlm_reqContcapabilities {APM_CONTAINER_CAP_CD} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_aptx_adaptive_enc_init_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aptx_adaptive_enc_profile_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aptx_adaptive_enc_original_samplerate_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aptx_adaptive_enc_switch_to_mono_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif //_APTX_ADAPTIVE_ENCODER_API_H_ diff --git a/spf/api/modules/aptx_adaptive_swb_decoder_api.h b/spf/api/modules/aptx_adaptive_swb_decoder_api.h new file mode 100755 index 0000000..d935405 --- /dev/null +++ b/spf/api/modules/aptx_adaptive_swb_decoder_api.h @@ -0,0 +1,106 @@ +/*============================================================================== + @file aptx_adaptive_swb_decoder_api.h + @brief This file contains aptx Adaptive SWB Decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _APTX_ADAPTIVE_SWB_DECODER_API_H_ +#define _APTX_ADAPTIVE_SWB_DECODER_API_H_ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +//#include "imcl_spm_intent_api.h" + + +/* Control port for receiving br info*/ +//#define COP_ENCODER_FEEDBACK_IN MM_NON_GUID(0xC0000001) + +/*============================================================================== + Parameters +==============================================================================*/ + +/** ID of the aptx adaptive SWB Speech decoder initialization parameter. This parameter should be set at init time.*/ +#define PARAM_ID_APTX_ADAPTIVE_SPEECH_DEC_INIT 0x0800118E +/* Structure payload for: PARAM_ID_APTX_ADAPTIVE_SPEECH_DEC_INIT */ +/** @h2xmlp_parameter {"PARAM_ID_APTX_ADAPTIVE_SPEECH_DEC_INIT ", PARAM_ID_APTX_ADAPTIVE_SPEECH_DEC_INIT } + @h2xmlp_description {- Configures the init parameters of the aptX Adaptive SWB Speech Decoder. \n + -} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct param_id_aptx_adaptive_speech_dec_init_t +{ + uint32_t speechMode; + /**< @h2xmle_description { Configures the Speech mode used by the aptX Kernel library \n + - note that both modes use a frame interval of 7.5mS} + @h2xmle_rangeList {"SWB Speech at 32kHz sample rate and 60 byte payload" = 0; + "SSWB Speech at 24kHz sample rate and 60 byte payload" = 4} + @h2xmle_default {0} */ + + uint32_t byteSwap; + /**< @h2xmle_description {Configures byte-swap of output buffer. \n + If enabled, transforms AABBCCDD to DDCCBBAA} + @h2xmle_rangeList {"Byte swap disabled" = 0; + "Byte swap enabled" = 1} + @h2xmle_default {0} */ + +} + +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_adaptive_speech_dec_init_t param_id_aptx_adaptive_speech_dec_init_t; + + + + + +/** @h2xml_title1 {aptX Adaptive R2 SWB Decoder} + @h2xml_title_agile_rev {aptX Adaptive R2 SWB Decoder} + @h2xml_title_date {Nov 21, 2019} +*/ +#define MODULE_ID_APTX_ADAPTIVE_SWB_DEC 0x07001083 +/** + @h2xmlm_module {"MODULE_ID_APTX_ADAPTIVE_SWB_DEC", MODULE_ID_APTX_ADAPTIVE_SWB_DEC} + @h2xmlm_displayName {"aptX Adaptive R2 SWB Speech Decoder"} + @h2xmlm_description {This module is used as the decoder for aptX Adaptive R2 SWB Speech use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_decoder_output_config_t : xxx_enc_cfg_t\n + - Encodes data to format-id = 0x00013208\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following params:\n + -- PARAM_ID_ENCODER_OUTPUT_CONFIG\n + -- PARAM_ID_ENC_BITRATE\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 24kHz 32kHz \n + -- Number of channels : 1\n + -- Bit Width : 32\n + -- Bits Per Sample : 32\n + -- Q format : Q31\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- maximum bit rates in bps:\n + --- mono : 64kbps \n + --- stereo : n/a \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_reqContcapabilities {APM_CONTAINER_CAP_CD} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @h2xml_Select {"param_id_aptx_adaptive_speech_dec_init_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif // _APTX_ADAPTIVE_SWB_DECODER_API_H_ diff --git a/spf/api/modules/aptx_adaptive_swb_encoder_api.h b/spf/api/modules/aptx_adaptive_swb_encoder_api.h new file mode 100755 index 0000000..d75be2f --- /dev/null +++ b/spf/api/modules/aptx_adaptive_swb_encoder_api.h @@ -0,0 +1,102 @@ +/*============================================================================== + @file aptx_adaptive_swb_encoder_api.h + @brief This file contains aptx Adaptive SWB Encoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _APTX_ADAPTIVE_SWB_ENCODER_API_H_ +#define _APTX_ADAPTIVE_SWB_ENCODER_API_H_ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "imcl_spm_intent_api.h" + + +/* Control port for receiving br info*/ +//#define COP_ENCODER_FEEDBACK_IN MM_NON_GUID(0xC0000001) + + +/*============================================================================== + Parameters +==============================================================================*/ +/** ID of the aptx adaptive SWB Speech encoder initialization parameter. This parameter should be set at init time.*/ +#define PARAM_ID_APTX_ADAPTIVE_SPEECH_ENC_INIT 0x0800118D +/* Structure payload for: PARAM_ID_APTX_ADAPTIVE_SPEECH_ENC_INIT*/ +/** @h2xmlp_parameter {"PARAM_ID_APTX_ADAPTIVE_SPEECH_ENC_INIT", PARAM_ID_APTX_ADAPTIVE_SPEECH_ENC_INIT} + @h2xmlp_description {- Configures the init parameters of the aptX Adaptive SWB Speech Encoder. \n + -} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct param_id_aptx_adaptive_speech_enc_init_t +{ + uint32_t speechMode; + /**< @h2xmle_description { Configures the Speech mode used by the aptX Kernel library \n + - note that both modes use a frame interval of 7.5mS.} + @h2xmle_rangeList {"SWB Speech at 32kHz sample rate and 60 byte payload" = 0; + "SSWB Speech at 24kHz sample rate and 60 byte payload" = 4} + @h2xmle_default {0} */ + + uint32_t byteSwap; + /**< @h2xmle_description {Configures byte-swap of output buffer. \n + If enabled, transforms AABBCCDD to DDCCBBAA} + @h2xmle_rangeList {"Byte swap disabled" = 0; + "Byte swap enabled" = 1} + @h2xmle_default {0} */ + +} + +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_adaptive_speech_enc_init_t param_id_aptx_adaptive_speech_enc_init_t; + + + + + +/** @h2xml_title1 {aptX Adaptive R2 SWB Encoder} + @h2xml_title_agile_rev {aptX Adaptive R2 SWB Encoder} + @h2xml_title_date {Nov 21, 2019} +*/ +#define MODULE_ID_APTX_ADAPTIVE_SWB_ENC 0x07001084 +/** + @h2xmlm_module {"MODULE_ID_APTX_ADAPTIVE_SWB_ENC", MODULE_ID_APTX_ADAPTIVE_SWB_ENC} + @h2xmlm_displayName {"aptX Adaptive R2 SWB Speech Encoder"} + @h2xmlm_description {This module is used as the encoder for aptX Adaptive R2 SWB Speech use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : xxx_enc_cfg_t\n + - Encodes data to format-id = 0x00013204\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following params:\n + -- PARAM_ID_ENCODER_OUTPUT_CONFIG\n + -- PARAM_ID_ENC_BITRATE\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 44.1, 48 \n + -- Number of channels : 2\n + -- Bit Width : 32\n + -- Bits Per Sample : 24\n + -- Q format : Q4.27\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- maximum bit rates in bps:\n + --- mono : n\a \n + --- stereo : xxxkbps \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_reqContcapabilities {APM_CONTAINER_CAP_CD} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_aptx_adaptive_speech_enc_init_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif //_APTX_ADAPTIVE_SWB_ENCODER_API_H_ diff --git a/spf/api/modules/aptx_classic_decoder_api.h b/spf/api/modules/aptx_classic_decoder_api.h new file mode 100644 index 0000000..3541f3a --- /dev/null +++ b/spf/api/modules/aptx_classic_decoder_api.h @@ -0,0 +1,46 @@ +/*============================================================================== + @file aptx_decoder_api.h + @brief This file contains aptx Classic decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _APTX_CLASSIC_DECODER_H_ +#define _APTX_CLASSIC_DECODER_H_ + +#include "common_enc_dec_api.h" +#include "ar_defs.h" + +/** @h2xml_title1 {aptX Classic Decoder} + @h2xml_title_agile_rev {aptX Classic Decoder} + @h2xml_title_date {August 8, 2019} +*/ + +#define MODULE_ID_APTX_CLASSIC_DEC 0x0700107D +/** + @h2xmlm_module {"MODULE_ID_APTX_CLASSIC_DEC", MODULE_ID_APTX_CLASSIC_DEC} + @h2xmlm_displayName {"aptx Classic Decoder"} + @h2xmlm_description {This module is used as the decoder for aptX Classic use cases.\n + - This module has only one input and one output port.\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_reqContcapabilities {APM_CONTAINER_CAP_CD} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> +*/ + +#endif //_APTX_CLASSIC_DECODER_H_ diff --git a/spf/api/modules/aptx_classic_encoder_api.h b/spf/api/modules/aptx_classic_encoder_api.h new file mode 100644 index 0000000..bbb51b9 --- /dev/null +++ b/spf/api/modules/aptx_classic_encoder_api.h @@ -0,0 +1,158 @@ +/*============================================================================== + @file aptx_classic_encoder_api.h + @brief This file contains aptx Classic encoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _APTX_CLASSIC_ENCODER_API_H_ +#define _APTX_CLASSIC_ENCODER_API_H_ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + + +/*============================================================================== + Parameters +==============================================================================*/ +/** ID of the aptx classic encoder output threshold parameter.This parameter should be set at init time.*/ +#define PARAM_ID_APTX_CLASSIC_SET_OUTPUT_THRESHOLD 0x08001180 +/* Structure payload for: PARAM_ID_APTX_CLASSIC_SET_OUTPUT_THRESHOLD*/ +/** @h2xmlp_parameter {"PARAM_ID_APTX_CLASSIC_SET_OUTPUT_THRESHOLD", PARAM_ID_APTX_CLASSIC_SET_OUTPUT_THRESHOLD} + @h2xmlp_description {- Configures the output threshold of aptX Classic Encoder. \n + - Permissible values are in the range 64 to 1500 bytes.. \n + - .. and must be divisible by 4, since 4 is the smallest possible output 'packet' from Classic Encoder. \n + -> Values outside the above range, or not divisible by 4, are rejected with EBADPARAM return code. \n + -> Since aptX compression ratio is fixed at 4:1, the input threshold is also configured from the output threshold.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct param_id_aptx_classic_output_threshold_payload_t +{ + uint32_t output_threshold; + /**< @h2xmle_description {Threshold in bytes, must be divisible by 4} + @h2xmle_range {64..1500} + @h2xmle_default {656} + */ +} +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_classic_output_threshold_payload_t param_id_aptx_classic_output_threshold_payload_t; + + +/** ID of the aptx classic encoder sync mode parameter.This parameter should be set at init time.*/ +#define PARAM_ID_APTX_CLASSIC_SET_SYNC_MODE 0x08001181 +/* Structure payload for: PARAM_ID_APTX_CLASSIC_SET_SYNC_MODE*/ +/** @h2xmlp_parameter {"PARAM_ID_APTX_CLASSIC_SET_SYNC_MODE", PARAM_ID_APTX_CLASSIC_SET_SYNC_MODE} + @h2xmlp_description {- Configures the autosync mode, startup mode, and CVR fade duration of aptX Classic Encoder} + + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct param_id_aptx_classic_sync_mode_payload_t +{ + int32_t sync_mode; + /**< @h2xmle_description { Configures the autosync mode of aptX Classic Encoder} + @h2xmle_rangeList {"STEREO SYNC" = 0; + "DUAL AUTOSYNC" = 1; + "NO AUTOSYNC" = 2} + @h2xmle_default {0} */ + + int32_t startup_mode; + /**< @h2xmle_description { Configures the startup sync mode of aptX Classic Encoder} + @h2xmle_rangeList {"STEREO_SYNC" = 0; + "DUAL AUTOSYNC" = 1} + @h2xmle_default {0} */ + + int32_t cvr_fade_duration; + /**< @h2xmle_description {Cosine Volume Ramp duration in mS, for transition between stereo and L+R/2 dual mono (TWS+ Earbuds removal use case)} + @h2xmle_range {1..255} + @h2xmle_default {255} + */ +} +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_classic_sync_mode_payload_t param_id_aptx_classic_sync_mode_payload_t; + + +/** ID of the aptx classic encoder switch parameter.This parameter can be set at run time.*/ +#define PARAM_ID_APTX_CLASSIC_SWITCH_ENC_PCM_INPUT 0x08001182 +/* Structure payload for: PARAM_ID_APTX_CLASSIC_SWITCH_ENC_PCM_INPUT*/ +/** @h2xmlp_parameter {"PARAM_ID_APTX_CLASSIC_SWITCH_ENC_PCM_INPUT", PARAM_ID_APTX_CLASSIC_SWITCH_ENC_PCM_INPUT} + @h2xmlp_description {- Switches the input PCM for aptX Classic Encoder to be either normal stereo, or (L+R/2) mix to both L & R channels. \n + - Permissible values are: \n + - 1 = transition from stereo to L+R/2 mono with CVR fade. \n + - 2 = transition from L+R/2 mono to stereo with CVR fade. \n + - payload values outside these valid values are rejected with EBADPARAM return code.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct param_id_aptx_classic_switch_enc_pcm_input_payload_t +{ + int32_t transition_direction; + /**< @h2xmle_description {Switches input PCM to be either normal stereo, or (L+R/2) mix to both L & R channels (TWS+ Earbuds removal use case)} + @h2xmle_rangeList {"transition from stereo to L+R/2 mono with CVR fade" = 1; + "transition from L+R/2 mono to stereo with CVR fade" = 2} + @h2xmle_default {1} */ +} +#include "spf_end_pack.h" +; + +typedef struct param_id_aptx_classic_switch_enc_pcm_input_payload_t param_id_aptx_classic_switch_enc_pcm_input_payload_t; + + +/*============================================================================== + Module +==============================================================================*/ + + +/** @h2xml_title1 {aptX Classic Encoder} + @h2xml_title_agile_rev {aptX Classic Encoder} + @h2xml_title_date {August 8, 2019} +*/ +#define MODULE_ID_APTX_CLASSIC_ENC 0x0700107E +/** + @h2xmlm_module {"MODULE_ID_APTX_CLASSIC_ENC", MODULE_ID_APTX_CLASSIC_ENC} + @h2xmlm_displayName {"aptX Classic Encoder"} + @h2xmlm_description {This module is used as the encoder for aptX Classic use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : xxx_enc_cfg_t\n + - Encodes data to format-id = 0x000131FF\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following params:\n + -- ------------------------ \n + -- --\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 44.1, 48 \n + -- Number of channels : 2\n + -- Bit Width : 16\n + -- Bits Per Sample : 16\n + -- Q format : Q15\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- maximum bit rates in bps:\n + --- mono : n\a \n + --- stereo : 384kbps (48K), 352.8kbps (44K1) \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_reqContcapabilities {APM_CONTAINER_CAP_CD} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_aptx_classic_output_threshold_payload_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aptx_classic_sync_mode_payload_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_aptx_classic_switch_enc_pcm_input_payload_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif //_APTX_CLASSIC_ENCODER_API_H_ diff --git a/spf/api/modules/aptx_hd_decoder_api.h b/spf/api/modules/aptx_hd_decoder_api.h new file mode 100644 index 0000000..b1e32b7 --- /dev/null +++ b/spf/api/modules/aptx_hd_decoder_api.h @@ -0,0 +1,46 @@ +/*============================================================================== + @file aptx_hd_decoder_api.h + @brief This file contains aptx HD decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _APTX_HD_DECODER_H_ +#define _APTX_HD_DECODER_H_ + +#include "common_enc_dec_api.h" +#include "ar_defs.h" + +/** @h2xml_title1 {aptX HD Decoder} + @h2xml_title_agile_rev {aptX HD Decoder} + @h2xml_title_date {December 6, 2019} +*/ + +#define MODULE_ID_APTX_HD_DEC 0x0700107F +/** + @h2xmlm_module {"MODULE_ID_APTX_HD_DEC", MODULE_ID_APTX_HD_DEC} + @h2xmlm_displayName {"aptx HD Decoder"} + @h2xmlm_description {This module is used as the decoder for aptX HD use cases.\n + - This module has only one input and one output port.\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_reqContcapabilities {APM_CONTAINER_CAP_CD} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> +*/ + +#endif //_APTX_HD_DECODER_H_ diff --git a/spf/api/modules/aptx_hd_encoder_api.h b/spf/api/modules/aptx_hd_encoder_api.h new file mode 100644 index 0000000..7e7e878 --- /dev/null +++ b/spf/api/modules/aptx_hd_encoder_api.h @@ -0,0 +1,55 @@ +/*============================================================================== + @file aptx_hd_encoder_api.h + @brief This file contains aptx HD encoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _APTX_HD_ENCODER_API_H_ +#define _APTX_HD_ENCODER_API_H_ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {aptX HD Encoder} + @h2xml_title_agile_rev {aptX HD Encoder} + @h2xml_title_date {November 15, 2019} +*/ +#define MODULE_ID_APTX_HD_ENC 0x07001080 +/** + @h2xmlm_module {"MODULE_ID_APTX_HD_ENC", MODULE_ID_APTX_HD_ENC} + @h2xmlm_displayName {"aptX HD Encoder"} + @h2xmlm_description {This module is used as the encoder for aptX HD use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : xxx_enc_cfg_t\n + - Encodes data to format-id = 0x00013200\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following params:\n + -- TBC \n + -- \n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 44.1, 48 \n + -- Number of channels : 2\n + -- Bit Width : 24\n + -- Bits Per Sample : 32\n + -- Q format : Q31\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- maximum bit rates in bps:\n + --- mono : n\a \n + --- stereo : 576kbps \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_reqContcapabilities {APM_CONTAINER_CAP_CD} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + +#endif //_APTX_HD_ENCODER_API_H_ diff --git a/spf/api/modules/asr_module_calibration_api.h b/spf/api/modules/asr_module_calibration_api.h new file mode 100644 index 0000000..380409d --- /dev/null +++ b/spf/api/modules/asr_module_calibration_api.h @@ -0,0 +1,937 @@ +/*================================================== + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + ==================================================*/ + +#ifndef ASR_MODULE_CALIBRATION_API_H +#define ASR_MODULE_CALIBRATION_API_H + +/** @h2xml_title1 {Adaptive Speech Recognition (ASR)} + @h2xml_title_agile_rev {Adaptive Speech Recognition (ASR)} + @h2xml_title_date {Feb 26, 2024} */ + +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/* ASR client id definitions */ +typedef enum asr_client_id_t +{ + ASR_CLIENT_INVALID = 0, + ASR_CLIENT_HLOS = 1, + ASR_CLIENT_LLS = 2 +} asr_client_id_t; + +typedef enum asr_output_mode_t +{ + ASR_NON_BUFFERED = 0, /* Send ASR engine output immediately. Each buffer shall have one payload + corresponding to a partial/complete segment of speech. + Typical usage : live display of output. */ + + ASR_BUFFERED, /* Buffer up ASR engine output based on configured buffer size from client. + Send the event to clients once buffer is full. + Typical usage : save transcription output in background. */ + + ASR_LOGGER, /* Buffer up ASR engine output based on configured buffer size from client. + Send the output when the client queries it. + Typical usage : save transcription output in a circular buffer. */ + + ASR_TS_NON_BUFFERED, /* Send ASR engine output with timestamps immediately. Each buffer shall have one payload + corresponding to a partial/complete segment of speech. + Typical usage : live display of output. */ + + ASR_TS_BUFFERED, /* Buffer up ASR engine output with timestamps based on configured buffer size from client. + Send the event to clients once buffer is full. + Typical usage : save transcription output in background. */ + + ASR_TS_LOGGER /* Buffer up ASR engine output with timestamps based on configured buffer size from client. + Send the output when the client queries it. + Typical usage : save transcription output in a circular buffer. */ +}asr_output_mode_t; + +/* +Supported language codes +*/ +typedef enum ASR_LANGUAGE_CODE_t{ + en_US=0, + zh_CN, + hi_IN, + es_US, + ko_KR, + ja_JP, + language_code_end_1 +}ASR_LANGUAGE_CODE_t; + +/* Global unique Module ID definition + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_ASR 0x7001176 + +/** + @h2xmlm_module {"MODULE_ID_ASR", + MODULE_ID_ASR} + @h2xmlm_displayName {"Adaptive Speech Recognition"} + @h2xmlm_description {ID of the ASR module.\n + + . This module supports the following parameter IDs:\n + . #PARAM_ID_ASR_CONFIG\n + . #PARAM_ID_ASR_FORCE_OUTPUT_V2\n + . #PARAM_ID_ASR_INPUT_THRESHOLD_V2\n + . #PARAM_ID_ASR_OUTPUT_CONFIG_V2\n + . #PARAM_ID_ASR_OUTPUT_V3\n + \n + . Supported Input Media Format: \n + . Data Format : FIXED_POINT \n + . fmt_id : MEDIA_FMT_ID_PCM \n + . Sample Rates : 16000 \n + . Number of channels : 1 \n + . Channel type : Supported channel mapping based on number of channels is given below. \n + . Bits per sample : 16 \n + . Q format : Q15 for bps = 16 \n + . Interleaving : Deinterleaved Unpacked \n + . Signed/unsigned : Signed \n + \n + . Supported Channel Mapping based on number of input channels: \n + . 1: mono [C] \n + \n + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @h2xmlm_ctrlDynamicPortIntent { "DAM-ASR Control" = INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL, + maxPorts= 1 } + + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + +*/ + + +#define ASR_ENPU_RELEASE_VERSION_MAJOR 0x00000001 +#define ASR_ENPU_RELEASE_VERSION_MINOR 0x00000000 + +#define PARAM_ID_ASR_VERSION 0x08001AA3 +/** @h2xmlp_parameter {"PARAM_ID_ASR_VERSION", PARAM_ID_ASR_VERSION} + @h2xmlp_description {Structure to get the current library version.} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +typedef struct asr_version_t asr_version_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asr_version_t +{ + uint32_t lib_version_low; + /**< @h2xmle_description {Lower 32 bits of the 64-bit library version number} + @h2xmle_default {ASR_ENPU_RELEASE_VERSION_MAJOR} */ + uint32_t lib_version_high; + /**< @h2xmle_description {Higher 32 bits of the 64-bit library version number} + @h2xmle_default {ASR_ENPU_RELEASE_VERSION_MINOR} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {asr_version_t} + @h2xmlm_InsertParameter */ + +/* ID of the ASR configuration parameter used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_CONFIG 0x08001AA4 + +/* Structure for the configuration parameters of ASR module. */ +typedef struct param_id_asr_config_t param_id_asr_config_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_CONFIG", PARAM_ID_ASR_CONFIG} + @h2xmlp_description {Configures the ASR module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_CONFIG parameter used by the + ASR module. + */ +struct param_id_asr_config_t +{ + uint32_t input_language_code; // input language code, refer enum ASR_LANGUAGE_CODE_t + /**< @h2xmle_description {Code to specify ASR input language.} + @h2xmle_rangeList {"en_US"=en_US;"zh_CN"=zh_CN;"hi_IN"=hi_IN;"es_US"=es_US;"ko_KR"=ko_KR;"ja_JP"=ja_JP;"language_code_end"=language_code_end_1} + @h2xmle_default {en_US} */ + uint32_t output_language_code; // output language code, refer enum ASR_LANGUAGE_CODE_t + /**< @h2xmle_description {Code to specify ASR output language.} + @h2xmle_rangeList {"en_US"=en_US;"zh_CN"=zh_CN;"hi_IN"=hi_IN;"es_US"=es_US;"ko_KR"=ko_KR;"ja_JP"=ja_JP;"language_code_end"=language_code_end_1} + @h2xmle_default {en_US} */ + uint32_t enable_language_detection; // language detection switch enable or disable flag + /**< @h2xmle_description {Flag to enable or disable the language detection switch.} + @h2xmle_rangeList {enabled=1;disabled=0} + @h2xmle_default {0} */ + uint32_t enable_translation; // translation switch enable or disable flag + /**< @h2xmle_description {Flag to enable or disable the translation switch.} + @h2xmle_rangeList {enabled=1;disabled=0} + @h2xmle_default {0} */ + uint32_t enable_continuous_mode; // continuous mode enable or disable flag + /**< @h2xmle_description {Flag to enable or disable the continuous mode.} + @h2xmle_rangeList {enabled=1;disabled=0} + @h2xmle_default {0} */ + uint32_t enable_partial_transcription; // partial transcription switch enable or disable flag + /**< @h2xmle_description {Flag to enable or disable the partial transcription switch.} + @h2xmle_rangeList {enabled=1;disabled=0} + @h2xmle_default {0} */ + uint32_t threshold; + /**< @h2xmle_description {Minimum confidence value (threshold) needed by the ASR to generate transcription.} + @h2xmle_range {0..100} + @h2xmle_default {50} */ + uint32_t timeout_duration; // ASR processing timeout (in ms) + /**< @h2xmle_description {ASR processing timeout (ASR will stop if cumulative buffer duration exceeds this value, even if speech continues), in ms.} + @h2xmle_range {0..30000} ms + @h2xmle_default {10000} */ + uint32_t vad_hangover_duration; // "No speech" duration needed before determining speech has ended (in ms) + /**< @h2xmle_description {'No speech' duration needed before determining speech has ended, in ms.} + @h2xmle_range {0..5000} ms + @h2xmle_default {1000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/* @h2xml_Select {param_id_asr_config_t} + @h2xmlm_InsertParameter */ + + +/* ID of the ASR input threshold parameter used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_INPUT_THRESHOLD 0x08001AA5 + +/* Structure for the input threshold parameter of ASR module. */ +typedef struct param_id_asr_input_threshold_t param_id_asr_input_threshold_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_INPUT_THRESHOLD", PARAM_ID_ASR_INPUT_THRESHOLD} + @h2xmlp_description {Param to control wakeup threshold for ASR engine based on input buffering i.e., to control the frequency or resolution at which ASR engine should be woken up periodically } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_INPUT_THRESHOLD parameter used by the + ASR module. + */ +struct param_id_asr_input_threshold_t +{ + uint32_t buf_duration_ms; // input threshold in milli seconds + /**< @h2xmle_description {Duration of input threshold in milli seconds, used to create input buffering and wakeup control.} + @h2xmle_range {100..20000} ms + @h2xmle_default {3000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_input_threshold_t} + @h2xmlm_InsertParameter */ + +/* ID of the ASR input threshold parameter V2 used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_INPUT_THRESHOLD_V2 0x08001BC5 + +/* Structure for the input threshold parameter V2 of ASR module with client ID support. */ +typedef struct param_id_asr_input_threshold_v2_t param_id_asr_input_threshold_v2_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_INPUT_THRESHOLD_V2", PARAM_ID_ASR_INPUT_THRESHOLD_V2} + @h2xmlp_description {Param to control wakeup threshold for ASR engine based on input buffering with client ID support} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_INPUT_THRESHOLD_V2 parameter used by the + ASR module. + */ +struct param_id_asr_input_threshold_v2_t +{ + uint32_t client_id; // Client ID/destination address + /**< @h2xmle_description {Client ID for this input threshold configuration. + This API allows multiple clients to have unique input threshold configurations. + ASR_CLIENT_HLOS - Client is HLOS. + ASR_CLIENT_LLS - Client is Sensor.} + @h2xmle_default {1} + @h2xmle_rangeList {"ASR_CLIENT_HLOS"=1, "ASR_CLIENT_LLS"=2} */ + uint32_t buf_duration_ms; // input threshold in milli seconds + /**< @h2xmle_description {Duration of input threshold in milli seconds, used to create input buffering and wakeup control.} + @h2xmle_range {100..20000} ms + @h2xmle_default {3000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_input_threshold_v2_t} + @h2xmlm_InsertParameter */ + +/* ID of the ASR force output parameter used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_FORCE_OUTPUT 0x08001AA6 + +/* Structure for the force output parameter of ASR module. */ +typedef struct param_id_asr_force_output_t param_id_asr_force_output_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_FORCE_OUTPUT", PARAM_ID_ASR_FORCE_OUTPUT} + @h2xmlp_description {Forces the ASR module to produce output event irrespective of configured input threshold} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_FORCE_OUTPUT parameter used by the + ASR module. + */ +struct param_id_asr_force_output_t +{ + uint32_t force_output; // forces ASR to process and produce output + /**< @h2xmle_description {forces ASR module to produce output with current data without waiting for further data accumulation.} + @h2xmle_default {1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_force_output_t} + @h2xmlm_InsertParameter */ + +/* ID of the ASR force output parameter V2 used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_FORCE_OUTPUT_V2 0x08001BC6 + +/* Structure for the force output parameter V2 of ASR module with client ID support. */ +typedef struct param_id_asr_force_output_v2_t param_id_asr_force_output_v2_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_FORCE_OUTPUT_V2", PARAM_ID_ASR_FORCE_OUTPUT_V2} + @h2xmlp_description {Forces the ASR module to produce output event for a specific client irrespective of configured input threshold} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_FORCE_OUTPUT_V2 parameter used by the + ASR module. + */ +struct param_id_asr_force_output_v2_t +{ + uint32_t client_id; // Client ID + /**< @h2xmle_description {Client ID for which to force output. + This API allows forcing output for a specific client in multi-client scenarios. + ASR_CLIENT_HLOS - Force output for HLOS client. + ASR_CLIENT_LLS - Force output for Sensor client.} + @h2xmle_default {1} + @h2xmle_rangeList {"ASR_CLIENT_HLOS"=1} */ + uint32_t force_output; // forces ASR to process and produce output + /**< @h2xmle_description {forces ASR module to produce output with current data without waiting for further data accumulation.} + @h2xmle_default {1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_force_output_v2_t} + @h2xmlm_InsertParameter */ + +/* ID of the ASR output configuration parameter used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_OUTPUT_CONFIG 0x08001AA7 + +/* Structure for the output configuration parameter of ASR module. */ +typedef struct param_id_asr_output_config_t param_id_asr_output_config_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_OUTPUT_CONFIG", PARAM_ID_ASR_OUTPUT_CONFIG} + @h2xmlp_description {Param to configure required output mode and buffering for ASR engine } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + + + +struct param_id_asr_output_config_t +{ + uint32_t output_mode; // mode of ASR output data requested by application + /**< @h2xmle_description {Configuration to specify transcription output mode depending on usecase requirement. + ASR_NON_BUFFERED - Output of each ASR algo process is immediately sent to client. + ASR_BUFFERED - Output of each ASR algo process is buffered and sent to client intermittently. + ASR_LOGGER - Output of each ASR algo process is stored and sent to client on demand. + ASR_TS_NON_BUFFERED - Output of each ASR algo process is immediately sent to client with timestamps. + ASR_TS_BUFFERED - Output of each ASR algo process is buffered and sent to client intermittently with timestamps. + ASR_TS_LOGGER - Output of each ASR algo process is stored and sent to client on demand with timestamps.} + @h2xmle_default {ASR_NON_BUFFERED} + @h2xmle_rangeList {"ASR_NON_BUFFERED"=0, "ASR_BUFFERED"=1, "ASR_LOGGER"=2, "ASR_TS_NON_BUFFERED"=3, "ASR_TS_BUFFERED"=4, "ASR_TS_LOGGER"=5} */ + uint32_t out_buf_size; // size in bytes of buffer to use in different output modes, primarily in buffered mode + /**< @h2xmle_description {Configuration to specify transcription output buffer size depending on usecase requirement. } + @h2xmle_default {0} // ASR engine controlled default if not configured + @h2xmle_range {0.. 262144} */ + uint32_t num_bufs; // Number of buffers + /**< @h2xmle_description {Configuration to specify number of output buffers . } + @h2xmle_default {1} // ASR engine controlled default if not configured + @h2xmle_range {1.. 16} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_output_config_t} + @h2xmlm_InsertParameter */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_asr_output_config_v2_base_t +{ + uint32_t client_id; // Client ID/destination address + /**< @h2xmle_description {Client details for this configuration. + This API allow multiple clients to have unique configurations + ASR_CLIENT_HLOS - Client is HLOS. + ASR_CLIENT_LLS - Client is Sensor.} + @h2xmle_default {1} + @h2xmle_rangeList {"ASR_CLIENT_HLOS"=1, "ASR_CLIENT_LLS"=2} */ + uint32_t output_mode; // mode of ASR output data requested by application + /**< @h2xmle_description {Configuration to specify transcription output mode depending on usecase requirement. + ASR_NON_BUFFERED - Output of every process input frame is immediately sent to client. + ASR_BUFFERED - Output of every process input frame is buffered and sent to client intermittently. + ASR_LOGGER - Output of every process input frame is stored and sent to client on demand. + ASR_TS_NON_BUFFERED - Output of every process input frame is immediately sent to client with timestamps. + ASR_TS_BUFFERED - Output of every process input frame is buffered and sent to client intermittently with timestamps. + ASR_TS_LOGGER - Output of every process input frame is stored and sent to client on demand with timestamps.} + @h2xmle_default {ASR_NON_BUFFERED} + @h2xmle_rangeList {"ASR_NON_BUFFERED"=0, "ASR_BUFFERED"=1, "ASR_LOGGER"=2, "ASR_TS_NON_BUFFERED"=3, "ASR_TS_BUFFERED"=4, "ASR_TS_LOGGER"=5} */ + uint32_t out_buf_size; // size in bytes of buffer to use in different output modes + /**< @h2xmle_description {Configuration to specify transcription output buffer size depending on usecase requirement.} + @h2xmle_default {0} // ASR engine controlled default if not configured + @h2xmle_range {0..262144} */ + uint32_t num_bufs; // Number of buffers + /**< @h2xmle_description {Configuration to specify number of output buffers.} + @h2xmle_default {1} // ASR engine controlled default if not configured + @h2xmle_range {1..16} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* ID of the ASR output configuration V2 parameter used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_OUTPUT_CONFIG_V2 0x08001BC3 + +/* Structure for the multi-client output configuration parameter of ASR module. */ +typedef struct param_id_asr_output_config_v2_t param_id_asr_output_config_v2_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_OUTPUT_CONFIG_V2", PARAM_ID_ASR_OUTPUT_CONFIG_V2} + @h2xmlp_description {Param to configure output mode and buffering for multiple ASR clients simultaneously} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_asr_output_config_v2_t +{ + uint32_t num_clients; + /**< @h2xmle_description {Number of client configurations provided (typically 1 or 2)} + @h2xmle_default {1} + @h2xmle_range {1..2} */ + +#if defined(__H2XML__) + param_id_asr_output_config_v2_base_t client_configs[0]; + /**< @h2xmle_description {Variable array of client-specific output configurations} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_output_config_v2_t} + @h2xmlm_InsertParameter */ + + +#define EVENT_ID_ASR_OUTPUT 0x08001AA8 + +/* Structure definition for Parameter */ +/** @parameter {"EVENT_ID_ASR_OUTPUT",EVENT_ID_ASR_OUTPUT} + @description {Event raised by ASR to the clients; registration and event have differnt payload types} + @toolPolicy {NO_SUPPORT}*/ + +/** ################################ Struct definitions for event registration################### */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_asr_output_reg_cfg_t +{ + uint32_t event_payload_type; + /**< @h2xmle_description {Field to configure event payload type} + QUERY - Client queries the output via getparam upon receiving ASR output event. + INBAND - ASR output event has the output payload inband in the event.} + OPTIMAL - ASR output event can be INBAND or QUERY based, flag in event + payload indicates the mode.} + @h2xmle_default {0} + @h2xmle_rangeList {"QUERY"=0, "INBAND"=1, "OPTIMAL"=2} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_asr_output_reg_cfg_t event_id_asr_output_reg_cfg_t; + +#define EVENT_ID_ASR_OUTPUT_V2 0x08001BCA + +/* Structure definition for Parameter V2 with client ID support */ +/** @parameter {"EVENT_ID_ASR_OUTPUT_V2",EVENT_ID_ASR_OUTPUT_V2} + @description {Event raised by ASR to the clients with client ID support; registration and event have different payload types} + @toolPolicy {NO_SUPPORT}*/ + +/* V2 event registration configuration with client ID */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_asr_output_reg_cfg_v2_t +{ + uint32_t client_id; + /**< @h2xmle_description {Field to identify client ID} + ASR_CLIENT_HLOS - Client is HLOS. + ASR_CLIENT_LLS - Client is Sensor.} + @h2xmle_default {1} + @h2xmle_rangeList {"ASR_CLIENT_HLOS"=1, "ASR_CLIENT_LLS"=2} */ + + uint32_t event_payload_type; + /**< @h2xmle_description {Field to configure event payload type} + QUERY - Client queries the output via getparam upon receiving ASR output event. + INBAND - ASR output event has the output payload inband in the event. + OPTIMAL - ASR output event can be INBAND or QUERY based, flag in event + payload indicates the mode.} + @h2xmle_default {0} + @h2xmle_rangeList {"QUERY"=0, "INBAND"=1, "OPTIMAL"=2} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_asr_output_reg_cfg_v2_t event_id_asr_output_reg_cfg_v2_t; + +/** ################################ Struct definitions for raised event ################### */ + + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Maximum transcription text size of ASR output in one process call */ +#define MAX_TRANSCRIPTION_CHAR_SIZE 1024 + +enum asr_output_status_value +{ + ASR_SUCCESS = 0, + ASR_FAIL = 1, + ASR_TIMEOUT = 12, +}; + +struct asr_output_status_t +{ + uint32_t status; + /**< @h2xmle_description {Status of ASR output in this payload} + @h2xmle_default {0} + @h2xmle_rangeList {"ASR_SUCCESS"=0,"ASR_FAIL"=1,"ASR_TIMEOUT"=12} */ + + uint32_t is_final; + /**< @h2xmle_description {Field indicating payload is partial output of ASR or complete} + @h2xmle_default {TRUE} + @h2xmle_rangeList {"TRUE"=1, "FALSE"=0} */ + + uint32_t confidence; + /**< @h2xmle_description {Field indicating confidence level of output} */ + + uint32_t text_size; + /**< @h2xmle_description {Field indicating size of valid text including NULL Char } */ + + uint8_t text[MAX_TRANSCRIPTION_CHAR_SIZE]; + /**< @h2xmle_description {ASR output text } */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct asr_output_status_t asr_output_status_t; + +#define PARAM_ID_ASR_LLM 0x08001AA9 + +typedef struct asr_model_param_t asr_model_param_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_LLM", PARAM_ID_ASR_LLM} + @h2xmlp_description {NN Model related parameters} + @h2xmlp_ToolPolicy {CALIBRATION} + @h2xmlp_isHwAccel {FALSE} + @h2xmlp_isNeuralNetParam {TRUE} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType { Shared } +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct asr_model_param_t +{ + uint32_t model_align; + /**< @h2xmle_description {Data Alignment required for the model_data} + @h2xmle_default {256} + @h2xmle_range {0..8192} + @h2xmle_group {SPF} + @h2xmle_subgroup {NNVAD} + @h2xmle_policy {Advanced} */ + + uint32_t model_offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of model by model_align} + @h2xmle_default {0} + @h2xmle_range {0..8191} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint32_t model_size; + /**< @h2xmle_description {Size of the model in bytes} + @h2xmle_default {0} + @h2xmle_range {0x00000000..0xFFFFFFFF} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint8_t model[0]; + /**< @h2xmle_description {Model data: The path to the model file on the platform} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/*TODO: move it to */ +/* Event config to provide the info of getparam vs inband vs both */ +struct event_id_asr_output_event_t +{ + uint32_t event_payload_type; + /**< @h2xmle_description {Event payload type. Default mode is Query. + QUERY = Client will query via getparam upon receiving this event, using the + output_token provided as part of this payload. + Inband = ASR output payload follows inband after the payload_size field } + @h2xmle_default {0} + @h2xmle_rangeList {"Query"=0, "Inband"=1} */ + uint32_t output_token; + /**< @h2xmle_description {Token provided by the AsR engine corresponding to an output. + This can be used by clients to query the payload param in 'Getparam' mode} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of outputs of type asr_output_status_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..16} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type asr_output_status_t . + Size '0' indicates this is an event generated without any valid output, + for example : in response to a force output param set by client. } + @h2xmle_default {0} + @h2xmle_range {0..262144} */ +#if defined(__H2XML__) + asr_output_status_t transcription_payload[0]; + /*@variableArraySize {payload_size} */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_asr_output_event_t event_id_asr_output_event_t; + + +/* ID of the ASR output get parameter used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_OUTPUT 0x08001AAA + +/* Structure for the output get parameter of ASR module. */ +typedef struct param_id_asr_output_t param_id_asr_output_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_OUTPUT", PARAM_ID_ASR_OUTPUT} + @h2xmlp_description {Get Param to query output from the module based on asr_out_mode in event_id_asr_output_event_t } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_OUTPUT parameter used by the + ASR module. + */ + +struct param_id_asr_output_t +{ + uint32_t output_token; + /**< @h2xmle_description {Token provided by the ASR engine corresponding to an output. + This can be used by clients to query the corresponding payload. + If not configured or invalid, Payload corresponds to output buffers + in sequential order as produced by ASR engine.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of outputs of type asr_output_status_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..16} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type asr_output_status_t . + Size '0' indicates this is an event generated without any valid output, + for example : in response to a force output param set by client. } + @h2xmle_default {0} + @h2xmle_range {0..262144} */ +#if defined(__H2XML__) + asr_output_status_t transcription_payload[0]; + /*@variableArraySize {payload_size} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_output_t} + @h2xmlm_InsertParameter */ + +/* ID of the ASR input threshold parameter used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_ALGO_MAX_INFERENCE_TIME 0x08001B06 + +/* Structure for the input threshold parameter of ASR module. */ +typedef struct param_id_asr_algo_max_inference_time_t param_id_asr_algo_max_inference_time_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_ALGO_MAX_INFERENCE_TIME", PARAM_ID_ASR_ALGO_MAX_INFERENCE_TIME} + @h2xmlp_description {Param to control input input buffers size in partial output mode, to prevent the PCM data overflow. It should be set based on the worst enpu inference time.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_ALGO_MAX_INFERENCE_TIME parameter used by the + ASR module. + */ +struct param_id_asr_algo_max_inference_time_t +{ + uint32_t worstcase_time_ms; // Max inference time taken by algo to process the input threshold amount worth of data. + /**< @h2xmle_description {Maximum duration to process the input data by the algorithm for one inference in ms. + This is taken as input as this can vary based on model and enpu capability etc., hence tuning this for memory requirements based on usecase needs external input.} + @h2xmle_range {80..30000} ms + @h2xmle_default {5000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_algo_max_inference_time_t} + @h2xmlm_InsertParameter */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +#define MAX_WORD_SIZE 28 + +struct asr_word_status_t +{ + uint32_t word_confidence; + /**< @h2xmle_description {Field indicating the confidence level of word detected by the algorithm between 0 to 100} */ + + uint32_t word_size; + /**< @h2xmle_description {Field indicating the number of characters present in the word. (Not including the NULL character)} */ + + uint8_t word[MAX_WORD_SIZE]; + /**< @h2xmle_description {Field indicating the array of characters (in a word) detected by the algorithm. MAX_WORD_SIZE to be a multiple of 4. Client should read only word_size from this array for the actual word which does not include any null term char} */ + + uint32_t word_start_time_ms_lsw; + /**< @h2xmle_description {Field indicating word start timestamp in ms least significant 32 bits.} */ + + uint32_t word_start_time_ms_msw; + /**< @h2xmle_description {Field indicating word start timestamp in ms most significant 32 bits.} */ + + uint32_t word_end_time_ms_lsw; + /**< @h2xmle_description {Field indicating word end timestamp in ms least significant 32 bits.} */ + + uint32_t word_end_time_ms_msw; + /**< @h2xmle_description {Field indicating word end timestamp in ms most significant 32 bits.} */ +}; + +struct asr_output_status_v2_t +{ + uint32_t status; + /**< @h2xmle_description {Status of ASR output in this payload} + @h2xmle_default {0} + @h2xmle_rangeList {"ASR_SUCCESS"=0,"ASR_FAIL"=1,"ASR_TIMEOUT"=12} */ + + uint32_t is_final; + /**< @h2xmle_description {Field indicating payload is partial output of ASR or complete} + @h2xmle_default {TRUE} + @h2xmle_rangeList {"TRUE"=1, "FALSE"=0} */ + + uint32_t confidence; + /**< @h2xmle_description {Field indicating confidence level of output} */ + + uint32_t text_size; + /**< @h2xmle_description {Field indicating size of valid text including NULL Char } */ + + uint8_t text[MAX_TRANSCRIPTION_CHAR_SIZE]; + /**< @h2xmle_description {ASR output text } */ + + uint32_t segment_start_time_ms_lsw; + /**< @h2xmle_description {Field indicating transcription start timestamp in ms least significant 32 bits.} */ + + uint32_t segment_start_time_ms_msw; + /**< @h2xmle_description {Field indicating transcription start timestamp in ms most significant 32 bits.} */ + + uint32_t segment_end_time_ms_lsw; + /**< @h2xmle_description {Field indicating transcription end timestamp in ms least significant 32 bits.} */ + + uint32_t segment_end_time_ms_msw; + /**< @h2xmle_description {Field indicating transcription end timestamp in ms most significant 32 bits.} */ + + uint32_t num_words; + /**< @h2xmle_description {Field indicating num of words produced by ASR engine. this is variable payload based on num_words field above.} */ + + #if defined(__H2XML__) + asr_word_status_t words[0]; + /**< @h2xmle_description {Field indicating the ptr to the words list of words produced by ASR engine.} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct asr_output_status_v2_t asr_output_status_v2_t; + + +/* ID of the ASR output get parameter used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_OUTPUT_V2 0x08001B04 + +/* Structure for the output get parameter of ASR module. */ +typedef struct param_id_asr_output_v2_t param_id_asr_output_v2_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_OUTPUT_V2", PARAM_ID_ASR_OUTPUT_V2} + @h2xmlp_description {Get Param to query output from the module based on asr_out_mode in event_id_asr_output_event_t } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_OUTPUT_V2 parameter used by the + ASR module. + */ + +struct param_id_asr_output_v2_t +{ + uint32_t output_token; + /**< @h2xmle_description {Token provided by the ASR engine corresponding to an output. + This can be used by clients to query the corresponding payload. + If not configured or invalid, Payload corresponds to output buffers + in sequential order as produced by ASR engine.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of outputs of type asr_output_status_v2_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type asr_output_status_v2_t . + Size '0' indicates this is an event generated without any valid output, + for example : in response to a force output param set by client. } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ +#if defined(__H2XML__) + asr_output_status_v2_t transcription_payload[0]; + /*@variableArraySize {payload_size} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_output_v2_t} + @h2xmlm_InsertParameter */ + +/* ID of the ASR output get parameter V3 used by MODULE_ID_ASR.*/ +#define PARAM_ID_ASR_OUTPUT_V3 0x08001BCB + +/* Structure for the output get parameter V3 of ASR module with client ID support. */ +typedef struct param_id_asr_output_v3_t param_id_asr_output_v3_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_OUTPUT_V3", PARAM_ID_ASR_OUTPUT_V3} + @h2xmlp_description {Get Param to query output from the module with client ID specification for multi-client support} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_OUTPUT_V3 parameter used by the + ASR module. + */ + +struct param_id_asr_output_v3_t +{ + uint32_t client_id; + /**< @h2xmle_description {Client ID to identify which client's output buffer to query. + This must match the client_id used in PARAM_ID_ASR_OUTPUT_CONFIG_V2. + Allows multiple clients to independently query their own output buffers.} + @h2xmle_default {ASR_CLIENT_HLOS} + @h2xmle_rangeList {"ASR_CLIENT_HLOS"=1, "ASR_CLIENT_LLS"=2} */ + uint32_t output_token; + /**< @h2xmle_description {Token provided by the ASR engine corresponding to an output. + This can be used by clients to query the corresponding payload. + If not configured or invalid, Payload corresponds to output buffers + in sequential order as produced by ASR engine.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of outputs of type asr_output_status_v2_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type asr_output_status_v2_t . + Size '0' indicates this is an event generated without any valid output, + for example : in response to a force output param set by client. } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ +#if defined(__H2XML__) + asr_output_status_v2_t transcription_payload[0]; + /*@variableArraySize {payload_size} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_output_v3_t} + @h2xmlm_InsertParameter */ + +/* ID of set ASR timestamp fmt.*/ +#define PARAM_ID_ASR_TIMESTAMP_FORMAT 0x08001B83 + +/* Structure to enable timestamp based on qtimer or UTC converted. */ +typedef struct param_id_asr_ts_fmt_t param_id_asr_ts_fmt_t; +/** @h2xmlp_parameter {"PARAM_ID_ASR_TIMESTAMP_FORMAT", PARAM_ID_ASR_TIMESTAMP_FORMAT} + @h2xmlp_description {Set Param to set the timestamp format associated with text. } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_ASR_TIMESTAMP_FORMAT parameter used by the + ASR module. + */ +struct param_id_asr_ts_fmt_t +{ + uint32_t ts_fmt; + /**< @h2xmle_description {Indicates the timestamp associated with ASR segment and words. Note: the this will only work with timestamp enabled modes.} + @h2xmle_default {0} + @h2xmle_rangeList {"UTC_FMT"=0, "QTIMER_FMT"=1} */ + uint32_t reset_period; + /**< @h2xmle_description {Indicates the period to read reference UTC time. Note: '0' means module latches to UTC time only at the beginning of the usecase and doesn't + periodically sync to UTC time for dynamic changes. For non-zero values say 'x' seconds, the module will dynamically sync and update the UTC time at every x seconds. + The maximum reset period allowed is a day.} + @h2xmle_default {0} + @h2xmle_range {0..86400} */ + uint32_t timestamp_unit; + /**< @h2xmle_description {Indicates the unit of timestamp. Currently only TIME_USEC is supported} + @h2xmle_default {1} + @h2xmle_rangeList {"TIME_USEC"=1} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_asr_ts_fmt_t} + @h2xmlm_InsertParameter */ +/** @} <-- End of the Module -->*/ +#endif /* ASR_MODULE_CALIBRATION_API_H */ diff --git a/spf/api/modules/audio_dam_buffer_api.h b/spf/api/modules/audio_dam_buffer_api.h new file mode 100644 index 0000000..2c4de51 --- /dev/null +++ b/spf/api/modules/audio_dam_buffer_api.h @@ -0,0 +1,366 @@ +#ifndef _AUDIO_DAM_BUFFER_API_H_ +#define _AUDIO_DAM_BUFFER_API_H_ +/** + * \file audio_dam_buffer_api.h + * \brief + * This file contains Public APIs for Audio Dam Buffer module. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "apm_graph_properties.h" +#include "imcl_fwk_intent_api.h" +#include "module_cmn_api.h" + +#define AUDIO_DAM_STACK_SIZE_REQUIREMENT 1024 + +/*============================================================================== + Constants +==============================================================================*/ +/* Global unique Module ID definition + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_AUDIO_DAM_BUFFER 0x07001020 + +/*============================================================================== + Constants +==============================================================================*/ +/** + @h2xml_title1 {Audio Dam buffer Module API} + @h2xml_title_agile_rev {Audio Dam buffer Module API} + @h2xml_title_date {April 4, 2019} */ + +/** + @h2xmlm_module { "MODULE_ID_AUDIO_DAM_BUFFER", MODULE_ID_AUDIO_DAM_BUFFER} + @h2xmlm_displayName { "Audio Dam Buffer" } + @h2xmlm_description { Supports the multi port stream buffering. + Other multiport, buffering, and threshold modules are not allowed in the container + where DAM module is placed.} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { AUDIO_DAM_STACK_SIZE_REQUIREMENT } + @h2xmlm_toolPolicy { Calibration } + @h2xmlm_dataMaxInputPorts { INFINITE } + @h2xmlm_dataMaxOutputPorts { INFINITE } + @h2xmlm_ctrlDynamicPortIntent { "DAM-DE Control" = INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL, + maxPorts= INFINITE} + + @{ <-- Start of the Module --> + */ + +/*============================================================================== + Constants +==============================================================================*/ +/* ID of the parameter used to input port configuration of the module. */ +#define PARAM_ID_AUDIO_DAM_INPUT_PORTS_CFG 0x08001058 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Sub struct forward deceleration. */ +typedef struct audio_dam_input_port_cfg_t audio_dam_input_port_cfg_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {The input port configuration consists of number of channels expected on this + input port stream. The number of channels should match with the input + media format. The channel IDs define the explicit channel IDs for + each channel.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct audio_dam_input_port_cfg_t +{ + uint32_t input_port_id; + /**< @h2xmle_description { Input port ID on which the following configuration needs to be set. } + @h2xmle_default { 0 } */ + + uint32_t num_channels; + /**< @h2xmle_description { Number of channels in the input port stream.} + @h2xmle_range {0..32} + @h2xmle_default {0} */ +#if defined(__H2XML__) + uint32_t channel_ids[0]; + /**< @h2xmle_description { Defines channel IDs for each of the channel index. + Range is defined between 1 to 63. Value '0' is considered + invalid and must not be set. } + @h2xmle_range { 0..63} + @h2xmle_variableArraySize { "num_channels" } */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Payload of the PARAM_ID_AUDIO_DAM_INPUT_PORTS_CFG command. */ +typedef struct param_id_audio_dam_input_ports_cfg_t param_id_audio_dam_input_ports_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_AUDIO_DAM_INPUT_PORTS_CFG", + PARAM_ID_AUDIO_DAM_INPUT_PORTS_CFG} + @h2xmlp_description {Sets the input port configuration for all the input ports of the audio dam buffer. + + Each input port configuration consists of number of channels expected on this + input port stream. The number of channels should match with the input + media format. The channel types define the explicit channel types for + each channel.} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_audio_dam_input_ports_cfg_t +{ + uint32_t num_input_ports; + /**< @h2xmle_description { Number of input ports connected to Audio Dam module. } + @h2xmle_default { 1 } */ +#if defined(__H2XML__) + audio_dam_input_port_cfg_t input_port_cfgs[0]; + /**< @h2xmle_description { Sub structure containing per input port configuration. The payload for + each input port is defined by the structure audio_dam_input_port_cfg_t. } + @h2xmle_range { 0..63} + @h2xmle_variableArraySize { "num_input_ports" } */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/*============================================================================== + Constants +==============================================================================*/ +/* ID of the parameter used to output port configuration of the module. */ +#define PARAM_ID_AUDIO_DAM_OUTPUT_PORTS_CFG 0x08001059 + +/*============================================================================== + Type definitions +==============================================================================*/ +/* Sub struct forward deceleration. */ +typedef struct channel_map_t channel_map_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Each channel being buffered in Audio Dam buffer is uniquely + identified by a input Channel ID. This structure contains the + (input Channel ID -> output Channel ID) pair. + + The output channel ID defines the channel type that must be + propagated downstream for the given input channel ID.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct channel_map_t +{ + uint32_t input_ch_id; + /**< @h2xmle_description { Channel type as expected from the source module.} + @h2xmle_range {1..63} + @h2xmle_default { 1} */ + + uint32_t output_ch_id; + /**< @h2xmle_description { Defines the type of the channel in the output stream. + This will be the channel type propagated downstream.} + @h2xmle_range {1..63} + @h2xmle_default { 1} */ +} +#include "spf_end_pack.h" +; + +/* Payload of the each output port configuration. */ +typedef struct audio_dam_output_port_cfg_t audio_dam_output_port_cfg_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {The input port configuration consists of number of channels expected on this + input port stream. The number of channels should match with the input + media format. The channel IDs define the explicit channel IDs for + each channel.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct audio_dam_output_port_cfg_t +{ + uint32_t output_port_id; + /**< @h2xmle_description { Output port ID on which the following configuration needs to be set. } + @h2xmle_default { 0 } */ + + uint32_t num_channels; + /**< @h2xmle_description { Number of channels in the port stream.} + @h2xmle_default { 0 } */ +#if defined(__H2XML__) + channel_map_t output_ch_map[0]; + /**< @h2xmle_description { Output channel map array. Each element in the array selects the output channels source + based on (Input port ID , Input channel type) and output channel type sets the channel + type that must be propagated to the downstream. } + @h2xmle_variableArraySize { "num_channels" } */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/* Payload of the PARAM_ID_AUDIO_DAM_OUTPUT_PORTS_CFG command. */ +typedef struct param_id_audio_dam_output_ports_cfg_t param_id_audio_dam_output_ports_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_AUDIO_DAM_OUTPUT_PORTS_CFG", + PARAM_ID_AUDIO_DAM_OUTPUT_PORTS_CFG} + @h2xmlp_description {Sets the output port configuration of all the output ports connected to Audio Dam module. + + Each The output channel map defines the list of the channels from input streams to the module. + Output channel map is represented as a variable array of (Input channel ID -> output channel ID) + vectors. } + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_audio_dam_output_ports_cfg_t +{ + uint32_t num_output_ports; + /**< @h2xmle_description { Number of output ports connected to Audio Dam module.} + @h2xmle_default { 0 } */ +#if defined(__H2XML__) + audio_dam_output_port_cfg_t output_port_cfgs[0]; + /**< @h2xmle_description { Per output port configuration. The payload for each output port is defined by the + structure audio_dam_output_port_cfg_t. } + @h2xmle_variableArraySize { "num_output_ports" } */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + + + +/*============================================================================== + Constants +==============================================================================*/ + +/* Parameter to set maximum duration required to setup the downstream subgraphs after + the keyword is detected by the detection engine. This is time taken by the HLOS + client to setup the downstream after receiving detection. This defines the minimum + amount of buffering required to avoid data loss, before HLOS sets up downstream sub + graph and starts reading the buffered data. */ +#define PARAM_ID_AUDIO_DAM_DOWNSTREAM_SETUP_DURATION 0x0800105A + +/*============================================================================== + Type Definitions +==============================================================================*/ + + +/* Sub structure to configure per port downstream setup duration. */ +typedef struct audio_dam_downstream_setup_duration_t audio_dam_downstream_setup_duration_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {This structure defines per output port downstream setup duration time. + + This is time taken by the HLOS client to setup the downstream after receiving detection. + This defines the minimum amount of buffering required to avoid data loss, before HLOS + sets up downstream subgraph and starts reading the buffered data. } + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct audio_dam_downstream_setup_duration_t +{ + uint32_t output_port_id; + /**< @h2xmle_description { Output port ID on which the following configuration needs to be set. } + @h2xmle_default { 0 } */ + + uint32_t dwnstrm_setup_duration_ms; + /**< @h2xmle_description { Maximum duration required to setup the downstream subgraphs after + the keyword is detected. } + @h2xmle_default { 250 } */ +} +#include "spf_end_pack.h" +; + +/* Structure to configure downstream setup duration. */ +typedef struct param_id_audio_dam_downstream_setup_duration_t param_id_audio_dam_downstream_setup_duration_t; + +/** @h2xmlp_parameter {"PARAM_ID_AUDIO_DAM_DOWNSTREAM_SETUP_DURATION", + PARAM_ID_AUDIO_DAM_DOWNSTREAM_SETUP_DURATION} + @h2xmlp_description {This parameter contains downstream setup duration config for all output ports. + + Down stream setup duration is the time taken by the HLOS client to setup the downstream + subgraph and start reading the data from dam module, upon receiving detection. + + This defines the minimum amount of buffering required to avoid data loss, before HLOS + sets up downstream subgraph and starts reading the buffered data. }*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_audio_dam_downstream_setup_duration_t +{ + uint32_t num_output_ports; + /**< @h2xmle_description { Number of output ports defined for the Audio Dam module.} + @h2xmle_default { 0 } */ +#if defined(__H2XML__) + audio_dam_downstream_setup_duration_t port_cfgs[0]; + /**< @h2xmle_description { Per port downstream setup duration config. } + @h2xmle_variableArraySize { "num_output_ports" } */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/*============================================================================== + Constants +==============================================================================*/ + +/* Parameter used by the to map the control link ID to the output data port ID. +*/ +#define PARAM_ID_AUDIO_DAM_CTRL_TO_DATA_PORT_MAP 0x0800105B + +/*============================================================================== + Type Definitions +==============================================================================*/ + +/** Sub structure forward declaration. */ +typedef struct audio_dam_port_binding_t audio_dam_port_binding_t; + +/** @h2xmlp_subStruct + @h2xmlp_description { This structure defines each of the control port to output data port mappings. + Each output port ID must be linked to only one control port ID. } + @h2xmlp_toolPolicy { Calibration } */ +#include "spf_begin_pack.h" +struct audio_dam_port_binding_t +{ + uint32_t control_port_id; + /**< @h2xmle_description { Control port ID of the module.} + @h2xmle_default { 0} */ + + uint32_t output_port_id; + /**< @h2xmle_description { The output port ID to which control port is linked to. } + @h2xmle_default { 0} */ +} +#include "spf_end_pack.h" +; + +/* Structure to define the Audio Dam buffer adjust */ +typedef struct param_id_audio_ctrl_to_data_port_map_t param_id_audio_ctrl_to_data_port_map_t; + +/** @h2xmlp_parameter {"PARAM_ID_AUDIO_DAM_CTRL_TO_DATA_PORT_MAP", + PARAM_ID_AUDIO_DAM_CTRL_TO_DATA_PORT_MAP} + @h2xmlp_description { This param ID defines the control ID to data port binding. Each control port ID + in Dam module must be coupled to an output port ID it needs to control. Each control + port can be coupled to only one output port ID, hence number of bindings is same as + number of control ports.} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_audio_ctrl_to_data_port_map_t +{ + uint32_t num_ctrl_ports; + /**< @h2xmle_description { Number of control port IDs attached to the module.} + @h2xmle_default {0} */ +#if defined(__H2XML__) + audio_dam_port_binding_t ctrl_to_outport_map[0]; + /**< @h2xmle_description { Control port to Data port map. } + @h2xmle_variableArraySize { "num_ctrl_ports" } */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/** @} <-- End of the module -- > */ + +#endif /* _AUDIO_DAM_BUFFER_API_H_ */ diff --git a/spf/api/modules/audio_hw_clk_api.h b/spf/api/modules/audio_hw_clk_api.h new file mode 100644 index 0000000..574dd20 --- /dev/null +++ b/spf/api/modules/audio_hw_clk_api.h @@ -0,0 +1,513 @@ +#ifndef _AUDIO_HW_CLK_API_H_ +#define _AUDIO_HW_CLK_API_H_ +/** + * \file audio_hw_clk_api.h + * \brief + * This file contains audio hw clock APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +/** + Param ID for audio hardware clocks + This ID should only be used under PRM module instance + Eg: Bit clocks for audio h/w interface like MI2S, PCM, TDM + Mclks for audio codec (internal / external) operation +*/ +#define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800102C + +/** Start of the range of MI2S clock IDs. */ +#define CLOCK_ID_MI2S_RANGE_START 0x100 + +/** Clock ID of the primary MI2S internal bit clock (IBIT). */ +#define CLOCK_ID_PRI_MI2S_IBIT 0x100 + +/** Clock ID of the primary MI2S external bit clock (EBIT). */ +#define CLOCK_ID_PRI_MI2S_EBIT 0x101 + +/** Clock ID of the secondary MI2S IBIT. */ +#define CLOCK_ID_SEC_MI2S_IBIT 0x102 + +/** Clock ID of the secondary MI2S EBIT. */ +#define CLOCK_ID_SEC_MI2S_EBIT 0x103 + +/** Clock ID of the tertiary MI2S IBIT. */ +#define CLOCK_ID_TER_MI2S_IBIT 0x104 + +/** Clock ID of the tertiary MI2S EBIT. */ +#define CLOCK_ID_TER_MI2S_EBIT 0x105 + +/** Clock ID of the quaternary MI2S IBIT. */ +#define CLOCK_ID_QUAD_MI2S_IBIT 0x106 + +/** Clock ID of the quaternary MI2S EBIT. */ +#define CLOCK_ID_QUAD_MI2S_EBIT 0x107 + +/** Clock ID of the quinary MI2S IBIT. */ +#define CLOCK_ID_QUI_MI2S_IBIT 0x108 + +/** Clock ID of the quinary MI2S EBIT. */ +#define CLOCK_ID_QUI_MI2S_EBIT 0x109 + +/** Clock ID of the quinary MI2S OSR. */ +#define CLOCK_ID_QUI_MI2S_OSR 0x10A + +/** Clock ID of the senary MI2S IBIT. */ +#define CLOCK_ID_SEN_MI2S_IBIT 0x10B + +/** Clock ID of the senary MI2S EBIT. */ +#define CLOCK_ID_SEN_MI2S_EBIT 0x10C + +/** Clock ID of the septenary MI2S IBIT. */ +#define CLOCK_ID_SEP_MI2S_IBIT 0x10D + +/** Clock ID of the sepetnary MI2S EBIT. */ +#define CLOCK_ID_SEP_MI2S_EBIT 0x10E + +/** Clock ID of the High speed I2S interface 0 IBIT. */ +#define CLOCK_ID_HS_I2S_IF0_IBIT 0x10F + +/** Clock ID of the high speed I2S interface 0 EBIT. */ +#define CLOCK_ID_HS_I2S_IF0_EBIT 0x110 + +/** Clock ID of the High speed interface 1 IBIT. */ +#define CLOCK_ID_HS_I2S_IF1_IBIT 0x111 + +/** Clock ID of the high speed interface 1 EBIT. */ +#define CLOCK_ID_HS_I2S_IF1_EBIT 0x112 + +/** Clock ID of the High speed interface 2 IBIT. */ +#define CLOCK_ID_HS_I2S_IF2_IBIT 0x113 + +/** Clock ID of the high speed interface 2 EBIT. */ +#define CLOCK_ID_HS_I2S_IF2_EBIT 0x114 + +/** Clock ID of the High speed interface 3 IBIT. */ +#define CLOCK_ID_HS_I2S_IF3_IBIT 0x115 + +/** Clock ID of the high speed interface 3 EBIT. */ +#define CLOCK_ID_HS_I2S_IF3_EBIT 0x116 + +/** Clock ID of the High speed interface 4 IBIT. */ +#define CLOCK_ID_HS_I2S_IF4_IBIT 0x117 + +/** Clock ID of the high speed interface 4 EBIT. */ +#define CLOCK_ID_HS_I2S_IF4_EBIT 0x118 + +/** End of the range of MI2S clock IDs. */ +#define CLOCK_ID_MI2S_RANGE_END 0x118 + +/** Start of the range of PCM clock IDs. */ +#define CLOCK_ID_PCM_RANGE_START 0x200 + +/** Clock ID of the primary PCM IBIT. */ +#define CLOCK_ID_PRI_PCM_IBIT 0x200 + +/** Clock ID of the primary PCM EBIT. */ +#define CLOCK_ID_PRI_PCM_EBIT 0x201 + +/** Clock ID of the secondary PCM IBIT. */ +#define CLOCK_ID_SEC_PCM_IBIT 0x202 + +/** Clock ID of the secondary PCM EBIT. */ +#define CLOCK_ID_SEC_PCM_EBIT 0x203 + +/** Clock ID of the tertiary PCM IBIT. */ +#define CLOCK_ID_TER_PCM_IBIT 0x204 + +/** Clock ID of the tertiary PCM EBIT. */ +#define CLOCK_ID_TER_PCM_EBIT 0x205 + +/** Clock ID of the quaternary PCM IBIT. */ +#define CLOCK_ID_QUAD_PCM_IBIT 0x206 + +/** Clock ID of the quaternary PCM EBIT. */ +#define CLOCK_ID_QUAD_PCM_EBIT 0x207 + +/** Clock ID of the quinary PCM IBIT. */ +#define CLOCK_ID_QUI_PCM_IBIT 0x208 + +/** Clock ID of the quinary PCM EBIT. */ +#define CLOCK_ID_QUI_PCM_EBIT 0x209 + +/** Clock ID of the quinary PCM OSR. */ +#define CLOCK_ID_QUI_PCM_OSR 0x20A + +/** Clock ID of the senary PCM IBIT. */ +#define CLOCK_ID_SEN_PCM_IBIT 0x20B + +/** Clock ID of the senary PCM EBIT. */ +#define CLOCK_ID_SEN_PCM_EBIT 0x20C + +/** Clock ID of the septenary PCM IBIT. */ +#define CLOCK_ID_SEP_PCM_IBIT 0x20D + +/** Clock ID of the septenary PCM EBIT. */ +#define CLOCK_ID_SEP_PCM_EBIT 0x20E + +/** Clock ID of the High speed PCM interface 0 IBIT. */ +#define CLOCK_ID_HS_PCM_IF0_IBIT 0x20F + +/** Clock ID of the high speed PCM interface 0 EBIT. */ +#define CLOCK_ID_HS_PCM_IF0_EBIT 0x210 + +/** Clock ID of the High speed PCM interface 1 IBIT. */ +#define CLOCK_ID_HS_PCM_IF1_IBIT 0x211 + +/** Clock ID of the high speed PCM interface 1 EBIT. */ +#define CLOCK_ID_HS_PCM_IF1_EBIT 0x212 + +/** Clock ID of the High speed PCM interface 2 IBIT. */ +#define CLOCK_ID_HS_PCM_IF2_IBIT 0x213 + +/** Clock ID of the high speed PCM interface 2 EBIT. */ +#define CLOCK_ID_HS_PCM_IF2_EBIT 0x214 + +/** Clock ID of the High speed PCM interface 3 IBIT. */ +#define CLOCK_ID_HS_PCM_IF3_IBIT 0x215 + +/** Clock ID of the high speed PCM interface 3 EBIT. */ +#define CLOCK_ID_HS_PCM_IF3_EBIT 0x216 + +/** Clock ID of the High speed PCM interface 4 IBIT. */ +#define CLOCK_ID_HS_PCM_IF4_IBIT 0x217 + +/** Clock ID of the high speed PCM interface 4 EBIT. */ +#define CLOCK_ID_HS_PCM_IF4_EBIT 0x218 + +/** End of of the range of PCM clock IDs. */ +#define CLOCK_ID_PCM_RANGE_END 0x218 + +/** Start of the TDM clock ID group. */ +#define CLOCK_ID_TDM_RANGE_START 0x200 + +/** Clock ID for the primary TDM IBIT. */ +#define CLOCK_ID_PRI_TDM_IBIT 0x200 + +/** Clock ID for the primary TDM EBIT. */ +#define CLOCK_ID_PRI_TDM_EBIT 0x201 + +/** Clock ID for the secondary TDM IBIT. */ +#define CLOCK_ID_SEC_TDM_IBIT 0x202 + +/** Clock ID for the secondary TDM EBIT. */ +#define CLOCK_ID_SEC_TDM_EBIT 0x203 + +/** Clock ID for the tertiary TDM IBIT. */ +#define CLOCK_ID_TER_TDM_IBIT 0x204 + +/** Clock ID for the tertiary TDM EBIT. */ +#define CLOCK_ID_TER_TDM_EBIT 0x205 + +/** Clock ID for the quaternary TDM IBIT. */ +#define CLOCK_ID_QUAD_TDM_IBIT 0x206 + +/** Clock ID for the quaternary TDM EBIT. */ +#define CLOCK_ID_QUAD_TDM_EBIT 0x207 + +/** Clock ID for the quinary TDM IBIT. */ +#define CLOCK_ID_QUI_TDM_IBIT 0x208 + +/** Clock ID for the quinary TDM EBIT. */ +#define CLOCK_ID_QUI_TDM_EBIT 0x209 + +/** Clock ID for the quinary TDM OSR. */ +#define CLOCK_ID_QUI_TDM_OSR 0x20A + +/** Clock ID for the senary TDM IBIT. */ +#define CLOCK_ID_SEN_TDM_IBIT 0x20B + +/** Clock ID for the senary TDM EBIT. */ +#define CLOCK_ID_SEN_TDM_EBIT 0x20C + +/** Clock ID of the septenary TDM IBIT. */ +#define CLOCK_ID_SEP_TDM_IBIT 0x20D + +/** Clock ID of the septenary TDM EBIT. */ +#define CLOCK_ID_SEP_TDM_EBIT 0x20E + +/** Clock ID of the High speed TDM interface 0 IBIT. */ +#define CLOCK_ID_HS_TDM_IF0_IBIT 0x20F + +/** Clock ID of the high speed TDM interface 0 EBIT. */ +#define CLOCK_ID_HS_TDM_IF0_EBIT 0x210 + +/** Clock ID of the High speed TDM interface 1 IBIT. */ +#define CLOCK_ID_HS_TDM_IF1_IBIT 0x211 + +/** Clock ID of the high speed TDM interface 1 EBIT. */ +#define CLOCK_ID_HS_TDM_IF1_EBIT 0x212 + +/** Clock ID of the High speed TDM interface 2 IBIT. */ +#define CLOCK_ID_HS_TDM_IF2_IBIT 0x213 + +/** Clock ID of the high speed TDM interface 2 EBIT. */ +#define CLOCK_ID_HS_TDM_IF2_EBIT 0x214 + +/** Clock ID of the High speed TDM interface 3 IBIT. */ +#define CLOCK_ID_HS_TDM_IF3_IBIT 0x215 + +/** Clock ID of the high speed TDM interface 3 EBIT. */ +#define CLOCK_ID_HS_TDM_IF3_EBIT 0x216 + +/** Clock ID of the High speed TDM interface 4 IBIT. */ +#define CLOCK_ID_HS_TDM_IF4_IBIT 0x217 + +/** Clock ID of the high speed TDM interface 4 EBIT. */ +#define CLOCK_ID_HS_TDM_IF4_EBIT 0x218 + +/** End of the TDM clock ID group. */ +#define CLOCK_ID_TDM_RANGE_END 0x218 + +/** Start of the range of MCLK clock IDs. */ +#define CLOCK_ID_MCLK_RANGE_START 0x300 + +/** Clock ID for MCLK 1. */ +#define CLOCK_ID_MCLK_1 0x300 + +/** Clock ID for MCLK 2. */ +#define CLOCK_ID_MCLK_2 0x301 + +/** Clock ID for MCLK 3. */ +#define CLOCK_ID_MCLK_3 0x302 + +/** Clock ID for MCLK 4. */ +#define CLOCK_ID_MCLK_4 0x303 + +/** Clock ID for MCLK 5. */ +#define CLOCK_ID_MCLK_5 0x304 + +/** Clock ID for MCLK for WSA core */ +#define CLOCK_ID_WSA_CORE_MCLK 0x305 + +/** Clock ID for NPL MCLK for WSA core */ +#define CLOCK_ID_WSA_CORE_NPL_MCLK 0x306 + +/** Clock ID for 2X WSA MCLK (2X MCLK or NPL MCLK, both are same) */ +#define CLOCK_ID_WSA_CORE_2X_MCLK CLOCK_ID_WSA_CORE_NPL_MCLK + +/** Clock ID for MCLK for VA core */ +#define CLOCK_ID_VA_CORE_MCLK 0x307 + +/** Clock ID for 2X VA MCLK (2X MCLK) */ +#define CLOCK_ID_VA_CORE_2X_MCLK 0x308 + +/** Clock ID for MCLK for TX */ +#define CLOCK_ID_TX_CORE_MCLK 0x30C + +/** Clock ID for NPL MCLK for TX */ +#define CLOCK_ID_TX_CORE_NPL_MCLK 0x30D + +/** Clock ID for TX CORE 2X MCLK (2X MCLK or NPL MCLK, both are same) */ +#define CLOCK_ID_TX_CORE_2X_MCLK CLOCK_ID_TX_CORE_NPL_MCLK + +/** Clock ID for MCLK for RX */ +#define CLOCK_ID_RX_CORE_MCLK 0x30E + +/** Clock ID for NPL MCLK for RX */ +#define CLOCK_ID_RX_CORE_NPL_MCLK 0x30F + +/** Clock ID for RX CORE 2X MCLK (2X MCLK or NPL MCLK, both are same) */ +#define CLOCK_ID_RX_CORE_2X_MCLK CLOCK_ID_RX_CORE_NPL_MCLK + +/** Clock ID for MCLK for WSA2 core */ +#define CLOCK_ID_WSA2_CORE_MCLK 0x310 + +/** Clock ID for NPL MCLK for WSA2 core */ +#define CLOCK_ID_WSA2_CORE_2X_MCLK 0x311 + +/** Clock ID for RX Core TX MCLK */ +#define CLOCK_ID_RX_CORE_TX_MCLK 0x312 + +/** Clock ID for RX CORE TX 2X MCLK */ +#define CLOCK_ID_RX_CORE_TX_2X_MCLK 0x313 + +/** Clock ID for WSA core TX MCLK */ +#define CLOCK_ID_WSA_CORE_TX_MCLK 0x314 + +/** Clock ID for WSA core TX 2X MCLK */ +#define CLOCK_ID_WSA_CORE_TX_2X_MCLK 0x315 + +/** Clock ID for WSA2 core TX MCLK */ +#define CLOCK_ID_WSA2_CORE_TX_MCLK 0x316 + +/** Clock ID for WSA2 core TX 2X MCLK */ +#define CLOCK_ID_WSA2_CORE_TX_2X_MCLK 0x317 + +/** Clock ID for RX CORE MCLK2 2X MCLK */ +#define CLOCK_ID_RX_CORE_MCLK2_2X_MCLK 0x318 + +/** End of the range of MCLK clock IDs. */ +#define CLOCK_ID_MCLK_RANGE_END 0x318 + +/** Start of the range of SPDIF clock IDs. */ +#define CLOCK_ID_SPDIF_RANGE_START 0x400 + +/** Clock ID for the primary SPDIF output core. */ +#define CLOCK_ID_PRI_SPDIF_OUTPUT_CORE 0x400 + +/** Clock ID for the secondary SPDIF output core. */ +#define CLOCK_ID_SEC_SPDIF_OUTPUT_CORE 0x401 + +/** Clock ID for the primary SPDIF input core. */ +#define CLOCK_ID_PRI_SPDIF_INPUT_CORE 0x402 + +/** Clock ID for the secondary SPDIF input core. */ +#define CLOCK_ID_SEC_SPDIF_INPUT_CORE 0x403 + +/** Clock ID for the secondary SPDIF output NPL clk. */ +#define CLOCK_ID_PRI_SPDIF_OUTPUT_NPL 0x404 + +/** Clock ID for the primary SPDIF output NPL clk. */ +#define CLOCK_ID_SEC_SPDIF_OUTPUT_NPL 0x405 + +/** End of the range of SPDIF clock IDs. */ +#define CLOCK_ID_SPDIF_RANGE_END 0x405 + +/** Max number of clock ids that can be requested/released at a command */ +#define MAX_AUD_HW_CLK_NUM_REQ 5 + +/** + Immediately following this structure is a variable length + array of audio_hw_clk_cfg_t or clock ID structure. Length + of array is determined by number of clock ID's being configured +*/ + +#include "spf_begin_pack.h" + +struct audio_hw_clk_cfg_req_param_t +{ + uint32_t num_clock_id; + /**< Number of clock ID's being configured */ +} + +#include "spf_end_pack.h" +; + +typedef struct audio_hw_clk_cfg_req_param_t audio_hw_clk_cfg_req_param_t; + +/** Clock attribute is invalid (reserved for internal use). */ +#define CLOCK_ATTRIBUTE_INVALID 0x0 + +/** Clock attribute for no coupled clocks. */ +#define CLOCK_ATTRIBUTE_COUPLE_NO 0x1 + +/** Clock attribute for the dividend of the coupled clocks. */ +#define CLOCK_ATTRIBUTE_COUPLE_DIVIDEND 0x2 + +/** Clock attribute for the divisor of the coupled clocks. */ +#define CLOCK_ATTRIBUTE_COUPLE_DIVISOR 0x3 + +/** Clock attribute for the invert-and-no-couple case. */ +#define CLOCK_ATTRIBUTE_INVERT_COUPLE_NO 0x4 + +/* Default clock id used as dont care when requesting clock by client */ +#define HW_INTF_CLK_ID_DEFAULT 0x0 + +/* Default clock frequency used as dont care when requesting clock by client */ +#define HW_INTF_CLK_FREQ_DEFAULT 0x0 + +/* Default clock attribute used as dont care when requesting clock by client */ +#define HW_INTF_CLK_ATTRI_DEFAULT 0x0 + +/** Default root clock source. */ +#define CLOCK_ROOT_DEFAULT 0x0 + +#include "spf_begin_pack.h" + +struct audio_hw_clk_cfg_t +{ + uint32_t clock_id; + /**< Unique Clock ID of the clock being requested */ + + uint32_t clock_freq; + /**< Clock frequency in Hz to set. */ + + uint32_t clock_attri; + /**< Divider for two clocks that are coupled, if necessary: + divider = A/B, where A is the dividend and B is the divisor. + @values + - #_CLOCK_ATTRIBUTE_COUPLE_NO -- For no divider-related clocks + - #_CLOCK_ATTRIBUTE_COUPLE_DIVIDEND + - #_CLOCK_ATTRIBUTE_COUPLE_DIVISOR + - #_CLOCK_ATTRIBUTE_INVERT_COUPLE_NO */ + + uint32_t clock_root; + /**< Root clock source. + @values #_CLOCK_ROOT_DEFAULT + Currently, only _CLOCK_ROOT_DEFAULT is valid. */ +} + +#include "spf_end_pack.h" +; + +typedef struct audio_hw_clk_cfg_t audio_hw_clk_cfg_t; + +#include "spf_begin_pack.h" + +struct audio_hw_clk_rel_cfg_t +{ + uint32_t clock_id; + /**< Unique Clock ID of the clock being released */ +} + +#include "spf_end_pack.h" +; + +typedef struct audio_hw_clk_rel_cfg_t audio_hw_clk_rel_cfg_t; + +/** + Immediately following this structure is a variable length + array of audio_hw_clk_status_cfg_t structure. Length of the array + is determined by number of clock ID's being configured which failed +*/ + +#include "spf_begin_pack.h" + +struct audio_hw_clk_rsp_cfg_t +{ + uint32_t num_failures; + /**< Number of failures while requesting for 1 or more clock ID's */ +} + +#include "spf_end_pack.h" +; + +typedef struct audio_hw_clk_rsp_cfg_t audio_hw_clk_rsp_cfg_t; + + +#include "spf_begin_pack.h" + +struct audio_hw_clk_status_cfg_t +{ + uint32_t clock_id; + /**< Unique Clock ID of the clock which failed to be requested/released */ + + uint32_t status; + /**< Status representing why clock id request/release failed + * @ Non-Zero - Failure + * */ +} + +#include "spf_end_pack.h" +; + +typedef struct audio_hw_clk_status_cfg_t audio_hw_clk_status_cfg_t; + +/** Default clock source. */ +#define CLOCK_ROOT_SRC_DEFAULT 0x0 + +/** Xo Clock source. */ +#define CLOCK_ROOT_SRC_XO 0x1 + +/** RCO Clock source. */ +#define CLOCK_ROOT_SRC_RCO 0x2 + +/** maximum clock sources. */ +#define CLOCK_ROOT_SRC_MAX CLOCK_ROOT_SRC_RCO + 1 + +#endif /* _AUDIO_HW_CLK_API_H_ */ diff --git a/spf/api/modules/audio_hw_dma_api.h b/spf/api/modules/audio_hw_dma_api.h new file mode 100644 index 0000000..507fea8 --- /dev/null +++ b/spf/api/modules/audio_hw_dma_api.h @@ -0,0 +1,48 @@ +#ifndef _AUDIO_HW_DMA_API_H_ +#define _AUDIO_HW_DMA_API_H_ +/** + * \file audio_hw_dma_api.h + * \brief + * This file contains dma api + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +/** + Param ID for dma + This ID should only be used under PRM module instance +*/ +#define PARAM_ID_RSC_DMA_READ_CHANNEL 0x080010CE +#define PARAM_ID_RSC_DMA_WRITE_CHANNEL 0x080010CF + +#include "spf_begin_pack.h" +/** Struct for DMA channel memory request/release/request response by HLOS */ +struct dma_rsc_t +{ + uint32_t dma_type; + /**< DMA channel type + @values #LPAIF_CORE_DMA */ + uint32_t num_dma_channels; + /**< Number of DMA channels + @values >= 0 */ +} +#include "spf_end_pack.h" +; + +typedef struct dma_rsc_t dma_rsc_t; +/* Immediately following this struct is a variable length payload that contains the DMA channel indices that were + reserved. + example: +< DMA resources payload > + dma_cfg_rsc_t + dma_type = LPAIF_CORE_DMA + num_dma_channels +< variable data payload > + num_dma_channels indices as 4 bytes each; contains the DMA index + */ + +#endif /* _AUDIO_HW_DMA_API_H_ */ diff --git a/spf/api/modules/audio_hw_lpm_api.h b/spf/api/modules/audio_hw_lpm_api.h new file mode 100644 index 0000000..4c9c789 --- /dev/null +++ b/spf/api/modules/audio_hw_lpm_api.h @@ -0,0 +1,93 @@ +#ifndef _AUDIO_HW_LPM_API_H_ +#define _AUDIO_HW_LPM_API_H_ +/** + * \file audio_hw_lpm_api.h + * \brief + * This file contains lpm api for requesting/releasing LPM memory resources for remote client + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +/** + Param ID for lpass core + This ID should only be used under PRM module instance +*/ +#define PARAM_ID_RSC_LOW_PWR_MEM 0x080010CD + +/* When LPM resources are successfully allocated and requested: + - The status field indicates a success + - The message payload contains the LPM resources response payload + - Data in the payload contains the physical address (lower 32 bits and higher 32 bits) of the LPM that was allocated by + the aDSP. + + For example, if 4 KB of LPM was requested and it is + successfully allocated, the data in the payload contains a valid physical address. + + If requested resources were not allocated successfully, the payload is + invalid. */ + +#include "spf_begin_pack.h" +/** Struct for response for LPM memory request by HLOS */ +struct lpm_rsc_request_t +{ + uint32_t lpm_type; + /**< LPM memory type + @values #LPAIF_CORE_LPM */ + uint32_t size_in_bytes; + /**< Amount of LPM needed in bytes */ +} +#include "spf_end_pack.h" +; + +typedef struct lpm_rsc_request_t lpm_rsc_request_t; + +#include "spf_begin_pack.h" +/** Struct for response for LPM memory request response by HLOS */ +/* This payload is for PRM_CMD_RSP_REQUEST_HW_RSC, + when the LPM resources are requested. + When the request is for LPM resources, this structure immediately + follows apm_module_param_data_t. +*/ +struct lpm_rsp_rsc_request_t +{ + uint32_t lpm_type; + /**< LPM memory type + @values #LPAIF_CORE_LPM */ + uint32_t size_in_bytes; + /**< Amount of LPM allocated in bytes */ + uint32_t phy_addr_lsw; + /**< LSW of allocated LPM physical address */ + uint32_t phy_addr_msw; + /**< MSW of allocated LPM physical address */ +} +#include "spf_end_pack.h" +; + +typedef struct lpm_rsp_rsc_request_t lpm_rsp_rsc_request_t; + +#include "spf_begin_pack.h" +/** Struct for LPM memory release by HLOS */ +struct lpm_rsc_release_t +{ + uint32_t lpm_type; + /**< LPM memory type + @values #LPAIF_CORE_LPM*/ + uint32_t size_in_bytes; + /**< Amount of LPM to release in bytes */ + uint32_t phy_addr_lsw; + /**< LSW of LPM physical address to release */ + uint32_t phy_addr_msw; + /**< MSW of LPM physical address to release */ +} +#include "spf_end_pack.h" +; + +typedef struct lpm_rsc_release_t lpm_rsc_release_t; + +/* Note: There is no response other than the prm error code for releasing from LPM */ + +#endif /* _AUDIO_HW_LPM_API_H_ */ diff --git a/spf/api/modules/audio_if_api.h b/spf/api/modules/audio_if_api.h new file mode 100644 index 0000000..d5b9697 --- /dev/null +++ b/spf/api/modules/audio_if_api.h @@ -0,0 +1,726 @@ +#ifndef _AUDIO_IF_API_H_ +#define _AUDIO_IF_API_H_ +/** + * \file audio_if_api.h + * \brief + * This file contains audio_if module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "hw_intf_cmn_api.h" +//#include "audio_if_dbg_api.h" + +/*# @h2xml_title1 {AUDIO IF Module API} + @h2xml_title_agile_rev {AUDIO IF Module API} + @h2xml_title_date {Dec 26, 2024} */ + +/*============================================================================== + audio_if related macros +==============================================================================*/ + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Input port ID of audio_if module. */ +#define PORT_ID_AUDIO_IF_INPUT 0x2 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Output port ID of audio_if module. */ +#define PORT_ID_AUDIO_IF_OUTPUT 0x1 + +/* Stack size for PCM_TDM Module*/ +#define AUDIO_IF_STACK_SIZE 2048 + +/*============================================================================== + Constants +==============================================================================*/ + +/* audio_if interface index types */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid indices of Audio Interface. + */ +typedef enum audio_if_idx_t +{ + AUDIO_IF_IDX_INVALID = -1, + AUDIO_IF_IDX_0 = 0, + AUDIO_IF_IDX_1, + AUDIO_IF_IDX_2, + AUDIO_IF_IDX_3, + AUDIO_IF_IDX_4, + AUDIO_IF_IDX_5, + AUDIO_IF_IDX_6, + AUDIO_IF_IDX_7, + AUDIO_IF_IDX_8, + AUDIO_IF_IDX_9, + AUDIO_IF_IDX_10, + AUDIO_IF_IDX_11, + AUDIO_IF_IDX_12, + AUDIO_IF_IDX_13, + AUDIO_IF_IDX_14, + AUDIO_IF_IDX_15, + AUDIO_IF_IDX_NUM_MAX +} audio_if_idx_t; + +/* audio_if interface modes */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid modes of Audio Interface. + */ +typedef enum audio_if_intf_mode_t +{ + AUDIO_IF_INTF_MODE_TDM = 0, + AUDIO_IF_INTF_MODE_PCM = 1, + AUDIO_IF_INTF_MODE_I2S = 2 +} audio_if_intf_mode_t; + +/* audio_if frame sync mode */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid frame sync modes. + */ +typedef enum audio_if_frame_sync_mode_t +{ + AUDIO_IF_FRAME_SYNC_MODE_SHORT_SYNC = 0, + AUDIO_IF_FRAME_SYNC_MODE_ONE_SLOT_SYNC = 1, + AUDIO_IF_FRAME_SYNC_MODE_LONG_SYNC = 2 +} audio_if_frame_sync_mode_t; + +/* audio_if frame sync data delay */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid frame sync data delay. + */ +typedef enum audio_if_frame_sync_data_delay_t +{ + AUDIO_IF_FRAME_SYNC_DATA_DELAY_0BCLK = 0, + AUDIO_IF_FRAME_SYNC_DATA_DELAY_1BCLK = 1, + AUDIO_IF_FRAME_SYNC_DATA_DELAY_2BCLK = 2 +} audio_if_frame_sync_data_delay_t; + +/* audio_if frame sync source */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid frame sync source. + */ +typedef enum audio_if_frame_sync_src_t +{ + AUDIO_IF_FRAME_SYNC_SRC_EXTERNAL = 0, + /* Frame sync generated from external source */ + + AUDIO_IF_FRAME_SYNC_SRC_INTERNAL + /* Frame sync generated internally by HW */ +} audio_if_frame_sync_src_t; + +/* audio_if Slots per frame */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid slots per frame. + */ +typedef enum audio_if_slots_per_frame_t +{ + AUDIO_IF_SLOTS_PER_FRAME_1 = 1, + AUDIO_IF_SLOTS_PER_FRAME_2 = 2, + AUDIO_IF_SLOTS_PER_FRAME_4 = 4, + AUDIO_IF_SLOTS_PER_FRAME_8 = 8, + AUDIO_IF_SLOTS_PER_FRAME_16 = 16, + AUDIO_IF_SLOTS_PER_FRAME_32 = 32, + AUDIO_IF_MAX_SLOTS_PER_FRAME = AUDIO_IF_SLOTS_PER_FRAME_32 +} audio_if_slots_per_frame_t; + +/* audio_if Slot width */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid slot width. + */ +typedef enum audio_if_slot_width_t +{ + AUDIO_IF_SLOT_WIDTH_16 = 16, + AUDIO_IF_SLOT_WIDTH_24 = 24, + AUDIO_IF_SLOT_WIDTH_32 = 32 +} audio_if_slot_width_t; + +/* Bit clock types */ + +/** @ingroup ar_spf_mod_hwep_common_mods + Valid bit clock types. + */ +typedef enum audio_if_bit_clk_type_t +{ + AUDIO_IF_I_BIT_CLK_EN = 0, + /* Enables I bit clock */ + + AUDIO_IF_E_BIT_CLK_EN, + /* Enables E-bit clock */ + + AUDIO_IF_SKIP_BIT_CLK_EN + /* Skips enabling bit clock at AIF. + * + * For example, for external clock source selection scenario, + * client fwk enables the bit clock by interacting + * with corebsp directly, so need to skip enabling the bit + * clock from audio driver. */ +} audio_if_bit_clk_type_t; + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for disabling the audio_if configuration ctrl_data_out_enable + parameter. The PCM block is the only master. */ +#define AUDIO_IF_CTRL_DATA_OE_DISABLE 0x0 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for enabling the audio_if configuration ctrl_data_out_enable + parameter. The PCM block shares the signal with other masters. */ +#define AUDIO_IF_CTRL_DATA_OE_ENABLE 0x1 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for the Normal synchronization. */ +#define AUDIO_IF_FRAME_SYNC_NORMAL 0 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for inverting the synchronization. */ +#define AUDIO_IF_FRAME_SYNC_INVERT 1 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for the bit clock supply without inversion to the blocks inside QAIF. */ +#define AUDIO_IF_INT_CLK_NORMAL 0 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for inverting the bit clock supply to the blocks inside QAIF. */ +#define AUDIO_IF_INT_CLK_INVERT 1 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for the bit clock supply without inversion to the blocks outside QAIF. */ +#define AUDIO_IF_EXT_CLK_NORMAL 0 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for the bit clock supply with inversion to the blocks outside QAIF. */ +#define AUDIO_IF_EXT_CLK_INVERT 1 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for normal capture clock. */ +#define AUDIO_IF_CAPTURE_CLK_NORMAL 0 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for inverting the capture clock. */ +#define AUDIO_IF_CAPTURE_CLK_INVERT 1 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for the Normal launch clock. */ +#define AUDIO_IF_LAUNCH_CLK_NORMAL 0 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Enumeration for inverting the launch clock. */ +#define AUDIO_IF_LAUNCH_CLK_INVERT 1 + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Maximum number of channels for the audio_if interface. @newpage */ +/*TODO: Need to remove hardcoding after having h2xml fix */ +#ifdef PROD_SPECIFIC_MAX_CH +#define AUDIO_IF_MAX_CHANNEL_CNT 128 +#else +#define AUDIO_IF_MAX_CHANNEL_CNT 32 +#endif + +/*============================================================================== + Type definition +==============================================================================*/ + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Identifier for the parameter that configure the audio_if interface. + + @msgpayload + param_id_audio_if_intf_cfg_t + */ +#define PARAM_ID_AUDIO_IF_INTF_CFG 0x08001B11 + +/*# @h2xmlp_parameter {"PARAM_ID_AUDIO_IF_INTF_CFG", PARAM_ID_AUDIO_IF_INTF_CFG} + @h2xmlp_description {ID for the parameter that configures the audio_if + interface.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Payload for #PARAM_ID_AUDIO_IF_CFG. + */ +#include "spf_begin_pack.h" +struct param_id_audio_if_intf_cfg_t +{ + uint16_t qaif_type; + /**< QAIF types. + + @valuesbul (See #qaif_type_t) + - QAIF (Default) + - @tablebulletend */ + + /*#< @h2xmle_description {Audio Interface types.} + @h2xmle_rangeList {"QAIF"=0; + "QAIF_VA"=1} + @h2xmle_default {0} */ + + uint16_t intf_idx; + /**< Index types for the audio_if interface. + + @valuesbul + - #AUDIO_IF_IDX_0 (Default) + - #AUDIO_IF_IDX_1 + - #AUDIO_IF_IDX_2 + - #AUDIO_IF_IDX_3 + - #AUDIO_IF_IDX_4 + - #AUDIO_IF_IDX_5 + - #AUDIO_IF_IDX_6 + - #AUDIO_IF_IDX_7 + - #AUDIO_IF_IDX_8 + - #AUDIO_IF_IDX_9 + - #AUDIO_IF_IDX_10 + - #AUDIO_IF_IDX_11 + - #AUDIO_IF_IDX_12 + - #AUDIO_IF_IDX_13 + - #AUDIO_IF_IDX_14 + - #AUDIO_IF_IDX_15 @tablebulletend */ + + /*#< @h2xmle_description {Defines audio_if interface type} + @h2xmle_rangeList {"AUDIO_IF_IDX_0"=0; + "AUDIO_IF_IDX_1"=1; + "AUDIO_IF_IDX_2"=2; + "AUDIO_IF_IDX_3"=3; + "AUDIO_IF_IDX_4"=4; + "AUDIO_IF_IDX_5"=5; + "AUDIO_IF_IDX_6"=6; + "AUDIO_IF_IDX_7"=7; + "AUDIO_IF_IDX_8"=8; + "AUDIO_IF_IDX_9"=9; + "AUDIO_IF_IDX_10"=10; + "AUDIO_IF_IDX_11"=11; + "AUDIO_IF_IDX_12"=12; + "AUDIO_IF_IDX_13"=13; + "AUDIO_IF_IDX_14"=14; + "AUDIO_IF_IDX_15"=15} + @h2xmle_default {0} */ + + + uint16_t intf_mode; + /**< Audio interface mode. + + @valuesbul + - #AUDIO_IF_INTF_MODE_TDM (Default) + - #AUDIO_IF_INTF_MODE_PCM + - #AUDIO_IF_INTF_MODE_I2S @tablebulletend */ + + /*#< @h2xmle_description {Interface operating mode } + @h2xmle_rangeList {"AUDIO_IF_INTF_MODE_TDM"=0; + "AUDIO_IF_INTF_MODE_PCM"=1, + "AUDIO_IF_INTF_MODE_I2S"=2} + @h2xmle_default {0} */ + + uint16_t ctrl_data_out_enable; + /**< Specifies whether the PCM block shares the data-out signal to the + driver with other masters. + + @valuesbul + - #AUDIO_IF_CTRL_DATA_OE_DISABLE + - #AUDIO_IF_CTRL_DATA_OE_ENABLE (Default) @tablebulletend */ + + /*#< @h2xmle_description {Specifies whether the PCM block shares the + data-out signal to the driver with other masters.} + @h2xmle_rangeList {"AUDIO_IF_CTRL_DATA_OE_DISABLE"=0; + "AUDIO_IF_CTRL_DATA_OE_ENABLE"=1} + @h2xmle_default {1} */ + + uint32_t active_slot_mask; + /**< Specifies the position of the active slot. + + @values 1 through (2^32)-1 (Default = 1) + + Bits 0 to 31 correspond to slots 0 to 31. When a bit is set, the + corresponding slot is active. The number of active slots can be + inferred from the number of bits set in the mask. + + 32 individual bits can be enabled.*/ + + /*#< @h2xmle_description {Specifies position of the active slot} + @h2xmle_range {1..4294967295} + @h2xmle_default {1} */ + + uint16_t nslots_per_frame; + /**< Number of slots per frame. + + @values 1 through 32 */ + + /*#< @h2xmle_description {Number of slots per frame.} + @h2xmle_rangeList {"AUDIO_IF_SLOTS_PER_FRAME_1"=1; + "AUDIO_IF_SLOTS_PER_FRAME_2"=2; + "AUDIO_IF_SLOTS_PER_FRAME_4"=4; + "AUDIO_IF_SLOTS_PER_FRAME_8"=8; + "AUDIO_IF_SLOTS_PER_FRAME_16"=16; + "AUDIO_IF_SLOTS_PER_FRAME_32"=32} + @h2xmle_default {1} */ + + uint16_t slot_width; + /**< Width of the slot in a audio_if frame. + + @valuesbul + - 16 bits (Default) + - 24 bits (Default) + - 32 bits @tablebulletend */ + + /*#< @h2xmle_description {Width of the slot in a audio_if frame.} + @h2xmle_rangeList {"AUDIO_IF_SLOT_WIDTH_16"=16; + "AUDIO_IF_SLOT_WIDTH_24"=24; + "AUDIO_IF_SLOT_WIDTH_32"=32} + @h2xmle_default {16} */ + + uint32_t active_lane_mask; + /**< Position of the active audio_if lanes: 1 to ((2^N)-1), where N is the number + of physical lanes supported by the hardware interface. + + Bits 0 to N-1 correspond to lanes 0 to N-1. When a bit is set, the + corresponding lane is active. + + The number of active lanes can be inferred from the number of bits set + in the mask. */ + + /*#< @h2xmle_description {Position of the active audio_if lanes: 1 to ((2^N)-1), + where N is the number of physical lanes supported + by the hardware interface. \n + Bits 0 to N-1 correspond to lanes 0 to N-1. \n + When a bit is set, the corresponding lane is + active. The number of active lanes can be inferred + from the number of bits set in the mask.} + @h2xmle_range {1..65535} + @h2xmle_default {1} */ + + uint32_t frame_sync_rate; + /**< Defines the sampling rate of frame sync of the interface. + + @values 8, 11.025, 12, 16, 22.05, 24,32, 44.1, 48, 88.2, 96, 176.4, + 192, 352.8, 384 kHz */ + + /*#< @h2xmle_description {Defines the sampling rate of frame sync of the interface. + For normal scenarios, can choose NATIVE, so, it is assumed + that frame sync sample rate same as HW EP media + format sample rate. + + For operating the interface at lower frame sync, then + need to set this frame sync sample rate can be different + but this frame sync sample rate should be factor or divisor + of HW EP media format sample rate. } + @h2xmle_rangeList {"NATIVE"=0; + "8 kHz"=8000; + "11.025 kHz"=11025; + "12 kHz"=12000; + "16 kHz"=16000; + "22.05 kHz"=22050; + "24 kHz"=24000; + "32 kHz"=32000; + "44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000; + "352.8 kHz"=352800; + "384 kHz"=384000} + @h2xmle_default {0} */ + + uint16_t frame_sync_src; + /**< Specifies the Slave or Master mode of operation. + + @valuesbul + - #AUDIO_IF_FRAME_SYNC_SRC_EXTERNAL + - #AUDIO_IF_FRAME_SYNC_SRC_INTERNAL (Default) @tablebulletend */ + + /*#< @h2xmle_description {Specifies the Slave or Master mode of operation.} + @h2xmle_rangeList {"AUDIO_IF_FRAME_SYNC_SRC_EXTERNAL"=0; + "AUDIO_IF_FRAME_SYNC_SRC_INTERNAL"=1} + @h2xmle_default {1} */ + + uint16_t frame_sync_mode; + /**< Indicates the audio_if Synchronization mode. + + @valuesbul + - #AUDIO_IF_FRAME_SYNC_MODE_SHORT_SYNC (Default) + - #AUDIO_IF_FRAME_SYNC_MODE_ONE_SLOT_SYNC + - #AUDIO_IF_FRAME_SYNC_MODE_LONG_SYNC @tablebulletend */ + + /*#< @h2xmle_description {Indicates the audio_if Synchronization mode.} + @h2xmle_rangeList {"AUDIO_IF_FRAME_SYNC_MODE_SHORT_SYNC"=0; + "AUDIO_IF_FRAME_SYNC_MODE_ONE_SLOT_SYNC"=1; + "AUDIO_IF_FRAME_SYNC_MODE_LONG_SYNC"=2} + @h2xmle_default {0} */ + + uint16_t invert_frame_sync_pulse; + /**< Specifies whether to invert synchronization. + + @valuesbul + - #AUDIO_IF_FRAME_SYNC_NORMAL (Default) + - #AUDIO_IF_FRAME_SYNC_INVERT @tablebulletend */ + + /*#< @h2xmle_description {Specifies whether to invert frame synchronization.} + @h2xmle_rangeList {"AUDIO_IF_FRAME_SYNC_NORMAL"=0; + "AUDIO_IF_FRAME_SYNC_INVERT"=1} + @h2xmle_default {0} */ + + uint16_t frame_sync_data_delay; + /**< Indicates the number of bit-clock cycles when delaying data for + synchronization. + + @valuesbul + - #AUDIO_IF_FRAME_SYNC_DATA_DELAY_0BCLK + - #AUDIO_IF_FRAME_SYNC_DATA_DELAY_1BCLK + - #AUDIO_IF_FRAME_SYNC_DATA_DELAY_2BCLK @tablebulletend */ + + /*#< @h2xmle_description {Indicates the number of bit-clock cycles when + delaying data for synchronization.} + @h2xmle_rangeList {"AUDIO_IF_FRAME_SYNC_DATA_DELAY_0BCLK"=0; + "AUDIO_IF_FRAME_SYNC_DATA_DELAY_1BCLK"=1; + "AUDIO_IF_FRAME_SYNC_DATA_DELAY_2BCLK"=2} + @h2xmle_default {1} */ + + uint16_t bit_clk_type; + /**< Indicates the bit clock type. + + @valuesbul + - #AUDIO_IF_I_BIT_CLK_EN (Default) + - #AUDIO_IF_E_BIT_CLK_EN + - #AUDIO_IF_SKIP_BIT_CLK_EN @tablebulletend */ + + /*#< @h2xmle_description {Indicates the bit clock type.} + @h2xmle_rangeList {"AUDIO_IF_I_BIT_CLK_EN"=0; + "AUDIO_IF_E_BIT_CLK_EN"=1; + "AUDIO_IF_SKIP_BIT_CLK_EN"=2} + @h2xmle_default {0} */ + + uint8_t inv_int_bit_clk; + /**< Specifies whether to invert the clock supplied to the blocks inside QAIF. + + @valuesbul + - #AUDIO_IF_INT_CLK_NORMAL (Default) + - #AUDIO_IF_INT_CLK_INVERT @tablebulletend */ + + /*#< @h2xmle_description {Specifies whether to invert the clock supplied to the blocks inside QAIF.} + @h2xmle_rangeList {"AUDIO_IF_INT_CLK_NORMAL"=0; + "AUDIO_IF_INT_CLK_INVERT"=1} + @h2xmle_default {0} */ + + uint8_t inv_ext_bit_clk; + /**< Specifies whether to invert the clock supplied to the blocks outside of QAIF. + + @valuesbul + - #AUDIO_IF_EXT_CLK_NORMAL (Default) + - #AUDIO_IF_EXT_CLK_INVERT @tablebulletend */ + + /*#< @h2xmle_description {Specifies whether to invert the clock supplied to the blocks outside of QAIF.} + @h2xmle_rangeList {"AUDIO_IF_EXT_CLK_NORMAL"=0; + "AUDIO_IF_EXT_CLK_INVERT"=1} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_audio_if_intf_cfg_t param_id_audio_if_intf_cfg_t; + +typedef enum audio_if_full_cycle_en_t +{ + AUDIO_IF_FULL_CYCLE_DISABLE = 0, + /* Disable full cycle */ + + AUDIO_IF_FULL_CYCLE_ENABLE + /* Enable full cycle */ +} audio_if_full_cycle_en_t; + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Identifier for the parameter that configure the full cycle setting of audio_if interface. + + @msgpayload + param_id_audio_if_intf_cfg_t + */ +#define PARAM_ID_AUDIO_IF_FULL_CYCLE_CFG 0x08001B12 + +/*# @h2xmlp_parameter {"PARAM_ID_AUDIO_IF_FULL_CYCLE_CFG", PARAM_ID_AUDIO_IF_FULL_CYCLE_CFG} + @h2xmlp_description {ID for the parameter that configures the audio_if + interface full cycle.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Payload for #PARAM_ID_AUDIO_IF_FULL_CYCLE_CFG. + */ +#include "spf_begin_pack.h" +struct param_id_audio_if_full_cycle_cfg_t +{ + uint16_t full_cycle_enable; + /**< Full Cycle configuration enable. + + @valuesbul (See #audio_if_full_cycle_en_t) + - AUDIO_IF_FULL_CYCLE_DISABLE + - AUDIO_IF_FULL_CYCLE_ENABLE + - @tablebulletend */ + + /*#< @h2xmle_description {Audio Interface loopback mode.} + @h2xmle_rangeList {"AUDIO_IF_FULL_CYCLE_DISABLE"=0; + "AUDIO_IF_FULL_CYCLE_ENABLE"=1} + @h2xmle_default {0} */ + + uint8_t inv_launch_clk; + /**< Specifies whether to invert the launch clock. + + @valuesbul + - #AUDIO_IF_LAUNCH_CLK_NORMAL (Default) + - #AUDIO_IF_LAUNCH_CLK_INVERT @tablebulletend */ + + /*#< @h2xmle_description {Specifies whether to invert the launch clock.} + @h2xmle_rangeList {"AUDIO_IF_LAUNCH_CLK_NORMAL"=0; + "AUDIO_IF_LAUNCH_CLK_INVERT"=1} + @h2xmle_default {0} */ + + uint8_t inv_capture_clk; + /**< Specifies whether to invert the capture clock. + + @valuesbul + - #AUDIO_IF_CAPTURE_CLK_NORMAL (Default) + - #AUDIO_IF_CAPTURE_CLK_INVERT @tablebulletend */ + + /*#< @h2xmle_description {Specifies whether to invert the capture clock.} + @h2xmle_rangeList {"AUDIO_IF_CAPTURE_CLK_NORMAL"=0; + "AUDIO_IF_CAPTURE_CLK_INVERT"=1} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_audio_if_full_cycle_cfg_t param_id_audio_if_full_cycle_cfg_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Identifier for the hardware audio_if Sink module. + + @subhead4{Supported parameter IDs} + - #PARAM_ID_AUDIO_IF_INTF_CFG @lstsp1 + - #PARAM_ID_HW_EP_MF_CFG @lstsp1 + - #PARAM_ID_HW_EP_FRAME_DURATION @lstsp1 + - #PARAM_ID_AUDIO_IF_FULL_CYCLE_CFG @lstsp1 + - #PARAM_ID_AUDIO_IF_DBG_LOOPBACK_CFG @lstsp1 + - #PARAM_ID_HW_DELAY + + + @subhead4{Supported input media formats} + - Data formats: @lstsep + - #DATA_FORMAT_FIXED_POINT (Default) @lstsp2 + - #DATA_FORMAT_IEC61937_PACKETIZED @lstsp2 + - #DATA_FORMAT_IEC60958_PACKETIZED @lstsp2 + - #DATA_FORMAT_DSD_OVER_PCM @lstsp2 + - #DATA_FORMAT_GENERIC_COMPRESSED @lstsp2 + - #DATA_FORMAT_RAW_COMPRESSED @lstsp1 + - fmt_id : Don't care @lstsp1 + - Sample rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, 88.2, 96, + 176.4, 192, 352.8, 384 kHz @lstsp1 + - Number of channels: 1..AUDIO_IF_MAX_CHANNEL_CNT @lstsp1 + - Channel type : Don't care @lstsp1 + - Bit width: @lstsep + - 16 bits per sample in Q15 format @lstsp2 + - 24 bits per sample in Q27 format @lstsp2 + - 32 bits per sample in Q31 format @newpage + - Q format : Q15 Q27, Q31 @lstsp1 + - Interleaving : De-interleaved unpacked, Interleaved + */ +#define MODULE_ID_AUDIO_IF_SINK 0x0700117C + +/*# @h2xmlm_module {"MODULE_ID_AUDIO_IF_SINK", MODULE_ID_AUDIO_IF_SINK} + @h2xmlm_displayName {"Audio_if Sink"} + @h2xmlm_modSearchKeys {hardware} + @h2xmlm_description {ID for the Audio If Sink module. For more + details, see AudioReach Signal Processing Framework + (SPF) API Reference.} + @h2xmlm_dataInputPorts {IN=PORT_ID_AUDIO_IF_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlDynamicPortIntent {"Qtimer HWEP drift info"=INTENT_ID_TIMER_DRIFT_INFO, + maxPorts= -1} + @h2xmlm_ctrlDynamicPortIntent {"HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, + maxPorts= -1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC,APM_CONTAINER_TYPE_PTC} + @h2xmlm_stackSize {AUDIO_IF_STACK_SIZE} + + @{ <-- Start of the Module --> + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_range {1..AUDIO_IF_MAX_CHANNEL_CNT} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + @h2xml_Select {param_id_audio_if_intf_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_frame_duration_t} + @h2xmle_range {1..100000} + @h2xmle_default {1} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_delay_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_audio_if_full_cycle_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_audio_if_dbg_loopback_cfg_t} + @h2xmlm_InsertParameter + @} <-- End of the Module --> */ + + +/** @ingroup ar_spf_mod_hwep_audio_if_mods + Identifier for the audio_if Source module. The module does not take any inputs. + + @subhead4{Supported parameter IDs} + - #PARAM_ID_AUDIO_IF_INTF_CFG @lstsp1 + - #PARAM_ID_HW_EP_MF_CFG @lstsp1 + - #PARAM_ID_HW_EP_FRAME_DURATION @lstsp1 + - #PARAM_ID_HW_EP_SRC_OUT_DATA_INTERLEAVING @lstsp1 + - #PARAM_ID_HW_EP_TIMESTAMP_PROPAGATION @lstsp1 + - #PARAM_ID_AUDIO_IF_FULL_CYCLE_CFG @lstsp1 + - #PARAM_ID_AUDIO_IF_DBG_LOOPBACK_CFG @lstsp1 + - PARAM_ID_HW_DELAY + + */ +#define MODULE_ID_AUDIO_IF_SOURCE 0x0700117D + +/*# @h2xmlm_module {"MODULE_ID_AUDIO_IF_SOURCE",MODULE_ID_AUDIO_IF_SOURCE} + @h2xmlm_displayName {"Audio_if Source"} + @h2xmlm_modSearchKeys {hardware} + @h2xmlm_description {ID for the audio_if Source module. For more + details, see AudioReach Signal Processing Framework + (SPF) API Reference.} + @h2xmlm_dataOutputPorts {OUT=PORT_ID_AUDIO_IF_OUTPUT} + @h2xmlm_dataMaxInputPorts {0} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlDynamicPortIntent {"Qtimer HWEP drift info"=INTENT_ID_TIMER_DRIFT_INFO, + maxPorts= -1} + @h2xmlm_ctrlDynamicPortIntent {"HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, + maxPorts= -1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC,APM_CONTAINER_TYPE_PTC} + @h2xmlm_stackSize {AUDIO_IF_STACK_SIZE} + + @{ <-- Start of the Module --> + @h2xml_Select {param_id_audio_if_intf_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_range {1..AUDIO_IF_MAX_CHANNEL_CNT} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_frame_duration_t} + @h2xmle_range {1..100000} + @h2xmle_default {1} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_delay_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_data_interleaving_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_timestamp_propagation_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_audio_if_full_cycle_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_audio_if_dbg_loopback_cfg_t} + @h2xmlm_InsertParameter + @} <-- End of the Module --> */ + + +#endif // _AUDIO_IF_API_H_ diff --git a/spf/api/modules/celt_enc_api.h b/spf/api/modules/celt_enc_api.h new file mode 100644 index 0000000..68ca539 --- /dev/null +++ b/spf/api/modules/celt_enc_api.h @@ -0,0 +1,95 @@ +#ifndef _CELT_ENCODER_API_H_ +#define _CELT_ENCODER_API_H_ +/*============================================================================== + @file celt_encoder_api.h + @brief This file contains CELT encoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of CELT module */ +#define CELT_ENC_DATA_INPUT_PORT 0x2 + +/* Output port ID of CELT module */ +#define CELT_ENC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of CELT module */ +#define CELT_ENC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of CELT module */ +#define CELT_ENC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of CELT module */ +#define CELT_ENC_MODULE_STACK_SIZE 8192 + +/*============================================================================== + Module +==============================================================================*/ +/** @h2xml_title1 {CELT Encoder Module API} + @h2xml_title_agile_rev {CELT Encoder Module API} + @h2xml_title_date {April 15, 2019} */ + +/** + * Module ID for CELT encoder. + * Encodes to data of format-id = MEDIA_FMT_ID_CELT + */ +#define MODULE_ID_CELT_ENC 0x07001090 + +/** + @h2xmlm_module {"MODULE_ID_CELT_ENC", MODULE_ID_CELT_ENC} + @h2xmlm_displayName {"CELT Encoder"} + @h2xmlm_description {This module is used as the encoder for CELT use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : CELT_enc_cfg_t\n + - Encodes data to format-id = MEDIA_FMT_ID_CELT\n + - Supports following params:\n + -- PARAM_ID_ENCODER_OUTPUT_CONFIG\n + -- PARAM_ID_ENC_BITRATE\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 32, 44.1, 48, 96 \n + -- Number of channels : 1, 2\n + -- Bit Width : 16\n + -- Bits Per Sample : 16\n + -- Q format : Q15\n + -- Interleaving : interleaved\n + -- Supported bit rates in each configuration :\n + -- minimum bit rate in bps:32000 \n + -- maximum bit rate in bps:1536000 \n + \n } + @h2xmlm_dataMaxInputPorts {CELT_ENC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {CELT_ENC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=CELT_ENC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=CELT_ENC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {CELT_ENC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_encoder_output_config_t"} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_encoder_output_config_t::fmt_id} + @h2xmle_rangeList {"Media format ID of CELT"=MEDIA_FMT_ID_CELT} + @h2xmle_default {0} + @h2xml_Select {"celt_enc_cfg_t"} + @h2xmlm_InsertStructure + @h2xml_Select {"param_id_enc_bitrate_param_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif //_CELT_ENCODER_API_H_ diff --git a/spf/api/modules/codec_dma_api.h b/spf/api/modules/codec_dma_api.h new file mode 100644 index 0000000..c076443 --- /dev/null +++ b/spf/api/modules/codec_dma_api.h @@ -0,0 +1,394 @@ +#ifndef _CODEC_DMA_API_H_ +#define _CODEC_DMA_API_H_ +/** + * \file codec_dma_api.h + * \brief + * This file contains CODEC_DMA module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "hw_intf_cmn_api.h" +//#include "prbdma_hw_api.h" + + /** @h2xml_title1 {Codec Dma Module API} + @h2xml_title_agile_rev {Codec Dma Module API} + @h2xml_title_date {Oct 11, 2018} */ + +/*============================================================================== + Constants +==============================================================================*/ + +/** @ingroup ar_spf_codec_dma_macros + Input port ID of Codec DMA module */ +#define PORT_ID_GEN_CNTR_DMA_INPUT 0x2 + +/** @ingroup ar_spf_codec_dma_macros + Output port ID of Codec DMA module */ +#define PORT_ID_GEN_CNTR_DMA_OUTPUT 0x1 + +/** @ingroup ar_spf_codec_dma_macros + Stack size for Codec DMA Module*/ +#define GEN_CNTR_DMA_STACK_SIZE 2048 + +/*============================================================================== + Type definition +==============================================================================*/ + +/** @ingroup ar_spf_codec_dma_macros + Parameter used to configure the CODEC DMA interface */ +#define PARAM_ID_CODEC_DMA_INTF_CFG 0x08001063 + +/** @ingroup ar_spf_codec_dma_macros + + Configures the CODEC DMA interface +*/ + +/** @h2xmlp_parameter {"PARAM_ID_CODEC_DMA_INTF_CFG", + PARAM_ID_CODEC_DMA_INTF_CFG} + @h2xmlp_description {Configures the CODEC DMA interface.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +/* Payload for parameter PARAM_ID_CODEC_DMA_INTF_CFG */ +struct param_id_codec_dma_intf_cfg_t +{ + uint32_t lpaif_type; + /**< LPAIF types. */ + + /**< @h2xmle_description {LPAIF types.} + @h2xmle_rangeList {"LPAIF"=0; + "LPAIF_RXTX"=1; + "LPAIF_WSA"=2; + "LPAIF_VA"=3; + "LPAIF_AXI"=4; + "LPAIF_AUD"=5; + "LPAIF_WSA2"=7; + "LPAIF_RXTX_SDCA"=8; + "LPAIF_WSA_SDCA"=9; + "LPAIF_QAIF"=10; + "LPAIF_QAIF_VA"=11} + @h2xmle_default {2} + */ + uint32_t intf_indx; + /**< CODEC DMA interface index which picks an instance of codec DMA. + Each interface supports different num of channels. */ + + /**< @h2xmle_description {CODEC DMA interface index which picks an instance of codec dma. + Each interface supports different num of channels} + */ + uint32_t active_channels_mask; + /**< Active channels mask to denote the bit mask for active channels. + Bits 0 to 15 denote channels 0 to 15. A set bit in the mask denotes + the channel is active while a 0 denotes a channel is inactive. + Mask should match the channel indices being set from codec side. */ + + /**< @h2xmle_description {Active channels mask to denote the bit mask for active channels. + Bits 0 to 15 denote channels 0 to 15. A set bit in the mask denotes + the channel is active while a 0 denotes a channel is inactive. + Mask should match the channel indices being set from codec side} + @h2xmle_range {1..65535} + @h2xmle_default {1} + */ +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_codec_dma_intf_cfg_t param_id_codec_dma_intf_cfg_t; + +/** @ingroup ar_spf_codec_dma_macros + Parameter used to configure the CODEC DMA interface Frame select */ +#define PARAM_ID_CODEC_DMA_CODEC_FS_SEL_CFG 0x08001B8B + +/** @ingroup ar_spf_codec_dma_macros + + Configures the CODEC DMA Frame select +*/ + +/** @h2xmlp_parameter {"PARAM_ID_CODEC_DMA_CODEC_FS_SEL_CFG", + PARAM_ID_CODEC_DMA_CODEC_FS_SEL_CFG} + @h2xmlp_description {Configures the CODEC DMA interface.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +/* Payload for parameter PARAM_ID_CODEC_DMA_CODEC_FS_SEL_CFG */ +struct param_id_codec_dma_codec_fs_sel_cfg_t +{ + uint16_t enable_codec_fs_config; + /**< @h2xmle_description { Enable. - allowed only when HLOS audio driver wants to program frame select value explictly. + Disable - (legacy approach) } + @h2xmle_rangeList {"Disable"=0; + "Enable"=1} + @h2xmle_default {0} + */ + uint16_t codec_fs_sel_value; + /**< @h2xmle_description {desired channel index to be set for frame strobe selection} + @h2xmle_range {0x0..0xf} + @h2xmle_default {0x0} */ + +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_codec_dma_codec_fs_sel_cfg_t param_id_codec_dma_codec_fs_sel_cfg_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + + +/** @ingroup ar_spf_codec_dma_macros + CODEC DMA Sink module. + + @subhead4{Supported parameter IDs} + - #PARAM_ID_CODEC_DMA_INTF_CFG @lstsp1 + - #PARAM_ID_HW_EP_MF_CFG @lstsp1 + - #PARAM_ID_HW_EP_FRAME_DURATION @lstsp1 + - #PARAM_ID_HW_EP_POWER_MODE_CFG @lstsp1 + - #PARAM_ID_HW_EP_DMA_DATA_ALIGN @lstsp1 + - PARAM_ID_HW_DELAY + + @subhead4{Supported input media format ID} + - Data Format : FIXED_POINT @lstsp1 + - fmt_id : Don't care @lstsp1 + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, + 88.2, 96, 176.4, 192, 352.8, 384 kHz @lstsp1 + - Number of channels : 1 to 16 @lstsp1 + - Channel type : Don't care @lstsp1 + - Bit Width : 16 (bits per sample 16 and Q15), + : 24 (bits per sample 24 and Q27) + : 32 (bits per sample 32 and Q31) @lstsp1 + - Q format : Q15, Q27, Q31 @lstsp1 + - Interleaving : I2S sink module needs de-interleaved unpacked or Interleaved */ + +#define MODULE_ID_CODEC_DMA_SINK 0x07001023 + +/** @h2xmlm_module {"MODULE_ID_CODEC_DMA_SINK", + MODULE_ID_CODEC_DMA_SINK} + @h2xmlm_displayName {"Codec DMA Sink"} + @h2xmlm_modSearchKeys{hardware} + @h2xmlm_description {CODEC_DMA Sink Module\n + - Supports following params: + - PARAM_ID_CODEC_DMA_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_DURATION \n + - PARAM_ID_HW_EP_POWER_MODE_CFG\n + - PARAM_ID_HW_EP_DMA_DATA_ALIGN\n + - PARAM_ID_HW_DELAY\n + - \n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT \n + - fmt_id : Don't care \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1 to 16 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 24 (bits per sample 24 and Q27) \n + - : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q27, Q31 \n + - Interleaving : Codec DMA sink module needs de-interleaved unpacked or interleaved } + @h2xmlm_dataInputPorts {IN = PORT_ID_GEN_CNTR_DMA_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { GEN_CNTR_DMA_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_rangeList {"ONE"=1; + "TWO"=2; + "THREE"=3; + "FOUR"=4; + "FIVE"=5; + "SIX"=6; + "SEVEN"=7; + "EIGHT"=8; + "NINE"=9; + "TEN"=10; + "ELEVEN"=11; + "TWELVE"=12; + "THIRTEEN"=13; + "FOURTEEN"=14; + "FIFTEEN"=15; + "SIXTEEN"=16} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + + @h2xml_Select {param_id_hw_ep_frame_duration_t} + @h2xmle_range {1..40000} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_power_mode_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_codec_dma_intf_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_codec_dma_intf_cfg_t::intf_indx} + @h2xmle_rangeList {"CODEC_RX0"=1; + "CODEC_RX1"=2; + "CODEC_RX2"=3; + "CODEC_RX3"=4; + "CODEC_RX4"=5; + "CODEC_RX5"=6; + "CODEC_RX6"=7; + "CODEC_RX7"=8; + "CODEC_RX8"=9; + "CODEC_RX9"=10; + "CODEC_RX10"=11; + "CODEC_RX11"=12; + "CODEC_RX12"=13; + "CODEC_RX13"=14; + "CODEC_RX14"=15; + "CODEC_RX15"=16; + "CODEC_RX16"=17; + "CODEC_RX17"=18} + @h2xmle_default {1} + + @h2xml_Select {param_id_hw_ep_dma_data_align_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_dma_data_align_t::dma_data_align} + @h2xmle_rangeList {"DMA_DATA_ALIGN_MSB"=0; + "DMA_DATA_ALIGN_LSB"=1} + @h2xmle_default {0} + @h2xml_Select {param_id_hw_delay_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + +/** @ingroup ar_spf_codec_dma_macros + CODEC DMA Source module + + @subhead4{Supported parameter IDs} + - #PARAM_ID_CODEC_DMA_INTF_CFG @lstsp1 + - #PARAM_ID_HW_EP_MF_CFG @lstsp1 + - #PARAM_ID_HW_EP_FRAME_DURATION @lstsp1 + - #PARAM_ID_HW_EP_POWER_MODE_CFG @lstsp1 + - PARAM_ID_HW_DELAY + - PARAM_ID_PRBDMA_ENABLE + - PARAM_ID_PRBDMA_DEBUG_CONFIG + + @subhead4{Supported input media format ID} + - Codec DMA source module does not take any inputs */ + +#define MODULE_ID_CODEC_DMA_SOURCE 0x07001024 + +/** @h2xmlm_module {"MODULE_ID_CODEC_DMA_SOURCE", + MODULE_ID_CODEC_DMA_SOURCE} + @h2xmlm_displayName {"Codec DMA Source"} + @h2xmlm_modSearchKeys{hardware} + @h2xmlm_description {CODEC_DMA Source Module \n + - Supports following params: + - PARAM_ID_CODEC_DMA_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_DURATION\n + - PARAM_ID_HW_EP_POWER_MODE_CFG\n + - PARAM_ID_HW_EP_DMA_DATA_ALIGN\n + - PARAM_ID_HW_DELAY\n + - PARAM_ID_PRBDMA_ENABLE\n + - PARAM_ID_PRBDMA_DEBUG_CONFIG\n + - PARAM_ID_SILENCE_DETECTION\n + - PARAM_ID_CODEC_DMA_CODEC_FS_SEL_CFG\n + - \n + - Supported Input Media Format: \n + - Codec dma source module doesn't take any inputs } + @h2xmlm_dataOutputPorts {OUT = PORT_ID_GEN_CNTR_DMA_OUTPUT} + @h2xmlm_dataMaxInputPorts {0} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "AAD-Codec DMA Control" = INTENT_ID_PRBDMA_CONTROL, + maxPorts= 1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { GEN_CNTR_DMA_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_rangeList {"ONE"=1; + "TWO"=2; + "THREE"=3; + "FOUR"=4; + "FIVE"=5; + "SIX"=6; + "SEVEN"=7; + "EIGHT"=8; + "NINE"=9; + "TEN"=10; + "ELEVEN"=11; + "TWELVE"=12; + "THIRTEEN"=13; + "FOURTEEN"=14; + "FIFTEEN"=15; + "SIXTEEN"=16} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_frame_duration_t} + @h2xmle_range {1..40000} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_power_mode_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_codec_dma_intf_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_codec_dma_intf_cfg_t::intf_indx} + @h2xmle_rangeList {"CODEC_TX0"=1; + "CODEC_TX1"=2; + "CODEC_TX2"=3; + "CODEC_TX3"=4; + "CODEC_TX4"=5; + "CODEC_TX5"=6; + "CODEC_TX6"=7; + "CODEC_TX7"=8; + "CODEC_TX8"=9; + "CODEC_TX9"=10; + "CODEC_TX10"=11; + "CODEC_TX11"=12; + "CODEC_TX12"=13; + "CODEC_TX13"=14; + "CODEC_TX14"=15; + "CODEC_TX15"=16; + "CODEC_TX16"=17; + "CODEC_TX17"=18; + "CODEC_TX18"=19; + "CODEC_TX19"=20; + "CODEC_TX20"=21; + "CODEC_TX21"=22; + "CODEC_TX22"=23} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_delay_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_prbdma_enable_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_prbdma_debug_config_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_data_interleaving_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_timestamp_propagation_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_silence_detection_t} + @h2xmlm_InsertParameter + @h2xml_Select {event_cfg_silence_detection_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_dma_data_align_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_dma_data_align_t::dma_data_align} + @h2xmle_rangeList {"DMA_DATA_ALIGN_MSB"=0; + "DMA_DATA_ALIGN_LSB"=1} + @h2xmle_default {0} + @h2xml_Select {param_id_hw_delay_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_codec_dma_codec_fs_sel_cfg_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ +#endif //_CODEC_DMA_API_H_ diff --git a/spf/api/modules/codec_metadata_api.h b/spf/api/modules/codec_metadata_api.h new file mode 100644 index 0000000..1df0e86 --- /dev/null +++ b/spf/api/modules/codec_metadata_api.h @@ -0,0 +1,167 @@ +#ifndef CODEC_METADATA_API_H +#define CODEC_METADATA_API_H +/** + * \file codec_metadata_api.h + * \brief + * This file contains codec related metadata IDs. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/** @h2xml_title1 {Metadata IDs} + @h2xml_title_agile_rev {Metadata IDs} + @h2xml_title_date {Apr 30 2019} */ +/** + @h2xmlx_xmlNumberFormat {int} +*/ + + +/** +* Metadata ID for Encoder frame info. +*/ +#define MODULE_CMN_MD_ID_ENCODER_FRAME_INFO 0x0A001052 + + +/* Payload of the metadata for encoder frame info, +* that can be put in the read metadata buffer + **/ +#include "spf_begin_pack.h" +struct module_cmn_md_encoder_per_frame_info_t +{ + uint32_t frame_size; + /**< Size of each frame in bytes (E.g. encoded frame size). + + @values > 0 */ + + uint32_t timestamp_lsw; + /**< Lower 32 bits of the 64-bit session time in microseconds of the + first sample in the frame. */ + + uint32_t timestamp_msw; + /**< Upper 32 bits of the 64-bit session time in microseconds of the + first sample in the frame. + */ + + uint32_t flags; + /**< Frame flags. + + @values{for bit 31} + - 1 -- Timestamp is valid + - 0 -- Timestamp is not valid + - To set this bit, use #RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG and + RD_SH_MEM_EP_SHIFT_TIMESTAMP_VALID_FLAG + + All other bits are reserved; the spf sets them to 0. + */ +} +#include "spf_end_pack.h" +; + +/* Structure for encoder frame info metadata */ +typedef struct module_cmn_md_encoder_per_frame_info_t module_cmn_md_encoder_per_frame_info_t; + + +/** +* Metadata ID for Codec.2.0 requirement. +*/ + +/** Metadata ID to specify the Start of the buffer + * This metadata has no payload. + */ +#define MODULE_CMN_MD_ID_BUFFER_START 0x0A001053 + + +/* Payload of the metadata to specify the start of the buffer + **/ +#include "spf_begin_pack.h" +struct module_cmn_md_buffer_start_t +{ + uint32_t buffer_index_lsw; + /** < + * Specifies the lower 32 bits of the 64-bit unique buffer index + */ + + uint32_t buffer_index_msw; + /** < + * SSpecifies the higher 32 bits of the 64-bit unique buffer index + */ +} +#include "spf_end_pack.h" +; + +/* Structure for Buffer Start metadata */ +typedef struct module_cmn_md_buffer_start_t module_cmn_md_buffer_start_t; + + +/** Metadata ID to specify the end of the buffer + */ +#define MODULE_CMN_MD_ID_BUFFER_END 0x0A001054 + + +/** Definition of metadata error status/result flag bitmask. */ +#define MD_END_PAYLOAD_FLAGS_BIT_MASK_ERROR_RESULT AR_NON_GUID(0x00000001) + +/** Definition of metadata error status/result flag shift value. */ +#define MD_END_PAYLOAD_FLAGS_SHIFT_ERROR_RESULT 0 + +/** Definition of metadata error recovery done flag bitmask. */ +#define MD_END_PAYLOAD_FLAGS_BIT_MASK_ERROR_RECOVERY_DONE AR_NON_GUID(0x00000002) + +/** Definition of metadata error status/result flag shift value. */ +#define MD_END_PAYLOAD_FLAGS_SHIFT_ERROR_RECOVERY_DONE 1 + +/** Definition of metadata error result value. */ +#define MD_END_RESULT_FAILED 1 + +/** Definition of metadata error result value. */ +#define MD_END_RESULT_ERROR_RECOVERY_DONE 1 + +/* Payload of the metadata to specify the end of the buffer + **/ +#include "spf_begin_pack.h" +struct module_cmn_md_buffer_end_t +{ + uint32_t buffer_index_lsw; + /** < + * Specifies the lower 32 bits of the 64-bit unique buffer index + */ + + uint32_t buffer_index_msw; + /** < + * Specifies the higher 32 bits of the 64-bit unique buffer index + */ + + uint32_t flags; + /**< Field to specify any related information to from/to the client. + * + * BIT_0 : specifies if any frame in the buffer has error + * 0 : no error + * 1 : at least one frame in the buffer has error + * BIT_1 : specifies if error recovery was done for any frame in the buffer + * 0 : no error recovery + * 1 : at least one frame in the buffer was recovered + * + * Other bit field values are reserved for future use and must be set to 0 + */ +} +#include "spf_end_pack.h" +; + +/* Structure for Buffer End metadata */ +typedef struct module_cmn_md_buffer_end_t module_cmn_md_buffer_end_t; + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + + +#endif /* CODEC_METADATA_API_H */ diff --git a/spf/api/modules/common_enc_dec_api.h b/spf/api/modules/common_enc_dec_api.h new file mode 100644 index 0000000..f9d12da --- /dev/null +++ b/spf/api/modules/common_enc_dec_api.h @@ -0,0 +1,479 @@ +#ifndef COMMON_ENC_DEC_API_H +#define COMMON_ENC_DEC_API_H +/** + * \file common_enc_dec_api.h + * \brief + * This file contains media format IDs and definitions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/** @h2xml_title1 {Common APIs for Encoders and Decoders} + @h2xml_title_agile_rev {Common APIs for Encoders and Decoders} + @h2xml_title_date {August 13, 2018} */ +/** + @h2xmlx_xmlNumberFormat {int} +*/ + +/** + * Parameter for setting the real module ID for the placeholder modules. + */ +#define PARAM_ID_REAL_MODULE_ID 0x0800100B + +/** @h2xmlp_parameter {"PARAM_ID_REAL_MODULE_ID", PARAM_ID_REAL_MODULE_ID} + @h2xmlp_description {Parameter for setting the real module ID for the placeholder modules. + } + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct param_id_placeholder_real_module_id_t +{ + uint32_t real_module_id; + /**< @h2xmle_description {ID of the real module-ID to be used in place of placeholder module. + * E.g. MODULE_ID_AAC_DEC or MODULE_ID_AAC_ENC, etc} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} + */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_placeholder_real_module_id_t param_id_placeholder_real_module_id_t; + + +/* This parameter is supported by MODULE_ID_PLACEHOLDER_ENCODER, MODULE_ID_PLACEHOLDER_DECODER modules. +* +* After setting the real-module-id to the placeholder using PARAM_ID_REAL_MODULE_ID +* the module is no longer a placeholder. Any set/get API directly goes to the CAPI. +* This API can be used to reset the placeholder module. +* The reset involves destroying the current real-module-id. After resetting, the +* PARAM_ID_REAL_MODULE_ID can be sent again. +* After reset, module regains placeholder-state +* +* No Payload +*/ +#define PARAM_ID_RESET_PLACEHOLDER_MODULE 0x08001173 + + +/** + * ID of the placeholder encoder + * + * Place holder module can be replaced only once. + * Any set param issued to the real module before PARAM_ID_REAL_MODULE_ID is set is cached. + */ +#define MODULE_ID_PLACEHOLDER_ENCODER 0x07001008 +/** + @h2xmlm_module {"MODULE_ID_PLACEHOLDER_ENCODER", MODULE_ID_PLACEHOLDER_ENCODER} + @h2xmlm_displayName {"Placeholder Encoder"} + @h2xmlm_description {To alleviate the need of creating a graph for every encoder a placeholder module is used. + The graph definition contains the placeholder module-id. It is replaced by the real encoder module before graph is started (if enabled). \n + PARAM_ID_REAL_MODULE_ID is used to replace with real module. Placeholder module can be replaced only once. + Any set param issued to the real module before PARAM_ID_REAL_MODULE_ID is set is cached. + PARAM_ID_MODULE_ENABLE is used to enable or disable the module. When disabled, modue is bypassed. \n + -# Supports PARAM_ID_REAL_MODULE_ID \n + *- Supported Input Media Format: See supported media formats of the encoder modules. + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize { 1024 } + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_placeholder_real_module_id_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {param_id_module_enable_t::enable} + @h2xmle_default {1} + @} <-- End of the Module --> +*/ + +/** + * ID of the placeholder decoder + * + * Place holder module can be replaced only once. + * Any set param issued to the real module before PARAM_ID_REAL_MODULE_ID is set is cached. + */ +#define MODULE_ID_PLACEHOLDER_DECODER 0x07001009 +/** + @h2xmlm_module {"MODULE_ID_PLACEHOLDER_DECODER", MODULE_ID_PLACEHOLDER_DECODER} + @h2xmlm_displayName {"Placeholder Decoder"} + @h2xmlm_description {To alleviate the need of creating a graph for every decoder a placeholder module is used. + The graph definition contains the placeholder module-id. It is replaced by the real decoder module before graph is started . \n + PARAM_ID_REAL_MODULE_ID is used to replace with real module. Place holder module can be replaced only once. + Any set param issued to the real module before PARAM_ID_REAL_MODULE_ID is set is cached. + PARAM_ID_MODULE_ENABLE is used to enable or disable the module. When disabled, modue is bypassed.\n + -# Supports PARAM_ID_REAL_MODULE_ID \n + *- Supported Input Media Format: - Data format: DATA_FORMAT_RAW_COMPRESSED . + See supported media formats of the decoder modules. + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { 1024 } + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_placeholder_real_module_id_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {param_id_module_enable_t::enable} + @h2xmle_default {1} + @} <-- End of the Module --> +*/ + +/** + * Param-ID to configure the PCM output format of PCM encoder, decoder or converter. + * + * Example scenarios that need this parameter are + * 1. decoder -> converter: This param must be set on both decoder and converter. + * The converter will act as back-up for the decoder. + * If decoder is not configured for 24 bit output and it outputs 16 bit, + * then using converter to get 24b bit doesn't give any benefit. + * 2. converter -> encoder: This param must be set on converter only. + * 3. converter use cases in PP/EP containers (E.g. pull mode/push mode). + */ +#define PARAM_ID_PCM_OUTPUT_FORMAT_CFG 0x08001008 + +/** @h2xmlp_parameter {"PARAM_ID_PCM_OUTPUT_FORMAT_CFG", PARAM_ID_PCM_OUTPUT_FORMAT_CFG} + @h2xmlp_description {Param-ID to configure the PCM output format of PCM encoder, decoder or converter. + Example scenarios that need this parameter are:\n\n + -- decoder -> pcm converter: This param must be set on both decoder and converter. + The converter will act as back-up for the decoder. E.g. for 24 bit output, both decoder + and converter are configured to have 24 bit output. In case the decoder can output at 24 bit, then + converter is pass-through. Otherwise, converter will do 16 to 24 bit conversion.\n\n + -- pcm converter -> encoder: This param must be set on converter only.\n\n + -- pcm converter use cases in PP/EP containers (E.g. pull mode/push mode).\n\n + + - Overall struct contains:\n + -- param_id_pcm_output_format_cfg_t pcfg;\n + -- uint8_t payload[payload_size]\n + -\n + } + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_pcm_output_format_cfg_t +{ + uint32_t data_format; + /**< @h2xmle_description {Format of the data} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0, + "DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_policy {Basic} */ + + uint32_t fmt_id; + /**< @h2xmle_description {Format ID of the data stream} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0, + "Media format ID of PCM"=MEDIA_FMT_ID_PCM} + @h2xmle_policy {Basic} */ + + uint32_t payload_size; + /**< @h2xmle_description {Size of the payload immediately following this structure.\n + The struct of payload is defined by combination of data_format and fmt_id. + E.g. PCM fixed point (payload_pcm_output_format_cfg_t) and floating point may have different payloads. + This size does not include bytes added for 32-bit alignment.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +#if defined(__H2XML__) + uint8_t payload[0]; + /**< + @h2xmle_description {Payload} + h2xmle_rangeList {"For fmt_id = PARAM_ID_PCM_OUTPUT_FORMAT_CFG and data_format=DATA_FORMAT_FIXED_POINT"=payload_pcm_output_format_cfg_t} + @h2xmle_policy {Basic} + @h2xmle_variableArraySize {payload_size}*/ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct param_id_pcm_output_format_cfg_t param_id_pcm_output_format_cfg_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for PARAM_ID_PCM_OUTPUT_FORMAT_CFG when fmt_id is MEDIA_FMT_ID_PCM and data_format is fixed point.\n + * Overall struct is:\n + * [\n + * payload_pcm_output_format_cfg_t cfg;\n + * uint8_t channel_mapping[num_channels];\n + * uint8_t 32bit_padding[if_any];\n + * ]\n + *\n + * Note: inconsistent configuration results in error.\n + * E.g. if bit width is 16, then Q format cannot be 27.\n + * E.g. bit width, bits per sample, alignment, q format are related. Hence, if one is native, others must also be native,\n + * if one is unset, others must be unset.\n + } + @h2xmlp_toolPolicy {Calibration} */ + +/** + * Payload for PARAM_ID_PCM_OUTPUT_FORMAT_CFG when fmt_id is MEDIA_FMT_ID_PCM and data_format is fixed point. + * + * Overall struct is: + * { + * payload_pcm_output_format_cfg_t cfg; + * uint8_t channel_mapping[num_channels]; + * uint8_t 32bit_padding[if_any]; + * } + * + * Note: inconsistent configuration results in error. + * E.g. if bit width is 16, then Q format cannot be 27. + * E.g. bit width, bits per sample, alignment, q format are related. Hence, if one is native, others must also be native, + * if one is unset, others must be unset. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct payload_pcm_output_format_cfg_t +{ + int16_t bit_width; + /**< @h2xmle_description {bit width of each sample. E.g. 16 bit, 24 bit or 32 bit} + @h2xmle_default {0} + @h2xmle_rangeList { "PARAM_VAL_UNSET"=-2; + "PARAM_VAL_NATIVE"=-1; + "PARAM_VAL_INVALID"=0; + ""=16; + ""=24; + ""=32} + @h2xmle_policy {Basic} */ + + int16_t alignment; + /**< @h2xmle_description {Indicates the alignment of bits_per_sample in sample_word_size. \n + Relevant only when bits_per_sample is 24 and word_size is 32 + For bits_per_sample 24, word_size 32, qfactor 23 -> PCM_LSB_ALIGNED \n + For bits_per_sample 24, word_size 32, qfactor 31 -> PCM_MSB_ALIGNED} + @h2xmle_default {0} + @h2xmle_rangeList { "PARAM_VAL_UNSET"=-2; + "PARAM_VAL_NATIVE"=-1; + "PARAM_VAL_INVALID"=0; + "PCM_LSB_ALIGNED"=1; + "PCM_MSB_ALIGNED"=2} + @h2xmle_policy {Basic} */ + + int16_t bits_per_sample; + /**< + @h2xmle_description {Bits needed to store one sample. + - 16-bits per sample always contain 16-bit samples. + - 24-bits per sample always contain 24-bit samples. + - 32-bits per sample have below cases: + - If bit width = 24 and alignment = LSB aligned, then + 24-bit samples are placed in the lower 24 bits of a 32-bit word. + Upper bits may or may not be sign-extended. + - If bit width = 24 and alignment = MSB aligned, then + 24-bit samples are placed in the upper 24 bits of a 32-bit word. + Lower bits may or may not be zeroed. + - If bit width = 32, 32-bit samples are placed in the + 32-bit words + } + @h2xmle_default {0} + @h2xmle_rangeList { "PARAM_VAL_UNSET"=-2; + "PARAM_VAL_NATIVE"=-1; + "PARAM_VAL_INVALID"=0; + ""=16; + ""=24; + ""=32 + } + @h2xmle_policy {Basic} */ + + int16_t q_factor; + /**< @h2xmle_description {Q factor of the PCM data. + 15 for 16 bit signed data + 23 for 24 bit signed packed (24 word size) data + 27 for LSB aligned 24 bit unpacked (32 word size) signed data used internal to spf. + 31 for MSB aligned 24 bit unpacked (32 word size) signed data + 23 for LSB aligned 24 bit unpacked (32 word size) signed data + 31 for 32 bit signed data} + @h2xmle_default {0} + @h2xmle_rangeList { "PARAM_VAL_UNSET"=-2; + "PARAM_VAL_NATIVE"=-1; + "PARAM_VAL_INVALID"=0; + ""=15; + ""=23; + ""=24; + ""=27; + ""=31 + } + @h2xmle_policy {Basic} */ + + + int16_t endianness; + /**< @h2xmle_description {Indicates whether PCM samples are stored in little endian or big endian format.} + @h2xmle_default {0} + @h2xmle_rangeList { "PARAM_VAL_UNSET"=-2; + "PARAM_VAL_NATIVE"=-1; + "PARAM_VAL_INVALID"=0; + "PCM_LITTLE_ENDIAN"=1; + "PCM_BIG_ENDIAN"=2 + } + @h2xmle_policy {Basic} */ + + int16_t interleaved; + /**< @h2xmle_description {Data is interleaved or not} + @h2xmle_default {0} + @h2xmle_rangeList { "PARAM_VAL_UNSET"=-2; + "PARAM_VAL_NATIVE"=-1; + "PARAM_VAL_INVALID"=0; + "PCM_INTERLEAVED"=1; + "PCM_DEINTERLEAVED_PACKED"=2; + "PCM_DEINTERLEAVED_UNPACKED"=3 + } + @h2xmle_policy {Basic} */ + + int16_t reserved; + /**< @h2xmle_description {Reserved for alignment; must be set to zero} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ + + int16_t num_channels; + /**< @h2xmle_description {Number of channels} + @h2xmle_default {0} + @h2xmle_rangeList { "PARAM_VAL_UNSET"=-2; + "PARAM_VAL_NATIVE"=-1; + "PARAM_VAL_INVALID"=0 + } + @h2xmle_rangeEnum {pcm_channel_map} + @h2xmle_policy {Basic} */ +#if defined(__H2XML__) + uint8_t channel_mapping[0]; + /**< @h2xmle_description {Channel mapping array of variable size. + Size of this array depends upon number of channels. + Channel[i] mapping describes channel i. Each element i of the array + describes channel i inside the buffer where i is less than num_channels. + An unused channel is set to 0.} + @h2xmle_variableArraySize {num_channels} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct payload_pcm_output_format_cfg_t payload_pcm_output_format_cfg_t; + +/** ID of the parameter used to configure the encoder bit rate */ +#define PARAM_ID_ENC_BITRATE 0x08001052 + + +/** @h2xmlp_parameter {"PARAM_ID_ENC_BITRATE", PARAM_ID_ENC_BITRATE} + @h2xmlp_description {Parameter for setting the bit rate on the encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_enc_bitrate_param_t +{ + uint32_t bitrate; + /**< @h2xmle_description {Defines bit rate in bits per second} + * @h2xmle_range {1..1536000} + @h2xmle_default {1}*/ +} +#include "spf_end_pack.h" +; +typedef struct param_id_enc_bitrate_param_t param_id_enc_bitrate_param_t; + +/** ID of the parameter used to configure the AAC encoder frame size */ +#define PARAM_ID_ENC_FRAME_SIZE_CONTROL 0x08001053 + +/** @h2xmlp_parameter {"PARAM_ID_ENC_FRAME_SIZE_CONTROL", PARAM_ID_ENC_FRAME_SIZE_CONTROL} + @h2xmlp_description {Parameter for configuring the frame control on the encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_enc_frame_size_control_t +{ + uint32_t frame_size_control_type; + /**< @h2xmle_description {type of frame size control.} + @h2xmle_rangeList {"MTU_SIZE"=0; + "PEAK_BIT_RATE"=1; + "BIT_RATE_MODE"=2} + @h2xmle_policy {Basic} */ + + uint32_t frame_size_control_value; + /**< @h2xmle_description {vaue of frame size control. + - MTU_SIZE: MTU size in bytes as per the connected BT sink device. + NOTE: Expectation is that mtu_size is >= 'frame size'. + - PEAK_BIT_RATE: Peak bit rate in bits/second. + Eg : 96000 if 96kbps is the peak bitrate to be set. + Assumption is that peak bit rate set is > configured bitrate. + BIT_RATE_MODE: Bit rate mode such as Constant + - Bit Rate (CBR), Variable Bit Rate (VBR) etc., + a) 0: Default(CBR) + b) 1: VBR} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_enc_frame_size_control_t param_id_enc_frame_size_control_t; + +/** Id of the parameter used to remove initial silence in gapless use cases. */ +#define PARAM_ID_REMOVE_INITIAL_SILENCE 0x0800114B + +/** @h2xmlp_parameter {"PARAM_ID_REMOVE_INITIAL_SILENCE", + PARAM_ID_REMOVE_INITIAL_SILENCE} + @h2xmlp_description { This parameter is sent to decoders during gapless use cases to remove initial zeros introduced by the + decoder. This parameter must be sent before the first data buffer is received by the decoder. Otherwise, + no initial zeros will be removed. If this parameter is sent multiple times before the first data buffer + is received by the decoder, only most recent value is considered. } + @h2xmlp_toolPolicy { Calibration } */ + +#include "spf_begin_pack.h" +struct param_id_remove_initial_silence_t +{ + uint32_t samples_per_ch_to_remove; + /**< @h2xmle_description { The number of samples per channel to remove. } + @h2xmle_default { 0 } + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy { Basic } */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_remove_initial_silence_t param_id_remove_initial_silence_t; + +/** Id of the parameter used to remove initial silence in gapless use cases. */ +#define PARAM_ID_REMOVE_TRAILING_SILENCE 0x0800115D + +/** @h2xmlp_parameter {"PARAM_ID_REMOVE_TRAILING_SILENCE", + PARAM_ID_REMOVE_TRAILING_SILENCE} + @h2xmlp_description { This parameter is sent to decoders during gapless use cases to remove trailing zeros introduced by the + decoder. This parameter must be sent before the last data buffer is received by the decoder. Otherwise, + no trailing zeros will be removed. If this parameter is sent multiple times before the last data buffer + is received by the decoder, only most recent value is considered. It is expected that the amount of + trailing silence is smaller than one frame. If the amount of trailing zeros is larger than one frame, + the entire last frame will be dropped, but the rest of the trailing zeros will remain. } + @h2xmlp_toolPolicy { Calibration } */ + +#include "spf_begin_pack.h" +struct param_id_remove_trailing_silence_t +{ + uint32_t samples_per_ch_to_remove; + /**< @h2xmle_description { The number of samples per channel to remove. } + @h2xmle_default { 0 } + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy { Basic } */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_remove_trailing_silence_t param_id_remove_trailing_silence_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + + +#endif /* COMMON_ENC_DEC_API_H */ diff --git a/spf/api/modules/congestion_buf_api.h b/spf/api/modules/congestion_buf_api.h new file mode 100644 index 0000000..ad5f600 --- /dev/null +++ b/spf/api/modules/congestion_buf_api.h @@ -0,0 +1,140 @@ +#ifndef __CONGESTION_BUF_H +#define __CONGESTION_BUF_H +/** + * \file congestion_buf_api.h + * \brief + * This file contains module published by Congestion Buf CAPI intialization. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/** + @h2xml_title1 {Congestion Audio Buffer Module} + @h2xml_title_agile_rev {Congestion Audio Buffer Module} + @h2xml_title_date {July 17, 2024} +*/ + +// Max number of ports supported by Congestion Buf module. +#define CAPI_CONGESTION_BUF_MAX_INPUT_PORTS (1) +#define CAPI_CONGESTION_BUF_MAX_OUTPUT_PORTS (1) + +/*============================================================================== + Constants +==============================================================================*/ + +/* Parameter description */ +#define PARAM_ID_CONGESTION_BUF_CONFIG 0x080014E2 +#define PARAM_ID_CONGESTION_BUF_SIZE_CONFIG 0x080014E5 + +/*============================================================================== + Type Definitions +==============================================================================*/ + +typedef struct param_id_congestion_buf_config_t param_id_congestion_buf_config_t; +/** @h2xmlp_parameter {"PARAM_ID_CONGESTION_BUF_CONFIG", + PARAM_ID_CONGESTION_BUF_CONFIG} + @h2xmlp_description { This param ID is used to configure Congestion Buffer module. } + @h2xmlp_toolPolicy {NO_SUPPORT} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_congestion_buf_config_t +{ + uint32_t bit_rate_mode; + /**< @h2xmle_description { Defines the bit rate mode of module } + @h2xmle_rangeList {"UNSET" = 0; "AVG" = 1; "MAX" = 2} */ + + uint32_t bit_rate; + /**< @h2xmle_description { Defines the bit rate of decoder. A value of '0' indicates unknown\unset bitrate} + @h2xmle_default { 0 } */ + + uint32_t congestion_buffer_duration_ms; + /**< @h2xmle_description { Defines the congestion buffer size (not latency) in milli seconds} + @h2xmle_default { 0 } + @h2xmle_range {0..300} */ + + uint32_t delay_buffer_duration_ms; + /**< @h2xmle_description { Reserved, set to 0 } + @h2xmle_default { 0 } */ + + uint32_t frame_size_mode; + /**< @h2xmle_description { Defines the mode of frame size which can be duration or samples } + @h2xmle_rangeList {"UNSET" = 0; "DURATION IN US" = 1; "SAMPLES" = 2} */ + + uint32_t frame_size_value; + /**< @h2xmle_description { Decoder frame size in us or samples - 0 : unset\variable} + @h2xmle_default { 0 } */ + + uint32_t sampling_rate; + /**< @h2xmle_description { Decoder sampling rate, used to derive frame duration when frame size mode is samples } */ + + uint32_t mtu_size; + /**< @h2xmle_description { Maximum Transfer Unit in bytes } + @h2xmle_default { 1024 } + @h2xmle_range {0..1200} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_congestion_buf_size_config_t param_id_congestion_buf_size_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_CONGESTION_BUF_SIZE_CONFIG", + PARAM_ID_CONGESTION_BUF_SIZE_CONFIG} + @h2xmlp_description { This param ID is used to configure Congestion Buffer size from QACT for debug purpose. } + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_congestion_buf_size_config_t +{ + uint32_t congestion_buffer_duration_ms; + /**< @h2xmle_description { Defines the congestion buffer size (not latency) in milli seconds} + @h2xmle_default { 0 } + @h2xmle_range {0..300} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** Module ID of the Congestion Buf Module. */ +#define MODULE_ID_CONGESTION_AUDIO_BUFFER 0x07010004 + +/** + @h2xmlm_module {"MODULE_ID_CONGESTION_AUDIO_BUFFER", MODULE_ID_CONGESTION_AUDIO_BUFFER} + @h2xmlm_displayName {"Congestion Audio Buffer"} + + @h2xmlm_description { This module is used to buffer compressed audio data for usecases such as BT Sink.\n + + \n This module supports the following parameter IDs:\n + - PARAM_ID_CONGESTION_BUF_CONFIG \n + - PARAM_ID_CONGESTION_BUF_SIZE_CONFIG\n + + \n Supported Input Media Format:\n +* - Data Format : RAW_COMPRESSED\n +* - fmt_id : Don't care\n } + + @h2xmlm_dataMaxInputPorts { 1 } + @h2xmlm_dataMaxOutputPorts { 1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { 1024 } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_congestion_buf_config_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_congestion_buf_size_config_t} + @h2xmlm_InsertParameter + @} <-- End of the Module --> */ + +#endif /*__CONGESTION_BUF_H*/ diff --git a/spf/api/modules/contexts_api.h b/spf/api/modules/contexts_api.h new file mode 100644 index 0000000..21a1c1e --- /dev/null +++ b/spf/api/modules/contexts_api.h @@ -0,0 +1,42 @@ +#ifndef _CONTEXTS_API_H_ +#define _CONTEXTS_API_H_ + +/*============================================================================== + @file contexts_api.h + @brief This file contains Public Context IDs that can be used by clients to configure the ACD module + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +/** Environment*/ +#define MODULE_CMN_CONTEXT_ID_ENV_HOME 0x08001324 +#define MODULE_CMN_CONTEXT_ID_ENV_OFFICE 0x08001325 +#define MODULE_CMN_CONTEXT_ID_ENV_RESTAURANT 0x08001326 +#define MODULE_CMN_CONTEXT_ID_ENV_INDOOR 0x08001327 +#define MODULE_CMN_CONTEXT_ID_ENV_INSTREET 0x08001328 +#define MODULE_CMN_CONTEXT_ID_ENV_OUTDOOR 0x08001329 +#define MODULE_CMN_CONTEXT_ID_ENV_INCAR 0x0800132A +#define MODULE_CMN_CONTEXT_ID_ENV_INTRAIN 0x0800132B +#define MODULE_CMN_CONTEXT_ID_ENV_UNKNOWN 0x0800132C + + +/** Event*/ +#define MODULE_CMN_CONTEXT_ID_EVENT_ALARM 0x0800132D +#define MODULE_CMN_CONTEXT_ID_EVENT_BABYCRYING 0x0800132E +#define MODULE_CMN_CONTEXT_ID_EVENT_DOGBARKING 0x0800132F +#define MODULE_CMN_CONTEXT_ID_EVENT_DOORBELL 0x08001330 +#define MODULE_CMN_CONTEXT_ID_EVENT_DOOROPENCLOSE 0x08001331 +#define MODULE_CMN_CONTEXT_ID_EVENT_CRASH 0x08001332 +#define MODULE_CMN_CONTEXT_ID_EVENT_GLASSBREAKING 0x08001333 +#define MODULE_CMN_CONTEXT_ID_EVENT_SIREN 0x08001334 + +/** Ambience*/ +#define MODULE_CMN_CONTEXT_ID_AMBIENCE_SPEECH 0x08001335 +#define MODULE_CMN_CONTEXT_ID_AMBIENCE_MUSIC 0x08001336 +#define MODULE_CMN_CONTEXT_ID_AMBIENCE_NOISY_SPL 0x08001337 +#define MODULE_CMN_CONTEXT_ID_AMBIENCE_SILENT_SPL 0x08001338 +#define MODULE_CMN_CONTEXT_ID_AMBIENCE_NOISY_SFLUX 0x08001339 +#define MODULE_CMN_CONTEXT_ID_AMBIENCE_SILENT_SFLUX 0x0800133A + +#endif //_CONTEXTS_API_H_ \ No newline at end of file diff --git a/spf/api/modules/cop_packetizer_cmn_api.h b/spf/api/modules/cop_packetizer_cmn_api.h new file mode 100644 index 0000000..ee0691a --- /dev/null +++ b/spf/api/modules/cop_packetizer_cmn_api.h @@ -0,0 +1,87 @@ +#ifndef COP_PACKETIZER_CMN_API_H +#define COP_PACKETIZER_CMN_API_H + +/*============================================================================== + @file cop_packetizer_cmn_api.h + @brief This file contains cop pack cmn module APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +// clang-format on + + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "module_cmn_api.h" + +/*============================================================================== + Constants +==============================================================================*/ +/* ID of the Output Media Format parameters used by MODULE_ID_PACKETIZER V0 and V1 */ +#define PARAM_ID_COP_PACKETIZER_OUTPUT_MEDIA_FORMAT 0x0800114F + +/** @h2xmlp_parameter {"PARAM_ID_COP_PACKETIZER_OUTPUT_MEDIA_FORMAT", PARAM_ID_COP_PACKETIZER_OUTPUT_MEDIA_FORMAT} + @h2xmlp_description {Structure for the output media format parameter used by the Packetizer module. + It is a mandatory param for pack module to work } + @h2xmlp_toolPolicy {Calibration; RTC} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_COP_PACKETIZER_OUTPUT_MEDIA_FORMAT parameter in the + Media Format Converter Module. Following this will be the variable payload for channel_map. */ +struct param_id_cop_pack_output_media_fmt_t +{ + uint32_t sampling_rate; + /**< @h2xmle_description {Sampling rate} + @h2xmle_rangeList {"8 kHz"=8000; + "11.025 kHz"=11025; + "12 kHz"=12000; + "16 kHz"=16000; + "22.05 kHz"=22050; + "24 kHz"=24000; + "32 kHz"=32000; + "44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000; + "352.8 kHz"=352800; + "384 kHz"=384000} + @h2xmle_default {48000} */ + + uint16_t bits_per_sample; + /**< @h2xmle_description {Bits per sample of audio samples \n + ->Samples with bit width of 16 (Q15 format) are stored in 16 bit words} + @h2xmle_rangeList {"16-bit"= 16} + @h2xmle_default {16} + */ + + uint16_t num_channels; + /**< @h2xmle_description {Number of channels. \n + ->Ranges from 1 to 2 channels} + @h2xmle_range {1..2} + @h2xmle_default {1} + */ + + uint16_t channel_type[0]; + /**< @h2xmle_description {Channel mapping array. \n + ->Specify a channel mapping for each output channel \n + ->If the number of channels is not a multiple of four, zero padding must be added + to the channel type array to align the packet to a multiple of 32 bits} + @h2xmle_variableArraySize {num_channels} + @h2xmle_rangeEnum {pcm_channel_map} + @h2xmle_default {1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Structure type def for above payload. */ +typedef struct param_id_cop_pack_output_media_fmt_t param_id_cop_pack_output_media_fmt_t; + + +#endif //COP_PACKETIZER_CMN_API_H diff --git a/spf/api/modules/cop_packetizer_v0_api.h b/spf/api/modules/cop_packetizer_v0_api.h new file mode 100644 index 0000000..f42a561 --- /dev/null +++ b/spf/api/modules/cop_packetizer_v0_api.h @@ -0,0 +1,111 @@ +#ifndef COP_PACKETIZER_V0_API_H +#define COP_PACKETIZER_V0_API_H + +/*============================================================================== + @file cop_packetizer_v0_api.h + @brief This file contains cop pack v0 module APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +// clang-format on + +/** @h2xml_title1 {CoP Packetizer V0} + @h2xml_title_agile_rev {COP Packetizer V0} + @h2xml_title_date {June 30, 2019} */ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "cop_packetizer_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/*============================================================================== + Constants +==============================================================================*/ +/* CoP Packetizer module stack size*/ +#define COP_PACK_V0_STACK_SIZE 6144 + +/* Input port ID of CoP Packetizer module */ +#define PORT_ID_COP_PACK_V0_INPUT 0x2 + +/* Output port ID of CoP Packetizer module */ +#define PORT_ID_COP_PACK_V0_OUTPUT 0x1 + +/* Static input control port ID's of CoP Packetizer module */ +/* Receives drift from cop depack on this port*/ +#define COP_PACKETIZER_FEEDBACK_IN AR_NON_GUID(0xC0000001) + + + /*============================================================================== + Param ID + ==============================================================================*/ + +/* Param ID of the Scrambling parameter used by MODULE_ID_PACKETIZER V0 */ + #define PARAM_ID_COP_PACKETIZER_ENABLE_SCRAMBLING 0x0800134D + + +/** @h2xmlp_parameter {"PARAM_ID_COP_PACKETIZER_ENABLE_SCRAMBLING", PARAM_ID_COP_PACKETIZER_ENABLE_SCRAMBLING} + @h2xmlp_description {Structure for the enable scrambling parameter used by the Packetizer module. } + @h2xmlp_toolPolicy {Calibration; RTC} */ + + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/* Payload of the PARAM_ID_COP_PACKETIZER_ENABLE_SCRAMBLING parameter in the +packetizer Module. Following this will be the variable payload for scrambler . */ + + struct param_id_cop_pack_enable_scrambling_t + { + uint32_t enable_scrambler; + /**< @h2xmle_description {flag for enabling scrambler. \n + ->1 = enable scrambler , 0 = disable scrambler} + @h2xmle_range {0,1} + @h2xmle_default {0} + */ + } +#include "spf_end_pragma.h" +#include "spf_end_pack.h" + ; +typedef struct param_id_cop_pack_enable_scrambling_t param_id_cop_pack_enable_scrambling_t; + + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** Module ID for CoP Packetizer module */ +#define MODULE_ID_COP_PACKETIZER_V0 0x0700106D +/** @h2xmlm_module {"MODULE_ID_COP_PACKETIZER_V0", + MODULE_ID_COP_PACKETIZER_V0} + @h2xmlm_displayName {"CoP V0 Packetizer"} + @h2xmlm_description {- CoP V0 Packetizer\n + - This module packetizes raw bitstream into Compressed Over PCM packetized bitstream\n + - This module should be in the same subgraph as the encoder\n + - This module has only one input and one output port\n + - Supports following mandatory param: \n + - PARAM_ID_COP_PACKETIZER_OUTPUT_MEDIA_FORMAT + - Supported Input Media Format: \n + - Data Format : CAPI_RAW_COMPRESSED + - fmt_id : Don't care \n} + @h2xmlm_dataInputPorts {IN = PORT_ID_COP_PACK_V0_INPUT} + @h2xmlm_dataOutputPorts {OUT = PORT_ID_COP_PACK_V0_OUTPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlStaticPort {"COP_PACKETIZER_FEEDBACK_IN" = 0xC0000001, + "HWEP BT drift info" = INTENT_ID_TIMER_DRIFT_INFO} + + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { COP_PACK_V0_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_cop_pack_output_media_fmt_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_cop_pack_enable_scrambling_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module -->*/ + +#endif //COP_PACKETIZER_V0_API_H diff --git a/spf/api/modules/cop_v2_depacketizer_api.h b/spf/api/modules/cop_v2_depacketizer_api.h new file mode 100644 index 0000000..480a577 --- /dev/null +++ b/spf/api/modules/cop_v2_depacketizer_api.h @@ -0,0 +1,99 @@ +#ifndef COP_V2_DEPACKETIZER_API_H +#define COP_V2_DEPACKETIZER_API_H + +/*============================================================================== + @file cop_v2_depacketizer_api.h + @brief This file contains cop depack module v2 APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +// clang-format on + +/** @h2xml_title1 {COP V2 Depacketizer } + @h2xml_title_agile_rev {COP V2 Depacketizer } + @h2xml_title_date {Oct 23, 2020} */ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" +#include "imcl_spm_intent_api.h" +#include "cop_v2_packetizer_api.h" +/*============================================================================== + Constants +==============================================================================*/ +/* CoP Depacketizer module stack size*/ +#define COP_V2_DEPACK_STACK_SIZE 6144 + +/* Input port ID of CoP Depacketizer module */ +#define PORT_ID_COP_V2_DEPACK_INPUT 0x2 + +/* Output port ID of CoP Depacketizer module */ +#define PORT_ID_COP_V2_DEPACK_OUTPUT 0x1 //TODO: multiple stream ids + +/* Max number of intent per control port of CoP Depacketizer module */ +#define COP_V2_DEPACK_MAX_INTENTS_PER_CTRL_PORT 1 + +/* Static output control port ID's of CoP Depacketizer module */ +#define REFCLK_REMOTE_TIMING_OUT_FOR_RAT_RENDER AR_NON_GUID(0xC0000001) //rx +#define REFCLK_REMOTE_TIMING_OUT_FOR_RAT_CAPTURE AR_NON_GUID(0xC0000002) //tx +#define COP_ENCODER_FEEDBACK_OUT AR_NON_GUID(0xC0000003) +#define COP_PACKETIZER_FEEDBACK_OUT AR_NON_GUID(0xC0000004) +#define DEADLINE_TIME_OUT AR_NON_GUID(0xC0000005) + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/** @h2xml_title1 {CoP V2 Depacketizer Module API} */ + +/** + * Module ID for CoP V2 Depacketizer. + */ +#define MODULE_ID_COP_V2_DEPACKETIZER 0x070010C1 +/** + @h2xmlm_module {"MODULE_ID_COP_V2_DEPACKETIZER", + MODULE_ID_COP_V2_DEPACKETIZER} + @h2xmlm_displayName {"CoP V2 Depacketizer "} + @h2xmlm_description { - CoP V2 Depacketizer\n + - This module has only one input and one output port + - Supports following params: mandatory param: \n + - PARAM_ID_COP_V2_STREAM_INFO + - Supported Input Media Format: \n + - Data Format : CAPI_COMPR_OVER_PCM_PACKETIZED + - fmt_id : Don't care \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1, 2 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 24 (bits per sample 24 and Q27) \n + - : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q27, Q31 \n + - Interleaving : Interleaved } + @h2xmlm_dataInputPorts {IN = PORT_ID_COP_V2_DEPACK_INPUT} + @h2xmlm_dataOutputPorts {OUT = PORT_ID_COP_V2_DEPACK_OUTPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlStaticPort {"REFCLK_REMOTE_TIMING_OUT_FOR_RAT_RENDER" = 0xC0000001, + "HWEP BT drift info" = INTENT_ID_TIMER_DRIFT_INFO} + @h2xmlm_ctrlStaticPort {"REFCLK_REMOTE_TIMING_OUT_FOR_RAT_CAPTURE" = 0xC0000002, + "HWEP BT drift info" = INTENT_ID_TIMER_DRIFT_INFO} + @h2xmlm_ctrlStaticPort {"COP_ENCODER_FEEDBACK_OUT" = 0xC0000003, + "BT encoder feedback" = INTENT_ID_BT_ENCODER_FEEDBACK} + @h2xmlm_ctrlStaticPort {"COP_PACKETIZER_FEEDBACK_OUT" = 0xC0000004, + "BT Packetizer feedback" = INTENT_ID_V2_PACKETIZER_FEEDBACK} + @h2xmlm_ctrlStaticPort {"DEADLINE_TIME_OUT" = 0xC0000005, + "BT Deadline Time" = INTENT_ID_BT_DEADLINE_TIME} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { COP_V2_DEPACK_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_cop_v2_stream_info_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + +#endif // COP_V2_DEPACKETIZER_API_H diff --git a/spf/api/modules/cop_v2_packetizer_api.h b/spf/api/modules/cop_v2_packetizer_api.h new file mode 100644 index 0000000..a2e73b8 --- /dev/null +++ b/spf/api/modules/cop_v2_packetizer_api.h @@ -0,0 +1,138 @@ +#ifndef COP_V2_PACKETIZER_API_H +#define COP_V2_PACKETIZER_API_H + +/*============================================================================== + @file cop_v2_packetizer_api.h + @brief This file contains cop pack v2 module APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +// clang-format on + +/**@h2xml_title1 {COP Packetizer V2} + @h2xml_title_agile_rev {COP Packetizer V2} + @h2xml_title_date {June 30 2020} */ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "cop_packetizer_cmn_api.h" +#include "imcl_spm_intent_api.h" + +/*============================================================================== + Constants +==============================================================================*/ +/* CoP Packetizer module stack size*/ +#define COP_V2_PACK_STACK_SIZE 6144 + +/* Input port ID of CoP Packetizer module */ +#define PORT_ID_COP_V2_PACK_INPUT 0x2 + +/* Output port ID of CoP Packetizer module */ +#define PORT_ID_COP_V2_PACK_OUTPUT 0x1 + +/* Max number of intent per control port of CoP Packetizer module */ +#define COP_PACK_MAX_INTENTS_PER_CTRL_PORT 1 + +/* Static input control port ID's of CoP Packetizer module */ +#define COP_PACKETIZER_FEEDBACK_IN AR_NON_GUID(0xC0000001) + +/* Direction of Stream Information for CoP Packetizer module */ +#define COP_V2_FROM_AIR 1 +#define COP_V2_TO_AIR 0 + +/*============================================================================== + Param ID +==============================================================================*/ + +/** Parameter ID of CoP V2 Stream Info */ +#define PARAM_ID_COP_V2_STREAM_INFO 0x08001255 + +/** @h2xmlp_parameter {"PARAM_ID_COP_V2_STREAM_INFO", PARAM_ID_COP_V2_STREAM_INFO} + @h2xmlp_description {Structure for the param_id_cop_v2_stream_info_t parameter used by the COP v2 modules. + It is a mandatory param for pack v2 module to work } + @h2xmle_policy {Basic} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct cop_v2_stream_info_map_t +{ + uint32_t stream_id; + uint32_t direction; + uint32_t channel_mask_lsw; + uint32_t channel_mask_msw; +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_cop_v2_stream_info_t +{ + uint32_t num_streams; + /** + @h2xmle_description {Number of Packetizer Output Streams} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0} + @h2xmle_policy {Basic} + */ + +#if defined (__H2XML__) + cop_v2_stream_info_map_t stream_map[0]; + /**< @h2xmle_description {Channel mapping from Stream ID to Bluetooth Channel ID. \n + ->Specify a mapping for each output stream} + @h2xmle_variableArraySize {num_streams} + @h2xmle_default {0} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_cop_v2_stream_info_t param_id_cop_v2_stream_info_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/** @h2xml_title1 {CoP V2 Packetizer Module API} */ + +/** + * Module ID for CoP V2 Packetizer + */ + +#define MODULE_ID_COP_V2_PACKETIZER 0x070010B0 +/** + @h2xmlm_module {"MODULE_ID_COP_V2_PACKETIZER", + MODULE_ID_COP_V2_PACKETIZER} + @h2xmlm_displayName {"CoP V2 Packetizer"} + @h2xmlm_description {- CoP V2 Packetizer\n + - This module packetizes deinterleaved raw bitstream into Compressed Over PCM packetized bitstream\n + - This module should be in the same subgraph as the encoder\n + - Supports following params: mandatory param: \n + - PARAM_ID_COP_PACKETIZER_OUTPUT_MEDIA_FORMAT + - PARAM_ID_COP_V2_STREAM_INFO + - Supported Input Media Format: \n + - Data Format : CAPI_DEINTERLEAVED_RAW_COMPRESSED, RAW_COMPRESSED + - fmt_id : Don't care \n} + @h2xmlm_dataInputPorts {IN = PORT_ID_COP_V2_PACK_INPUT} + @h2xmlm_dataOutputPorts {OUT = PORT_ID_COP_V2_PACK_OUTPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlStaticPort {"COP_PACKETIZER_FEEDBACK_IN" = 0xC0000001, + "BT Packetizer feedback intent" = INTENT_ID_V2_PACKETIZER_FEEDBACK} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {COP_V2_PACK_STACK_SIZE} + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_cop_pack_output_media_fmt_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_cop_v2_stream_info_t} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ +#endif // COP_V2_PACKETIZER_API_H diff --git a/spf/api/modules/cps_data_router.h b/spf/api/modules/cps_data_router.h new file mode 100644 index 0000000..949a3f2 --- /dev/null +++ b/spf/api/modules/cps_data_router.h @@ -0,0 +1,111 @@ +#ifndef __SP_CPS_DATA_ROUTER_H__ +#define __SP_CPS_DATA_ROUTER_H__ + +/*============================================================================== + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + + @file cps_data_router.h + @brief This file contains APIs for Speaker Protection Module +==============================================================================*/ + +/** @h2xml_title1 {Speaker Protection v5 CPS Data Router} + @h2xml_title_date {January 30, 2022} */ +#include "module_cmn_api.h" +#include "ar_defs.h" +#include "imcl_spm_intent_api.h" +#include "rtm_logging_api.h" + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ +#define CPS_STACK_SIZE 1024 +#define CPS_NUM_MAX_SPKRS 8 +#define CPS_MAX_INPUT_PORTS 1 +#define CPS_MAX_OUTPUT_PORTS 0 + +/* Unique Module ID */ +#define MODULE_ID_CPS_DATA_ROUTER_V7 0x07001180 + +/** @h2xmlm_module {"MODULE_ID_CPS_DATA_ROUTER", + MODULE_ID_CPS_DATA_ROUTER} + @h2xmlm_displayName {"CPS DATA ROUTER"} + @h2xmlm_toolPolicy {Calibration;CALIBRATION} + @h2xmlm_description {ID of the CPS Data Router module.\n + + This module supports the following parameter IDs:\n + - #PARAM_ID_MODULE_ENABLE \n + + All parameter IDs are device independent.\n + + Supported Input Media Format:\n +* - Data Format : FIXED_POINT\n +* - fmt_id : Don't care\n +* - Sample Rates : 24000\n +* - Number of channels : 1, 2, 3, 4\n +* - Channel type : 1 to 63\n +* - Bits per sample : 32 \n +* - Q format : 27 \n +* - Interleaving : de-interleaved unpacked\n +* - Signed/unsigned : Signed } + + @h2xmlm_toolPolicy {Calibration} + + @h2xmlm_dataMaxInputPorts {CPS_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {CPS_MAX_OUTPUT_PORTS} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {CPS_STACK_SIZE} + @h2xmlm_ctrlDynamicPortIntent { "Intent ID for communicating CPS related data to SP module" = INTENT_ID_CPS, maxPorts= +1 } + @h2xmlm_ToolPolicy {Calibration} + + @{ <-- Start of the Module --> + + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + */ +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_CPS_CHANNEL_MAP 0x08001B5F //todo: Mention explicitly in CCB as well that this is for channel ordering and not for left, right or center etc channels +/* Unique Param ID for spv5 */ +#define PARAM_ID_CPS_CHANNEL_MAP_V5 0x080013CB + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_cps_ch_map_t param_id_cps_ch_map_t; + +/** @h2xmlp_parameter {"PARAM_ID_CPS_CHANNEL_MAP", + PARAM_ID_CPS_CHANNEL_MAP} + @h2xmlp_description {parameter used to configure the channel map for CPS processing.} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_cps_ch_map_t +{ + uint32_t num_ch; // PCM signal sampling rate + /**< @h2xmle_description {Number of channels} + @h2xmle_rangeList {"mono"=1;"stereo"=2; "three" = 3; "quad"= 4} + @h2xmle_default {2} */ + + uint32_t ch_info[CPS_NUM_MAX_SPKRS]; + /**< @h2xmle_description {channel mapping for cps data} + @h2xmle_defaultList {1, 2, 3, 4} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/** @} <-- End of the Module --> */ + +#endif /* __SP_CPS_DATA_ROUTER_H__ */ diff --git a/spf/api/modules/data_logging_api.h b/spf/api/modules/data_logging_api.h new file mode 100644 index 0000000..4cf84eb --- /dev/null +++ b/spf/api/modules/data_logging_api.h @@ -0,0 +1,161 @@ +/** + * \file data_logging_api.h + * \brief + * This file contains Public APIs for Data logging Module + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _DATA_LOGGING_API_H_ +#define _DATA_LOGGING_API_H_ + + /*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "module_cmn_api.h" +#include "apm_container_api.h" + +#define DATA_LOGGING_MAX_INPUT_PORTS 0x1 + +#define DATA_LOGGING_MAX_OUTPUT_PORTS 0x1 + +#define DATA_LOGGING_STACK_SIZE_REQUIREMENT 2048 + +/** + @h2xmlx_xmlNumberFormat {int} +*/ + +/*============================================================================== + Param ID +==============================================================================*/ + +/* ID of the parameter used to set configuration for Data logging module. */ +#define PARAM_ID_DATA_LOGGING_CONFIG 0x08001031 + +/*============================================================================== + Param structure defintions +==============================================================================*/ + +/** @h2xmlp_parameter {"PARAM_ID_DATA_LOGGING_CONFIG", PARAM_ID_DATA_LOGGING_CONFIG} + @h2xmlp_description {Configures the data logging module.\n} + @h2xmlp_toolPolicy {Calibration; RTC} */ + +#include "spf_begin_pack.h" +struct data_logging_config_t +{ + uint32_t log_code; + /**< logging code for this module instance + + @values 0 to 0x19B1 */ + /**< @h2xmle_description {logging code} + @h2xmle_default {0} + @h2xmle_range { 0..6577} + @h2xmle_policy {Basic} */ + + uint32_t log_tap_point_id; + /**< logging tap point of this module instance + + @values 0 to 0x10FC5 */ + /**< @h2xmle_description {logging tap point} + @h2xmle_default {0} + @h2xmle_range { 0..69573} + @h2xmle_policy {Basic} */ + + uint32_t mode; + /**< Mode to indicate whether to log immediately (1) or wait until + * log buffer is completely filled (0) + + @values 0, 1 */ + /**< @h2xmle_description {Buffering mode} + @h2xmle_default {0} + @h2xmle_range { 0..1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +/* Structure type def for above payload. */ +typedef struct data_logging_config_t data_logging_config_t; + +/* ID of the parameter used to configure Island logging for Data logging module. */ +#define PARAM_ID_DATA_LOGGING_ISLAND_CFG 0x08001313 + +/** @h2xmlp_parameter {"PARAM_ID_DATA_LOGGING_ISLAND_CFG", PARAM_ID_DATA_LOGGING_ISLAND_CFG} + @h2xmlp_description {Force logging for a logging module in an Island Container. Enabling this causes island exit\n} + @h2xmlp_toolPolicy {Calibration; RTC} */ + +#include "spf_begin_pack.h" +struct data_logging_island_t +{ + uint32_t forced_logging; + /**< @h2xmle_description {Specifies whether the data logging module needs to log in island by exiting island.} + @h2xmle_rangeList {"disallowed"=0; + "allowed"=1} + @h2xmle_default {0} + @h2xmle_range { 0..1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +/* Structure type def for above payload. */ +typedef struct data_logging_island_t data_logging_island_t; + +/* + * ID of the Logging module + * + * Supported Input Media Format: + * - Data Format : any + * - fmt_id : Don't care + * - Sample Rates : 1-384 kHz + * - Number of channels : 1-32 + * - Bit Width : 16 (bits per sample 16 and Q15), + * : 24 (bits per sample 24 and Q23, bits per sample 32 and Q23 or Q27 or Q31), + * : 32 (bits per sample 32 and Q31) + * - Interleaving : interleaved, deinterleaved unpacked, deinterleaved packed. + * - Endianess : little, big + * + */ +#define MODULE_ID_DATA_LOGGING 0x0700101A + +/** @h2xml_title1 {Module Data Logging} + @h2xml_title_agile_rev {Module Data Logging} + @h2xml_title_date {March 29, 2019} + */ + +/** + @h2xmlm_module {"MODULE_ID_DATA_LOGGING", MODULE_ID_DATA_LOGGING} + @h2xmlm_displayName {"Data Logging"} + @h2xmlm_description { + This module is used to log PCM data and bit stream data + This module has only one input and one output port. + This module is an in place module. + This module supports the following parameter IDs, \n + - PARAM_ID_DATA_LOGGING_CONFIG\n + - PARAM_ID_DATA_LOGGING_ISLAND_CFG\n + } + + @h2xmlm_dataMaxInputPorts {DATA_LOGGING_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN = 2} + @h2xmlm_dataMaxOutputPorts {DATA_LOGGING_MAX_OUTPUT_PORTS} + @h2xmlm_dataOutputPorts {OUT = 1} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_SC,APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize { DATA_LOGGING_STACK_SIZE_REQUIREMENT } + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"data_logging_config_t"} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_module_enable_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_module_enable_t::enable} + @h2xmle_default {1} + + @h2xml_Select {"data_logging_island_t"} + @h2xmlm_InsertParameter + + @} <-- End of the Module --> +*/ + +#endif /* _DATA_LOGGING_API_H_ */ diff --git a/spf/api/modules/data_marker_api.h b/spf/api/modules/data_marker_api.h new file mode 100644 index 0000000..34ed840 --- /dev/null +++ b/spf/api/modules/data_marker_api.h @@ -0,0 +1,129 @@ +#ifndef DATA_MARKER_API_H +#define DATA_MARKER_API_H + +/** + * \file data_marker_api.h + * + * \brief data_marker_api.h: This file contains the Module Id, Param IDs and configuration structures exposed by the + * DATA_MARKER Module. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" +#include "metadata_api.h" + +/** + @h2xml_title1 {Data Marker API} + @h2xml_title_agile_rev {Data Marker API} + @h2xml_title_date {June 18, 2019} + */ + +/*============================================================================== + Constants +==============================================================================*/ + +#define CAPI_DATA_MARKER_STACK_SIZE 2048 + +#define CAPI_DATA_MARKER_MAX_PORTS 1 + +/** ID of the DATA_MARKER module, which is used to insert and intercept metadata. + + @gpr_hdr_fields + Opcode -- MODULE_ID_DATA_MARKER + */ +#define MODULE_ID_DATA_MARKER 0x0700106A +/** + @h2xmlm_module {"MODULE_ID_DATA_MARKER", + MODULE_ID_DATA_MARKER} + @h2xmlm_displayName {"DATA MARKER"} + @h2xmlm_description {ID of the DATA MARKER module. This module is used to insert metadata + at one point and intercept at another point in a graph. \n + + * Supported Input Media Format: \n + * - Data Format : FIXED_POINT \n + * - fmt_id : Don't care \n + * - Sample Rates : Any (>0) \n + * - Number of channels : 1 to 32 \n + * - Channel type : 1 to 63 \n + * - Bits per sample : 16, 24, 32 \n + * - Q format : 15, 27, 31 \n + * - Interleaving : Any \n + * - Signed/unsigned : Any \n + *} + @h2xmlm_dataMaxInputPorts {CAPI_DATA_MARKER_MAX_PORTS} + @h2xmlm_dataMaxOutputPorts {CAPI_DATA_MARKER_MAX_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_stackSize {CAPI_DATA_MARKER_STACK_SIZE} + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> +*/ + +/** + ID of the MD Insert parameter, used by the Data Marker Module + */ + +#define PARAM_ID_DATA_MARKER_INSERT_MD 0x08001155 +/** @h2xmlp_parameter {"PARAM_ID_DATA_MARKER_INSERT_MD", PARAM_ID_DATA_MARKER_INSERT_MD} + @h2xmlp_description {Structure for PARAM_ID_DATA_MARKER_INSERT_MD parameter. + This tells the module to create a metadatum of said ID and insert to the propagated list. + It also provides a token to uniquely identify the inserted MD.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +/** Payload of the PARAM_ID_DATA_MARKER_INSERT_MD parameter. + */ +struct param_id_data_marker_insert_md_t +{ + uint32_t metadata_id; + /**< @h2xmle_description {Specifies the metadata_id to create and propagate.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF}*/ + + uint32_t token; + /**< @h2xmle_description {Token to uniquely track the inserted md} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF}*/ +} +#include "spf_end_pack.h" +; +/* Structure for PARAM_ID_DATA_MARKER_INSERT_MD parameter. */ +typedef struct param_id_data_marker_insert_md_t param_id_data_marker_insert_md_t; + +/* Unique Parameter id */ +#define EVENT_ID_DELAY_MARKER_INFO 0x08001156 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_DELAY_MARKER_INFO", + EVENT_ID_DELAY_MARKER_INFO} + @h2xmlp_description { Event raised by the module to convey the path delay.} + @h2xmlp_toolPolicy { Calibration}*/ + +#include "spf_begin_pack.h" +struct event_id_delay_marker_info_t +{ + uint32_t delay; + /**< @h2xmle_description {Delay as seen by the module that raises the event (us)} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF}*/ + + uint32_t token; + /**< @h2xmle_description {Token provided by the Delay marker insertion module} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF}*/ +} +#include "spf_end_pack.h" +; + +/* Structure for EVENT_ID_DELAY_MARKER_INFO parameter. */ +typedef struct event_id_delay_marker_info_t event_id_delay_marker_info_t; + +/** @} <-- End of the Module -->*/ + +#endif /* DATA_MARKER_API_H */ diff --git a/spf/api/modules/detection_cmn_api.h b/spf/api/modules/detection_cmn_api.h new file mode 100644 index 0000000..b3c3dda --- /dev/null +++ b/spf/api/modules/detection_cmn_api.h @@ -0,0 +1,738 @@ +#ifndef _DETECTION_CMN_API_H_ +#define _DETECTION_CMN_API_H_ +/** + * \file detection_cmn_api.h + * \brief + * This file contains common parameters for listen libraries + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" + +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ + +#define DETECTION_ENGINE_MAX_REGISTERED_MODELS 20 + +/*Detection Statuses*/ + +/** Status (Detected) sent to notify that the detection engine has + detected a keyword. + */ +#define DETECTION_STATUS_SUCCESS 0 + +/** Status (Rejected) sent to notify the that a detection module has + rejected a keyword. +.*/ +#define DETECTION_STATUS_FAILURE 1 + +/* Maximum Number of Models that are + * supported for this Module + */ +#define MAX_MODELS_SUPPORTED 8 +/* Maximum Number of keyword per model that are + * supported for this Module + */ +#define MAX_KEYWORDS_SUPPORTED 8 + +/* Unique Paramter id */ +#define PARAM_ID_DETECTION_ENGINE_CONFIG 0x08001049 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ + +/** @h2xmlp_parameter {"PARAM_ID_DETECTION_ENGINE_CONFIG", + PARAM_ID_DETECTION_ENGINE_CONFIG} + @h2xmlp_description {Configures the Detection Engine module.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct param_id_detection_engine_config_t +{ + uint16_t mode; + /**< @h2xmle_description {Flags that configure the Detection Engine module to + run in different modes.} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {detectionMode} + @h2xmle_description {Keyword/Pattern Detection mode.} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {verificationMode} + @h2xmle_description {User Verification mode.} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000004} + @h2xmle_bitName {eventMode} + @h2xmle_description {Detection events are sent to the HLOS.} + @h2xmle_rangeList {Success=0;Always=1} + @h2xmle_bitFieldEnd + + @h2xmle_default {1} */ + + uint16_t custom_payload_size; + /**< @h2xmle_description {Size of of additional custom configuration sent to + the Detection Engine module. \n + \n + If custom_payload_size is not 4-byte aligned, the + caller must fill padding bytes to ensure that the + entire calibration is 4-byte aligned. \n + \n + Immediately following this variable is the custom + configuration payload of size custom_payload_size.} + @h2xmle_range {0..0xFFFF} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_detection_engine_config_t param_id_detection_engine_config_t; + +/* Unique Paramter id */ +#define PARAM_ID_DETECTION_GAIN 0x0800104B + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ + +/** @h2xmlp_parameter {"PARAM_ID_DETECTION_GAIN", + PARAM_ID_DETECTION_GAIN} + @h2xmlp_description {Sets the gain that is applied to incoming audio data.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_detection_gain_t +{ + int16_t gain; + /**< @h2xmle_description {Gain that is applied to the data.} + @h2xmle_default {0x100} + @h2xmle_dataFormat {Q8} + @h2xmle_policy {Basic}*/ + + uint16_t reserved; + /**< @h2xmle_description {Used for alignment; must be set to 0.} + @h2xmle_readonly {true} + @h2xmle_default {0} + @h2xmle_policy {Basic}*/ +} +#include "spf_end_pack.h" +; +typedef struct param_id_detection_gain_t param_id_detection_gain_t; + +/* Unique Parameter id */ +#define PARAM_ID_DETECTION_ENGINE_SOUND_MODEL 0x0800104C +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_emptyParameter {"PARAM_ID_DETECTION_ENGINE_SOUND_MODEL", + PARAM_ID_DETECTION_ENGINE_SOUND_MODEL} + @h2xmlp_description {Registers a sound model with a module. \n + \n + -The sound model is a blob of data interpreted by the module that + supports this parameter. The model contains unique sound + characteristics and signatures that are used by the algorithm hosted + in the module. \n + \n + -This paramter must be registered by using the + APM_CMD_REGISTER_CFG with the sound model in a persistent + payload only. \n + \n + -All calibration parameters start from a 4-byte aligned address. + This parameter for this module has an additional 8-byte alignment + requirement because it performs vector processing directly on the + data.} + @h2xmlp_persistType { Shared } + @h2xmlp_toolPolicy {Calibration} */ + +/* Unique Parameter id */ +#define PARAM_ID_DETECTION_ENGINE_REGISTER_MULTI_SOUND_MODEL 0x0800124E +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_Parameter {"PARAM_ID_DETECTION_ENGINE_REGISTER_MULTI_SOUND_MODEL", + PARAM_ID_DETECTION_ENGINE_REGISTER_MULTI_SOUND_MODEL} + @h2xmlp_description {Registers a sound model of a specific model id with a module. \n + \n + -The sound model is a blob of data interpreted by the module that + supports this parameter. The model contains unique sound + characteristics and signatures that are used by the algorithm hosted + in the module. \n + \n + -This paramter must be registered by using the + APM_CMD_REGISTER_CFG with the sound model in a persistent + payload and using APM_CMD_SET_CFG in a non-persistent payload \n + \n + -All calibration parameters start from a 4-byte aligned address. + This parameter for this module has an additional 256-byte alignment + requirement if MLA is enabled and 8 byte alignment if MLA is disabled.} + @h2xmlp_toolPolicy {Calibration} */ + +/* Structure definition for Parameter */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_detection_engine_register_multi_sound_model_t +{ + uint32_t model_id; + /**< @h2xmle_description {This is an unique number to differentiate + between different sound models to be loaded on DSP} + @h2xmle_range {0..0xFFFFFFFE} + @h2xmle_default {0x0}*/ + + uint32_t model_size; + /**< @h2xmle_description {Indicated the size of the sound model. + Sound model payload follows this variable} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0x0}*/ + + uint8_t model[0]; + /**< @h2xmle_description {Sound Model Data Blob which is interpreted by the Library + This Sound Model blob must be 256 bytes aligned if MLA is used + This Sound Model blob must be 8byte aligned if MLA is not used.} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct param_id_detection_engine_register_multi_sound_model_t param_id_detection_engine_register_multi_sound_model_t; + +/* Unique Parameter id */ +#define PARAM_ID_DETECTION_ENGINE_DEREGISTER_MULTI_SOUND_MODEL 0x08001250 +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_Parameter {"PARAM_ID_DETECTION_ENGINE_DEREGISTER_MULTI_SOUND_MODEL", + PARAM_ID_DETECTION_ENGINE_DEREGISTER_MULTI_SOUND_MODEL} + @h2xmlp_description {Deregisters a sound model of a specific model id with a module. \n + \n + -This paramter must be used to deregister a sound model \n} + @h2xmlp_persistType { Shared } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/* Structure definition for Parameter */ + +#include "spf_begin_pack.h" +struct param_id_detection_engine_deregister_multi_sound_model_t +{ + uint32_t model_id; + /**< @h2xmle_description {This is an unique number to differentiate + between different sound models to be unloaded from DSP} + @h2xmle_range {0..0xFFFFFFFE} + @h2xmle_default {0x0}*/ +} +#include "spf_end_pack.h" +; +typedef struct param_id_detection_engine_deregister_multi_sound_model_t param_id_detection_engine_deregister_multi_sound_model_t; + + +/* Unique Parameter id */ +#define PARAM_ID_BEST_CH_ENABLE 0x08001065 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ + +/** @h2xmlp_parameter {"PARAM_ID_BEST_CH_ENABLE", PARAM_ID_BEST_CH_ENABLE} + @h2xmlp_description {Enables the reporting of best channel to DAM Module.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct param_id_best_ch_enable_t +{ + uint32_t enable; + /**< @h2xmle_description {Enables or disables best ch reporting.} + @h2xmle_rangeList {Disabled=0; Enabled=1} + @h2xmle_default {0} + @h2xmle_policy {Basic}*/ +} +#include "spf_end_pack.h" +; +typedef struct param_id_best_ch_enable_t param_id_best_ch_enable_t; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Parameter id */ +#define PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG 0x0800104E + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +/** @h2xmlp_parameter {"PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG", + PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG} + @h2xmlp_description { Configures the payload of the detection events. } + @h2xmlp_toolPolicy {Calibration}*/ +#include "spf_begin_pack.h" +struct param_id_detection_engine_generic_event_cfg_t +{ + uint32_t event_mode; + /**< @h2xmle_description {Bit field used to indicate which type of information + is to be embedded in the event. Set this field only + if the event_type variable is set to 1.} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {confidence_level_information} + @h2xmle_description {Includes confidence level information in detection + events.} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {keyword_indices_information} + @h2xmle_description {Includes keyword index information in detection + events from the detection engine.} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000004} + @h2xmle_bitName {detection_timestamp} + @h2xmle_description {Includes detection timestamp info in the detection event payload.} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000008} + @h2xmle_bitName {ftrt_data_information} + @h2xmle_description {Includes ftrt data length information in the detection + event payload.} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000010} + @h2xmle_bitName {best_channel_index_information} + @h2xmle_description {Includes best channel index information in detection events + from the Engine} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000020} + @h2xmle_bitName {voice_ui_multi_model_result_info_t} + @h2xmle_description {Includes result information in detection events + from the SVA5 Engine} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_bitFieldEnd + + @h2xmle_default {1}*/ +} +#include "spf_end_pack.h" +; +typedef struct param_id_detection_engine_generic_event_cfg_t param_id_detection_engine_generic_event_cfg_t; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Parameter id */ +#define EVENT_ID_DETECTION_ENGINE_GENERIC_INFO 0x0800104F + +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_DETECTION_ENGINE_GENERIC_INFO", + EVENT_ID_DETECTION_ENGINE_GENERIC_INFO} + @h2xmlp_description { Detection event raised by the Detection Engine module.} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +#include "spf_begin_pack.h" +struct event_id_detection_engine_generic_info_t +{ + uint16_t status; + /**< Status sent by the Detection Engine module to the client. + + @values + - #DETECTION_STATUS_SUCCESS + - #DETECTION_STATUS_FAILURE @tablebulletend */ + + uint16_t payload_size; + /**< Actual size of the parameter data payload that follows this structure. + + @values > 0 bytes */ +} +#include "spf_end_pack.h" +; +typedef struct event_id_detection_engine_generic_info_t event_id_detection_engine_generic_info_t; + +/** IDs for keyword index information and confidence value information in + the detection engine generic event payload. + structure which contains key_id and actual payload size of each key. + */ +typedef enum detection_engine_event_key_id_info_t +{ + KEY_ID_CONFIDENCE_LEVELS_INFO = 0x2000, /**< Confidence levels detected per sound model. */ + KEY_ID_KWD_POSITION_INFO, /**< Keyword start and end timestamps. */ + KEY_ID_TIMESTAMP_INFO, /**< Detetion timestamp info */ + KEY_ID_FTRT_DATA_INFO, /**< FTRT Data length in the circular buffer. */ + KEY_ID_BEST_CH_IDX_INFO, /**< Best Ch Idx detected by the algorithm */ + KEY_ID_VOICE_UI_MULTI_MODEL_RESULT_INFO, /**< Multi Model Detection Engine result info */ + KEY_ID_MAX_VALUE = 0x7FFFFFFF /**< Maxium supported value for KEY_ID. */ +}detection_engine_event_key_id_info_t; + +/* subStruct */ +#include "spf_begin_pack.h" +/** @weakgroup weak_detection_event_info_header_t +@{ */ +/* detection event header info structure */ +struct detection_event_info_header_t +{ + detection_engine_event_key_id_info_t key_id; + /**< Different key_ids + @values + - #KEY_ID_CONFIDENCE_LEVELS_INFO + - #KEY_ID_KWD_POSITION_INFO + - #KEY_ID_TIMESTAMP_INFO + - #KEY_ID_FTRT_DATA_INFO + - #KEY_ID_BEST_CH_IDX_INFO + - #KEY_ID_VOICE_UI_MULTI_MODEL_RESULT_INFO @tablebulletend */ + + uint32_t payload_size; + /**< Size of a specific key payload. + + @values 0..0xFFFFFFFF (Default is 0) */ +} +#include "spf_end_pack.h" +; +typedef struct detection_event_info_header_t detection_event_info_header_t; + +/* Payload associated with the KEY_ID_CONFIDENCE_LEVELS_INFO type*/ +/** @h2xmlp_subStruct */ + +/** @h2xmlp_description {Information about confidence levels. Used when + confidence level information is expected in a generic + detection engine event. To get the information, the + mode field in PARAM_ID_DETECTION_ENGINE_EVENT_MODE + must be set accordingly.} */ +struct confidence_level_info_t +{ + uint32_t number_of_confidence_values; + /**< @h2xmle_description {Sum of all keyword models plus the active user + models.} + @h2xmle_range {1..20} + @h2xmle_default {1} */ + + uint8_t confidence_levels[DETECTION_ENGINE_MAX_REGISTERED_MODELS]; + /**< @h2xmle_description {Array of confidence levels for each keyword and + active user pair. \n + \n + This array is of size DETECTION_ENGINE_MAX_REGISTERED_MODELS. + Each element is 1 byte long. \n + \n + Assuming N keywords and M active user models are + included in the model, the first N elements of + this parameter correspond to the confidence of N + keywords. The N+1 to N+M elements control the + confidence level of the M active user model. Each + element maps confidence values for entries (keyword + or user specific keyword) whose order is specified + in the sound model.} */ +}; +typedef struct confidence_level_info_t confidence_level_info_t; + +/* Payload associated with the KEY_ID_POSITION_INFO type */ + +/** @h2xmlp_subStruct + @h2xmlp_toolPolicy {NO_SUPPORT} */ +/**<@h2xmlp_description {Statistics for keyword positions. Used when keyword + index information is expected in a generic detection + engine event. To get the information, the mode field in + PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG must be set + accordingly} */ +struct keyword_position_info_t +{ + uint32_t kw_start_timestamp_lsw; + /**< @h2xmle_description {Lower 32 bits of the 64-bit Keyword start time stamp. (in us).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t kw_start_timestamp_msw; + /**< @h2xmle_description {Upper 32 bits of the 64-bit Keyword start time stamp. (in us).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t kw_end_timestamp_lsw; + /**< @h2xmle_description {Lower 32 bits of the 64-bit Keyword end time stamp. (in us).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t kw_end_timestamp_msw; + /**< @h2xmle_description {Upper 32 bits of the 64-bit Keyword end time stamp. (in us).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ +}; +typedef struct keyword_position_info_t keyword_position_info_t; +/* Payload associated with the KEY_ID_TIMESTAMP_INFO type*/ + +/** @h2xmlp_subStruct + @h2xmlp_toolPolicy {NO_SUPPORT}*/ +/**<@h2xmlp_description { Payload contains timestamp of the detection event. Used when keyword + index information is expected in a generic detection + engine event. To get the information, the mode field in + PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG must be set + accordingly} */ +struct detection_timestamp_info_t +{ + uint32_t detection_timestamp_lsw; + /**< @h2xmle_description {Lower 32 bits of the 64-bit detection timestamp. (in milliseconds).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t detection_timestamp_msw; + /**< @h2xmle_description {Upper 32 bits of the 64-bit detection timestamp (in milliseconds).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ +}; +typedef struct detection_timestamp_info_t detection_timestamp_info_t; + +/* Payload associated with the KEY_ID_FTRT_DATA_INFO type*/ + +/** @h2xmlp_subStruct + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/**<@h2xmlp_description {Information about the key ID ftrt data length. Used + when ftrt data information is expected in a generic + detection engine event. To get the information, the + mode field in PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG + must be set accordingly.} */ +struct ftrt_data_info_t +{ + uint32_t ftrt_data_length_in_us; + /**< @h2xmle_description {Amount of data (in micro seconds) buffered in Dam module, to read data + in FTRT mode.} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ +}; +typedef struct ftrt_data_info_t ftrt_data_info_t; + +/* Payload associated with the KEY_ID_BEST_CH_IDX_INFO type*/ + +/** @h2xmlp_subStruct + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/**<@h2xmlp_description {Information about the key ID best channel index. Used + when this best ch information is expected in a generic + detection engine event. To get the information, the + mode field in PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG + must be set accordingly.} */ +struct best_ch_idx_info_t +{ + uint32_t best_ch_idx; + /**< @h2xmle_description {Best Channel Index} + @h2xmle_range {0..15} + @h2xmle_default {0} */ +}; +typedef struct best_ch_idx_info_t best_ch_idx_info_t; + +/* Payload associated with the KEY_ID_VOICE_UI_MULTI_MODEL_RESULT_INFO type*/ + +/** @h2xmlp_subStruct + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/**<@h2xmlp_description {Information about the key ID Stage1 SVA5 Result info. Used + when this SVA5 result information is expected in a generic + detection engine event. To get the information, the + mode field in PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG + must be set accordingly.} */ +struct voice_ui_multi_model_result_info_t +{ + uint32_t num_detected_models; + /**< @h2xmle_description {Indicates number of models that got detected. + If 3 models are registered with STAGE1_SVA5 and + detected happened for 2 models, + then this value will be set to 2 + Following this will be num_detected_models + number of model_stats_t type payloads + each containing the result statistics + for each detected model} + @h2xmle_range {1..MAX_MODELS_SUPPORTED} + @h2xmle_default {0}*/ +}; +typedef struct voice_ui_multi_model_result_info_t voice_ui_multi_model_result_info_t; + +struct model_stats_t +{ + uint32_t detected_model_id; + /**< @h2xmle_description {Model ID of the model which got detected} + @h2xmle_range {0..0xFFFFFFFE} + @h2xmle_default {0} */ + + uint32_t detected_keyword_id; + /**< @h2xmle_description {Keyword ID of the keyword which got detected} + @h2xmle_range {0..MAX_KEYWORDS_SUPPORTED} + @h2xmle_default {0} */ + + uint32_t best_channel_idx; + /**< @h2xmle_description {Best channel index} + @h2xmle_range {0..15} + @h2xmle_default {0} */ + + uint32_t best_confidence_level; + /**< @h2xmle_description {Best Confidence Level for the detected model} + @h2xmle_range {0..100} + @h2xmle_default {0} */ + + uint32_t kw_start_timestamp_lsw; + /**< @h2xmle_description {Lower 32 bits of the 64-bit Keyword start time stamp. (in us).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t kw_start_timestamp_msw; + /**< @h2xmle_description {Upper 32 bits of the 64-bit Keyword start time stamp. (in us).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t kw_end_timestamp_lsw; + /**< @h2xmle_description {Lower 32 bits of the 64-bit Keyword end time stamp. (in us).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t kw_end_timestamp_msw; + /**< @h2xmle_description {Upper 32 bits of the 64-bit Keyword end time stamp. (in us).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t detection_timestamp_lsw; + /**< @h2xmle_description {Lower 32 bits of the 64-bit detection timestamp. (in milliseconds).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ + + uint32_t detection_timestamp_msw; + /**< @h2xmle_description {Upper 32 bits of the 64-bit detection timestamp (in milliseconds).} + @h2xmle_range {0..4294967295} + @h2xmle_default {0} */ +}; +typedef struct model_stats_t model_stats_t; +/** @} */ /* end_weakgroup weak_detection_event_info_header_t */ +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Parameter id */ +#define PARAM_ID_DETECTION_ENGINE_RESET 0x08001051 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/**@h2xmlp_emptyParameter {"PARAM_ID_DETECTION_ENGINE_RESET", + PARAM_ID_DETECTION_ENGINE_RESET} + @h2xmlp_description {Resets the Detection Engine module to its initial + algorithm stage and begins a new detection.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/*============================================================================== + Constants +==============================================================================*/ +/* Unique Parameter id */ +#define PARAM_ID_DETECTION_ENGINE_BUFFERING_CONFIG 0x08001044 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ + +/** @h2xmlp_parameter {"PARAM_ID_DETECTION_ENGINE_BUFFERING_CONFIG", + PARAM_ID_DETECTION_ENGINE_BUFFERING_CONFIG} + @h2xmlp_description { Set the buffering requirements for the detection module. + Based on this requirements, detection module resizes the Audio + Dam buffers via IMCL.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct param_id_detection_engine_buffering_config_t +{ + uint32_t hist_buffer_duration_msec; + /**< @h2xmle_description {Duration (in milliseconds) of the history buffer + that holds the keyword. The duration is limited by the + memory available in the system.} + @h2xmle_policy {Basic} + @h2xmle_default {0} */ + + uint32_t pre_roll_duration_msec; + /**< @h2xmle_description {Amount of data before a keyword start (in + milliseconds).} + @h2xmle_policy {Basic} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_detection_engine_buffering_config_t param_id_detection_engine_buffering_config_t; + + +#define PARAM_ID_DETECTION_ENGINE_MULTI_MODEL_BUFFERING_CONFIG 0x0800124F + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ + +/** @h2xmlp_parameter {"PARAM_ID_DETECTION_ENGINE_MULTI_MODEL_BUFFERING_CONFIG", + PARAM_ID_DETECTION_ENGINE_MULTI_MODEL_BUFFERING_CONFIG} + @h2xmlp_description { Set the buffering requirements for the PDK module. + Based on this requirements, PDK resizes the Audio + Dam buffers via IMCL.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct param_id_detection_engine_multi_model_buffering_config_t +{ + uint32_t model_id; + /**< @h2xmle_description {Model id of the model for which buffering config is being done + The Model has to be registered before sending this set param} + @h2xmle_policy {Basic} + @h2xmle_range {0..0xFFFFFFFE} + @h2xmle_default {0} */ + uint32_t hist_buffer_duration_msec; + /**< @h2xmle_description {Duration (in milliseconds) of the history buffer + that holds both the data before keyword detection + and the keyword. The duration is limited by the + memory available in the system.} + @h2xmle_policy {Basic} + @h2xmle_default {0} */ + + uint32_t pre_roll_duration_msec; + /**< @h2xmle_description {Amount of data before a keyword start (in + milliseconds).} + @h2xmle_policy {Basic} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_detection_engine_multi_model_buffering_config_t param_id_detection_engine_multi_model_buffering_config_t; + +#define PARAM_ID_DETECTION_ENGINE_PER_MODEL_RESET 0x080014ED +/** @h2xmlp_parameter {"PARAM_ID_DETECTION_ENGINE_PER_MODEL_RESET", PARAM_ID_DETECTION_ENGINE_PER_MODEL_RESET} + @h2xmlp_description { Resets the Detection Engine model to its initial algorithm stage and begins a new detection\n} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_detection_engine_per_model_reset_t +{ + uint32_t model_id; + /**< @h2xmle_description {This is an unique number to differentiate between different sound models to perform reset} + @h2xmle_default {0x0} + @h2xmle_range {0..0xFFFFFFFE} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_detection_engine_per_model_reset_t param_id_detection_engine_per_model_reset_t; + +#endif /* _DETECTION_CMN_API_H_ */ diff --git a/spf/api/modules/display_port_api.h b/spf/api/modules/display_port_api.h new file mode 100644 index 0000000..8c99304 --- /dev/null +++ b/spf/api/modules/display_port_api.h @@ -0,0 +1,171 @@ +#ifndef _DISPLAY_PORT_API_H_ +#define _DISPLAY_PORT_API_H_ +/** + * \file display_port_api.h + * \brief + * This file contains DISPLAY_PORT module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "hw_intf_cmn_api.h" + +/** @h2xml_title1 {Display Port Module API} + @h2xml_title_agile_rev {Display Port Module API} + @h2xml_title_date {May 28, 2019} */ + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of DISPLAY_PORT module */ +#define PORT_ID_DISPLAY_PORT_INPUT 0x2 + +/* Stack size for DISPLAY_PORT Module*/ +#define DISPLAY_PORT_STACK_SIZE 1024 +/*============================================================================== + Type definition +==============================================================================*/ + +/** Parameter used to configure the DISPLAY_PORT interface */ +#define PARAM_ID_DISPLAY_PORT_INTF_CFG 0x08001154 +/** @h2xmlp_parameter {"PARAM_ID_DISPLAY_PORT_INTF_CFG", + PARAM_ID_DISPLAY_PORT_INTF_CFG} + @h2xmlp_description {Configures the DISPLAY_PORT interface.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +/** Payload for parameter PARAM_ID_DISPLAY_PORT_INTF_CFG */ +struct param_id_display_port_intf_cfg_t +{ + uint32_t channel_allocation; + /**< @h2xmle_description {HDMI channel allocation information for programming an HDMI frame. The default is FL_FR_0_0_0_0_0_0 + (Stereo).This information is defined in the HDMI standard, CEA 861-D. The number of + channels is also inferred from this parameter. 0 in name below indicates blank channel allocation.} + @h2xmle_rangeList {"FL_FR_0_0_0_0_0_0" = 0; + "FL_FR_LFE_0_0_0_0_0" = 1; + "FL_FR_0_FC_0_0_0_0" = 2; + "FL_FR_LFE_FC_0_0_0_0" = 3; + "FL_FR_0_0_RC_0_0_0" = 4; + "FL_FR_LFE_0_RC_0_0_0" = 5; + "FL_FR_0_FC_RC_0_0_0" = 6; + "FL_FR_LFE_FC_RC_0_0_0" = 7; + "FL_FR_0_0_RL_RR_0_0" = 8; + "FL_FR_LFE_0_RL_RR_0_0" = 9; + "FL_FR_0_FC_RL_RR_0_0" = 10; + "FL_FR_LFE_FC_RL_RR_0_0" = 11; + "FL_FR_0_0_RL_RR_RC_0" = 12; + "FL_FR_LFE_0_RL_RR_RC_0" = 13; + "FL_FR_0_FC_RL_RR_RC_0" = 14; + "FL_FR_LFE_FC_RL_RR_RC_0" = 15; + "FL_FR_0_0_RL_RR_RLC_RRC" = 16; + "FL_FR_LFE_0_RL_RR_RLC_RRC" = 17; + "FL_FR_0_FC_RL_RR_RLC_RRC" = 18; + "FL_FR_LFE_FC_RL_RR_RLC_RRC"= 19; + "FL_FR_0_0_0_0_FLC_FRC" = 20; + "FL_FR_LFE_0_0_0_FLC_FRC" = 21; + "FL_FR_0_FC_0_0_FLC_FRC" = 22; + "FL_FR_LFE_FC_0_0_FLC_FRC" = 23; + "FL_FR_0_0_RC_0_FLC_FRC" = 24; + "FL_FR_LFE_0_RC_0_FLC_FRC" = 25; + "FL_FR_0_FC_RC_0_FLC_FRC" = 26; + "FL_FR_LFE_FC_RC_0_FLC_FRC" = 27; + "FL_FR_0_0_RL_RR_FLC_FRC" = 28; + "FL_FR_LFE_0_RL_RR_FLC_FRC" = 29; + "FL_FR_0_FC_RL_RR_FLC_FRC" = 30; + "FL_FR_LFE_FC_RL_RR_FLC_FRC"= 31} + @h2xmle_default {0} + */ + + uint32_t mst_idx; + /**< @h2xmle_description {Valid Multi-Steam Transport index depending upon the hardware capabilities. + Suppported values range from 0 to (Max streams supported - 1).} + @h2xmle_rangeList {"Video Stream 0"=0; + "Video Stream 1"=1} + + @h2xmle_default {0} + */ + + uint32_t dptx_idx; + /**< @h2xmle_description {Valid DPTX instance index depending upon the hardware capabilities. + Suppported values range from 0 to (Max DPTX controllers supported - 1).} + @h2xmle_rangeList {"DP Controller Instance 0"=0; + "DP Controller Instance 1"=1} + @h2xmle_default {0} + */ +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_display_port_intf_cfg_t param_id_display_port_intf_cfg_t; +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** Module ID for DISPLAY_PORT sink module */ +#define MODULE_ID_DISPLAY_PORT_SINK 0x07001069 +/** @h2xmlm_module {"MODULE_ID_DISPLAY_PORT_SINK", + MODULE_ID_DISPLAY_PORT_SINK} + @h2xmlm_displayName {"Display Port Sink"} + @h2xmlm_description {- Display Port Sink Module\n + - Supports following params: \n + - PARAM_ID_DISPLAY_PORT_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - Supported Input Media Format: \n + - Data Format: FIXED_POINT, IEC61937_PACKETIZED \n + - fmt_id : Don't care \n + - Sample Rates : 8, 16, 22.05, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192 kHz \n + - Number of channels : 2-8 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 24 (bits per sample 24 and Q27) \n + - Q format : Q15, Q27 \n + - Interleaving : DISPLAY_PORT sink module needs de-interleaved unpacked } + @h2xmlm_dataInputPorts {IN = PORT_ID_DISPLAY_PORT_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { DISPLAY_PORT_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_range { 2..8 } + @h2xmle_default {2} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList { "DATA_FORMAT_FIXED_POINT"=1; + "DATA_FORMAT_IEC61937_PACKETIZED"=2} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::sample_rate} + @h2xmle_rangeList {"8 kHz"=8000; + "16 kHz"=16000; + "22.05 kHz"=22050; + "32 kHz"=32000; + "44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000} + @h2xmle_default {48000} + @h2xml_Select {param_id_hw_ep_mf_t::bit_width} + @h2xmle_rangeList { "16-bit"=16; + "24-bit"=24 } + @h2xmle_default {16} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_display_port_intf_cfg_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + +#endif //_DISPLAY_PORT_API_H_ diff --git a/spf/api/modules/dls_api.h b/spf/api/modules/dls_api.h new file mode 100644 index 0000000..364cf4e --- /dev/null +++ b/spf/api/modules/dls_api.h @@ -0,0 +1,279 @@ +#ifndef _DLS_API_H_ +#define _DLS_API_H_ +/** + * \file dls_api.h + * \brief + * This file contains Data Logging Service command/param/event ID's and public + * data structures. + * This file should be used only when the DIAG service is not supported. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*------------------------------------------------------------------------------ + * Include Files + *----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/*------------------------------------------------------------------------------ + * Global Definitions/Declarations + *----------------------------------------------------------------------------*/ +/** @ingroup spf_mods_dls + Identifier for an instance of the Audio Logging Server module. */ + +#define DLS_MODULE_INSTANCE_ID 0x0000000A + +/*# h2xmlm_module {"DLS_MODULE_INSTANCE_ID", + DLS_MODULE_INSTANCE_ID} + h2xmlm_displayName {"Audio Logging Server"} + h2xmlm_description {Identifier for data logging service instance} + h2xmlm_dataMaxInputPorts {0} + h2xmlm_dataMaxOutputPorts {0} + h2xmlm_stackSize {0} + h2xmlm_ToolPolicy {Calibration} + + { <-- Start of the Module --> + } <-- End of the Module --> */ + +/** @ingroup spf_dls_commands + Used to configure the data logging service buffer information. + DLS client will allocate the memory and sends this command to the DLS to + configure the buffer information, like, buffer address, size, etc. + This will be the first command from DLS client to the server. is_cfg field + shall be set to 1, to configure the buffer information in the beginning of + the data logging process. At the end of the process this flag shall be set + to 0, to deconfigure [zeroing out all the fields] the buffer information. + + @msgpayload + dls_param_id_config_buffer_t @newpage +*/ +#define DLS_PARAM_ID_CONFIG_BUFFER 0x08001A83 + +/** @ingroup spf_dls_commands + Payload for #DLS_CMD_CONFIG_BUFFER. + + Consists the 64-bit buffer starting address in buf_start_addr_lsw and + buf_start_addr_msw. Followed by a single buffer size and the total + allocated buffer size for DLS. Finally a configuration flag to config + or deconfig the buffer information in the DLS +*/ +#include "spf_begin_pack.h" +struct dls_param_id_config_buffer_t +{ + uint32_t buf_start_addr_lsw; + /**< Lower 32-bits of the 64-bit buffer starting address. + This field is an input configuration parameter. */ + + uint32_t buf_start_addr_msw; + /**< Upper 32-bits of the 64-bit buffer starting address. + This field is an input configuration parameter. */ + + uint32_t mem_map_handle; + /**< Unique identifier for a shared memory address. + + @values + - NULL -- buffer address is the physical memory address and it doesn't + need mapping. + - Non-NULL -- when buffers starting address needs to be mapped to fetch + the physical address. */ + + uint32_t total_buf_size; + /**< Total allocated buffer size for the data logging service. + This field is an input configuration parameter. */ + + uint32_t max_log_pkt_size; + /**< Maximum one single log packet size. + This field is an input configuration parameter. + -1 - default: maximum single buffer size will be used the internal + from the DLS internal define */ + + uint32_t is_cfg; + /**< This parameter is used to differentiate between the buffer configuration + before starting the data logging and deconfiguration when the data + logging is complete + 1 - Configuration at the beginning to use the given memory space for the + data logging. + 0 - Deconfigiuration, to not use the given memory space for the data + logging */ +} +#include "spf_end_pack.h" +; +typedef struct dls_param_id_config_buffer_t dls_param_id_config_buffer_t; + +/** @ingroup spf_dls_commands + Used to configure the log code to start/stop the data logging. + This command will be issued by the DLS client to enable/disable logging the + data on a specific log code. This log code will be used to prepare the + buffer header when the buffer is committed. + + @msgpayload + dls_param_id_enable_disable_log_code_t @newpage +*/ +#define DLS_PARAM_ID_ENABLE_DISABLE_LOG_CODE 0x08001A84 + +/** @ingroup spf_dls_commands + Payload for #DLS_PARAM_ID_ENABLE_DISABLE_LOG_CODE. + + Consists the 32-bit log_code to start/stop the data logging and a flag to + to enable/disable the log code. +*/ +#include "spf_begin_pack.h" +struct dls_param_id_enable_disable_log_code_t +{ + uint32_t is_enabled; + /**< Flag to indicate the log code is requested to be enabled or disabled. + 1 - Enable log code + 0 - Disable log code + This field is an input configuration parameter. */ + + uint32_t num_log_codes; + /**< Number of log codes to enable/disable. + This field is an input configuration parameter. */ + + uint32_t log_codes[0]; + /**< This is a Flexible Array Member to list the log codes to be + enabled/disabled. + This field is an input configuration parameter. */ +} +#include "spf_end_pack.h" +; +typedef struct dls_param_id_enable_disable_log_code_t dls_param_id_enable_disable_log_code_t; + +/** @ingroup spf_dls_commands + Used to let the client know that a buffer of data is logged and is ready to + be read at client side. + This data event will be raised by the DLS to notify the client. + + @msgpayload + dls_data_event_id_commit_log_buffer_t @newpage +*/ +#define DLS_DATA_EVENT_ID_COMMIT_LOG_BUFFER 0x06001006 + +#include "spf_begin_pack.h" +struct dls_buf_start_addr_t +{ + uint32_t buf_addr_lsw; + /**< This field contains the lower 32-bits of the 64-bit buffer starting + address. */ + + uint32_t buf_addr_msw; + /**< This field contains the upper 32-bits of the 64-bit buffer starting + address. */ + + uint32_t mem_map_handle; + /**< Unique identifier for a shared memory address. + + @values + - NULL -- buffer address is the physical memory address and it doesn't + need mapping. + - Non-NULL -- when buffer starting address is a mapped address. */ +} +#include "spf_end_pack.h" +; +typedef struct dls_buf_start_addr_t dls_buf_start_addr_t; + +/** @ingroup spf_dls_commands + Payload for #DLS_DATA_CMD_BUFFER_RETURN + + Consists the lower 32-bits and upper 32-bits of the logged buffer starting + address. This address will be read by the client to parse the header and to + work with the logged data. +*/ +#include "spf_begin_pack.h" +struct dls_data_event_id_commit_log_buffer_t +{ + uint32_t num_bufs; + /**< Total number of logged buffers that are committed. */ + + dls_buf_start_addr_t buf_start_addr[0]; + /**< This is a flexible array member and it contains the following: + lower 32-bits of the 64-bit buffer starting addresses + upper 32-bits of the 64-bit buffer starting addresses */ +} +#include "spf_end_pack.h" +; +typedef struct dls_data_event_id_commit_log_buffer_t dls_data_event_id_commit_log_buffer_t; + +/** @ingroup spf_dls_commands + Used to return the logged buffer. This data command will be issued by the + client, after reading the logged buffer [after finishing the process of + DLS_DATA_CMD_BUFFER_RETURN data event]. After receiving this command, the + DLS server will clean the buffer and make it available for the next data + logging. + + @msgpayload + dls_data_cmd_buffer_return_t @newpage +*/ +#define DLS_DATA_CMD_BUFFER_RETURN 0x0400100D + +/** @ingroup spf_dls_commands + Payload for #DLS_DATA_CMD_BUFFER_RETURN + + Consists the lower 32-bits and upper 32-bits of the buffer starting address + to clear the buffer and to make it available for next data logging. + It also includes a flag to indicate to clean the entire buffer. +*/ +#include "spf_begin_pack.h" +struct dls_data_cmd_buffer_return_t +{ + uint32_t num_bufs; + /**< Total number of buffers that need to be returned. */ + + dls_buf_start_addr_t buf_start_addr[0]; + /**< This field contains the 64-bit buffer starting addresses */ +} +#include "spf_end_pack.h" +; +typedef struct dls_data_cmd_buffer_return_t dls_data_cmd_buffer_return_t; +/** Used to identify the state of the buffer. When the buffer is first created + implicit state would be DLS_BUF_AVAILABLE. When DLS Server requests for an + available buffer [via posal data logging], the state will be updated to + DLS_BUF_ACQUIRED. When the data written to buffer, the state will be updated + to DLS_BUF_READY. Once the DLS client read the buffer, the buffer shall be + reset using DLS_DATA_CMD_BUFFER_RETURN command and the server will update the + buffer state to DLS_BUF_AVAILABLE. + */ +typedef enum +{ + DLS_BUF_UNAVAILABLE = 0, + DLS_BUF_AVAILABLE, + DLS_BUF_ACQUIRED, + DLS_BUF_READY +} dls_buf_state_t; + +#include "spf_begin_pack.h" +struct dls_buf_hdr_t +{ + uint32_t buf_size; + /**< It indicates the size of the data logged into the buffer. This will be + used at the client side to read buf_size number of bytes from the + buffer */ + + dls_buf_state_t buf_state; + /**< It indicates the current state of a data logging buffer. This will be + used in server to update/know the buffer state. This is useful to find + the available buffer. + The buffer state is not required at the client side but the client + needs to skip this data to read the actual logged buffer. */ + + uint32_t buf_in_use; + /**< It indicates the available buffer space in percentage. This varies + between 0 and 100. This is used at the client end and when the available + buffer size goes below a threshold limit [decided by the client] client + may take decision to reconfigure the buffer information. */ +} +#include "spf_end_pack.h" +; +typedef struct dls_buf_hdr_t dls_buf_hdr_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif // #ifdef _DLS_API_H_ diff --git a/spf/api/modules/dls_log_pkt_hdr_api.h b/spf/api/modules/dls_log_pkt_hdr_api.h new file mode 100644 index 0000000..ee6d997 --- /dev/null +++ b/spf/api/modules/dls_log_pkt_hdr_api.h @@ -0,0 +1,205 @@ +#ifndef _DLS_LOG_PKT_HDR_API_H_ +#define _DLS_LOG_PKT_HDR_API_H_ +/** + * \file dls_log_pkt_hdr_api.h + * \brief + * This file contains data structures for log packet header. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*------------------------------------------------------------------------------ + * Include Files + *----------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/*------------------------------------------------------------------------------ + * Global Definitions/Declarations + *----------------------------------------------------------------------------*/ +#define DLS_PACKED(x) x __attribute__((__packed__)) + +// TODO: Support the list of buffers to commit and return +/* Overall log packet structure + For PCM data, the containers are in following order: + DLS_HEADER + VERSION + DATA_FORMAT_TAG + DLS_CMN_HEADER + DLS_PCM_HEADER + DLS_PCM_BUFFER_DATA + + For bitsream data, + DLS_HEADER + VERSION + DATA_FORMAT_TAG + DLS_CMN_HEADER + DLS_BITSTREAM_HEADER + DLS_BITSTREAM_BUFFER_DATA +*/ + +typedef enum +{ + AUDIOLOG_PCM_DATA_FORMAT = 4, + AUDIOLOG_BS_DATA_FORMAT = 5 +} dls_audiolog_tag_t; + +typedef enum +{ + AUDIOLOG_FIXED_POINT_DATA_FORMAT = 0, + AUDIOLOG_FLOATING_POINT_DATA_FORMAT = 1 +} dls_audiolog_data_format_t; + +/** Audio log PCM data format container. */ +typedef DLS_PACKED(struct) +{ + uint32_t sampling_rate; + /**< PCM sampling rate (8000 Hz, 48000 Hz, etc.). */ + + uint16_t num_channels; + /**< Number of channels in the PCM stream. */ + + uint8_t bits_per_sample; + /**< Bits per sample for the PCM data. */ + + bool_t interleaved : 8; + /**< Specifies whether the data is interleaved. */ + + uint8_t q_factor; + /**< qfactor information. */ + + dls_audiolog_data_format_t data_format : 8; + /**< Data format information for this container. */ + + uint8_t channel_mapping[1]; + /**< Variable Array of channel mappings. @newpagetable */ +} +dls_header_pcm_data_t; + +/** Audio log header for bitstream data. */ +typedef DLS_PACKED(struct) +{ + uint32_t media_fmt_id; + /**< Media format ID for the audio/voice encoder/decoder. */ +} +dls_header_bitstream_data_t; + +/** Common header structure for PCM/bitstream data. */ +typedef DLS_PACKED(struct) +{ + uint32_t log_session_id; + /**< Log session ID. */ + + uint32_t log_tap_id; + /**< GUID for the tap point. */ + + uint32_t log_ts_lsw; + /*!< The lower 32-bits of the timestamp (in microseconds) for the log packet */ + + uint32_t log_ts_msw; + /*!< The upper 32-bits of the timestamp (in microseconds) for the log packet */ + + uint32_t log_seg_number; + /**< Log segment number */ + + uint32_t log_segment_size; + /**< Size in bytes of the payload, excluding the header. */ + + uint32_t log_fragment_offset; + /**< Fragment offset*/ +} +dls_header_cmn_t; + +/*! log_hdr_type ,includes length, code and timestamp */ +typedef DLS_PACKED(struct) +{ + uint16_t len; + /*!< Specifies the length, in bytes of the + entry, including this header. */ + + uint16_t code; + /*!< Specifies the log code for the entry as + enumerated above. Note: This is + specified as word to guarantee size. */ + + uint32_t ts_lsw; + /*!< The lower 32-bits of the system timestamp for the log entry. The + upper 48 bits represent elapsed time since + 6 Jan 1980 00:00:00 in 1.25 ms units. The + low order 16 bits represent elapsed time + since the last 1.25 ms tick in 1/32 chip + units (this 16 bit counter wraps at the + value 49152). */ + uint32_t ts_msw; + /*!< The upper 32-bits of the system timestamp for the log entry */ +} +dls_log_hdr_type; + +/** Complete log packet structure for logging PCM data. */ +typedef DLS_PACKED(struct) +{ + dls_log_hdr_type hdr; + /**< Length of the packet in bytes, including this header, the QXDM Pro log + code, and system timestamp. Each log packet must begin with a + member of type log_hdr_type. */ + + uint16_t version; + /** < Version information of the header. + POSAL_PINE_VERSION_V1 + POSAL_PINE_VERSION_V2 + POSAL_PINE_VERSION_V3 */ + + uint16_t data_format_tag; + /**< Tag information for this container. + AUDIOLOG_BITSTREAM_DATA_FORMAT + AUDIOLOG_PCM_DATA_FORMAT */ + + dls_header_cmn_t log_header_cmn; + /**< Audio log header for common info */ + + dls_header_pcm_data_t log_header_pcm; + /**< Audio log header for PCM data. */ + + uint8_t payload[1]; + /**< Logged packet data. */ +} +dls_log_pkt_pcm_data_t; + +/** Complete log packet structure for logging bitstream data. */ +typedef DLS_PACKED(struct) +{ + dls_log_hdr_type hdr; + /**< Length of the packet in bytes including this header, the QXDM Pro log + code, and system timestamp. Each log packet must begin with a + member of type log_hdr_type. */ + + uint16_t version; + /** < Version information of the header. + POSAL_PINE_VERSION_V1 + POSAL_PINE_VERSION_V2 + POSAL_PINE_VERSION_V3 */ + + uint16_t data_format_tag; + /**< Tag information for this container. + AUDIOLOG_BITSTREAM_DATA_FORMAT + AUDIOLOG_PCM_DATA_FORMAT */ + + dls_header_cmn_t log_header_cmn; + /**< Audio log header for common info */ + + dls_header_bitstream_data_t log_header_bs; + /**< Audio log header for bitstream data. */ + + uint8_t payload[1]; + /**< logged packet data. */ +} +dls_log_pkt_bitstream_data_t; + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif // #ifdef _DLS_LOG_PKT_HDR_API_H_ \ No newline at end of file diff --git a/spf/api/modules/dtmf_detection_api.h b/spf/api/modules/dtmf_detection_api.h new file mode 100644 index 0000000..80f55eb --- /dev/null +++ b/spf/api/modules/dtmf_detection_api.h @@ -0,0 +1,50 @@ +/** + * \file dtmf_detection_api.h + * \brief + * This file contains DTMF Detection Event api + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef DTMF_DETECTION_API_H +#define DTMF_DETECTION_API_H + +#include "ar_defs.h" + +#define EVENT_ID_DTMF_DETECTION 0x0800113B + +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_DTMF_DETECTION", + EVENT_ID_DTMF_DETECTION} + @h2xmlp_description { Detection event raised by the DTMF Detector Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + + +typedef struct dtmf_detect_event_t dtmf_detect_event_t; + +/* Payload returned by DTMF module in response to the EVENT_ID_DTMF_DETECTION + * registered by the client */ +#include "spf_begin_pack.h" +struct dtmf_detect_event_t +{ + uint16_t tone_low_freq; + /**< @h2xmle_description {Low frequency (in Herz) from the below list} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE" = 0,697,770,852,941} + @h2xmle_policy {Basic} */ + + uint16_t tone_high_freq; + /**< @h2xmle_description {High frequency (in Herz) from the below list} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE" = 0,1209,1336,1477,1633} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +#endif // DTMF_DETECTION_API_H diff --git a/spf/api/modules/flac_decoder_api.h b/spf/api/modules/flac_decoder_api.h new file mode 100644 index 0000000..c39459f --- /dev/null +++ b/spf/api/modules/flac_decoder_api.h @@ -0,0 +1,89 @@ +#ifndef _FLAC_DECODER_API_H_ +#define _FLAC_DECODER_API_H_ + +/*============================================================================== + @file flac_decoder_api.h + @brief This file contains FLAC decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + ==============================================================================*/ +// clang-format off + +/*============================================================================== + * Include files + ==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {FLAC Decoder Module API} + @h2xml_title_agile_rev {FLAC Decoder Module API} + @h2xml_title_date {April 15, 2019} */ + + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of FLAC module */ +#define FLAC_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of FLAC module */ +#define FLAC_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of FLAC module */ +#define FLAC_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of FLAC module */ +#define FLAC_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of FLAC module */ +#define FLAC_DEC_MODULE_STACK_SIZE 8192 + + +/*============================================================================== + Module +==============================================================================*/ + +/** + * Module ID for FLAC decoder. + * Decodes data of format-id = MEDIA_FMT_ID_FLAC + */ +#define MODULE_ID_FLAC_DEC 0x0700102F + +/** + @h2xmlm_module {"MODULE_ID_FLAC_DEC", MODULE_ID_FLAC_DEC} + @h2xmlm_displayName {"FLAC Decoder"} + @h2xmlm_description {This module is used as the decoder for FLAC use cases.\n + - This module has only one input and one output port.\n + - Payload for media_format_t: payload_media_fmt_flac_t\n + - Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_FLAC\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + -- PARAM_ID_REMOVE_INITIAL_SILENCE\n + -- PARAM_ID_REMOVE_TRAILING_SILENCE\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_FLAC\n + -- payload : payload_media_fmt_flac_t\n + } + @h2xmlm_dataMaxInputPorts {FLAC_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {FLAC_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=FLAC_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=FLAC_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {FLAC_DEC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> + */ + #endif // _FLAC_DECODER_API_H_ + diff --git a/spf/api/modules/fluence_ffv_common_calibration.h b/spf/api/modules/fluence_ffv_common_calibration.h new file mode 100644 index 0000000..c724158 --- /dev/null +++ b/spf/api/modules/fluence_ffv_common_calibration.h @@ -0,0 +1,618 @@ +#ifndef FLUENCE_FFV_COMMON_CALIBRATION_H +#define FLUENCE_FFV_COMMON_CALIBRATION_H + +/*============================================================================== + @file fluence_ffv_common_calibration.h + @brief This file contains audio rtm logging parameters. + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + +==============================================================================*/ + +#include "ar_defs.h" + +/*============================================================================== + Param ID +==============================================================================*/ + +#define PARAM_ID_FLUENCE_SEC_CMN_ECPP 0x08001086 + +/*============================================================================== + Param structure defintions +==============================================================================*/ + +/** @h2xmlp_parameter {"PARAM_ID_FLUENCE_SEC_CMN_ECPP", PARAM_ID_FLUENCE_SEC_CMN_ECPP} + @h2xmlp_description { SEC Common Post Filtering configuration.} + @h2xmlp_toolPolicy { Calibration, RTC } */ +#include "spf_begin_pack.h" +struct sec_cmn_ecpp_param_t +{ + int16_t ec_vad_thresh_l16q15; + /**< @h2xmle_description {EC_CNI near-end VAD threshold} + @h2xmle_default {0x4000} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x4000"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x4000"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x4000"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x6666"} + + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_thresh2_l16q15; + /**< @h2xmle_description {EC_CNI near-end VAD threshold-II} + @h2xmle_default {0x4000} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x4000"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x4000"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x4000"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x6666"} + + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_pwr_scale_l16q15; + /**< @h2xmle_description {EC_CNI near-end VAD noise power scale factor} + @h2xmle_default {0x0100} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_hangover_max_l16; + /**< @h2xmle_description {EC_CNI near-end VAD hangover duration} + @h2xmle_default {0x1E} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x1E"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x1E"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x1E"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x0F"} + + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_alpha_snr_l16q15; + /**< @h2xmle_description {EC_CNI near-end VAD probability estimation smoothing factor (higher value means more smoothing)} + @h2xmle_default {0x0CCE} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_avar_scale_l16q13; + /**< @h2xmle_description {EC_CNI near-end VAD noise variance scaling factor} + @h2xmle_default {0x2000} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_sub_nc_l16; + /**< @h2xmle_description {EC_CNI near-end VAD noise floor tracking window length} + @h2xmle_default {0x19} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_snr_diff_max_l16q8; + /**< @h2xmle_description {EC_CNI near-end VAD SNR difference max threshold} + @h2xmle_default {0x0C00} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_snr_diff_min_l16q8; + /**< @h2xmle_description {EC_CNI near-end VAD SNR difference min threshold} + @h2xmle_default {0x0A00} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_init_length_l16; + /**< @h2xmle_description {EC_CNI near-end VAD initial frames length for power initialization} + @h2xmle_default {0x64} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_max_val_l16q15; + /**< @h2xmle_description {EC_CNI near-end VAD max bound on noise estimate} + @h2xmle_default {0x0288} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_init_bound_l16q15; + /**< @h2xmle_description {EC_CNI near-end VAD initial bound for noise estimation} + @h2xmle_default {0x64} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_reset_bound_l16q15; + /**< @h2xmle_description {EC_CNI near-end VAD reset bound for noise estimation} + @h2xmle_default {0x0122} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t ec_vad_spow_min_l16q15; + /**< @h2xmle_description {EC_CNI near-end minimum bound for VAD speech power estimate} + @h2xmle_default {0x019A} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_saec_pathchange_factor_l16q15; + /**< @h2xmle_description {Path change factor for extra gain clipping in EC} + @h2xmle_default {0x7FFF} + @h2xmle_range {0x8000..0x7FFF} + + @h2xmle_group {Echo_PCD} + @h2xmle_subgroup {PCD_Aggressiveness} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_num_spectral_bands_l16; + /**< @h2xmle_description {Number of spectral bands for EC PF} + @h2xmle_default {0x20} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x20"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x20"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x20"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x14"} + + @h2xmle_range {8..513} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_lin_log_freq_l16; + /**< @h2xmle_description {Linear-log boundary frequency for Mel scale in EC PF processing} + @h2xmle_default {0x02BC} + @h2xmle_range {0x02BC..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_pc_add_agg_q_l16; + /**< @h2xmle_description {Additional Q-factor for EC PF aggressiveness during path change} + @h2xmle_default {0x03} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x03"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x03"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x03"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x01"} + + @h2xmle_group {Echo_PCD} + @h2xmle_subgroup {PCD_Aggressiveness} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_pf_gain_floor_l16q15[32]; + /**< @h2xmle_description {Minimum EC PF gain for each band} + @h2xmle_default {0x02} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x02"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x02"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x02"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x62"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Aggressiveness} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_pf_nlp_st_agg_l16q15; + /**< @h2xmle_description {EC PF aggressiveness during single talk (far-end alone)} + @h2xmle_default {0x7D00} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x7D00"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x7D00"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x7D00"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x4800"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Aggressiveness} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_pf_nlp_dt_agg_l16q15; + /**< @h2xmle_description {EC PF aggressiveness during double talk} + @h2xmle_default {0x7530} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x7530"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x7530"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x7530"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x4800"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Aggressiveness} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_pf_agg_q_l16; + /**< @h2xmle_description {Q-factor for EC PF aggressiveness} + @h2xmle_default {0x06} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x06"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x06"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x06"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x02"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Aggressiveness} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_pf_nlp_boost_l16q12; + /**< @h2xmle_description {Slope Boost factor for the non-linear EC PF processing} + @h2xmle_default {0x1000} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Aggressiveness} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_rx_ec_factor_l16q13; + /**< @h2xmle_description {Factor for applying Rx energy to estimated echo energy} + @h2xmle_default {0x2000} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x2000"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x2000"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x2000"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x1000"} + + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_pf_energy_t_factor_l16q15[32]; + /**< @h2xmle_description {EC PF energy factor to apply for spectral band 1} + @h2xmle_default {0x0320} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x0320"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x0320"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x0320"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x0333"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Aggressiveness} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_pf_salph_l16q15; + /**< @h2xmle_description {Smoothing factor for the Mic energy input in EC PF (Higher value means less smoothing)} + @h2xmle_default {0x7332} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x7332"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x7332"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x7332"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x7EB8"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Smoothing} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_salph_edown_l16q15; + /**< @h2xmle_description {Smoothing factor for the echo energy input in EC PF (Higher value means less smoothing)} + @h2xmle_default {0x2666} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x2666"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x2666"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x2666"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x6000"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Smoothing} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_galph_l16q15; + /**< @h2xmle_description {Smoothing factor for the EC PF gain (Higher value means less smoothing)} + @h2xmle_default {0x7F1C} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x7F1C"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x7F1C"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x7F1C"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x6666"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Smoothing} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_lin_log_l16q13; + /**< @h2xmle_description {Normalized transition frequency in EC PF} + @h2xmle_default {0x02BC} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x02BC"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x02BC"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x02BC"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x02CC"} + + @h2xmle_range {0x02BC..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_mela_l16q8; + /**< @h2xmle_description {Multiplication factor in EC PF} + @h2xmle_default {0x0A00} + @h2xmle_range {0x0280..0x1400} + @h2xmle_policy {Basic} */ + + + int16_t aec_pf_clip_saec_clip_factor2_l16q15; + /**< @h2xmle_description {EC PF gain clip factor to be applied during initial duration after call start} + @h2xmle_default {0x0147} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x0147"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x0147"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x0147"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x0CCD"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Initial_Aggressiveness} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_clip_sinit_frames_l16; + /**< @h2xmle_description {Initial duration for applying the EC PF gain clip factor} + @h2xmle_default {0xC8} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0xC8"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0xC8"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0xC8"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x64"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Initial_Aggressiveness} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_pf_clip_saec_clip_factor_l16q15; + /**< @h2xmle_description {EC PF gain clip factor to be applied in normal cases} + @h2xmle_default {0x0CCD} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_Clipper} + @h2xmle_policy {Basic} */ + + int16_t aec_cn_norm_const_l16q15; + /**< @h2xmle_description {EC_CNI scaling factor} + @h2xmle_default {0x6000} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x6000"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x6000"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x6000"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x4666"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_CNI} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_cn_norm_const_q_l16; + /**< @h2xmle_description {EC_CNI estimate Q factor} + @h2xmle_default {0x02} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x02"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x02"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x02"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x03"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_CNI} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_cn_salph_l16q15; + /**< @h2xmle_description {Smoothing factor for the EC_CNI noise estimate estimate (Higher value means less smoothing)} + @h2xmle_default {0x3333} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_cn_ms_frames_l16; + /**< @h2xmle_description {EC_CNI noise floor estimation window length} + @h2xmle_default {0xC8} + @h2xmle_range {0x0001..0x03E8} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_CNI} + @h2xmle_policy {Advanced} */ + + int16_t aec_cn_ms_num_blk_l16; + /**< @h2xmle_description {EC_CNI minimum statistics bulk size} + @h2xmle_default {0x0A} + @h2xmle_range {0x0001..0x03E8} + @h2xmle_policy {Basic} */ + + int16_t aec_pf_rx_echo_shift; + /**< @h2xmle_description {Rx energy echo shift factor for EC PP} + @h2xmle_default {0xFFF8} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0xFFFC"} + + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t abf_echo_shift; + /**< @h2xmle_description {Q0 shift factor for scaling echo energy computed from Rx signal} + @h2xmle_default {0xFFF8} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0xFFFC"} + + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aeccfg_abf_echo_shift; + /**< @h2xmle_description {Q0 shift factor for scaling echo energy computed from Rx signal} + @h2xmle_default {0xFFF8} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0xFFF8"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0xFFFC"} + + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aeccfg_farendvadpfcfg_shangovermax; + /**< @h2xmle_description {EC Postprocesing far-end VAD hangover in number of frames} + @h2xmle_default {0x04} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x04"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x04"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x04"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x05"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Far_end_VAD} + @h2xmle_range {0x0000..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_lb_clipflag_al_bitshift; + /**< @h2xmle_description {Q0 shift factor for smoothing Mic1 clipper detection likelihood} + @h2xmle_default {0x01} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_Clipper} + @h2xmle_policy {Advanced} */ + + int16_t aec_hb_clipflag_al_bitshift; + /**< @h2xmle_description {Q0 shift factor for smoothing Mic1 high band clipper detection threshold} + @h2xmle_default {0x01} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_Clipper} + @h2xmle_policy {Advanced} */ + + int16_t aec_clip_flag_lb_frac_l16q15; + /**< @h2xmle_description {Threshold for the low band NLMS output error to mic ratio for applying extra clipping} + @h2xmle_default {0x2710} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x2710"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x2710"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x2710"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x0444"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_Clipper} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_clip_flag_hb_frac_l16q15; + /**< @h2xmle_description {Threshold for the high band NLMS output error to mic ratio for applying extra clipping} + @h2xmle_default {0x2710} + + @h2xmle_defaultDependency { Samplerate = "8000" , default = "0x2710"} + @h2xmle_defaultDependency { Samplerate = "16000" , default = "0x2710"} + @h2xmle_defaultDependency { Samplerate = "32000" , default = "0x2710"} + @h2xmle_defaultDependency { Samplerate = "48000" , default = "0x0444"} + + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_Clipper} + @h2xmle_range {0x8000..0x7FFF} + @h2xmle_policy {Basic} */ + + int16_t aec_f_vad_shangover_max_pf_nb; // fbCfg.aecCfg.farEndVadCfg.sHangoverMaxPF + /**< @h2xmle_description {Far-end VAD for EC post-filtering hangover duration (frames) for low band} + @h2xmle_default {10} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Far_end_VAD} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_f_vad_shangover_max_pf_hb; // fbCfg.aecCfg.farEndVadCfg.sHangoverMaxPF + /**< @h2xmle_description {Far-end VAD for EC post-filtering hangover duration (frames) for high band} + @h2xmle_default {10} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Far_end_VAD} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_glb_flag_fvad_nb_cnt; + /**< @h2xmle_description {minimum number of active subbands to determine far-end activity (0-4kHz)} + @h2xmle_default {5} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Far_end_VAD} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_glb_flag_fvad_hb_cnt; + /**< @h2xmle_description {minimum number of active subbands to determine far-end activity (>4kHz)} + @h2xmle_default {2} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {Far_end_VAD} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_glb_flag_dtd_nb_cnt; + /**< @h2xmle_description {minimum number of active subbands to determine double-talk activity (0-4kHz)} + @h2xmle_default {5} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {DTD} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_glb_flag_dtd_hb_cnt; + /**< @h2xmle_description {minimum number of active subbands to determine double-talk activity (>4kHz)} + @h2xmle_default {5} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {DTD} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_glb_flag_clip_nb_cnt; + /**< @h2xmle_description {minimum number of active subbands to determine clipping (0-4kHz)} + @h2xmle_default {20} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_Clipper} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_glb_flag_clip_hb_cnt; + /**< @h2xmle_description {minimum number of active subbands to determine clipping (>4kHz)} + @h2xmle_default {20} + @h2xmle_group {Post_Filtering} + @h2xmle_subgroup {EC_Clipper} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_glb_flag_pcd_nb_cnt; + /**< @h2xmle_description {minimum number of active subbands to determine path change activity (0-4kHz)} + @h2xmle_default {16} + @h2xmle_group {Echo_PCD} + @h2xmle_subgroup {PCD} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ + + int16_t aec_glb_flag_pcd_hb_cnt; + /**< @h2xmle_description {minimum number of active subbands to determine path change activity (>4kHz)} + @h2xmle_default {16} + @h2xmle_group {Echo_PCD} + @h2xmle_subgroup {PCD} + @h2xmle_range {0..0x7FFF} + @h2xmle_policy {Advanced} */ +} +#include "spf_end_pack.h" +; +/* Type definition for the above structure. */ +typedef struct sec_cmn_ecpp_param_t sec_cmn_ecpp_param_t; + +/** + Param ID to support dynamic enablement/disablement of Audio effects. + This PID will be common for all audio effects and will be shared accross multiple module IDs. + HLOS will use regular set/get param interface to set/get effects to/from DSP. This PID will not be visible in ARCT. + Each module will generally use 0th bit to set effect. If a module supports more than one effect than subsequent LSB bits can be used. + + payload size -- 4 bytes +*/ +#define PARAM_ID_FLUENCE_CMN_GLOBAL_EFFECT 0x080010BB + +/* Structure for setting/Querying Audio module effects. */ + +/** @h2xmlp_parameter {"PARAM_ID_FLUENCE_CMN_GLOBAL_EFFECT", PARAM_ID_FLUENCE_CMN_GLOBAL_EFFECT} + @h2xmlp_description {To dynamically enable/disable Audio effects.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct qcmn_global_effect_param_t +{ + int32_t ecns_effect_mode; + /**< @h2xmle_description {ecns_effect_mode -1:NO EFFECT, 0:EC and NS disabled, 1:EC enabled, 2:NS enabled, 3: EC and NS enabled} + @h2xmle_default {0xFFFFFFFF} + @h2xmle_range {0xFFFFFFFF..0x00000003} + @h2xmle_policy {Advanced}*/ +} +#include "spf_end_pack.h" +; +/* Type definition for the above structure.*/ +typedef struct qcmn_global_effect_param_t qcmn_global_effect_param_t; + +#endif diff --git a/spf/api/modules/gapless_api.h b/spf/api/modules/gapless_api.h new file mode 100644 index 0000000..effff10 --- /dev/null +++ b/spf/api/modules/gapless_api.h @@ -0,0 +1,208 @@ +#ifndef _GAPLESS_API_H_ +#define _GAPLESS_API_H_ +/** + * \file gapless_api.h + * \brief + * This file contains the Gapless module APIs. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "module_cmn_api.h" + +/*# @h2xml_title1 {Gapless Module} + @h2xml_title_agile_rev {Gapless Module} + @h2xml_title_date {August 12, 2019} */ + +/*============================================================================== + Constants +==============================================================================*/ + +/** @ingroup ar_spf_mod_gapless_macros + Maximum number of input ports supported by the Gapless module. */ +#define GAPLESS_MAX_INPUT_PORTS 0x2 + +/** @ingroup ar_spf_mod_gapless_macros + Maximum number of output ports supported by the Gapless module. */ +#define GAPLESS_MAX_OUTPUT_PORTS 0x1 + +/** @ingroup ar_spf_mod_gapless_macros + Size of the stack for the Gapless module. */ +#define GAPLESS_STACK_SIZE 4096 + +/*============================================================================== + Event ID +==============================================================================*/ + +/** @ingroup ar_spf_mod_gapless_mod + GUID for an early end-of-stream event. + + This event is raised immediately when an EOS enters the Gapless module. + + This event can trigger the client to prepare to send the next stream. While + the client is setting up the next stream, the Gapless module drains its + buffered data. The amount of buffered data is equal to the maximum time the + client takes to switch streams. The time is configured as part of + #PARAM_ID_EARLY_EOS_DELAY. + + For the delay buffer (and therefore for gapless switching) to be used for + the stream, this event, along with PARAM_ID_EARLY_EOS_DELAY, must be sent + before the stream is started. + + @msgpayload + event_id_gapless_early_eos_event_t +*/ +#define EVENT_ID_EARLY_EOS 0x08001126 + +/*============================================================================== + Event Type definitions +==============================================================================*/ + +/*# @h2xmlp_parameter {"EVENT_ID_EARLY_EOS", EVENT_ID_EARLY_EOS} + @h2xmlp_description {GUID for an early EOS event. This event is raised + immediately when an EOS enters the Gapless module. + For more details, see the AudioReach Module User + Guide (80-VN500-4).} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_gapless_mod + Payload for #EVENT_ID_EARLY_EOS. + */ +#include "spf_begin_pack.h" +struct event_id_gapless_early_eos_event_t +{ + uint32_t src_module_iid; + /**< Identifier for the #MODULE_ID_WR_SHARED_MEM_EP instance of the stream + that is about to end. */ + + /*#< @h2xmle_description {Instance ID of the MODULE_ID_WR_SHARED_MEM_EP + of the stream that is about to end.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pack.h" +; +typedef struct event_id_gapless_early_eos_event_t event_id_gapless_early_eos_event_t; + + +/*============================================================================== + Param ID +==============================================================================*/ + +/** @ingroup ar_spf_mod_gapless_mod + Identifier for the parameter sent to the Gapless module to configure the + maximum time the client will take to switch streams. + + This parameter determines the size of the Gapless module's delay buffers. + The size does not include delay that is downstream of the early EOS. + + For the delay buffer (and therefore gapless switching) to be used for a + stream, this parameter, along with #EVENT_ID_EARLY_EOS, must be sent before + the stream is started. + + @msgpayload + param_id_gapless_early_eos_delay_t @newpage +*/ +#define PARAM_ID_EARLY_EOS_DELAY 0x0800114C + +/*# @h2xmlp_parameter {"PARAM_ID_EARLY_EOS_DELAY", PARAM_ID_EARLY_EOS_DELAY} + @h2xmlp_description {ID for the parameter sent to the Gapless module to + configure the maximum time the client will take to + switch streams. \n + This parameter determines the size of the Gapless + module's delay buffers. The size does not + include delay that is downstream of the early EOS. + For the delay buffer (and therefore gapless switching) + to be used for a stream, this parameter, along with + EVENT_ID_EARLY_EOS, must be sent before the stream is + started.} + @h2xmlp_toolPolicy {Calibration} */ + + +/*============================================================================== + Param structure definitions +==============================================================================*/ + +/** @ingroup ar_spf_mod_gapless_mod + Payload for #PARAM_ID_EARLY_EOS_DELAY. +*/ +#include "spf_begin_pack.h" +struct param_id_gapless_early_eos_delay_t +{ + uint32_t early_eos_delay_ms; + /**< Duration in milliseconds between the early EOS notification and the EOS + notification rendered from the hardware endpoint. + + Delay that is downstream of the early EOS is not accounted for in this + value. This delay determines the size of the Gapless module's internal + delay buffers. */ + + /*#< @h2xmle_description {Duration in milliseconds between the early EOS + notification and the EOS notification rendered + from the hardware endpoint. \n + Delay that is downstream of the early EOS is not + accounted for in this value. This delay determines + the size of the Gapless module's internal delay + buffers.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_gapless_early_eos_delay_t param_id_gapless_early_eos_delay_t; + +/*============================================================================== + Module +==============================================================================*/ + +/** @ingroup ar_spf_mod_gapless_mod + Identifier for the Gapless module, which allows for gapless switching + between two input streams. The output remains continuous through the stream + switch. + + @subhead4{Supported input media format ID} + - Data format : #DATA_FORMAT_FIXED_POINT @lstsp1 + - fmt_id : #MEDIA_FMT_ID_PCM @lstsp1 + - Sample rates : Any @lstsp1 + - Number of channels: Any @lstsp1 + - Channel type : Don't care @lstsp1 + - Bit width : Any @lstsp1 + - Interleaving : De-interleaved unpacked @lstsp1 + - Endianness : Any + + Input ports can have different input media formats. +*/ +#define MODULE_ID_GAPLESS 0x0700104D + +/*# @h2xmlm_module {"MODULE_ID_GAPLESS", MODULE_ID_GAPLESS} + @h2xmlm_displayName {"Gapless"} + @h2xmlm_description {ID for the module that allows for gapless + switching between two input streams. \n + The output remains continuous through the + stream switch. Input ports are allowed to have + different input media formats. For more + details, see the AudioReach Module User + Guide (80-VN500-4).} + @h2xmlm_dataMaxInputPorts {GAPLESS_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {GAPLESS_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN0 = 2; + IN1 = 4} + @h2xmlm_dataOutputPorts {OUT = 3} + @h2xmlm_toolPolicy {Calibration} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC, APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {GAPLESS_STACK_SIZE} + + @{ <-- Start of the Module --> + @h2xml_Select {param_id_gapless_early_eos_delay_t} + @h2xmlm_InsertParameter + @} <-- End of the Module --> */ + + +#endif /*_GAPLESS_API_H_*/ diff --git a/spf/api/modules/gate_api.h b/spf/api/modules/gate_api.h new file mode 100644 index 0000000..80a8821 --- /dev/null +++ b/spf/api/modules/gate_api.h @@ -0,0 +1,82 @@ +#ifndef GATE_API_H_ +#define GATE_API_H_ +/** + * \file gate_api.h + * \brief + * API file for Gate Module + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of GATE */ +#define GATE_DATA_INPUT_PORT 0x2 + +/* Output port ID of GATE */ +#define GATE_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of GATE */ +#define GATE_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of GATE */ +#define GATE_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of GATE */ +#define GATE_STACK_SIZE 1024 + +/* Control port for receiving deadline time*/ +#define DEADLINE_TIME_INFO_IN AR_NON_GUID(0xC0000001) + +/*============================================================================== + Module +==============================================================================*/ + +/** @h2xml_title1 {GATE API} + @h2xml_title_agile_rev {GATE API} + @h2xml_title_date {July 7, 2019} */ + +/** + * Module ID for Gate Module + */ +#define MODULE_ID_GATE 0x07001042 + +/** + @h2xmlm_module {"Gate", MODULE_ID_GATE} + @h2xmlm_displayName {"Gate"} + @h2xmlm_description {- This module gates data flow based on calculated deadline time\n + - It doesn't modify data in any way. + - Supports following params:\n + -- PARAM_ID_GATE_EP_TRANSMISSION_DELAY\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1 to 32 \n + - Channel type : Don't care \n + - Bit Width : Don't care \n + - Q format : Don't care \n + - Interleaving : Dont care} + + @h2xmlm_dataMaxInputPorts {GATE_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {GATE_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=GATE_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=GATE_DATA_OUTPUT_PORT} + @h2xmlm_ctrlStaticPort {"DEADLINE_TIME_INFO_IN" = 0xC0000001, + "Deadline time intent" = INTENT_ID_BT_DEADLINE_TIME} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_stackSize {GATE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + +#endif //GATE_API_H_ diff --git a/spf/api/modules/history_buffer_api.h b/spf/api/modules/history_buffer_api.h new file mode 100644 index 0000000..857008c --- /dev/null +++ b/spf/api/modules/history_buffer_api.h @@ -0,0 +1,169 @@ +#ifndef __HISTORY_BUFFER_API_H__ +#define __HISTORY_BUFFER_API_H__ + +/** + * \file history_buffer_api.h + * + * \brief + * + * History Buffer API for Voice UI + * + * + * \copyright + *  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + *  SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" +#include "detection_cmn_api.h" +#include "imcl_fwk_intent_api.h" +/** + @h2xml_title1 {Module history buffer API} + @h2xml_title_agile_rev {Module history buffer API} + @h2xml_title_date {May 19, 2025} +*/ + +/*============================================================================== + Constants +==============================================================================*/ + +/* History buffer is a sink module so it has only input port.*/ +#define HISTORY_BUFFER_MAX_INPUT_PORTS 1 + +/* History buffer is a sink module so it doesn't have an output port */ +#define HISTORY_BUFFER_MAX_OUTPUT_PORTS 0 + +/* History buffer has a control port which can be connected to other modules, which + expects the FTRT data info or any other information from History Buffer. + */ +#define HISTORY_BUFFER_MAX_CONTROL_PORTS ( 1 ) + +#define HISTORY_BUFFER_MAX_INTENTS_PER_CTRL_PORT ( 1 ) + +/* Stack size requirement(in bytes) is a static module property. It is the peak stack memory + requirement of the module. This is accounted only for the module, do not have to include + framework requirement.*/ +#define HISTORY_BUFFER_STACK_SIZE_REQUIREMENT 4096 /* Bytes */ + +/*============================================================================== + Param ID +==============================================================================*/ + +/* Parameter to trigger the detection event */ +#define PARAM_ID_HISTORY_BUFFER_DETECTION_TRIGGER 0x08001B7E + +/**@h2xmlp_emptyParameter {"PARAM_ID_HISTORY_BUFFER_DETECTION_TRIGGER", + PARAM_ID_HISTORY_BUFFER_DETECTION_TRIGGER} + @h2xmlp_description {Sets the History buffer parameter to trigger the + new detection event.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/*Parameter to configure the Streaming mode requirement in History Buffer Module*/ +#define PARAM_ID_HISTORY_BUFFER_MODE 0x08001B87 + +/*============================================================================== + Type Definitions +==============================================================================*/ + +#define HISTORY_BUFFER_ON_DEMAND 0 + /* In this mode History buffer sends the data, equal to DAM buffer size to the + * client. If FTRT buffer drains, data flow switches to RT mode.*/ + +#define HISTORY_BUFFER_BATCHING 1 + /* In this mode history buffer sends the data to the client in batches till reset + * i.e. data sent only after batch amount of data is accumulated in the dam.*/ + +typedef struct param_id_history_buffer_mode_t param_id_history_buffer_mode_t; +/** @h2xmlp_parameter {"PARAM_ID_HISTORY_BUFFER_MODE", + PARAM_ID_HISTORY_BUFFER_MODE} + @h2xmlp_description { Parameter to set the out data flow mode. History buffer module + supports two modes for data flow from DAM to the client + On_demand and Batching. } + @h2xmlp_toolPolicy { Calibration} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_history_buffer_mode_t +{ + uint32_t data_flow_mode; + /**< @h2xmle_description {0: HISTORY_BUFFER_ON_DEMAND sends the data, equal to DAM buffer. + 1: HISTORY_BUFFER_BATCHING sends the data to the client in batches.} + @h2xmle_rangeList {"HISTORY_BUFFER_ON_DEMAND"=0, "HISTORY_BUFFER_BATCHING"=1} + @h2xmle_policy {Basic} + @h2xmle_default {0} */ + + uint32_t batch_size_ms; + /**< @h2xmle_description {Size of the batch (in milli secs) for sending the data + to client, applicable only for batching mode and don't care + for on_demand mode.} + @h2xmle_policy {Basic} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*------------------------------------------------------------------------------ + Module ID +------------------------------------------------------------------------------*/ + +/* History Buffer module ID */ +#define MODULE_ID_HISTORY_BUFFER 0x07001182 + +/** + @h2xmlm_module {"MODULE_ID_HISTORY_BUFFER", MODULE_ID_HISTORY_BUFFER} + @h2xmlm_displayName {"HISTORY_BUFFER"} + @h2xmlm_description { History Buffer Module provides the history/past data + from the DAM module to the client on demand. + This module supports the following parameter IDs, \n + - PARAM_ID_DETECTION_ENGINE_GENERIC_EVENT_CFG + - PARAM_ID_DETECTION_ENGINE_RESET + - PARAM_ID_DETECTION_ENGINE_BUFFERING_CONFIG + - PARAM_ID_MODULE_ENABLE + - PARAM_ID_HISTORY_BUFFER_DETECTION_TRIGGER + - PARAM_ID_HISTORY_BUFFER_MODE \n + \n} + + @h2xmlm_dataMaxInputPorts {HISTORY_BUFFER_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {HISTORY_BUFFER_MAX_OUTPUT_PORTS} + @h2xmlm_ctrlDynamicPortIntent { "DAM-HB Control" = INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL, maxPorts= 1 } + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize {HISTORY_BUFFER_STACK_SIZE_REQUIREMENT } + + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> + + @h2xml_Select { param_id_module_enable_t } + @h2xmlp_description { This is a common param, shared by other modules. + It is used to enable/disable the module runtime. + This is an optional param, if the module doesn't + need this param it can be removed. } + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy { Calibration, RTC } + @h2xml_Select {param_id_module_enable_t::enable} + @h2xmle_default {1} + + @h2xml_Select {param_id_detection_engine_generic_event_cfg_t} + @h2xmlm_InsertParameter + @h2xmlp_description { Configures the payload of the detection events. + History Buffer supports only FTRT event.} + + + @h2xml_Select {param_id_detection_engine_buffering_config_t} + @h2xmlm_InsertParameter + @h2xmlp_description { Set the buffering required by History Buffer module. Resizes + the Audio Dam buffers via IMCL. pre_roll_duration_in_ms is + don't care for history buffer module.} + + @h2xml_Select {PARAM_ID_DETECTION_ENGINE_RESET} + @h2xmlm_InsertParameter + + @h2xml_Select {PARAM_ID_HISTORY_BUFFER_DETECTION_TRIGGER} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_history_buffer_mode_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module -->*/ + +#endif // #ifndef __HISTORY_BUFFER_API_H__ diff --git a/spf/api/modules/hw_core_api.h b/spf/api/modules/hw_core_api.h new file mode 100644 index 0000000..bd0461a --- /dev/null +++ b/spf/api/modules/hw_core_api.h @@ -0,0 +1,46 @@ +#ifndef _HW_CORE_API_H_ +#define _HW_CORE_API_H_ +/** + * \file hw_core_api.h + * \brief + * This file contains hw core api + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "lpass_core_api.h" + + +/** + Param ID for hw core + This ID should only be used under PRM module instance +*/ +#define PARAM_ID_RSC_HW_CORE 0x08001032 + +// uncomment once build errors are fixed on OTTP end +//#define PARAM_ID_RSC_LPASS_CORE 0x0800102B + +#include "spf_begin_pack.h" +/** Struct for response for hw core request by HLOS */ +struct hw_core_request_t +{ + uint32_t hw_core_id; + /**< HW core id + * @values #HW_CORE_ID_LPASS + * #HW_CORE_ID_DCODEC */ +} +#include "spf_end_pack.h" +; + +typedef struct hw_core_request_t hw_core_request_t; + +/* LPASS core id */ +#define HW_CORE_ID_LPASS 1 + +/* DCODEC core id */ +#define HW_CORE_ID_DCODEC 2 + +#endif /* _HW_CORE_API_H_ */ diff --git a/spf/api/modules/hw_intf_cmn_api.h b/spf/api/modules/hw_intf_cmn_api.h new file mode 100644 index 0000000..82f129d --- /dev/null +++ b/spf/api/modules/hw_intf_cmn_api.h @@ -0,0 +1,394 @@ +#ifndef HW_INTF_CMN_API +#define HW_INTF_CMN_API +/** + * \file hw_intf_cmn_api.h + * \brief + * + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" +#include "audio_hw_clk_api.h" +#include "imcl_fwk_intent_api.h" +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ +/* Frame size in milliseconds (inclusive) */ +#define FRAME_SIZE_FACTOR_1 1 +#define FRAME_SIZE_MIN_MS 1 +#define FRAME_SIZE_MAX_MS 40 + +typedef enum lpaif_type_t +{ + LPAIF = 0, // Default type + LPAIF_RXTX = 1, + LPAIF_WSA = 2, + LPAIF_VA = 3, + LPAIF_AXI = 4, + LPAIF_AUD = 5, + LPAIF_SDR = 6, + LPAIF_WSA2 = 7, + LPAIF_RXTX_SDCA = 8, + LPAIF_RXTX_WSA = 9, + LPAIF_QAIF_AUD = 10, + LPAIF_QAIF_VA = 11, + MAX_NUM_LPAIF_TYPES, + LPAIF_BLK_INVALID = 0x7FFFFFFF +} lpaif_type_t; + + +typedef enum qaif_type_t +{ + QAIF_AUD = 0, // Default type + QAIF_VA = 1, + MAX_NUM_QAIF_TYPES, + QAIF_BLK_INVALID = 0x7FFFFFFF +}qaif_type_t; + + +/*============================================================================== + Type definitions +==============================================================================*/ + +/** Parameter used to configure the Silence detection for the CODEC DMA Interface + To be notified of the detection status, client can register with the codec dma source module using EVENT_ID_SILENCE_DETECTION. +*/ +#define PARAM_ID_SILENCE_DETECTION 0x08001AC2 + +/** @h2xmlp_parameter {"PARAM_ID_SILENCE_DETECTION", + PARAM_ID_SILENCE_DETECTION} + @h2xmlp_description {Configures the Silence detection param for the CODEC DMA Interface. + To be notified of the detection status, client can register with the codec dma source module using EVENT_ID_SILENCE_DETECTION. } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +/** Payload for parameter PARAM_ID_SILENCE_DETECTION */ +struct param_id_silence_detection_t +{ + uint32_t enable_detection; + /**< @h2xmle_description {Indicates if Silence detection is enabled/disabled} + @h2xmle_range {0,1} + @h2xmle_default {0} */ + + uint32_t detection_duration_ms; + /**< @h2xmle_description {Continuous silence duration of mic signal that is required to confirm silence detection} + @h2xmle_range {1000..30000} + @h2xmle_default {3000} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_silence_detection_t param_id_silence_detection_t; + + +/** + Payload for silence detection status. +*/ +#include "spf_begin_pack.h" +struct event_cfg_silence_detection_status_t +{ + uint32_t status_ch_mask; + /**< Current silence detection status mask for groups of 32 channels */ + + /*#< @h2xmle_description {Current silence detection status mask for groups of + 32 channels based on num_32_channel_group. + Here nth channel status will be present at n-1 th bit. + If num_32_channel_group = 1, the status includes channels 1-32 + If num_32_channel_group = 2, the status includes channels 33-64 etc.} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +typedef struct event_cfg_silence_detection_status_t event_cfg_silence_detection_status_t; + + +/** Identifier of the silence detection event from CODEC DMA module. + Payload of the configuration that the client is to register with the module + through APM_CMD_REGISTER_MODULE_EVENTS + event_cfg_silence_detection_t + The events are raised based on the configuration provided using PARAM_ID_SILENCE_DETECTION + */ +#define EVENT_ID_SILENCE_DETECTION 0x08001AC3 +/** @h2xmlp_parameter {"EVENT_ID_SILENCE_DETECTION", + EVENT_ID_SILENCE_DETECTION} + @h2xmlp_description {ID of the event raised by codec DMA module based on configuration provided using PARAM_ID_SILENCE_DETECTION. } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/** Payload of the #EVENT_ID_SILENCE_DETECTION event. +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_cfg_silence_detection_t +{ + uint32_t num_32_channel_group; + /**< Number of silence detection 32 channel groups. + If num_32_channel_group=1 then status contain information of 32 channels. + If num_32_channel_group=2 then status contain information of 64 channels etc. + */ + + /*#< @h2xmle_description {Number of silence detection 32 channel groups. + If num_32_channel_group=1 then then status contain information of 32 channels. + If num_32_channel_group=2 then status contain information of 64 channels etc.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + event_cfg_silence_detection_status_t detections[0]; + /**< Array of silence detection status of size num_32_channel_group. */ + /*#< @h2xmle_description {Array of silence detection status of size + num_32_channel_group.} + @h2xmle_variableArraySize {num_32_channel_group} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_cfg_silence_detection_t event_cfg_silence_detection_t; +/** ID of the parameter used to configure the HW endpoint media format */ +#define PARAM_ID_HW_EP_MF_CFG 0x08001017 + +/** @h2xmlp_parameter {"PARAM_ID_HW_EP_MF_CFG", + PARAM_ID_HW_EP_MF_CFG} + @h2xmlp_description {Configures the media format of the HW endpoint interface.} + @h2xmlp_toolPolicy {Calibration} +*/ + +#include "spf_begin_pack.h" +struct param_id_hw_ep_mf_t +{ + uint32_t sample_rate; + /**< @h2xmle_description {Defines sample rate of the interface.} + @h2xmle_rangeList {"8 kHz"=8000; + "11.025 kHz"=11025; + "12 kHz"=12000; + "16 kHz"=16000; + "22.05 kHz"=22050; + "24 kHz"=24000; + "32 kHz"=32000; + "44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000; + "352.8 kHz"=352800; + "384 kHz"=384000} + @h2xmle_default {48000} + */ + uint16_t bit_width; + /**< @h2xmle_description {Bit width in bits per sample.} + @h2xmle_rangeList {"16-bit"=16; + "24-bit"=24; + "32-bit"=32} + @h2xmle_default {16} + */ + uint16_t num_channels; + /**< @h2xmle_description {Number of channels.} + @h2xmle_range {1..32} + @h2xmle_default {1} + */ + uint32_t data_format; + /**< @h2xmle_description {Format of the data} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1; + "DATA_FORMAT_IEC61937_PACKETIZED"=2; + "DATA_FORMAT_IEC60958_PACKETIZED"=3; + "DATA_FORMAT_IEC60958_PACKETIZED_NON_LINEAR"= 8; + "DATA_FORMAT_DSD_OVER_PCM"=4; + "DATA_FORMAT_GENERIC_COMPRESSED"=5; + "DATA_FORMAT_RAW_COMPRESSED"=6; + "DATA_FORMAT_COMPR_OVER_PCM_PACKETIZED"= 7} + @h2xmle_default {1} + */ +} +#include "spf_end_pack.h" +; +/* Structure type def for above payload. */ +typedef struct param_id_hw_ep_mf_t param_id_hw_ep_mf_t; + + +/** ID of the parameter used to configure the operating frame size */ +#define PARAM_ID_HW_EP_FRAME_SIZE_FACTOR 0x08001018 + +/** @h2xmlp_parameter {"PARAM_ID_HW_EP_FRAME_SIZE_FACTOR", + PARAM_ID_HW_EP_FRAME_SIZE_FACTOR} + @h2xmlp_description {Configures the operating frame size} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_frame_size_factor_t +{ + uint32_t frame_size_factor; + /**< @h2xmle_description {Frame size factor used to derive operating frame size in number of samples per channel.} + @h2xmle_range {1..40} + @h2xmle_default {1} + */ +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_frame_size_factor_t param_id_frame_size_factor_t; + + +/* ID of the paramter used to configure or enable HW clocks */ +#define PARAM_ID_HW_INTF_CLK_CFG 0x0800113C + +/** @h2xmlp_parameter {"PARAM_ID_HW_INTF_CLK_CFG", + PARAM_ID_HW_INTF_CLK_CFG} + @h2xmlp_description {Configures or enables HW clocks} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_hw_intf_clk_cfg_t +{ + uint32_t clock_id; + /**< @h2xmle_description {Unique Clock ID of the clock being requested.} + @h2xmle_default {HW_INTF_CLK_ID_DEFAULT} + @h2xmle_rangeList {"HW_INTF_CLK_ID_DEFAULT"=HW_INTF_CLK_ID_DEFAULT} */ + + uint32_t clock_freq; + /**< @h2xmle_description {Clock frequency in Hz to set.} + @h2xmle_default {HW_INTF_CLK_FREQ_DEFAULT} */ + + uint32_t clock_attri; + /**< @h2xmle_description {Configures clock attributes.} + @h2xmle_default {HW_INTF_CLK_ATTRI_DEFAULT} + @h2xmle_rangeList {"HW_INTF_CLK_ATTRI_DEFAULT"=HW_INTF_CLK_ATTRI_DEFAULT; + "CLOCK_ATTRIBUTE_INVERT_COUPLE_NO"=CLOCK_ATTRIBUTE_INVERT_COUPLE_NO} */ + + uint32_t clock_root; + /**< @h2xmle_description {Root clock source.} + @h2xmle_default {CLOCK_ROOT_DEFAULT} + @h2xmle_rangeList {"CLOCK_ROOT_DEFAULT"=CLOCK_ROOT_DEFAULT} */ +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_hw_intf_clk_cfg_t param_id_hw_intf_clk_cfg_t; + +/* ID of the paramter used to configure or enable HW clocks */ +#define PARAM_ID_HW_EP_POWER_MODE_CFG 0x08001176 + +#define POWER_MODE_0 0 //default +#define POWER_MODE_1 1 //XO shutdown allowed +#define POWER_MODE_2 2 //XO shutdown disallowed +#define HW_EP_POWER_MODE_MAX POWER_MODE_2 +/** @h2xmlp_parameter {"PARAM_ID_HW_EP_POWER_MODE_CFG", + PARAM_ID_HW_EP_POWER_MODE_CFG} + @h2xmlp_description {Configures the power mode (XO Shutdown).} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_hw_ep_power_mode_cfg_t +{ + uint32_t power_mode; + /**< @h2xmle_description {Power mode - indicates the sleep latency XO mode vote + in a low power scenario; \n + -# POWER_MODE_0 -> EP is not in LPI - Default Mode; \n + -# POWER_MODE_1 -> XO shutdown is allowed (deep sleep)\n + -# POWER_MODE_2 -> XO shutdown is NOT allowed} + @h2xmle_default {POWER_MODE_0} + @h2xmle_rangeList {"POWER_MODE_0"=POWER_MODE_0; + "POWER_MODE_1"=POWER_MODE_1; + "POWER_MODE_2"=POWER_MODE_2} */ +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_hw_ep_power_mode_cfg_t param_id_hw_ep_power_mode_cfg_t; + +/*********************************** HW EP Source Custom Channel Map ******************************/ +/** + * Param ID used to configure hw ep source custom channel maps + */ +#define PARAM_ID_HW_EP_SRC_CHANNEL_MAP 0x0800108A + +/** @h2xmlp_parameter {"PARAM_ID_HW_EP_SRC_CHANNEL_MAP", PARAM_ID_HW_EP_SRC_CHANNEL_MAP} + @h2xmlp_description {Param ID used to configure hw ep source custom channel maps. } + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_hw_ep_src_channel_map_t +{ + uint16_t num_channels; + /**< @h2xmle_description {Number of channels} + @h2xmle_default {0} + @h2xmle_range { 0..16 } + @h2xmle_policy {Basic} */ +#if defined(__H2XML__) + uint16_t channel_mapping[0]; + /**< @h2xmle_description {Channel mapping array whose size is num_channels defined above. + Each element i of the channel_mapping[i] array, describes the channel i inside + the buffer where i is less than num_channels. An unused channel is set to 0. + Each used channel should be between the values 48 and 63} + @h2xmle_rangeList {"PCM_CUSTOM_CHANNEL_MAP_1" = PCM_CUSTOM_CHANNEL_MAP_1, + "PCM_CUSTOM_CHANNEL_MAP_2" = PCM_CUSTOM_CHANNEL_MAP_2, + "PCM_CUSTOM_CHANNEL_MAP_3" = PCM_CUSTOM_CHANNEL_MAP_3, + "PCM_CUSTOM_CHANNEL_MAP_4" = PCM_CUSTOM_CHANNEL_MAP_4, + "PCM_CUSTOM_CHANNEL_MAP_5" = PCM_CUSTOM_CHANNEL_MAP_5, + "PCM_CUSTOM_CHANNEL_MAP_6" = PCM_CUSTOM_CHANNEL_MAP_6, + "PCM_CUSTOM_CHANNEL_MAP_7" = PCM_CUSTOM_CHANNEL_MAP_7, + "PCM_CUSTOM_CHANNEL_MAP_8" = PCM_CUSTOM_CHANNEL_MAP_8, + "PCM_CUSTOM_CHANNEL_MAP_9" = PCM_CUSTOM_CHANNEL_MAP_9, + "PCM_CUSTOM_CHANNEL_MAP_10" = PCM_CUSTOM_CHANNEL_MAP_10, + "PCM_CUSTOM_CHANNEL_MAP_11" = PCM_CUSTOM_CHANNEL_MAP_11, + "PCM_CUSTOM_CHANNEL_MAP_12" = PCM_CUSTOM_CHANNEL_MAP_12, + "PCM_CUSTOM_CHANNEL_MAP_13" = PCM_CUSTOM_CHANNEL_MAP_13, + "PCM_CUSTOM_CHANNEL_MAP_14" = PCM_CUSTOM_CHANNEL_MAP_14, + "PCM_CUSTOM_CHANNEL_MAP_15" = PCM_CUSTOM_CHANNEL_MAP_15, + "PCM_CUSTOM_CHANNEL_MAP_16" = PCM_CUSTOM_CHANNEL_MAP_16} + @h2xmle_default {PCM_CUSTOM_CHANNEL_MAP_1} + @h2xmle_variableArraySize {"num_channels"} + @h2xmle_policy {Basic} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct param_id_hw_ep_src_channel_map_t param_id_hw_ep_src_channel_map_t; + +/** Parameter used to configure DMA data alignment for Codec DMA interface */ + +#define PARAM_ID_HW_EP_DMA_DATA_ALIGN 0x08001233 + +#define DMA_DATA_ALIGN_MSB 0 // DMA data is MSB aligned +#define DMA_DATA_ALIGN_LSB 1 // DMA data is LSB aligned + +/** @h2xmlp_parameter {"PARAM_ID_HW_EP_DMA_DATA_ALIGN", + PARAM_ID_HW_EP_DMA_DATA_ALIGN} + @h2xmlp_description {Configures DMA data alignment.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +/** Payload for parameter PARAM_ID_HW_EP_DMA_DATA_ALIGN */ +struct param_id_hw_ep_dma_data_align_t +{ + uint32_t dma_data_align; + /**< @h2xmle_description {DMA data alignment.\n + Indicates the data alignment in DMA buffer. \n + + # DMA_DATA_ALIGN_MSB - DMA data aligned towards MSB \n + # DMA_DATA_ALIGN_LSB - DMA data aligned towrads LSB} + @h2xmle_rangeList {"DMA_DATA_ALIGN_MSB"=0; + "DMA_DATA_ALIGN_LSB"=1} + @h2xmle_default {0} + */ +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_hw_ep_dma_data_align_t param_id_hw_ep_dma_data_align_t; + +#endif /* HW_INTF_CMN_API */ diff --git a/spf/api/modules/i2s_api.h b/spf/api/modules/i2s_api.h new file mode 100644 index 0000000..df37ba5 --- /dev/null +++ b/spf/api/modules/i2s_api.h @@ -0,0 +1,301 @@ +#ifndef _I2S_API_H_ +#define _I2S_API_H_ +/** + * \file i2s_api.h + * \brief + * This file contains I2S module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "hw_intf_cmn_api.h" + +/** @h2xml_title1 {I2S Module API} + @h2xml_title_agile_rev {I2S Module API} + @h2xml_title_date {July 12, 2018} */ + +/*============================================================================== + Constants +==============================================================================*/ + +/** I2S interface index types */ +#define I2S_INTF_TYPE_PRIMARY 0 +#define I2S_INTF_TYPE_SECONDARY 1 +#define I2S_INTF_TYPE_TERTIARY 2 +#define I2S_INTF_TYPE_QUATERNARY 3 +#define I2S_INTF_TYPE_QUINARY 4 + +/* I2S lines and multi-channel operation */ + +/** Enumeration for setting the I2S configuration sd_line_idx parameter to + serial data wire number 0 (SD0). + */ +#define I2S_SD0 0x1 + +/** Enumeration for setting the I2S configuration sd_line_idx parameter to + serial data wire number 1 (SD1). + */ +#define I2S_SD1 0x2 + +/** Enumeration for setting the I2S configuration sd_line_idx parameter to + serial data wire number 2 (SD2). + */ +#define I2S_SD2 0x3 + +/** Enumeration for setting the I2S configuration sd_line_idx parameter to + serial data wire number 3 (SD3). + */ +#define I2S_SD3 0x4 + +/** Enumeration for setting the I2S configuration sd_line_idx parameter to + SD0 and SD1. + */ +#define I2S_QUAD01 0x5 + +/** Enumeration for setting the I2S configuration sd_line_idx parameter to + SD2 and SD3. + */ +#define I2S_QUAD23 0x6 + +/** Enumeration for setting the I2S configuration sd_line_idx parameter to + six channels. + */ +#define I2S_6CHS 0x7 + +/** Enumeration for setting the I2S configuration sd_line_idx parameter to + 8 channels. + */ +#define I2S_8CHS 0x8 + +/* Master Slave configuration */ + +/** Enumeration for setting the I2S configuration ws_src parameter to + external. + */ +#define CONFIG_I2S_WS_SRC_EXTERNAL 0x0 + +/** Enumeration for setting the I2S configuration ws_src parameter to + internal. @newpage + */ +#define CONFIG_I2S_WS_SRC_INTERNAL 0x1 + +/* Input port ID of I2S module */ +#define PORT_ID_I2S_INPUT 0x2 + +/* Output port ID of I2S module */ +#define PORT_ID_I2S_OUTPUT 0x1 + +/* Stack size for I2s Module*/ +/** On MDMs, audio runs in root PD. Since MMPM calls on MDMs + are not optimized, we would need more stack size than MSM. + + I2S stack size would be 4KB for MDM and 2KB for MSM. +*/ +#ifdef USES_AUDIO_IN_ROOTPD +#define I2S_STACK_SIZE 4096 +#else +#define I2S_STACK_SIZE 2048 +#endif +/*============================================================================== + Type definition +==============================================================================*/ + +/** Parameter used to configure the I2S interface */ +#define PARAM_ID_I2S_INTF_CFG 0x08001019 +/** @h2xmlp_parameter {"PARAM_ID_I2S_INTF_CFG", + PARAM_ID_I2S_INTF_CFG} + @h2xmlp_description {Configures the I2S interface.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +/** Payload for parameter PARAM_ID_I2S_INTF_CFG */ +struct param_id_i2s_intf_cfg_t +{ + uint32_t lpaif_type; + /**< @h2xmle_description {LPAIF types.} + @h2xmle_rangeList {"LPAIF"=0; + "LPAIF_RXTX"=1; + "LPAIF_WSA"=2; + "LPAIF_VA"=3; + "LPAIF_AXI"=4} + @h2xmle_default {0} + */ + uint32_t intf_idx; + /**< @h2xmle_description {I2S interface index types.} + @h2xmle_rangeList {"I2S_INTF_TYPE_PRIMARY"=0; + "I2S_INTF_TYPE_SECONDARY"=1; + "I2S_INTF_TYPE_TERTIARY"=2; + "I2S_INTF_TYPE_QUATERNARY"=3; + "I2S_INTF_TYPE_QUINARY"=4} + @h2xmle_default {0} + */ + uint16_t sd_line_idx; + /**< @h2xmle_description {I2S serial data line idx} + @h2xmle_rangeList {"I2S_SD0"=1; + "I2S_SD1"=2; + "I2S_SD2"=3; + "I2S_SD3"=4; + "I2S_QUAD01"=5; + "I2S_QUAD23"=6; + "I2S_6CHS"=7; + "I2S_8CHS"=8} + @h2xmle_default {1} + */ + uint16_t ws_src; + /**< @h2xmle_description {Specifies Master slave configuration.} + @h2xmle_rangeList {"CONFIG_I2S_WS_SRC_EXTERNAL"=0; + "CONFIG_I2S_WS_SRC_INTERNAL"=1} + @h2xmle_default {1} + */ +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_i2s_intf_cfg_t param_id_i2s_intf_cfg_t; +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** Module ID for I2S sink module */ +#define MODULE_ID_I2S_SINK 0x0700100A +/** @h2xmlm_module {"MODULE_ID_I2S_SINK", + MODULE_ID_I2S_SINK} + @h2xmlm_displayName {"I2S Sink"} + @h2xmlm_description {- I2S Sink Module\n + - Supports following params: \n + - PARAM_ID_I2S_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - PARAM_ID_HW_INTF_CLK_CFG \n + - PARAM_ID_HW_EP_POWER_MODE_CFG\n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT, IEC60958_PACKETIZED,\n + IEC60958_PACKETIZED_NON_LINEAR, COMPR_OVER_PCM_PACKETIZED,\n + IEC61937_PACKETIZED, GENERIC_COMPRESSED \n + - fmt_id : Don't care \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1, 2, 4, 6 or 8 \n + - For DATA_FORMAT_IEC60958_NON_LINEAR: 2 or 8 only \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 24 (bits per sample 24 and Q27) \n + - : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q27, Q31 \n + - Interleaving : I2S sink module needs de-interleaved unpacked } + @h2xmlm_dataInputPorts {IN = PORT_ID_I2S_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { I2S_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_rangeList {"ONE"=1; + "TWO"=2; + "FOUR"=4; + "SIX"=6; + "EIGHT"=8} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"FIXED POINT"=1; + "IEC60958 PACKETIZED"=3; + "IEC60958 PACKETIZED NON LINEAR"=8; + "COMPR OVER PCM PACKETIZED"=7; + "IEC61937 PACKETIZED"=2; + "GENERIC COMPRESSED"=5} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_intf_clk_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_id} + @h2xmle_rangeList {"HW_INTF_CLK_ID_DEFAULT"=HW_INTF_CLK_ID_DEFAULT; + "CLOCK_ID_QUI_MI2S_OSR"=CLOCK_ID_QUI_MI2S_OSR} + @h2xmle_default {HW_INTF_CLK_ID_DEFAULT} + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_attri} + @h2xmle_rangeList {"HW_INTF_CLK_ATTRI_DEFAULT"=HW_INTF_CLK_ATTRI_DEFAULT} + @h2xmle_default {HW_INTF_CLK_ATTRI_DEFAULT} + + @h2xml_Select {param_id_i2s_intf_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_power_mode_cfg_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + +/** Module ID for I2S source module */ +#define MODULE_ID_I2S_SOURCE 0x0700100B +/** @h2xmlm_module {"MODULE_ID_I2S_SOURCE", + MODULE_ID_I2S_SOURCE} + @h2xmlm_displayName {"I2S Source "} + @h2xmlm_description {- I2S Source Module\n + - Supports following params: \n + - PARAM_ID_I2S_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - PARAM_ID_HW_INTF_CLK_CFG \n + - PARAM_ID_HW_EP_POWER_MODE_CFG\n + - PARAM_ID_HW_EP_SRC_CHANNEL_MAP\n + - Supported Input Media Format: \n + - I2S source module doesn't take any inputs } + @h2xmlm_dataOutputPorts {OUT = PORT_ID_I2S_OUTPUT} + @h2xmlm_dataMaxInputPorts {0} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { I2S_STACK_SIZE } + @h2xmlm_toolPolicy { Calibration } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_rangeList {"ONE"=1; + "TWO"=2; + "FOUR"=4; + "SIX"=6; + "EIGHT"=8} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"FIXED POINT"=1; + "IEC60958 PACKETIZED"=3; + "IEC60958 PACKETIZED NON LINEAR"=8; + "COMPR OVER PCM PACKETIZED"=7; + "IEC61937 PACKETIZED"=2; + "GENERIC COMPRESSED"=5} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_intf_clk_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_id} + @h2xmle_rangeList {"HW_INTF_CLK_ID_DEFAULT"=HW_INTF_CLK_ID_DEFAULT; + "CLOCK_ID_QUI_MI2S_OSR"=CLOCK_ID_QUI_MI2S_OSR} + @h2xmle_default {HW_INTF_CLK_ID_DEFAULT} + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_attri} + @h2xmle_rangeList {"HW_INTF_CLK_ATTRI_DEFAULT"=HW_INTF_CLK_ATTRI_DEFAULT} + @h2xmle_default {HW_INTF_CLK_ATTRI_DEFAULT} + + @h2xml_Select {param_id_i2s_intf_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_power_mode_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_src_channel_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_src_channel_map_t::num_channels} + @h2xmle_range { 0..15 } + @h2xmle_default {HW_INTF_CLK_ID_DEFAULT} + @} <-- End of the Module -->*/ + +#endif //_I2S_API_H_ diff --git a/spf/api/modules/imcl_fwk_intent_api.h b/spf/api/modules/imcl_fwk_intent_api.h new file mode 100644 index 0000000..f81a615 --- /dev/null +++ b/spf/api/modules/imcl_fwk_intent_api.h @@ -0,0 +1,96 @@ +#ifndef _IMCL_FWK_INTENT_API_H_ +#define _IMCL_FWK_INTENT_API_H_ +/** + * \file imcl_fwk_intent_api.h + * \brief + * This file contains all the public intent names. + * The intent related structs are defined in internal header file + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*------------------------------------------------------------------------------ + * Header Includes + *----------------------------------------------------------------------------*/ + +/** @addtogroup ar_spf_mod_ctrl_port_int_ids + Intents used by the I2S, PCM-TDM, Sample Slip, Sample Slip EC, and SPR + modules. +*/ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/* ----------------------------------------------------------------------- + * Type Declarations + * ----------------------------------------------------------------------- */ + +/* clang-format off */ + +/* clang-format on */ + +/*============================================================================== + Intent IDs +==============================================================================*/ + +/** @ingroup ar_spf_mod_ctrl_port_int_ids + Identifier for the IMCL intent used to share a real-time drift source's + accumulated drift relative to the local timer with rate matching modules. +*/ +#define INTENT_ID_TIMER_DRIFT_INFO 0x080010C2 + +/** @ingroup ar_spf_mod_ctrl_port_int_ids + Identifier for the IMCL intent used to send a module instance ID. */ +#define INTENT_ID_MODULE_INSTANCE_INFO 0x08001089 + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS // to end of file + +/** Identifier for the IMCL intent used to send a deadline time. */ +#define INTENT_ID_BT_DEADLINE_TIME 0x080010D3 + +/** Identifier for the IMCL intent used to define the payload structure of an + IMCL message. + + The SVA and Dam modules support the following functionalities: + - Channel resizing -- An input intent ID exposed by the Dam module. This + intent allows resizing of the channel buffers based on the SVA module's + buffering requirement. + - Output port data flow control -- An input intent ID exposed by the Dam + module. This intent is used to open or close the Dam output port gates by + SVA module. + - Best channel output -- This intent allows detection engines to send the + best channel indices to the Dam module. Upon receiving the best channel + indices, the Dam module outputs only the best channels from the given + output port. + - FTRT data availably information -- An output intent ID exposed by the Dam + module to send the unread data length [FTRT data] length present in + channel buffers to the SVA module. +*/ +#define INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL 0x08001064 + +/** Identifier for the IMCL intent used for the control link between the + detection engine and stage 2 detection engine. */ +#define INTENT_ID_DETECTION_ENGINE_STAGE2_TO_STAGE1 0x0800124B + +/** Identifier for the IMCL intent used to send sideband data to the encoder. + + @subhead4{Supported parameter IDs} + - #IMCL_PARAM_ID_BT_SIDEBAND_ENCODER_FEEDBACK @lstsp1 + - #IMCL_PARAM_ID_BIT_RATE_LEVEL_ENCODER_FEEDBACK +*/ +#define INTENT_ID_BT_ENCODER_FEEDBACK 0x080010D7 + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _IMCL_FWK_INTENT_API_H_ */ diff --git a/spf/api/modules/imcl_spm_intent_api.h b/spf/api/modules/imcl_spm_intent_api.h new file mode 100644 index 0000000..c0c5bc5 --- /dev/null +++ b/spf/api/modules/imcl_spm_intent_api.h @@ -0,0 +1,148 @@ +/**======================================================================== + @file imcl_spm_intent_api.h + + @brief This file contains all the public intent names + the intent related structs are defined in internal header files + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + + ====================================================================== */ + +#ifndef _IMCL_SPM_INTENT_API_H_ +#define _IMCL_SPM_INTENT_API_H_ + +/*------------------------------------------------------------------------------ + * Header Includes + *----------------------------------------------------------------------------*/ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/** ----------------------------------------------------------------------- + ** Type Declarations + ** ----------------------------------------------------------------------- */ + +/* clang-format off */ + +/*============================================================================== + Intent ID +==============================================================================*/ +/**< Intent defines the payload structure of the IMCL message. +SVA and Dam modules supports the following functionalities – +1. Channel resizing – This as an input intent ID exposed by Dam module, which allows resizing the channel buffers based +on SVA module’s buffering requirement. +2. Output port data flow control - This as an input intent ID exposed by Dam module. This intent is used to open/close +the Dam output ports gates by SVA module. +3. Best channel output – This intent allows detection engines to send the best channel indices to Dam module. Upon +receiving the best channel indices, Dam module outputs only the best channels from the given output port. +4. FTRT data availably info - This as an output intent ID exposed by Dam module. This intent is used by Dam module to +send the unread data length [FTRT data] length present in the channel buffers to the SVA module. */ + +#define INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL 0x08001064 + +/*============================================================================== + Intent ID +==============================================================================*/ +// Intent ID for the control link between FFECNS and detection engine. +#define INTENT_ID_FFECNS_SVA_FREEZE 0x080010BA + +/*============================================================================== + Intent ID +==============================================================================*/ +/**< +Intent ID for the control link between AVC Tx and Rx module. + +The AVC module automatically adjusts the loudness of the Rx voice in +response to the near-end noise level on the Tx path. This adjustment +improves the intelligibility of the receive path voice signal. +*/ +#define INTENT_ID_AVC 0x080010DB + +/*============================================================================== + Intent ID +==============================================================================*/ +/**< +Intent ID to send DRC parameters over control link. +e.g. +Control link between Rx DRC and Tx AVC modules in voice path. +*/ +#define INTENT_ID_DRC_CONFIG 0x080010F3 + +/*============================================================================== + Intent ID +==============================================================================*/ +/**< +Intent ID for the control link to send gain information. +This intent can be used by a module to send its gain to another module. + +e.g. +Soft Volume Control sends the target gain to AVC-TX module in voice path. +*/ +#define INTENT_ID_GAIN_INFO 0x080010F5 + +/*============================================================================== + Intent ID +==============================================================================*/ +// Intent ID for the control link between Soft Vol and Popless Equalizer. +#define INTENT_ID_P_EQ_VOL_HEADROOM 0x08001118 + +/*============================================================================== + Intent ID +==============================================================================*/ +/**< +Intent ID for the control link between RVE Tx and Rx module. + +The RVE module automatically adjusts the loudness of the Rx voice in +response to the near-end noise level on the Tx path. This adjustment +improves the intelligibility of the receive path voice signal. +*/ +#define INTENT_ID_RVE 0x080010DD + +/*============================================================================== + Intent ID +==============================================================================*/ +/** IMCL intent ID for sending sideband data to the encoder + * This intent id supports two param ids: + * 1. IMCL_PARAM_ID_BT_SIDEBAND_ENCODER_FEEDBACK + * 2. IMCL_PARAM_ID_BIT_RATE_LEVEL_ENCODER_FEEDBACK */ +#define INTENT_ID_BT_ENCODER_FEEDBACK 0x080010D7 + +/*============================================================================== + Intent ID +==============================================================================*/ +/** IMCL intent ID for sending the notification to the packetizer v1 + * to send sideband ack to BT that the primer sideband has been + * received by the RX RAT module */ +#define INTENT_ID_PACKETIZER_V1_FEEDBACK 0x08001148 + +/*============================================================================== + Intent ID +==============================================================================*/ +/**< +Intent ID for the control link between CTM Tx and Rx module. +*/ +#define INTENT_ID_CTM_TTY 0x08001191 + +/*============================================================================== + Intent ID +==============================================================================*/ +/**< +Intent ID for the control link between TTY module(1x/CTM/LTE_TTY in Rx path) and soft volume module(in Tx path). +TTY module communicates with the soft volume module to indicate whether to +mute or unmute the stream in the Tx path. The parameter - PARAM_ID_IMCL_MUTE +is used for this communication. + +*/ +#define INTENT_ID_MUTE 0x08001195 + +/* clang-format on */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* _IMCL_SPM_INTENT_API_H_ */ diff --git a/spf/api/modules/irm_api.h b/spf/api/modules/irm_api.h new file mode 100644 index 0000000..9f4ac0a --- /dev/null +++ b/spf/api/modules/irm_api.h @@ -0,0 +1,759 @@ +#ifndef _IRM_API_H_ +#define _IRM_API_H_ +/** + * \file irm_api.h + * \brief + * API header for Integrated Resource Monitor (IRM). + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*---------------------------------------------------------------------------------------------------------------------- + Include files + ---------------------------------------------------------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "apm_graph_properties.h" + +/** @addtogroup spf_mods_irm +@{ */ + +/** Minor version of the Integrated Resource Monitor (IRM) module. */ +#define IRM_MINOR_VERSION 1 + +// clang-format off + +/** Type of IRM processor is invalid or unknown. */ +#define IRM_PROCESSOR_TYPE_UNSUPPORTED 0 + +/** IRM processor type is a Hexagon processor. */ +#define IRM_PROCESSOR_TYPE_HEXAGON 1 + +/** IRM processor type is an Arm processor. */ +#define IRM_PROCESSOR_TYPE_ARM 2 + +/** IRM processor type is an x86 processor. */ +#define IRM_PROCESSOR_TYPE_x86 3 + + +/** ID for the IRM block is invalid or unknown. */ +#define IRM_BLOCK_ID_UNSUPPORTED 0 + +/** IRM block is a processor. */ +#define IRM_BLOCK_ID_PROCESSOR 1 + +/** IRM block is a container. */ +#define IRM_BLOCK_ID_CONTAINER 2 + +/** IRM block is a module. @newpage */ +#define IRM_BLOCK_ID_MODULE 3 + +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ + +/** Identifier for the Integrated Resource Monitor (IRM) module. + + This module supports the following metric and parameter IDs: + - #IRM_METRIC_ID_PROCESSOR_CYCLES + - #IRM_BASIC_METRIC_ID_CURRENT_CLOCK + - #IRM_METRIC_ID_HEAP_INFO + - #IRM_METRIC_ID_PACKET_COUNT + - #IRM_METRIC_ID_MEM_TRANSACTIONS + - #PARAM_ID_IRM_VERSION + - #PARAM_ID_IRM_SYSTEM_CAPABILITIES + - #PARAM_ID_IRM_METRIC_CAPABILITIES + - #PARAM_ID_IRM_PROFILING_PARAMS + - #PARAM_ID_IRM_ENABLE_DISABLE_PROFILING + - #PARAM_ID_IRM_REPORT_METRICS + */ +#define IRM_MODULE_INSTANCE_ID 6 +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ + +// clang-format on +/*--------------------------------------------------------------------------------------------------------------------*/ + +/** Number of elapsed processor cycles during the given frame period + (frame_size_ms). + + Processor cycles can be used to calculate the processor load in cycles per + second (CPS), where: + - CPS = (cycles * 1000 / frame_size_ms); + - MCPS = CPS/1000000 + + @msgpayload{irm_metric_id_processor_cycles_t} + @table{weak__irm__metric__id__processor__cycles__t} + */ +#define IRM_METRIC_ID_PROCESSOR_CYCLES 0x0800120B + + +/** @weakgroup weak_irm_metric_id_processor_cycles_t +@{ */ +#include "spf_begin_pack.h" +struct irm_metric_id_processor_cycles_t +{ + uint32_t processor_cycles; + /**< Number of processor cycles that elapsed during the frame size time + (in Hertz). */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_metric_id_processor_cycles_t */ +typedef struct irm_metric_id_processor_cycles_t irm_metric_id_processor_cycles_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/** Current system clock rate. + + @msgpayload{irm_metric_id_current_clock_t} + @table{weak__irm__metric__id__current__clock__t} @newpage + */ +#define IRM_BASIC_METRIC_ID_CURRENT_CLOCK 0x0800120C + + +/** @weakgroup weak_irm_metric_id_current_clock_t +@{ */ +#include "spf_begin_pack.h" +struct irm_metric_id_current_clock_t +{ + uint32_t current_clock; + /**< Current system clock rate (in kilohertz). */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_metric_id_current_clock_t */ +typedef struct irm_metric_id_current_clock_t irm_metric_id_current_clock_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/** Information related to the heap memory usage during the frame size period + (#irm_report_metric_payload_t::frame_size_ms), including: + - Current heap usage (in bytes) + - Peak heap usage (in bytes) + - Maximum allowed heap allocation + + @msgpayload{irm_metric_id_heap_info_t} + @tablens{weak__irm__metric__id__heap__info__t} + + @par Heap payload (irm_per_heap_id_info_payload_t) + @table{weak__irm__per__heap__id__info__payload__t} + */ +#define IRM_METRIC_ID_HEAP_INFO 0x0800120D + + +/** @weakgroup weak_irm_metric_id_heap_info_t +@{ */ +/** + Contains information about heap statistics per heap ID. This structure is + followed by a variable array structure where the number of elements = + num_heap_id. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct irm_metric_id_heap_info_t +{ + uint32_t num_heap_id; + /**< Number of heap IDs. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_metric_id_heap_info_t */ +typedef struct irm_metric_id_heap_info_t irm_metric_id_heap_info_t; + + +/** @weakgroup weak_irm_per_heap_id_info_payload_t +@{ */ +#include "spf_begin_pack.h" +struct irm_per_heap_id_info_payload_t +{ + uint32_t heap_id; + /**< Heap ID */ + + uint32_t current_heap_usage; + /**< Current heap usage (in bytes). */ + + uint32_t max_allowed_heap_size; + /**< Maximum possible heap usage (in bytes). The heap usage percentage is + calculated as follows: \n + @indent{12pt} heap usage = current_heap_usage/max_allowed_heap_size */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_per_heap_id_info_payload_t */ +typedef struct irm_per_heap_id_info_payload_t irm_per_heap_id_info_payload_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/** Number of packets executed during the frame size period. + + This macro is used to calculate the packets per second per hardware thread + statistics, where: + - PPS = packet_count * 1000/(frame_size_ms) + - MPPS = PPS/1000000 + + @msgpayload{irm_metric_id_packet_count_t} + @table{weak__irm__metric__id__packet__count__t} @newpage + */ +#define IRM_METRIC_ID_PACKET_COUNT 0x0800120E + + +/** @weakgroup weak_irm_metric_id_packet_count_t +@{ */ +#include "spf_begin_pack.h" +struct irm_metric_id_packet_count_t +{ + uint32_t packet_count; + /**< Number of packets executed in the frame size period + (#irm_report_metric_payload_t::frame_size_ms). */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_metric_id_packet_count_t */ +typedef struct irm_metric_id_packet_count_t irm_metric_id_packet_count_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/** Number of memory read and writes that occurred during the frame size period + (#irm_report_metric_payload_t::frame_size_ms). + + This macro is used to calculate the memory bandwidth usage: + - read_bw = read_memory_transactions_bytes * 1000 / frame_size_ms + (in bytes per second) + - write_bw = write_memory_transactions_bytes * 1000 / frame_size_ms + (in bytes per second) + + @msgpayload{irm_metric_id_mem_transactions_t} + @table{weak__irm__metric__id__mem__transactions__t} + */ +#define IRM_METRIC_ID_MEM_TRANSACTIONS 0x0800120F + + +/** @weakgroup weak_irm_metric_id_mem_transactions_t +@{ */ +#include "spf_begin_pack.h" +struct irm_metric_id_mem_transactions_t +{ + uint32_t read_mem_transactions_bytes; + /**< Number of read memory transactions (in bytes). */ + + uint32_t write_mem_transactions_bytes; + /**< Number of write memory transactions (in bytes). */ +} +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_metric_id_mem_transactions_t */ +typedef struct irm_metric_id_mem_transactions_t irm_metric_id_mem_transactions_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ + +/** Identifier for the parameter that gets the IRM version. + + @msgpayload{param_id_irm_version_t} + @table{weak__param__id__irm__version__t} @newpage +*/ +#define PARAM_ID_IRM_VERSION 0x0800119E + + +/** @weakgroup weak_param_id_irm_version_t +@{ */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_irm_version_t +{ + uint32_t version; + /**< Version of the IRM. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_param_id_irm_version_t */ +typedef struct param_id_irm_version_t param_id_irm_version_t; + + +/*--------------------------------------------------------------------------------------------------------------------*/ +/* IRM PRIVATE METRICS BEGIN */ +/*--------------------------------------------------------------------------------------------------------------------*/ +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define IRM_METRIC_ID_Q6_HW_INFO 0x08001322 +struct irm_metric_id_q6_hw_info_t +{ + uint32_t num_hw_threads; /* Number of hardware threads present */ + uint32_t q6_arch_version; /* Q6 architecture version */ +} +#include "spf_end_pack.h" +; +typedef struct irm_metric_id_q6_hw_info_t irm_metric_id_q6_hw_info_t; +/*--------------------------------------------------------------------------------------------------------------------*/ +#define IRM_METRIC_ID_TIMESTAMP 0x08001323 +#include "spf_begin_pack.h" +struct irm_metric_id_timestamp_t +{ + uint64_t timestamp_ms; /* Time stamp during which the profiling was done in ms*/ +} +#include "spf_end_pack.h" +; +typedef struct irm_metric_id_timestamp_t irm_metric_id_timestamp_t; + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ +/*--------------------------------------------------------------------------------------------------------------------*/ +/* IRM PRIVATE METRICS END */ +/*--------------------------------------------------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ + +/** Identifier for the parameter that gets the IRM system capabilities. + + @msgpayload{param_id_irm_system_capabilities_t} + @tablens{weak__param__id__irm__system__capabilities__t} + + @par System capabilities (irm_system_capabilities_t) + @table{weak__irm__system__capabilities__t} @newpage +*/ +#define PARAM_ID_IRM_SYSTEM_CAPABILITIES 0x0800108B + + +/** @weakgroup weak_param_id_irm_system_capabilities_t +@{ */ +/** Contains information about system capabilities per processor domain ID. + This structure is followed by a variable array structure + (%irm_system_capabilities_t) where the number of elements = + num_proc_domain. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_irm_system_capabilities_t +{ + uint32_t num_proc_domain; + /**< Number of processor domain IDs. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_param_id_irm_system_capabilities_t */ +typedef struct param_id_irm_system_capabilities_t param_id_irm_system_capabilities_t; + + +/** @weakgroup weak_irm_system_capabilities_t +@{ */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct irm_system_capabilities_t +{ + uint32_t proc_domain; + /**< ID for the processor domain. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + + uint32_t processor_type; + /**< Type of processor the IRM is running. + + @valuesbul + - #IRM_PROCESSOR_TYPE_UNSUPPORTED + - #IRM_PROCESSOR_TYPE_HEXAGON + - #IRM_PROCESSOR_TYPE_ARM + - #IRM_PROCESSOR_TYPE_x86 @tablebulletend */ + + uint32_t min_profiling_period_us; + /**< Minimum number of profiling periods in which statistics are collected. + + @values 1000..0xFFFFFFFF (microseconds) */ + + uint32_t min_profile_per_report; + /**< Minimum number of times profiling is to be done before it must be + reported. + + @values 1..0xFFFFFFFF (microseconds) */ + + uint32_t max_num_containers_supported; + /**< Maximum number of threads supported by the IRM that is to be + profiled. */ + + uint32_t max_module_supported; + /**< Maximum number of modules supported by the IRM that is to be + profiled. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_system_capabilities_t */ +typedef struct irm_system_capabilities_t irm_system_capabilities_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ + +/** Identifier for the parameter that gets IRM metric capabilities. + + @msgpayload{param_id_irm_metric_capabilities_t} + @tablens{weak__param__id__irm__metric__capabilities__t} + + @par IRM metric capabilities (irm_metric_capabilities_t) + @tablens{weak__irm__metric__capabilities__t} + + @par Metric identifiers (irm_metric_capability_block_t) + @tablens{weak__irm__metric__capability__block__t} @newpage +*/ +#define PARAM_ID_IRM_METRIC_CAPABILITIES 0x080010BC + + +/** @weakgroup weak_param_id_irm_metric_capabilities_t +@{ */ +/** Contains metric capabilities information per processor domain. This + structure is followed by a variable array structure + (%irm_metric_capabilities_t) where the number of elements = + num_proc_domain. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_irm_metric_capabilities_t +{ + uint32_t num_proc_domain; + /**< Number of processor domain IDs. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_param_id_irm_metric_capabilities_t */ +typedef struct param_id_irm_metric_capabilities_t param_id_irm_metric_capabilities_t; + + +/** @weakgroup weak_irm_metric_capabilities_t +@{ */ +/** Contains metric capabilities information per block. This structure is + followed by a variable array structure (%irm_metric_capability_block_t) + where the number of elements = num_blocks. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct irm_metric_capabilities_t +{ + uint32_t proc_domain; + /**< ID for the processor domain. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + + uint32_t num_blocks; + /**< Number of blocks in the array. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_metric_capabilities_t */ +typedef struct irm_metric_capabilities_t irm_metric_capabilities_t; + + +/** @weakgroup weak_irm_metric_capability_block_t +@{ */ +/** + Contains metric IDs. This structure is followed by a variable array of metric + IDs where the number of elements = num_metric_ids. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct irm_metric_capability_block_t +{ + uint32_t block_id; + /**< Valid block IDs. + + @valuesbul + - #IRM_BLOCK_ID_UNSUPPORTED + - #IRM_BLOCK_ID_PROCESSOR + - #IRM_BLOCK_ID_CONTAINER + - #IRM_BLOCK_ID_MODULE @tablebulletend */ + + uint32_t num_metric_ids; + /**< Number of metric IDs. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_metric_capability_block_t */ +typedef struct irm_metric_capability_block_t irm_metric_capability_block_t; + + +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ + +/** Identifier for the parameter that gets the IRM profiling parameters. + + @msgpayload{param_id_irm_profiling_params_t} + @table{weak__param__id__irm__profiling__params__t} @newpage +*/ +#define PARAM_ID_IRM_PROFILING_PARAMS 0x0800119A + + +/** @weakgroup weak_param_id_irm_profiling_params_t +@{ */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_irm_profiling_params_t +{ + uint32_t proc_domain; + /**< ID for the processor domain. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + + uint32_t profiling_period_us; + /**< Profiling period in which statistics is to be collected (in + microseconds). */ + + uint32_t num_profiles_per_report; + /**< Number of profiles to be done before they are to be reported. The + report period is calculated as follows: + + @indent{12pt} report_period = profiling_period_us * num_profiles_per_report. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_param_id_irm_profiling_params_t */ +typedef struct param_id_irm_profiling_params_t param_id_irm_profiling_params_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ +/** Identifier for the parameter that enables or disables profiling metrics on + specific IRM blocks and instances. + + @msgpayload{param_id_enable_disable_metrics_t} + @tablens{weak__param__id__enable__disable__metrics__t} + + @par Block configuration {irm_enable_disable_block_t} + @tablens{weak__irm__enable__disable__block__t} @newpage +*/ +#define PARAM_ID_IRM_ENABLE_DISABLE_PROFILING 0x080011AA + + +/** @weakgroup weak_param_id_enable_disable_metrics_t +@{ */ +/** Contains the enable and disable information per block. This structure is + followed by a variable array structure (%irm_enable_disable_block_t) where + the number of elements = num_blocks. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_enable_disable_metrics_t +{ + uint32_t is_enable; + /**< Indicates whether the entire variable array is enabled. + + @valuesbul + - 0x0 -- Disabled + - 0x1 -- Enabled @tablebulletend */ + + uint32_t proc_domain; + /**< ID for the processor domain. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + + uint32_t num_blocks; + /**< Number of blocks. + + If is_enable = 0 and num_blocks = 0, the IRM disables all configured + block IDs, instance IDs, and metric IDs. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_param_id_enable_disable_metrics_t */ +typedef struct param_id_enable_disable_metrics_t param_id_enable_disable_metrics_t; + + +/** @weakgroup weak_irm_enable_disable_block_t +@{ */ +/** Contains metrics IDs. This structure is followed by a variable array where + the number of elements = num_metric_ids. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct irm_enable_disable_block_t +{ + uint32_t block_id; + /**< Valid block IDs. + + @valuesbul + - #IRM_BLOCK_ID_UNSUPPORTED + - #IRM_BLOCK_ID_PROCESSOR + - #IRM_BLOCK_ID_CONTAINER + - #IRM_BLOCK_ID_MODULE @tablebulletend */ + + uint32_t instance_id; + /**< Instance ID for the block. */ + + uint32_t num_metric_ids; + /**< Number of metric IDs. + + When is_enable = 0 and num_metric_ids = 0, the IRM disables all metric + IDs for the given instance ID/block ID. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_enable_disable_block_t */ +typedef struct irm_enable_disable_block_t irm_enable_disable_block_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ + +/** Identifier for the parameter that reports the profiled information of all + enabled metrics for each instance of provided block IDs. + + @msgpayload{param_id_report_metrics_t} + @tablens{weak__param__id__report__metrics__t} + + @par Metrics block (irm_report_metrics_block_t) + @tablens{weak__irm__report__metrics__block__t} + + @par Metrics data (irm_report_metric_t) + @tablens{weak__irm__report__metric__t} @newpage + + @par Collected metric information (irm_report_metric_payload_t) + @tablens{weak__irm__report__metric__payload__t} +*/ +#define PARAM_ID_IRM_REPORT_METRICS 0x08001210 + + +/** @weakgroup weak_param_id_report_metrics_t +@{ */ +/** Contains collected metric information per block. This structure is + followed by a variable array structure (%irm_report_metrics_block_t) where + the number of elements = num_blocks. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_report_metrics_t +{ + uint32_t routing_id; + /**< Routing ID for the block. Currently, this field is not used. */ + + uint32_t proc_domain; + /**< ID for the processor domain. + + @valuesbul + - #APM_PROC_DOMAIN_ID_MDSP + - #APM_PROC_DOMAIN_ID_ADSP + - #APM_PROC_DOMAIN_ID_SDSP + - #APM_PROC_DOMAIN_ID_CDSP + - #APM_PROP_ID_DONT_CARE (Default) @tablebulletend */ + + uint32_t num_blocks; + /**< Number of blocks that are collected. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_param_id_report_metrics_t */ +typedef struct param_id_report_metrics_t param_id_report_metrics_t; + + +/** @weakgroup weak_irm_report_metrics_block_t +@{ */ +/** Contains information about a block ID, instance ID, and the number of + metric IDs. This structure is followed by a variable array structure where + the number of elements = num_metric_ids. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct irm_report_metrics_block_t +{ + uint32_t block_id; + /**< Valid block IDs. + + @valuesbul + - #IRM_BLOCK_ID_UNSUPPORTED + - #IRM_BLOCK_ID_PROCESSOR + - #IRM_BLOCK_ID_CONTAINER + - #IRM_BLOCK_ID_MODULE @tablebulletend */ + + uint32_t instance_id; + /**< Instance ID for the block */ + + uint32_t num_metric_ids; + /**< Number of metric IDs. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_report_metrics_block_t */ +typedef struct irm_report_metrics_block_t irm_report_metrics_block_t; + + +/** @weakgroup weak_irm_report_metric_t +@{ */ +/** Contains information about a metric ID and the number of metric payloads. + This structure is followed by a variable array structure + (%irm_report_metric_payload_t) where the number of elements = + num_metric_payloads. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct irm_report_metric_t +{ + uint32_t metric_id; + /**< ID for the metric information. */ + + uint32_t num_metric_payloads; + /**< Number of payloads present for the given metric ID. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_report_metric_t */ +typedef struct irm_report_metric_t irm_report_metric_t; + + +/** @weakgroup weak_irm_report_metric_payload_t +@{ */ +/** Contains collected metric information per profiling period. This structure + is followed by the actual payload (size = payload_size) that contains the + metric information. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct irm_report_metric_payload_t +{ + uint32_t is_valid; + /**< Indicates whether the payload information is valid. + + @valuesbul + - 0 -- Disable + - 1 -- Enable @tablebulletend */ + + uint32_t frame_size_ms; + /**< Frame size (in milliseconds) during which the metric data was + accumulated. */ + + uint32_t payload_size; + /**< Size of the metric payload. */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/** @} */ /* end_weakgroup weak_irm_report_metric_payload_t */ +typedef struct irm_report_metric_payload_t irm_report_metric_payload_t; + +/*--------------------------------------------------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------------------------------------------------*/ + +/** @} */ /* end_addtogroup spf_mods_irm */ + +#endif //_IRM_API_H_ diff --git a/spf/api/modules/jitter_buf_api.h b/spf/api/modules/jitter_buf_api.h new file mode 100644 index 0000000..309bc34 --- /dev/null +++ b/spf/api/modules/jitter_buf_api.h @@ -0,0 +1,154 @@ +#ifndef __JITTER_BUF_H +#define __JITTER_BUF_H +/** + * \file jitter_buf_api.h + * \brief + * This file contains module published by Jitter Buf CAPI intialization. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/** + @h2xml_title1 {Jitter Buffer Module} + @h2xml_title_agile_rev {Jitter Buffer Modulee} + @h2xml_title_date {July 17, 2024} +*/ + +// Max number of ports supported by Jitter Buf module. +#define CAPI_JITTER_BUF_MAX_INPUT_PORTS (1) +#define CAPI_JITTER_BUF_MAX_OUTPUT_PORTS (1) +#define CAPI_JITTER_BUF_MAX_CTRL_PORTS (1) + +/*============================================================================== + Constants +==============================================================================*/ + +/* Parameter description */ +#define PARAM_ID_JITTER_BUF_CONFIG 0x080014E3 +#define PARAM_ID_JITTER_BUF_SETTLING_TIME 0x080014E4 +#define PARAM_ID_JITTER_BUF_SIZE_CONFIG 0x080014E6 + +/*============================================================================== + Type Definitions +==============================================================================*/ + + +/** @h2xmlp_parameter {"PARAM_ID_JITTER_BUF_CONFIG", + PARAM_ID_JITTER_BUF_CONFIG} + @h2xmlp_description { This param ID is used to configure Jitter Buf module. } + @h2xmlp_toolPolicy {NO_SUPPORT} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_jitter_buf_config_t +{ + uint32_t jitter_allowance_in_ms; + /**< @h2xmle_description { It defines the range of jitter for client buffers. + If 0 then used to disable module. } + @h2xmle_default { 200 } + @h2xmle_range {0..300}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure to define the Jitter Buf configuration.*/ +typedef struct param_id_jitter_buf_config_t param_id_jitter_buf_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_JITTER_BUF_SETTLING_TIME", + PARAM_ID_JITTER_BUF_SETTLING_TIME} + @h2xmlp_description { This param ID is used to configure settling time before accurate drift can be reported. } + @h2xmlp_toolPolicy {CALIBRATION} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_jitter_buf_settling_time_t +{ + uint32_t drift_settlement_in_ms; + /**< @h2xmle_description { It defines the max time usually taken to settle. + in steady state to start reporting drift. } + @h2xmle_default { 0 } + @h2xmle_range {0..10000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure to define the Jitter Buf configuration.*/ +typedef struct param_id_jitter_buf_settling_time_t param_id_jitter_buf_settling_time_t; + +/** @h2xmlp_parameter {"PARAM_ID_JITTER_BUF_SIZE_CONFIG", + PARAM_ID_JITTER_BUF_SIZE_CONFIG} + @h2xmlp_description { This param ID is used to configure Jitter Buf module size from QACT for debug purposes. } + @h2xmlp_toolPolicy {CALIBRATION} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_jitter_buf_size_config_t +{ + uint32_t jitter_allowance_in_ms; + /**< @h2xmle_description { It defines the range of jitter for client buffers. + If 0 then used to disable module. } + @h2xmle_default { 200 } + @h2xmle_range {0..300}*/ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_jitter_buf_size_config_t param_id_jitter_buf_size_config_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** Module ID of the Jitter Buffer Module. */ +#define MODULE_ID_JITTER_BUFFER 0x07010005 + +/** + @h2xmlm_module {"MODULE_ID_JITTER_BUFFER", MODULE_ID_JITTER_BUFFER} + @h2xmlm_displayName {"Jitter Buffer Module"} + + @h2xmlm_description { This module acts a delay buffer between BT decoder and sink.\n + + \n This module supports the following parameter IDs:\n + - PARAM_ID_JITTER_BUF_CONFIG\n + - PARAM_ID_JITTER_BUF_SETTLING_TIME\n + - PARAM_ID_JITTER_BUF_SIZE_CONFIG\n + + \n Supported Input Media Format:\n +* - Data Format : FIXED_POINT\n +* - fmt_id : Don't care\n +* - Sample Rates : 44100, 48000\n +* - Number of channels : 1 and 2\n +* - Channel type : 1 to 63\n +* - Bits per sample : 16, 24 \n +* - Q format : 15 for bps = 16 and 27 for bps = 24\n +supported bps +* - Interleaving : de-interleaved unpacked\n +* - Signed/unsigned : Signed } + + @h2xmlm_dataMaxInputPorts { 1 } + @h2xmlm_dataMaxOutputPorts { 1 } + @h2xmlm_ctrlDynamicPortIntent { "Jitter Buf - SS" = INTENT_ID_TIMER_DRIFT_INFO, + maxPorts= 1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { 1024 } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_jitter_buf_config_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_jitter_buf_settling_time_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_jitter_buf_size_config_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module --> */ + +#endif /*__JITTER_BUF_H*/ diff --git a/spf/api/modules/lc3_decoder_api.h b/spf/api/modules/lc3_decoder_api.h new file mode 100644 index 0000000..6e213e7 --- /dev/null +++ b/spf/api/modules/lc3_decoder_api.h @@ -0,0 +1,196 @@ +/*============================================================================== + @file lc3_decoder_api.h + @brief This file contains LC3 1.0 decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _LC3_DECODER_API_H_ +#define _LC3_DECODER_API_H_ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "imcl_fwk_intent_api.h" + +/*============================================================================== + Parameters +==============================================================================*/ + +/** ID of the LC3 Dec_Init parameter.This parameter should be set at init time.*/ +#define PARAM_ID_LC3_DEC_INIT 0x080012F8 + +/** @h2xmlp_subStruct */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct __attribute__((__packed__)) lc3_config_t +{ + uint32_t api_version; + /**< @h2xmle_description {informs the LC3 Decoder CAPI of api_version. Currently ignored by the CAPI} + @h2xmle_range {0..1} + @h2xmle_default {0} + */ + uint32_t sampling_Frequency; + /**< @h2xmle_description {sets the LC3 Decoder input sample rate in Hz.} + @h2xmle_range {8000..48000} + @h2xmle_default {48000} + */ + uint32_t max_octets_per_frame; + /**< @h2xmle_description {sets the LC3 Decoder max octets per encoded frame} + @h2xmle_range {60..600} + @h2xmle_default {155} + */ + uint32_t frame_duration; + /**< @h2xmle_description {sets the LC3 Decoder output frame duration} + @h2xmle_rangeList {7500, 10000} + @h2xmle_default {10000} + */ + uint32_t bit_depth; + /**< @h2xmle_description {sets the LC3 Decoder input PCM bits per sample} + @h2xmle_rangeList {16, 24} + @h2xmle_default {24} + */ + uint32_t num_blocks; + /**< @h2xmle_description {sets the LC3 Decoder output blocks per SDU} + @h2xmle_range {1..2} + @h2xmle_default {1} + */ + uint8_t default_q_level; + /**< @h2xmle_description {sets the LC3 Decoder qlevel, which sets the bit error resilience level} + @h2xmle_rangeList {0, 1, 2, 3} + @h2xmle_default {3} + */ + uint8_t vendor_specific[16]; + /**< @h2xmle_description {carries BT host capability exchange bytes to LC3 Decoder} + @h2xmle_range {0..255} + @h2xmle_default {0} + */ + uint32_t mode; + /**< @h2xmle_description {sets the LC3 Decoder unicast or broadcast mode} + @h2xmle_range {0..1} + @h2xmle_default {0} + */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct lc3_config_t lc3_config_t; + + +/** @h2xmlp_subStruct */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct __attribute__((__packed__)) stream_map_t +{ + uint32_t audio_location; + /**< @h2xmle_description {sets the input PCM channel mask part of stream map triplet} + @h2xmle_rangeList {0, 1, 2, 3} + @h2xmle_default {3} + */ + uint8_t stream_id; + /**< @h2xmle_description {sets the input or output stream id for a triplet} + @h2xmle_range {0..255} + @h2xmle_default {0} + */ + uint8_t direction; + /**< @h2xmle_description {sets to air or from air for the triplet} + @h2xmle_range {0..1} + @h2xmle_default {0} + */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct stream_map_t stream_map_t; + + +/* Structure payload for: PARAM_ID_LC3_DEC_INIT*/ +/** @h2xmlp_parameter {"PARAM_ID_LC3_DEC_INIT", PARAM_ID_LC3_DEC_INIT} + @h2xmlp_description { Configures the parameters of the LC3 Decoder after the module has been instantiated. } + @h2xmlx_expandStructs {false} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_lc3_decoder_config_payload_t +{ + lc3_config_t fromAirConfig; + + uint32_t decoder_output_channel; + /**< @h2xmle_description {sets the LC3 decoder output number of channels} + @h2xmle_range {1..2} + @h2xmle_default {2} + */ + + uint32_t stream_map_size; + /**< @h2xmle_description {The size - in triplets - of the stream map entity(s) that follows this element. Each stream map entity has 3 elements - audio location, stream-id, and direction} + @h2xmle_range {1..2} + @h2xmle_default {2} + */ + + stream_map_t streamMapIn[0]; + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_lc3_decoder_config_payload_t param_id_lc3_decoder_config_payload_t; + + + +/*============================================================================== + Module +==============================================================================*/ + + +/** @h2xml_title1 {LC3 Decoder} + @h2xml_title_agile_rev {LC3 Decoder} + @h2xml_title_date {November 27th, 2020} +*/ +#define MODULE_ID_LC3_DEC 0x070010C2 +/** + @h2xmlm_module {"MODULE_ID_LC3_DEC", MODULE_ID_LC3_DEC} + @h2xmlm_displayName {"LC3 1.0 Decoder"} + @h2xmlm_description {This module is used as the decoder for LC3 use cases.\n + - This module has only one input and one output port.\n + - The input media format is Deinterleaved Raw Compressed\n + - This module should be used in the same subgraph as the CoPv2 Depacketizer\n + - Supports following params:\n + -- PARAM_ID_LC3_DEC_INIT \n + - Supported Input Media Format:\n + -- Data Format : CAPI_V2_DEINTERLEAVED_RAW_COMPRESSED\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 48,44.1, 32, 24, 16, 8 \n + -- Number of channels : 1, 2\n + -- Bit Width : 16\n + -- Bits Per Sample : 32\n + -- Q format : Q31\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- maximum bit rates in bps:\n + -- mono : depends on selected LC3 frame duration and sample rate \n + -- stereo : depends on selected LC3 frame duration and sample rate \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {lc3_config_t} + @h2xmlm_InsertParameter + @h2xml_Select {stream_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_lc3_decoder_config_payload_t} + @h2xmlm_InsertParameter + @} <-- End of the Module --> + +*/ + +#endif //_LC3_DECODER_API_H_ diff --git a/spf/api/modules/lc3_encoder_api.h b/spf/api/modules/lc3_encoder_api.h new file mode 100644 index 0000000..fe56a0f --- /dev/null +++ b/spf/api/modules/lc3_encoder_api.h @@ -0,0 +1,144 @@ +/*============================================================================== + @file lc3_encoder_api.h + @brief This file contains LC3 1.0 encoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _LC3_ENCODER_API_H_ +#define _LC3_ENCODER_API_H_ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "imcl_spm_intent_api.h" +#include "lc3_decoder_api.h" + +/* Control port for receiving br info*/ +#define COP_ENCODER_FEEDBACK_IN AR_NON_GUID(0xC0000001) + + +/*============================================================================== + Parameters +==============================================================================*/ + +/** ID of the LC3 Enc_Init parameter.This parameter should be set at init time, but not run time.*/ +#define PARAM_ID_LC3_ENC_INIT 0x0800118B + +/** @h2xmlp_parameter {"PARAM_ID_LC3_ENC_INIT", PARAM_ID_LC3_ENC_INIT} + @h2xmlp_description { Configures the parameters of the LC3 Encoder after the module has been instantiated. } + @h2xmlx_expandStructs {false} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_lc3_encoder_config_payload_t +{ + lc3_config_t toAirConfig; + + uint32_t stream_map_size; + /**< @h2xmle_description {The size - in triplets - of the stream map Encoderntity(s) that follows this element. Each stream map entity has 3 elements - audio location, stream-id, and direction} + @h2xmle_range {1..2} + @h2xmle_default {1} + */ + + stream_map_t streamMapOut[0]; +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_lc3_encoder_config_payload_t param_id_lc3_encoder_config_payload_t; + + +/*============================================================================== + Parameters +==============================================================================*/ + +/** ID of the LC3 encoder downmix to mono parameter.This parameter can be set at run time.*/ +#define PARAM_ID_LC3_ENC_DOWNMIX_2_MONO 0x0800118C +/* Structure payload for: PARAM_ID_LC3_ENC_DOWNMIX_2_MONO*/ +/** @h2xmlp_parameter {"PARAM_ID_LC3_ENC_DOWNMIX_2_MONO", PARAM_ID_LC3_ENC_DOWNMIX_2_MONO} + @h2xmlp_description {- Switches the input PCM for LC3 Encoder to be either normal stereo, or (L+R/2) mix to both L and R channels. \n + - Permissible values are: \n + - 1 = transition from stereo to L+R/2 mono with CVR fade. \n + - 2 = transition from L+R/2 mono to stereo with CVR fade. \n + - payload values outside these valid values are rejected with EBADPARAM return code.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_lc3_encoder_switch_enc_pcm_input_payload_t +{ + int32_t transition_direction; + /**< @h2xmle_description {Switches input PCM to be either normal stereo, or (L+R/2) mix to both L and R channels} + @h2xmle_rangeList {"transition from stereo to L+R/2 mono with CVR fade" = 1; + "transition from L+R/2 mono to stereo with CVR fade" = 2} + @h2xmle_default {1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_lc3_encoder_switch_enc_pcm_input_payload_t param_id_lc3_encoder_switch_enc_pcm_input_payload_t; + + + +/*============================================================================== + Module +==============================================================================*/ + + +/** @h2xml_title1 {LC3 Encoder} + @h2xml_title_agile_rev {LC3 Encoder} + @h2xml_title_date {November 4th, 2020} +*/ +#define MODULE_ID_LC3_ENC 0x07001085 +/** + @h2xmlm_module {"MODULE_ID_LC3_ENC", MODULE_ID_LC3_ENC} + @h2xmlm_displayName {"LC3 1.0 Encoder"} + @h2xmlm_description {This module encodes 24-bit PCM audio into LC3-encoded stream(s)\n + - The output media format is Deinterleaved Raw Compressed\n + - This module should be used in the same subgraph as the CoPv2 Packetizer\n + - Required container capabilities : APM_CONTAINER_CAP_ID_CD\n + - Supports following mandatory params:\n + -- PARAM_ID_LC3_ENC_INIT - configures the LC3 Encoder parameters\n + -- Supports following optional params:\n + -- PARAM_ID_LC3_ENC_DOWNMIX_2_MONO - downmixes stereo PCM_BIG_ENDIAN input to mono before encoding\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 48, 44.1, 32, 24, 16, 8 \n + -- Number of channels : 1, 2\n + -- PCM Bits Per Sample : 24\n + -- input PCM Q format : Q31\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- mono : depends on selected LC3 frame duration and sample rate \n + -- stereo : depends on selected LC3 frame duration and sample rate \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_ctrlStaticPort {"COP_ENCODER_FEEDBACK_IN" = 0xC0000001, + "Bit rate level encoder feedback intent" = INTENT_ID_BT_ENCODER_FEEDBACK} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {lc3_config_t} + @h2xmlm_InsertParameter + @h2xml_Select {stream_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_lc3_encoder_config_payload_t} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_lc3_encoder_switch_enc_pcm_input_payload_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> + +*/ + +#endif //_LC3_ENCODER_API_H_ + diff --git a/spf/api/modules/ldac_encoder_api.h b/spf/api/modules/ldac_encoder_api.h new file mode 100644 index 0000000..1501b54 --- /dev/null +++ b/spf/api/modules/ldac_encoder_api.h @@ -0,0 +1,168 @@ +#ifndef _LDAC_ENCODER_API_H_ +#define _LDAC_ENCODER_API_H_ +/*============================================================================== + @file aac_encoder_api.h + @brief This file contains LDAC encoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" +#include "imcl_fwk_intent_api.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of LDAC module */ +#define LDAC_ENC_DATA_INPUT_PORT 0x2 + +/* Output port ID of LDAC module */ +#define LDAC_ENC_DATA_OUTPUT_PORT 0x1 + +/* Stack size of LDAC module */ +#define LDAC_ENC_MODULE_STACK_SIZE 8192 + +/* Control port for receiving br info*/ +#define COP_ENCODER_FEEDBACK_IN AR_NON_GUID(0xC0000001) +/*============================================================================== + Parameters +==============================================================================*/ +/** ID of the encoder Bit Rate level map parameter.This parameter can be set at run time.*/ +#define PARAM_ID_LDAC_BIT_RATE_LEVEL_MAP 0x08001171 +/* Structure payload for: PARAM_ID_LDAC_BIT_RATE_LEVEL_MAP*/ +/** @h2xmlp_parameter {"PARAM_ID_LDAC_BIT_RATE_LEVEL_MAP", PARAM_ID_LDAC_BIT_RATE_LEVEL_MAP} + @h2xmlp_description {- Configures the table which maps each bitrate level received to the actual bitrate value \n + -> Quality levels are always in ascending order of bit rate + - (even if we add a new level at the bottom in the future) \n + - i.e. a lower quality level always refers to a lower bit rate \n + -> For a given bit rate level, the encoder will never encode at a + - bit rate higher than that defined by the corresponding mapping \n + -> The mapping table can be sent multiple times on the fly and each time, + - the new table received will be cached and used to set the bitrate for the next frame.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +struct bitrate_level_map_t +{ + uint32_t level; + /**< @h2xmle_description {Index of each quality level, since maximum levels supported is 7 this index ranges from 0 to 7} + @h2xmle_range {0..7} + @h2xmle_default {0} + */ + uint32_t bitrate; + /**< @h2xmle_description {Bit-rate values supported by ldac encoder} + @h2xmle_rangeList {"BIT_RATE_909000" = 909000; + "BIT_RATE_606000" = 606000; + "BIT_RATE_452000" = 452000; + "BIT_RATE_363000" = 363000; + "BIT_RATE_303000" = 303000; + "BIT_RATE_990000" = 990000; + "BIT_RATE_660000" = 660000; + "BIT_RATE_492000" = 492000; + "BIT_RATE_396000" = 396000; + "BIT_RATE_330000" = 330000} + @h2xmle_default {330000} + */ +} +#include "spf_end_pack.h" +; + +typedef struct bitrate_level_map_t bitrate_level_map_t; + +#include "spf_begin_pack.h" +struct param_id_ldac_bitrate_level_map_payload_t +{ + uint32_t num_levels; + /**< @h2xmle_description {Number of bitrate quality levels} + @h2xmle_range {0..7} + @h2xmle_default {0} + */ +#if 0 + bitrate_level_map_t br_lev_tbl[num_levels]; +#endif +} +#include "spf_end_pack.h" +; + +typedef struct param_id_ldac_bitrate_level_map_payload_t param_id_ldac_bitrate_level_map_payload_t; + +/*============================================================================== + Module +==============================================================================*/ +/** @h2xml_title1 {LDAC Encoder Module API} + @h2xml_title_agile_rev {LDAC Encoder Module API} + @h2xml_title_date {July 15, 2019} */ + +/** + * Module ID for LDAC encoder. + * Encodes to data of format-id = MEDIA_FMT_ID_LDAC + */ +#define MODULE_ID_LDAC_ENC 0x0700107A + +/** + @h2xmlm_module {"MODULE_ID_LDAC_ENC", MODULE_ID_LDAC_ENC} + @h2xmlm_displayName {"LDAC Encoder"} + @h2xmlm_description {This module is used as the encoder for LDAC use cases.\n + - This module has only one input and one output port.\n + - Encodes data to format-id = MEDIA_FMT_ID_LDAC\n + - Supports following params:\n + -- PARAM_ID_ENC_OUTPUT_CONFIG + -- PARAM_ID_ENC_BITRATE\n + -- PARAM_ID_BIT_RATE_LEVEL_MAP\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates and corresponding bitrates: \n + -- For sampling rates = 44.1KHz, 88.2KHz: + -- bit rates: 909, 606, 452, 363, 303 Kbps + -- For sampling rates = 48KHz, 96KHz: + -- bit rates: 990, 660, 492, 396, 330 Kbps + -- Number of channels : 1, 2\n + -- Bit Width : 16, 24, 32\n + -- Bits Per Sample : 16, 24, 32\n + -- Q format : Q15, Q23, Q31\n + -- Interleaving : interleaved\n} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN=LDAC_ENC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=LDAC_ENC_DATA_OUTPUT_PORT} + @h2xmlm_ctrlStaticPort {"COP_ENCODER_FEEDBACK_IN" = 0xC0000001, + "Bit rate level encoder feedback intent" = INTENT_ID_BT_ENCODER_FEEDBACK} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {LDAC_ENC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + + @h2xml_Select {"param_id_enc_bitrate_param_t"} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_enc_bitrate_param_t::bitrate} + @h2xmle_rangeList {"990000"= 990000; + "909000"= 909000; + "660000"= 660000; + "606000"= 606000; + "492000"= 492000; + "452000"= 452000; + "396000"= 396000; + "363000"= 363000; + "330000"= 330000; + "303000"= 303000} + @h2xmle_default {330000} + @h2xml_Select {"param_id_ldac_bitrate_level_map_payload_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_encoder_output_config_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"ldac_enc_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> +*/ + +#endif //_LDAC_ENCODER_API_H_ diff --git a/spf/api/modules/lpass_core_api.h b/spf/api/modules/lpass_core_api.h new file mode 100644 index 0000000..db6622e --- /dev/null +++ b/spf/api/modules/lpass_core_api.h @@ -0,0 +1,21 @@ +#ifndef _LPASS_CORE_API_H_ +#define _LPASS_CORE_API_H_ +/** + * \file lpass_core_api.h + * \brief + * This file contains lpass core api + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + Param ID for lpass core + This ID should only be used under PRM module instance +*/ + + +#define PARAM_ID_RSC_LPASS_CORE 0x0800102B + +#endif /* _LPASS_CORE_API_H_ */ diff --git a/spf/api/modules/mailbox_api.h b/spf/api/modules/mailbox_api.h new file mode 100644 index 0000000..02ec9cd --- /dev/null +++ b/spf/api/modules/mailbox_api.h @@ -0,0 +1,432 @@ +/** + * \file mailbox_api.h + * \brief + * This file contains CAPI Mailbox rx and tx module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _MAILBOX_API_H_ +#define _MAILBOX_API_H_ + + /** + @h2xml_title1 {Module Mailbox rx and tx} + @h2xml_title_agile_rev {Module Mailbox rx and tx} + @h2xml_title_date {June 9, 2019} + */ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "apm_graph_properties.h" +#include "imcl_fwk_intent_api.h" +#include "imcl_spm_intent_api.h" + +#define MAILBOX_TX_MAX_INPUT_PORTS 0x1 + +#define MAILBOX_TX_MAX_OUTPUT_PORTS 0x0 + +#define MAILBOX_TX_STACK_SIZE_REQUIREMENT 4096 + +#define MAILBOX_RX_MAX_INPUT_PORTS 0x0 + +#define MAILBOX_RX_MAX_OUTPUT_PORTS 0x1 + +#define MAILBOX_RX_STACK_SIZE_REQUIREMENT 4096 + +/** + @h2xmlx_xmlNumberFormat {int} +*/ + +/*============================================================================== + Static Control port ID +==============================================================================*/ + +/* static control port id connected to DTMF generator module */ +#define MAILBOX_RX_DTMF_GEN_STATIC_CONTROL_PORT_ID AR_NON_GUID(0xC0000001) + +/*************************************************** DTMF media format *************************************************/ +/** + * Media format ID for DTMF tone and the payload. + */ +#define MEDIA_FMT_ID_DTMF 0x09001038 + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** + * Payload of fmt-id = MEDIA_FMT_ID_DTMF + */ +struct payload_media_fmt_dtmf_tone_t +{ + uint16_t low_freq; + /**< @h2xmle_description {DTMF Tone low frequency in Hz} + @h2xmle_default {697} + @h2xmle_rangeList {0=697, 1=770, 2=852, 3=941} + @h2xmle_policy {Basic} */ + + uint16_t high_freq; + /**< @h2xmle_description {DTMF Tone high frequency in Hz} + @h2xmle_default {1209} + @h2xmle_rangeList {0=1209, 1=1336, 2=1477, 3=1633} + @h2xmle_policy {Basic} */ + + uint32_t duration_ms; + /**< @h2xmle_description {Duration of the tone in milliseconds. The duration includes + ramp-up and ramp-down periods of 1 ms and 2 ms, respectively. + -1 - Infinite or Continuous tone mode, tone is played until stop is received. + 0 - Stops the current tone, + >0 - tone is generated for the given duration (milli secs) } + @h2xmle_default {0} + @h2xmle_range {0...0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint16_t gain; + /**< @h2xmle_description {DTMF tone linear gain. Because the level of tone generation is fixed + at 0 dBFS, this parameter must be set to a value in Q13 format.} + @h2xmle_default {8192} + @h2xmle_dataFormat {Q13} + @h2xmle_policy {Basic} */ + + uint16_t generate_unmixed_output; + /**< @h2xmle_description { Flag to inidicate if the generated DTMF tone needs to be mixed or not. + >0 - Indicates only tone must be played + 0 - Indicates tone needs to be mixed with primary path. } + @h2xmle_default {0} + @h2xmle_range {0,1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct payload_media_fmt_dtmf_tone_t payload_media_fmt_dtmf_tone_t; + + +/*============================================================================== + Events +==============================================================================*/ + +/*Event sent from Mailbox(ADSP) to VS(Modem) indicating that + packet is having a NO_DATA frame. +*/ +#define MAILBOX_PKTEXG_EVT_NO_DATA_PACKET 0x08001257 + +/*============================================================================== + Param ID +==============================================================================*/ + +/* Parameter id to be used to configuration info for mailbox module. + + Before issuing this set-param, APM_CMD_SHARED_MEM_MAP_REGIONS must be + issued and memory corresponding to mailbox circular buffer must be mapped. + + */ +#define PARAM_ID_MAILBOX_CFG 0x080010DF + +/*============================================================================== + Param structure defintions +==============================================================================*/ + +#include "spf_begin_pack.h" +typedef struct mailbox_config_t mailbox_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_MAILBOX_CFG", PARAM_ID_MAILBOX_CFG} + @h2xmlp_description {Parameter id to be used to configure + shared mem info for mailbox + configuration. + Before issuing this set-param, + APM_CMD_SHARED_MEM_MAP_REGIONS must be + issued and memory for the circular + buffer must be mapped. } + @h2xmlp_toolPolicy {NO_SUPPORT} */ +struct mailbox_config_t +{ + uint32_t mem_handle; + /**< @h2xmle_description {Unique identifier for the shared memory address of the mailbox vocoder + packet exchange data. + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t circ_buf_mem_address_lsw; + /**< @h2xmle_description {Lower 32 bits of the address of the circular buffer used to hold vocoding + requests. } + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t circ_buf_mem_address_msw; + /**< @h2xmle_description {Upper 32 bits of the address of the circular buffer used to hold vocoding + requests. } + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t circ_buf_mem_size; + /**< @h2xmle_description {Size of the memory(in bytes) allocated for the circular buffer. + The amount of memory available to hold vocoding requests must be an + integer multiple of the size of a single vocoding request data structure.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pack.h" +; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct mailbox_voc_packet_t mailbox_voc_packet_t; + +struct mailbox_voc_packet_t +{ + uint32_t minor_version; + /**< @h2xmle_description {Minor version of the vocoder packet.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFF } + @h2xmle_policy {Basic} */ + + uint64_t timestamp_us; + /**< @h2xmle_description {Capture timestamp at microphone in microseconds. + The clock source used for interpreting the timestamp is specific + per product requirements.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t status_mask; + /**< @h2xmle_description {Bitmask that indicates the vocoder packet status. + - if bit 0 is set -- Indicates a general vocoding error, informing + that the packet has been dropped. The data_size set to 0. + - bits 1 to 31 are Reserved.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t media_fmt_id; + /**< @h2xmle_description {Media format ID of the vocoder packet.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t data_size; + /**< @h2xmle_description {Actual size of the vocoder media data, in bytes.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ +#if defined(__H2XML__) + uint8_t data[0]; + /**< Vocoder media data of size data_size. */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +#include "spf_begin_pack.h" +typedef struct mailbox_voc_request_t mailbox_voc_request_t; + +/** + @h2xmlp_description {Structure for specifying an vocoding request. + An encoding request allows the client to specify the + timestamp of when an encoder packet is to be delivered + into shared memory. The client ensures + that the vocoding request is available + in shared memory at least 5 + milliseconds before the requested + timestamp. The client is to provide the + next vocoding request immediately after + picking up an vocoder packet. + If the difference in timestamp values between two adjacent vocoding requests + is not exactly an vocoder packet duration in microseconds, a skew occurs + between the client timeline and stream timeline.} +*/ +struct mailbox_voc_request_t +{ + uint32_t mem_address_lsw; + /**< @h2xmle_description {Lower 32 bits shared memory address of the vocoder packet.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t mem_address_msw; + /**< @h2xmle_description {Upper 32 bits of shared memory address of the vocoder packet.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t mem_size; + /**< @h2xmle_description {Size of the memory allocated for the vocoder packet. + The amount of memory allocated must be sufficient to hold the + largest possible vocoder packet for the media ID currently configured on the stream.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/* Type definition for mailbox_voc_req_circ_buffer_t. */ +typedef struct mailbox_voc_req_circ_buffer_t mailbox_voc_req_circ_buffer_t; + +/**< @h2xmle_description{Structure for specifying the format of a circular buffer that holds + vocoding requests. + + Each time a vocoding request is written into data[], the write offset is + advanced by the size of the request. After each vocoding request is read from + data[], the read offset is advanced by the size of the request. Any request + written into data[] is not modified before it is read. + + The read offset and write offset reset to 0 when they reach the end of + data[]. + + The data[] array is empty when the read offset and write offset are equal. + It is full when space is available to hold only one vocoding request. The + client does not write a new vocoding request when data[] is full. + + The client shall provide a separate circular buffer + (mailbox_voc_req_circ_buffer_t) for each direction of the + stream subgraph. The circular buffer is used to hold the client's vocoding requests. + + Mailbox circular buffer can be reclaimed by the client only after the + following: + - The client has successfully destroyed the Voice stream subgraph. + + Making a mailbox vocoding request: + - The client places the request inside the corresponding circular buffer. + - The client advances the circular buffer's write offset by the size of + the request. + - When the mailbox module honors a vocoding request, it advances the circular + buffer's read offset by the size of the request. + - When mailbox module is running, the client can reclaim the vocoder packet + associated with the vocoding request only after the request is + completed.} */ +struct mailbox_voc_req_circ_buffer_t +{ + uint32_t read_offset; + /**< @h2xmle_description {Offset in bytes from the beginning of data[] where the next vocoding + request is read.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint8_t padding_1[ 252 ]; + /**< @h2xmle_description {Padding for cache line alignment. The content in the padding is + ignored.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint32_t write_offset; + /**< @h2xmle_description {Offset in bytes from the beginning of data[] where the next vocoding + request is written.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ + + uint8_t padding_2[ 252 ]; + /**< @h2xmle_description {Padding for cache line alignment. The content in the padding is + ignored.} + @h2xmle_default {0} + @h2xmle_range { 0..0xFFFFFFFF } + @h2xmle_policy {Basic} */ +#if defined(__H2XML__) + uint8_t data[0]; /**< Circular buffer data. */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Module defintions +==============================================================================*/ + +/* + * ID of the Mailbox Rx Module + * + * Supported Input Media Format: + * - Data Format : RAW_COMPRESSED. + * - fmt_id : Don't care. + * - Sample Rates : 8kHz, 16kHz, 32kHz, 48kHz. + * - Number of channels : 1 + * - Bit Width : 16 (bits per sample 16 and Q15), + * : 24 (bits per sample 24 and Q23, bits per sample 32 and Q23 or Q27 or Q31), + * : 32 (bits per sample 32 and Q31) + * - Interleaving : interleaved, deinterleaved unpacked, deinterleaved packed. + * - Endianess : little, big + */ +#define MODULE_ID_MAILBOX_RX 0x07001057 +/** + @h2xmlm_module {"MODULE_ID_MAILBOX_RX", + MODULE_ID_MAILBOX_RX} + @h2xmlm_displayName {"Mailbox EndPoint - Downlink"} + @h2xmlm_description { + This module is used to write data to + spf from the client through + mailbox circular buffer mechanism. + } + @h2xmlm_dataMaxInputPorts {MAILBOX_RX_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {MAILBOX_RX_MAX_OUTPUT_PORTS} + @h2xmlm_ctrlStaticPort {"DTMF_GEN_CTRL" = 0xC0000001, + "DTMF generator ctrl" = INTENT_ID_DTMF_GENERATOR_CTRL} + @h2xmlm_ctrlDynamicPortIntent { "VFR drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= 1 } + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { + MAILBOX_RX_STACK_SIZE_REQUIREMENT + } + @h2xmlm_toolPolicy {Calibration} + + @{ <-- Start of the Module --> + @h2xml_Select {"mailbox_config_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +/* + * ID of the Mailbox Tx Module + * + * Supported Input Media Format: + * - Data Format : RAW_COMPRESSED. + * - fmt_id : Don't care. + * - Sample Rates : 8kHz, 16kHz, 32kHz, 48kHz. + * - Number of channels : 1 + * - Bit Width : 16 (bits per sample 16 and Q15), + * : 24 (bits per sample 24 and Q23, bits per sample 32 and Q23 or Q27 or Q31), + * : 32 (bits per sample 32 and Q31) + * - Interleaving : interleaved, deinterleaved unpacked, deinterleaved packed. + * - Endianess : little, big + */ +#define MODULE_ID_MAILBOX_TX 0x07001056 +/** + @h2xmlm_module {"MODULE_ID_MAILBOX_TX", + MODULE_ID_MAILBOX_TX} + @h2xmlm_displayName {"Mailbox EndPoint - Uplink"} + @h2xmlm_description { + This module is used to read data + from spf to the Client through + shared circular buffer mechanism. + } + @h2xmlm_dataMaxInputPorts {MAILBOX_TX_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {MAILBOX_TX_MAX_OUTPUT_PORTS} + @h2xmlm_ctrlDynamicPortIntent { "VFR drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= 1 } + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_stackSize {MAILBOX_TX_STACK_SIZE_REQUIREMENT} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"mailbox_config_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif // _MAILBOX_API_H_ diff --git a/spf/api/modules/media_fmt_api.h b/spf/api/modules/media_fmt_api.h new file mode 100644 index 0000000..9e9bbf7 --- /dev/null +++ b/spf/api/modules/media_fmt_api.h @@ -0,0 +1,18 @@ +#ifndef MEDIA_FMT_API_H +#define MEDIA_FMT_API_H +/** + * \file media_fmt_api.h + * \brief + * This file contains media format IDs and definitions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "media_fmt_api_basic.h" +#include "media_fmt_api_ext.h" + + +#endif /* MEDIA_FMT_API_H */ diff --git a/spf/api/modules/media_fmt_api_basic.h b/spf/api/modules/media_fmt_api_basic.h new file mode 100644 index 0000000..c12c4f2 --- /dev/null +++ b/spf/api/modules/media_fmt_api_basic.h @@ -0,0 +1,939 @@ +#ifndef MEDIA_FMT_API_BASIC_H +#define MEDIA_FMT_API_BASIC_H +/** + * \file media_fmt_api_basic.h + * \brief + * This file contains media format IDs and definitions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "media_fmt_api_ext.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/*# @h2xml_title1 {Media Format APIs} + @h2xml_title_agile_rev {Media Format APIs} + @h2xml_title_date {August 13, 2018} */ + +/*# @h2xmlx_xmlNumberFormat {int} */ + + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for infinity. */ +#define INFINITE -1 + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for an invalid value. */ +#define INVALID_VALUE 0 + + +/*********************************************** Channel Map Values ***************************************************/ +/** @ingroup ar_spf_mod_media_fmt_ids + Channel map values. +*/ +enum pcm_channel_map +{ + PCM_CHANNEL_L = 1, /**< Front left channel. */ + PCM_CHANNEL_R = 2, /**< Front right channel. */ + PCM_CHANNEL_C = 3, /**< Front center channel. */ + PCM_CHANNEL_LS = 4, /**< Left surround channel. */ + PCM_CHANNEL_RS = 5, /**< Right surround channel. */ + PCM_CHANNEL_LFE = 6, /**< Low frequency effect channel. */ + PCM_CHANNEL_CS = 7, /**< Center surround channel; rear + center channel. */ + PCM_CHANNEL_CB = PCM_CHANNEL_CS, /**< Center back channel. */ + PCM_CHANNEL_LB = 8, /**< Left back channel; rear left + channel. */ + PCM_CHANNEL_RB = 9, /**< Right back channel; rear right + channel. */ + PCM_CHANNEL_TS = 10, /**< Top surround channel. */ + PCM_CHANNEL_CVH = 11, /**< Center vertical height channel. */ + PCM_CHANNEL_TFC = PCM_CHANNEL_CVH, /**< Top front center channel. */ + PCM_CHANNEL_MS = 12, /**< Mono surround channel. */ + PCM_CHANNEL_FLC = 13, /**< Front left of center channel. */ + PCM_CHANNEL_FRC = 14, /**< Front right of center channel. */ + PCM_CHANNEL_RLC = 15, /**< Rear left of center channel. */ + PCM_CHANNEL_RRC = 16, /**< Rear right of center channel. */ + PCM_CHANNEL_LFE2 = 17, /**< Secondary low frequency effect + channel. */ + PCM_CHANNEL_SL = 18, /**< Side left channel. */ + PCM_CHANNEL_SR = 19, /**< Side right channel. */ + PCM_CHANNEL_TFL = 20, /**< Top front left channel. */ + PCM_CHANNEL_LVH = PCM_CHANNEL_TFL, /**< Left vertical height channel. */ + PCM_CHANNEL_TFR = 21, /**< Top front right channel. */ + PCM_CHANNEL_RVH = PCM_CHANNEL_TFR, /**< Right vertical height channel. */ + PCM_CHANNEL_TC = 22, /**< Top center channel. */ + PCM_CHANNEL_TBL = 23, /**< Top back left channel. */ + PCM_CHANNEL_TBR = 24, /**< Top back right channel. */ + PCM_CHANNEL_TSL = 25, /**< Top side left channel. */ + PCM_CHANNEL_TSR = 26, /**< Top side right channel. */ + PCM_CHANNEL_TBC = 27, /**< Top back center channel. */ + PCM_CHANNEL_BFC = 28, /**< Bottom front center channel. */ + PCM_CHANNEL_BFL = 29, /**< Bottom front left channel. */ + PCM_CHANNEL_BFR = 30, /**< Bottom front right channel. */ + PCM_CHANNEL_LW = 31, /**< Left wide channel. */ + PCM_CHANNEL_RW = 32, /**< Right wide channel. */ + PCM_CHANNEL_LSD = 33, /**< Left side direct channel. */ + PCM_CHANNEL_RSD = 34, /**< Right side direct channel. */ + + /* Channel map 48 to 63 are reserved for custom channel maps */ + PCM_CUSTOM_CHANNEL_MAP_1 = 48, /**< Custom channel map 48 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_2 = 49, /**< Custom channel map 49 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_3 = 50, /**< Custom channel map 50 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_4 = 51, /**< Custom channel map 51 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_5 = 52, /**< Custom channel map 52 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_6 = 53, /**< Custom channel map 53 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_7 = 54, /**< Custom channel map 54 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_8 = 55, /**< Custom channel map 55 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_9 = 56, /**< Custom channel map 56 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_10 = 57, /**< Custom channel map 57 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_11 = 58, /**< Custom channel map 58 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_12 = 59, /**< Custom channel map 59 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_13 = 60, /**< Custom channel map 60 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_14 = 61, /**< Custom channel map 61 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_15 = 62, /**< Custom channel map 62 is reserved. */ + PCM_CUSTOM_CHANNEL_MAP_16 = 63, /**< Custom channel map 63 is reserved. */ + + PCM_MAX_CHANNEL_MAP = 63 /**< Last item in the list. */ +}; + + +/*********************************************** Bits Per Sample Values *********************************************** */ + +/** @ingroup ar_spf_mod_media_fmt_ids + Sixteen bits per sample (= sample word size). */ +#define BITS_PER_SAMPLE_16 16 + +/** @ingroup ar_spf_mod_media_fmt_ids + Twenty-four bits per sample (= sample word size). */ +#define BITS_PER_SAMPLE_24 24 + +/** @ingroup ar_spf_mod_media_fmt_ids + Thirty-two bits per sample (= sample word size). */ +#define BITS_PER_SAMPLE_32 32 + + +/********************************************** Bytes Per Sample Values ************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Two bytes per sample. */ +#define BYTES_PER_SAMPLE_TWO 2 + +/** @ingroup ar_spf_mod_media_fmt_ids + Three bytes per sample. */ +#define BYTES_PER_SAMPLE_THREE 3 + +/** @ingroup ar_spf_mod_media_fmt_ids + Four bytes per sample. */ +#define BYTES_PER_SAMPLE_FOUR 4 + + +/********************************************** Bit Width Values ****************************************************** */ + +/** @ingroup ar_spf_mod_media_fmt_ids + Sample has a bit width of 16 (the actual width of the sample in a word). */ +#define BIT_WIDTH_16 16 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sample has a bit width of 24 (the actual width of the sample in a word). */ +#define BIT_WIDTH_24 24 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sample has a bit width of 32 (the actual width of the sample in a word). */ +#define BIT_WIDTH_32 32 + + +/********************************************** Alignment Values ******************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for LSB alignment. */ +#define PCM_LSB_ALIGNED 1 + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for MSB alignment. */ +#define PCM_MSB_ALIGNED 2 + + +/********************************************** Q Factor Values *******************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for the Q15 factor. */ +#define PCM_Q_FACTOR_15 15 + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for the Q23 factor. */ +#define PCM_Q_FACTOR_23 23 + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for the Q27 factor. */ +#define PCM_Q_FACTOR_27 27 + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for the Q31 factor. */ +#define PCM_Q_FACTOR_31 31 + +/** @ingroup ar_spf_mod_media_fmt_ids + Shift factor for Q31 <=> Q28 conversion for 32-bit P. */ +#define PCM_QFORMAT_SHIFT_FACTOR (PCM_Q_FACTOR_31 - PCM_Q_FACTOR_27) + + +/********************************************** Sampling Rates ********************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 8 kHz. */ +#define SAMPLE_RATE_8K 8000 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 11.025 kHz. */ +#define SAMPLE_RATE_11_025K 11025 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 12 kHz. */ +#define SAMPLE_RATE_12K 12000 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 16 kHz. */ +#define SAMPLE_RATE_16K 16000 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 22.05 kHz. */ +#define SAMPLE_RATE_22_05K 22050 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 24 kHz. */ +#define SAMPLE_RATE_24K 24000 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 32 kHz. */ +#define SAMPLE_RATE_32K 32000 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 44.1 kHz. */ +#define SAMPLE_RATE_44_1K 44100 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 48 kHz. */ +#define SAMPLE_RATE_48K 48000 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 88.2 kHz. */ +#define SAMPLE_RATE_88_2K 88200 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 96 kHz. */ +#define SAMPLE_RATE_96K 96000 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 176.4 kHz. */ +#define SAMPLE_RATE_176_4K 176400 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 192 kHz. */ +#define SAMPLE_RATE_192K 192000 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 352.8 kHz. */ +#define SAMPLE_RATE_352_8K 352800 + +/** @ingroup ar_spf_mod_media_fmt_ids + Sampling rate is 384 kHz. */ +#define SAMPLE_RATE_384K 384000 + + +/********************************************** Endianess Values*******************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Byte order is little endian. */ +#define PCM_LITTLE_ENDIAN 1 + +/** @ingroup ar_spf_mod_media_fmt_ids + Byte order is big endian. */ +#define PCM_BIG_ENDIAN 2 + + +/********************************************** Interleaving Values*****************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + PCM data is interleaved. */ +#define PCM_INTERLEAVED 1 + +/** @ingroup ar_spf_mod_media_fmt_ids + PCM data is de-interleaved packed. + + A buffer of maximum size M with C channels and N/C actual bytes per channel + is de-interleaved packed if (M - N) is zero. + */ +#define PCM_DEINTERLEAVED_PACKED 2 + +/** @ingroup ar_spf_mod_media_fmt_ids + PCM data is de-interleaved unpacked. + + A buffer of maximum size M with C channels and N/C actual bytes per channel + is de-interleaved unpacked if (M - N) is nonzero. + + Or, each channel has its own buffers where the actual length is less than + the maximum length. + */ +#define PCM_DEINTERLEAVED_UNPACKED 3 + + +/********************************************** Data Formats **********************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Enumeration for the fixed-point data format. */ +#define DATA_FORMAT_FIXED_POINT 1 + +/** @ingroup ar_spf_mod_media_fmt_ids + Data format is an IEC 61937 packetized stream. + + Like PCM, the data has properties such as sample rate, number of channels, + and bit width. */ +#define DATA_FORMAT_IEC61937_PACKETIZED 2 + +/** @ingroup ar_spf_mod_media_fmt_ids + Data format is IEC 60958 packetized stream for PCM only. + + Like PCM, the data has properties such as sample rate, number of channels, + and bit width. */ +#define DATA_FORMAT_IEC60958_PACKETIZED 3 + +/** @ingroup ar_spf_mod_media_fmt_ids + Data format is a DSD-over-PCM stream. + + Like PCM, the data has properties such as sample rate, number of channels, + and bit width. */ +#define DATA_FORMAT_DSD_OVER_PCM 4 + +/** @ingroup ar_spf_mod_media_fmt_ids + Data format is a generic compressed stream. + + Like PCM, the data has properties such as sample rate, number of channels, + and bit width. */ +#define DATA_FORMAT_GENERIC_COMPRESSED 5 + +/** @ingroup ar_spf_mod_media_fmt_ids + Data format is a Raw compressed stream. + + Like PCM, the data does not have properties such as sample rate, number of + channels, and bit width. */ +#define DATA_FORMAT_RAW_COMPRESSED 6 + +/** @ingroup ar_spf_mod_media_fmt_ids + Compressed bitstreams are packetized like PCM using a QTI-designed + packetizer. */ +#define DATA_FORMAT_COMPR_OVER_PCM_PACKETIZED 7 + +/** @ingroup ar_spf_mod_media_fmt_ids + Data format is an IEC 60958 packetized stream for compressed streams. + + Like PCM, the data has properties such as sample rate, number of channels, + and bit width. */ +#define DATA_FORMAT_IEC60958_PACKETIZED_NON_LINEAR 8 + + +/********************************************** Configuration Modes****************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Value of a configured parameter (like bits_per_sample and num_channels) is + don't care . The module should continue to use the previously set + configuration (or module defaults). + + For example, if the client is to control num_channels from the host but + control bits_per_sample from the ACDB, the ACDB will have the value of -2. + After a graph is opened, the host can issue a command with bits_per_sample + = -2 and num_channels with a proper value. +*/ +#define PARAM_VAL_UNSET (-2) + +/** @ingroup ar_spf_mod_media_fmt_ids + Value of a configured parameter (like bits_per_sample and num_channels) + must follow the input media format that the module will receive or has + received. */ +#define PARAM_VAL_NATIVE (-1) + +/** @ingroup ar_spf_mod_media_fmt_ids + Value of a configured parameter (like bits_per_sample and num_channels) is + considered invalid and the Set parameter command should result in an error. + + This mode is used to detect explicit initialization vs. initialization by + a zero-memory setting. @newpage */ +#define PARAM_VAL_INVALID 0 + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS // for IEC61937 and IEC60958 + +/************************* IEC61937_PACKETIZED and IEC60958_PACKETIZED data format ************************************/ + +/* Payload of data_format = DATA_FORMAT_IEC61937_PACKETIZED or DATA_FORMAT_IEC60958_PACKETIZED + Contains media format information independent of payload for packetized media_fmt_id + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct payload_data_fmt_iec_packetized_t +{ + uint32_t sample_rate; + /*#< @h2xmle_description {Sampling rate of audio stream.} + @h2xmle_default {0} + @h2xmle_rangeList {"44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000} + @h2xmle_policy {Basic} */ + + uint16_t num_channels; + /*#< @h2xmle_description {Number of channels.} + @h2xmle_default {0} + @h2xmle_rangeList {"TWO"=2; + "EIGHT"=8} + @h2xmle_policy {Basic} */ + + uint16_t reserved; + /*#< @h2xmle_description {Used for alignment; must be set to 0.} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct payload_data_fmt_iec_packetized_t payload_data_fmt_iec_packetized_t; + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + + +/************************* GENERIC_COMPRESSED data format ************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Payload structure used when media_format_t::data_format = + #DATA_FORMAT_GENERIC_COMPRESSED. + + This structure contains media format information that is independent of the + payload for the generic compressed media_fmt_id. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct payload_data_fmt_generic_compressed_t +{ + uint32_t sample_rate; + /**< Number of samples per second in the audio stream. + + @values 0 to 384 kHz */ + + /*#< @h2xmle_description {Number of samples per second in the audio stream.} + @h2xmle_default {0} + @h2xmle_rangeList {"8 kHz"=8000; + "11.025 kHz"=11025; + "12 kHz"=12000; + "16 kHz"=16000; + "22.05 kHz"=22050; + "24 kHz"=24000; + "32 kHz"=32000; + "44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000; + "352.8 kHz"=352800; + "384 kHz"=384000} + @h2xmle_policy {Basic} */ + + uint16_t bits_per_sample; + /**< Number of bits required to store one sample. + + @valuesbul + - #INVALID_VALUE (Default) + - #BITS_PER_SAMPLE_16 + - #BITS_PER_SAMPLE_32 @tablebulletend */ + + /*#< @h2xmle_description {Number of bits required to store one sample.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0; + "BITS_PER_SAMPLE_16"=16; + "BITS_PER_SAMPLE_32"=32} + @h2xmle_policy {Basic} */ + + uint16_t num_channels; + /**< Number of channels. + + @values 0 through 32 (Default = 0) */ + + /*#< @h2xmle_description {Number of channels.} + @h2xmle_default {0} + @h2xmle_range {0..32} + @h2xmle_policy {Basic} @newpagetable */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct payload_data_fmt_generic_compressed_t payload_data_fmt_generic_compressed_t; + + +/*************************************************** PCM Media Format *************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Identifier for the media format used to identify a PCM stream. + + Following is the overall payload structure: + + @code + struct complete_media_fmt_pcm_t + { + payload_media_fmt_pcm_t pcm; + uint8_t ch_map[num_channels]; + } + @endcode + + @msgpayload + payload_media_fmt_pcm_t + */ +#define MEDIA_FMT_ID_PCM 0x09001000 + + +/** @ingroup ar_spf_mod_media_fmt_ids + Payload of #MEDIA_FMT_ID_PCM when media_format_t::fmt_id = + #MEDIA_FMT_ID_PCM and data_format = #DATA_FORMAT_FIXED_POINT. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct payload_media_fmt_pcm_t +{ + uint32_t sample_rate; + /**< Number of samples per second in the audio stream. + + @values 0 to 384000 Hz */ + + /*#< @h2xmle_description {Number of samples per second in the audio stream.} + @h2xmle_default {0} + @h2xmle_rangeList {"8 kHz"=8000; + "11.025 kHz"=11025; + "12 kHz"=12000; + "16 kHz"=16000; + "22.05 kHz"=22050; + "24 kHz"=24000; + "32 kHz"=32000; + "44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000; + "352.8 kHz"=352800; + "384 kHz"=384000} + @h2xmle_policy {Basic} */ + + uint16_t bit_width; + /**< Bit width of each sample. + + @valuesbul + - #INVALID_VALUE (Default) + - #BIT_WIDTH_16 + - #BIT_WIDTH_24 + - #BIT_WIDTH_32 @tablebulletend */ + + /*#< @h2xmle_description {Bit width of each sample.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0; + "BIT_WIDTH_16"=16; + "BIT_WIDTH_24"=24; + "BIT_WIDTH_32"=32} + @h2xmle_policy {Basic} */ + + uint8_t alignment; + /**< Alignment of bits_per_sample in sample_word_size. + + This field is relevant only when bits_per_sample = 24 and word_size + = 32. + + @valuesbul + - #INVALID_VALUE (Default) + - #PCM_LSB_ALIGNED + - #PCM_MSB_ALIGNED @tablebulletend */ + + /*#< @h2xmle_description {Alignment of bits_per_sample in sample_word_size. + This field is relevant only when bits_per_sample = + 24 and word_size = 32.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0; + "PCM_LSB_ALIGNED"=1; + "PCM_MSB_ALIGNED"=2} + @h2xmle_policy {Basic} */ + + uint8_t interleaved; + /**< Indicates whether the data is interleaved. + + When the value is invalid, the data is assumed to be interleaved. + + @valuesbul + - #INVALID_VALUE (Default) + - #PCM_INTERLEAVED @tablebulletend */ + + /*#< @h2xmle_description {Indicates whether the data is interleaved. When + the value is invalid, the data is assumed to be + interleaved.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0; + "PCM_INTERLEAVED"=1} + @h2xmle_policy {Basic} */ + + uint16_t bits_per_sample; + /**< Number of bits required to store one sample. + + @valuesbul + - #INVALID_VALUE (Default) + - #BITS_PER_SAMPLE_16 + - #BITS_PER_SAMPLE_24 + - #BITS_PER_SAMPLE_32 + + @tblsubhdbul{For BITS\_PER\_SAMPLE\_32} + - If bit_width = 24 and alignment = LSB aligned, the 24-bit samples are + placed in the lower 24 bits of the 32-bit word. The upper bits might + be sign-extended. + - If bit_width = 24 and alignment = MSB aligned, the 24-bit samples are + placed in the upper 24 bits of the 32-bit word. The lower bits might + be set to 0. + - If bit width = 32, 32-bit samples are placed in the 32-bit words. + @tablebulletend */ + + /*#< @h2xmle_description {Number of bits required to store one sample.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0; + "BITS_PER_SAMPLE_16"=16; + "BITS_PER_SAMPLE_24"=24; + "BITS_PER_SAMPLE_32"=32} + @h2xmle_policy {Basic} */ + + uint16_t q_factor; + /**< Indicates the Q factor of the PCM data: + - Q15 for 16-bit_width signed data. + - Q23 for 24-bit_width signed packed (24-bits_per_sample) data. + - Q27 for LSB-aligned, 24-bit_width unpacked (32-bits_per_sample) + signed data used internally to the SPF. + - Q31 for MSB-aligned, 24-bit_width unpacked (32 bits_per_sample) + signed data. + - Q23 for LSB-aligned, 24-bit_width unpacked (32 bits_per_sample) + signed data. + - Q31 for 32-bit_width signed data@tablebulletend */ + + /*#< @h2xmle_description {Indicates the Q factor of the PCM data: + - Q15 for 16-bit_width signed data + - Q23 for 24-bit_width signed packed + (24-bits_per_sample) data + - Q27 for LSB-aligned, 24-bit_width unpacked + (32-bits_per_sample) signed data used internally + to the SPF + - Q31 for MSB-aligned, 24-bit_width unpacked + (32 bits_per_sample) signed data + - Q23 for LSB-aligned, 24-bit_width unpacked + (32 bits_per_sample) signed data + - Q31 for 32-bit_width signed data} + @h2xmle_default {0} + @h2xmle_rangeList {"PARAM_VAL_INVALID"=0; + "Q15"=15; + "Q23"=23; + "Q27"=27; + "Q31"=31} + @h2xmle_policy {Basic} */ + + uint16_t endianness; + /**< Indicates whether PCM samples are stored in little endian or big endian + format. + + @valuesbul + - #INVALID_VALUE (Default) + - #PCM_LITTLE_ENDIAN + - #PCM_BIG_ENDIAN @tablebulletend */ + + /*#< @h2xmle_description {Indicates whether PCM samples are stored in little + endian or big endian format.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0; + "PCM_LITTLE_ENDIAN"=1; + "PCM_BIG_ENDIAN"=2} + @h2xmle_policy {Basic} */ + + uint16_t num_channels; + /**< Number of channels in the channel_mapping array. + + @values 0 through 32 (Default = 0) */ + + /*#< @h2xmle_description {Number of channels.} + @h2xmle_default {0} + @h2xmle_range {0..32} + @h2xmle_policy {Basic} */ + +#if defined(__H2XML__) + uint8_t channel_mapping[0]; + /**< Array of channel mappings of size num_channels. + + Channel[i] mapping describes channel i. Each element i of the array + describes channel i inside the buffer where i is less than + num_channels. An unused channel is set to 0. @newpagetable */ + + /*#< @h2xmle_description {Channel mapping array of variable size. The + size of this array depends upon number of + channels. Channel[i] mapping describes + channel i. Each element i of the array + describes channel i inside the buffer where i + is less than num_channels. An unused channel + is set to 0.} + h2xmle_variableArraySize {(num_channels*4 + 3) / 4} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ + +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct payload_media_fmt_pcm_t payload_media_fmt_pcm_t; + + +/********************************************** Media Format Parameter ************************************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Identifier for the parameter used to set the media format on any Shared + Memory Endpoint module. + + This parameter ID is set via APM_CMD_SET_CFG (see the AudioReach SPF + API Reference (80-VN500-5)). It is accepted only when the subgraph is + in the Stop or Prepare state. + + @msgpayload + media_format_t + */ +#define PARAM_ID_MEDIA_FORMAT 0x0800100C + +/*# @h2xmlp_parameter {"PARAM_ID_MEDIA_FORMAT", PARAM_ID_MEDIA_FORMAT} + @h2xmlp_toolPolicy {Calibration} + @h2xmlp_description {ID for the parameter used to set the media format on + any Shared Memory Endpoint module. This parameter ID + is set via APM_CMD_SET_CFG (see the AudioReach SPF + API Reference (80-VN500-5)). It is accepted only + when the subgraph is in the Stop or Prepare state.} */ + +/** @ingroup ar_spf_mod_media_fmt_ids + Payload structure used by the following opcodes: + - #PARAM_ID_MEDIA_FORMAT + - #DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT + - #DATA_EVENT_ID_RD_SH_MEM_EP_MEDIA_FORMAT + + Immediately following this structure is a payload_size number of bytes that + represent the actual media format block. + + Following is the overall payload structure: + + @code + media_format_t mf; + uint8_t payload[payload_size]; + @endcode @vertspace{6} + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct media_format_t +{ + uint32_t data_format; + /**< Format of the data. + + @valuesbul + - #INVALID_VALUE (Default) + - #DATA_FORMAT_FIXED_POINT + - #DATA_FORMAT_IEC61937_PACKETIZED + - #DATA_FORMAT_IEC60958_PACKETIZED + - #DATA_FORMAT_DSD_OVER_PCM + - #DATA_FORMAT_GENERIC_COMPRESSED + - #DATA_FORMAT_RAW_COMPRESSED @tablebulletend */ + + /*#< @h2xmle_description {Format of the data.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0, + "DATA_FORMAT_FIXED_POINT"=1, + "DATA_FORMAT_IEC61937_PACKETIZED"=2, + "DATA_FORMAT_IEC60958_PACKETIZED"=3, + "DATA_FORMAT_DSD_OVER_PCM"=4, + "DATA_FORMAT_GENERIC_COMPRESSED"=5, + "DATA_FORMAT_RAW_COMPRESSED"=6} + @h2xmle_policy {Basic} */ + + uint32_t fmt_id; + /**< Media format ID of the data stream. + + @valuesbul + - #INVALID_VALUE (Default) + - #MEDIA_FMT_ID_PCM @tablebulletend */ + + /*#< @h2xmle_description {Media format ID of the data stream.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0, + "Media format ID of PCM"=MEDIA_FMT_ID_PCM} + @h2xmle_policy {Basic} */ + + uint32_t payload_size; + /**< Size of the payload that immediately follows this structure. + + This size does not include bytes added for 32-bit alignment. */ + + /*#< @h2xmle_description {Size of the payload that immediately follows this + structure. This size does not include bytes added + for 32-bit alignment.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + +#if defined(__H2XML__) + uint8_t payload[0]; + /**< Payload for media format configurations. + + The payload structure varies depending on the combination of the + data_format and fmt_id fields and is of size payload_size. For example, + a PCM fixed point (payload_media_fmt_pcm_t) and floating point might + have different payloads. @newpagetable */ + + /*#< @h2xmle_description {Payload for media format configurations. + The payload structure varies depending on + the combination of the data_format and + fmt_id fields and is of size payload_size. + For example, if fmt_id=PARAM_ID_PCM_OUTPUT_FORMAT_CFG + and data_format=DATA_FORMAT_FIXED_POINT, the + payload is of type payload_media_fmt_pcm_t. + The floating point might have a different + payload.} + @h2xmle_policy {Basic} */ + +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct media_format_t media_format_t; + + +/*********************************** Encoder Configuration Block (Encoder Output Config) ******************************/ + +/** @ingroup ar_spf_mod_media_fmt_ids + Identifier for the parameter that configures the encoder. + + Encoding occurs at the incoming sample rate, number of channels, and bit + width. These parameters are controlled by the resamplers, MFC, channel + mixer, or PCM converter. Not all encoders support the encoder output + configuration. + + Following is the overall payload structure: + + @code + { + param_id_encoder_output_config_t cfg; + uint8_t custom_enc_cfg[payload_size]; + uint8_t padding[if_any]; + } + @endcode + + @msgpayload + param_id_encoder_output_config_t @newpage + */ +#define PARAM_ID_ENCODER_OUTPUT_CONFIG 0x08001009 + +/*# @h2xmlp_parameter {"PARAM_ID_ENCODER_OUTPUT_CONFIG", + PARAM_ID_ENCODER_OUTPUT_CONFIG} + @h2xmlp_description {ID for the parameter that configures the encoder. + Encoding occurs at the incoming sample rate, number + of channels, and bit width. These parameters are + controlled by the resamplers, MFC, channel mixer, or + PCM converter. Not all encoders support the encoder + output configuration. + @h2xmlp_toolPolicy {Calibration} */ + + +/** @ingroup ar_spf_mod_media_fmt_ids + Payload of the #PARAM_ID_ENCODER_OUTPUT_CONFIG parameter. +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_encoder_output_config_t +{ + uint32_t data_format; + /**< Format of the output data. + + @valuesbul + - #INVALID_VALUE (Default) + - #DATA_FORMAT_FIXED_POINT @tablebulletend */ + + /*#< @h2xmle_description {Format of the output data.} + @h2xmle_default {0} + @h2xmle_rangeList {"PARAM_VAL_INVALID"=0, + "DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_policy {Basic} */ + + uint32_t fmt_id; + /**< Media format ID for the output data stream. + + For the PCM encoding use case, this value must match the fmt_id in + #PARAM_ID_PCM_OUTPUT_FORMAT_CFG. + + @valuesbul + - #INVALID_VALUE (Default) + - #MEDIA_FMT_ID_PCM @tablebulletend */ + + /*#< @h2xmle_description {Media format ID of the output data stream. + For the PCM encoding use case, this value must + match the fmt_id in + PARAM_ID_PCM_OUTPUT_FORMAT_CFG.} + @h2xmle_default {0} + @h2xmle_rangeList {"INVALID_VALUE"=0, + "Media format ID of PCM"=MEDIA_FMT_ID_PCM} + @h2xmle_policy {Basic} */ + + uint32_t payload_size; + /**< Size of the custom payload that immediately follows this structure. + + This size does not include bytes added for 32-bit alignment. */ + + /*#< @h2xmle_description {Size of the custom payload that immediately + follows this structure. This size does not + include bytes added for 32-bit alignment.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + +#if defined(__H2XML__) + uint8_t payload[0]; + /**< Custom payload for encoder output configuration of size payload_size. + + The payload structure varies depending on the combination of the + data_format and fmt_id fields of size payload_size. For example, a PCM + fixed point (payload_media_fmt_pcm_t) and floating point might have + different payloads. + + The floating point data format might have a different payload. */ + + /*#< @h2xmle_description {Payload for encoder output configuration of + size payload_size. The payload structure + varies depending on the combination of the + data_format and fmt_id fields. For example, + if data_format=#DATA_FORMAT_FIXED_POINT and + fmt_id = #MEDIA_FMT_ID_PCM, the payload is + payload_pcm_output_format_cfg_t. + The floating-point data format might have a + different payload.} + @h2xmle_policy {Basic} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct param_id_encoder_output_config_t param_id_encoder_output_config_t; + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /* MEDIA_FMT_API_BASIC_H */ diff --git a/spf/api/modules/media_fmt_api_ext.h b/spf/api/modules/media_fmt_api_ext.h new file mode 100644 index 0000000..c03204b --- /dev/null +++ b/spf/api/modules/media_fmt_api_ext.h @@ -0,0 +1,1626 @@ +#ifndef MEDIA_FMT_API_EXT_H +#define MEDIA_FMT_API_EXT_H +/** + * \file media_fmt_api.h + * \brief + * This file contains media format IDs and definitions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + * Portions copied from The Apple Lossless Audio Codec (ALAC) ALACMagicCookieDescription.txt, under + * Apache-2.0 license. Not a contribution + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/** @h2xml_title1 {Media Format APIs} + @h2xml_title_agile_rev {Media Format APIs} + @h2xml_title_date {August 13, 2018} */ +/** + @h2xmlx_xmlNumberFormat {int} +*/ + +/********************************************* Vocoder Rates ************************************************/ + +/** Enumerations for various vocoder rates */ + +/** Enumeration for invalid vocoder Rate **/ +#define VOCODER_INVALID_RATE 0 + +/** Enumeration for 1/8 vocoder rate.*/ +#define VOCODER_ONE_EIGHTH_RATE 1 + +/** Enumeration for 1/4 vocoder rate. */ +#define VOCODER_QUARTER_RATE 2 + +/** Enumeration for 1/2 vocoder rate. */ +#define VOCODER_HALF_RATE 3 + +/** Enumeration for full vocoder rate. */ +#define VOCODER_FULL_RATE 4 + +/*************************************************** AAC Media Format *************************************************/ +/** + * Media format ID for AAC, which identifies both MPEG2 and + * MPEG4 AAC formats. + */ +#define MEDIA_FMT_ID_AAC 0x09001001 + +/** Enumeration for the audio data transport stream AAC format. */ +#define AAC_FORMAT_FLAG_ADTS 0 + +/** Enumeration for the low overhead audio stream AAC format. */ +#define AAC_FORMAT_FLAG_LOAS 1 + +/** Enumeration for the audio data interchange format AAC format. */ +#define AAC_FORMAT_FLAG_ADIF 2 + +/** Enumeration for the raw AAC format. */ +#define AAC_FORMAT_FLAG_RAW 3 + +/** Enumeration for the low overhead audio transport multiplex AAC format. */ +#define AAC_FORMAT_FLAG_LATM 4 + +/** Enumeration for the AAC low complexity audio object type: + - When used for aac_fmt_flag in payload_media_fmt_aac_t, this parameter + specifies that the AOT in the AAC stream is LC. + - When used for enc_mode in payload_enc_cfg_aac_t, this parameter specifies + that the Encoding mode to be used is LC. +*/ +#define AAC_AOT_LC 2 + +/** Enumeration for the AAC spectral band replication AOT: + - When used for aac_fmt_flag in payload_media_fmt_aac_t, this parameter + specifies that the AOT in the AAC stream is SBR. + - When used for enc_mode in payload_enc_cfg_aac_t, this parameter specifies + that the Encoding mode to be used is AAC+. +*/ +#define AAC_AOT_SBR 5 + +/** Enumeration for the AAC parametric stereo AOT: + - When used for aac_fmt_flag in payload_media_fmt_aac_t, this parameter + specifies that the AOT in the AAC stream is PS. + - When used for enc_mode in payload_enc_cfg_aac_t, this parameter specifies + that the Encoding mode to be used is eAAC+. +*/ +#define AAC_AOT_PS 29 + +/** Enumeration for the bit-sliced arithmetic coding AOT: + - When used for aac_fmt_flag in payload_media_fmt_aac_t, this parameter + specifies that the AOT in the AAC stream is BSAC. + - This parameter must not be used for enc_mode in + payload_enc_cfg_aac_t. BSAC encoding is not supported. +*/ +#define AAC_AOT_BSAC 22 + +/** AOT=17 is the ER AAC-LC format, which currently is not supported. */ + +typedef struct payload_media_fmt_aac_t payload_media_fmt_aac_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the AAC decoder format block parameters in the + MEDIA_FMT_ID_AAC media format. If the total size of PCE > 0 bits, the PCE information follows the + structure. In this case, the client must pad the additional bits for 32-bit alignment} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct payload_media_fmt_aac_t +{ + uint16_t aac_fmt_flag; + /**< @h2xmle_description {Bit stream format option.} + @h2xmle_rangeList {"AAC_FORMAT_FLAG_ADTS"=0, + "AAC_FORMAT_FLAG_LOAS"=1, + "AAC_FORMAT_FLAG_ADIF"=2, + "AAC_FORMAT_FLAG_RAW"=3, + "AAC_FORMAT_FLAG_LATM"=4} + @h2xmle_policy {Basic} */ + + uint16_t audio_obj_type; + /**< @h2xmle_description {Audio Object Type (AOT) present in the AAC stream.} + @h2xmle_default {AAC_AOT_LC} + @h2xmle_rangeList {"AAC_AOT_LC"=2, + "AAC_AOT_SBR"=5, + "AAC_AOT_BSAC"=22, + "AAC_AOT_PS"=29} + @h2xmle_policy {Basic} */ + + uint16_t num_channels; + /**< @h2xmle_description {Number of channels present in the AAC stream.} + @h2xmle_rangeList {"PCE"=0, + "Mono"=1, + "Stereo"=2, + "5.1 content"=6} + @h2xmle_policy {Basic} */ + + uint16_t total_size_of_PCE_bits; + /**< @h2xmle_description {For RAW formats and if channel_config=0 (PCE), the client can send + the bit stream containing PCE immediately following this structure + (in band) + If this field is set to 0, the PCE information is assumed to be + available in the audio bit stream and not in band. + If this field is greater than 0, the PCE information follows this + structure. Additional bits might be required for 32-bit alignment.} + @h2xmle_range {0...0xFFFF} + @h2xmle_policy {Basic} */ + + uint32_t sample_rate; + /**< @h2xmle_description {Number of samples per second. This field must be equal to the sample + rate of the AAC-LC decoder output. + - For MP4 or 3GP containers, this sample rate is indicated by the + samplingFrequencyIndex field in the AudioSpecificConfig element. + - For ADTS format, this sample rate is indicated by the + samplingFrequencyIndex in the ADTS fixed header. + - For ADIF format, this sample rate is indicated by the + samplingFrequencyIndex in the program_config_element present in the + ADIF header.} + @h2xmle_default {0} + @h2xmle_rangeList {INVALID_VALUE=0, 8000, 11025, 12000, 16000, 22050, 24000, 32000, + 44100, 48000, 64000, 88200, 96000} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +typedef struct aac_enc_cfg_t aac_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the AAC encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct aac_enc_cfg_t +{ + uint16_t enc_mode; + /**< + @h2xmle_description {AAC encoding mode} + @h2xmle_default {AAC_AOT_LC} + @h2xmle_rangeList { "AAC_AOT_LC"=2; + "AAC_AOT_SBR"=5; + "AAC_AOT_PS"=29 } + @h2xmle_policy {Basic} */ + + uint16_t aac_fmt_flag; + /**< + @h2xmle_description {AAC format flag} + @h2xmle_default {AAC_FORMAT_FLAG_ADTS} + @h2xmle_rangeList { "AAC_FORMAT_FLAG_ADTS"=0; + "AAC_FORMAT_FLAG_LOAS"=1; + "AAC_FORMAT_FLAG_RAW" =3; + "AAC_FORMAT_FLAG_LATM"=4 } + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/*************************************************** AC3/EAC3 Media Format ********************************************/ +/** + * Media format ID for AC3 streams + */ +#define MEDIA_FMT_ID_AC3 0x09001018 + +/** + * Media format ID for EAC3 streams + */ +#define MEDIA_FMT_ID_EAC3 0x09001017 + +/*************************************************** DTS Media Format ********************************************/ +#define MEDIA_FMT_ID_DTS 0x09001016 + +/*************************************************** ATRAC Media Format ***********************************************/ +#define MEDIA_FMT_ID_ATRAC 0x09001012 + +/*********************************************** DTHD Media Format ******************************************/ +#define MEDIA_FMT_ID_DTHD 0x09001014 + +/*************************************************** MAT Media Format *************************************************/ +#define MEDIA_FMT_ID_MAT 0x09001015 + +/*************************************************** ALAC Media Format ************************************************/ +/** + * Media format ID for ALAC streams + */ +#define MEDIA_FMT_ID_ALAC 0x09001002 + +typedef struct payload_media_fmt_alac_t payload_media_fmt_alac_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the ALAC decoder format block parameters in the + MEDIA_FMT_ID_ALAC media format} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct payload_media_fmt_alac_t +{ + uint32_t frame_length; + /**< @h2xmle_description {Frames per packet when no explicit frames per packet setting is + present in the packet header. The encoder frames per packet can be explicitly set, but for maximum + compatibility, use the default encoder setting of 4096.} + @h2xmle_policy {Basic} */ + + uint8_t compatible_version; + /**< @h2xmle_description {Specifies the compatible version.} + @h2xmle_rangeList {"0" = 0} + @h2xmle_policy {Basic} */ + + uint8_t bit_depth; + /**< @h2xmle_description {Bit depth of the source PCM data.} + @h2xmle_default {16} + @h2xmle_rangeList {"16" = 16, + "24" = 24} + @h2xmle_policy {Basic} */ + + uint8_t pb; + /**< @h2xmle_description {Tuning parameter. (Currently not used.)} + @h2xmle_rangeList {"40" = 40} + @h2xmle_default {40} + @h2xmle_policy {Basic} */ + + uint8_t mb; + /**< @h2xmle_description {Tuning parameter. (Currently not used.)} + @h2xmle_rangeList {"10" = 10} + @h2xmle_default {10} + @h2xmle_policy {Basic} */ + + uint8_t kb; + /**< @h2xmle_description {Tuning parameter. (Currently not used.)} + @h2xmle_rangeList {"14" = 14} + @h2xmle_default {14} + @h2xmle_policy {Basic} */ + + uint8_t num_channels; + /**< @h2xmle_description {Number of channels for multichannel decoding.} + @h2xmle_rangeList {INVALID_VALUE=0,1...8} + @h2xmle_policy {Basic} */ + + uint16_t max_run; + /**< @h2xmle_description {Currently not used} + @h2xmle_rangeList {"255" = 255} + @h2xmle_default {255} + @h2xmle_policy {Basic} */ + + uint32_t max_frame_bytes; + /**< @h2xmle_description {Maximum size of an Apple Lossless packet within the encoded stream.} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t avg_bit_rate; + /**< @h2xmle_description {Average bit rate in bits per second of the Apple Lossless stream.} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t sample_rate; + /**< @h2xmle_description {Number of samples per second in Hertz.} + @h2xmle_rangeList {INVALID_VALUE=0, "8000"=8000, "11025"=11025, "12000"=12000, + "16000"=16000, "22050"=22050, "24000"=24000, "32000"=32000, + "44100"=44100, "48000"=48000, "64000"=64000, "88200"=88200, + "96000"=96000, "128000"=128000, "176400"=176400, "192000"=192000} + @h2xmle_policy {Basic} */ + + /* following channel layout of the bitstream is defined in ALACAudioTypes.h)*/ + uint32_t channel_layout_tag; + /**< @h2xmle_description {Indicates whether channel layout information is present in the + bit stream.0 means, Channel layout information is not present. + Constants are extracted when channel layout information is present} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +/*************************************************** APE Media Format *************************************************/ +/** + * Media format ID for APE streams + */ +#define MEDIA_FMT_ID_APE 0x09001003 + +typedef struct payload_media_fmt_ape_t payload_media_fmt_ape_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the APE decoder format block parameters in the + MEDIA_FMT_ID_APE media format} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct payload_media_fmt_ape_t +{ + uint16_t version; + /**< @h2xmle_description {Specifies the compatible version.} + @h2xmle_rangeList {"0" = 0} + @h2xmle_policy {Basic} */ + + uint16_t compression_level; + /**< @h2xmle_description {Compression level present in the encoded packet. + The nBlocksPerFrame parameter value is based on the compression level.} + @h2xmle_rangeList {"COMPRESSION_LEVEL_FAST" = 1000, + "COMPRESSION_LEVEL_NORMAL" = 2000, + "COMPRESSION_LEVEL_HIGH" = 3000, + "COMPRESSION_LEVEL_EXTRA_HIGH" = 4000, + "COMPRESSION_LEVEL_INSANE" = 5000, + INVALID_VALUE=0} + @h2xmle_policy {Basic} */ + + uint32_t format_flags; + /**< @h2xmle_description {Reserved for future use.} + @h2xmle_policy {Basic} */ + + uint32_t blocks_per_frame; + /**< @h2xmle_description {Number of audio blocks (channel samples) in one frame present in the + encoded packet header.} + @h2xmle_rangeList {"Any value present in the APE header" = 0} + @h2xmle_policy {Basic} */ + + uint32_t final_frame_blocks; + /**< @h2xmle_description {Number of audio blocks (channel samples) in the final frame present + in the encoded packet header} + @h2xmle_rangeList {"Any value present in the APE header" = 0} + @h2xmle_policy {Basic} */ + + uint32_t total_frames; + /**< @h2xmle_description {Total number of frames.} + @h2xmle_rangeList {"Any value present in the APE header" = 0} + @h2xmle_policy {Basic} */ + + uint16_t bit_width; + /**< @h2xmle_description {Bit width of the source PCM data.} + @h2xmle_default {16} + @h2xmle_rangeList {"16" = 16,"24" = 24} + @h2xmle_policy {Basic} */ + + uint16_t num_channels; + /**< @h2xmle_description {Number of channels for decoding} + @h2xmle_rangeList {"Mono" = 1,"Stereo"= 2,INVALID_VALUE=0} + @h2xmle_policy {Basic} */ + + uint32_t sample_rate; + /**< @h2xmle_description {Number of samples per second.} + @h2xmle_rangeList {INVALID_VALUE=0, "8000"=8000, "11025"=11025, "12000"=12000, + "16000"=16000, "22050"=22050, "24000"=24000, "32000"=32000, + "44100"=44100, "48000"=48000, "64000"=64000, "88200"=88200, + "96000"=96000, "128000"=128000, "176400"=176400, "192000"=192000} + @h2xmle_policy {Basic} */ + + uint32_t is_seek_table_present; + /**< @h2xmle_description {Flag used to indicate the presence of the seek table. This flag is + not part of the APE header.} + @h2xmle_rangeList {"Not present" = 0, + "Present" = 1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/*************************************************** FLAC Media Format ************************************************/ +/** + * Media format ID for FLAC streams + */ +#define MEDIA_FMT_ID_FLAC 0x09001004 + +typedef struct payload_media_fmt_flac_t payload_media_fmt_flac_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the FLAC decoder format block structure parameters in the + MEDIA_FMT_ID_FLAC media format..\n } + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct payload_media_fmt_flac_t +{ + uint16_t num_channels; + /**< @h2xmle_description {Number of channels present in the Flac stream.} + @h2xmle_default {1} + @h2xmle_rangeList {"Mono"=1, + "Stereo"=2} + @h2xmle_policy {Basic} */ + + + uint16_t sample_size; + /**< @h2xmle_description {Bits per sample} + @h2xmle_default {16} + @h2xmle_rangeList {16,24} + @h2xmle_policy {Basic} */ + + uint16_t min_blk_size; + /**< @h2xmle_description {Minimum block size (in samples) used in the stream. + It must be lessthan or equal to max_blk_size.} + @h2xmle_policy {Basic} */ + + uint16_t max_blk_size; + /**< @h2xmle_description {Maximum block size (in samples) used in the stream. + If the minimum block size equals the maximum block size, + a fixed block size stream is implied} + @h2xmle_policy {Basic} */ + + + uint32_t sample_rate; + /**< @h2xmle_description {Supported sampling rates} + @h2xmle_default {0} + @h2xmle_rangeList {INVALID_VALUE=0,0,8000, 11025, 12000, 16000, 22050, 24000, 32000, + 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000} + @h2xmle_policy {Basic} */ + + uint32_t min_frame_size; + /**< @h2xmle_description {Minimum frame size. This should be greater than 0} + @h2xmle_policy {Basic} */ + + uint32_t max_frame_size; + /**< @h2xmle_description {Maximum frame size. This should be greater than 0} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pack.h" +; +/*************************************************** Vorbis Media Format **********************************************/ +/** + * Media format ID for Vorbis streams + */ +#define MEDIA_FMT_ID_VORBIS 0x09001005 + +typedef struct payload_media_fmt_vorbis_t payload_media_fmt_vorbis_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the VORBIS decoder format block structure parameters in the + MEDIA_FMT_ID_VORBIS media format. \n } + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct payload_media_fmt_vorbis_t +{ + uint32_t bit_stream_fmt; + /**< @h2xmle_description {Transcoded bit stream containing the size of the frame + as the first word in each frame.} + @h2xmle_default {1} + @h2xmle_rangeList {"Transcoded Bit Stream"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/*************************************************** WMAPro Media Format **********************************************/ +/** + * Media format ID for the WMAPRO streams. + */ +#define MEDIA_FMT_ID_WMAPRO 0x09001006 + +typedef struct payload_media_fmt_wmapro_t payload_media_fmt_wmapro_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the WMAPRO decoder format block parameters in the + MEDIA_FMT_ID_WMAPRO media format} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct payload_media_fmt_wmapro_t +{ + uint16_t fmt_tag; + /**< @h2xmle_description {WMA format type.} + @h2xmle_rangeList {"WMA 9 Pro" = 0x162, + "WMA 9 Pro Lossless" = 0x163, + "WMA 10 Pro" = 0x166, + "WMA 10 Pro Lossless" = 0x167, + INVALID_VALUE=0} + @h2xmle_policy {Basic} */ + + uint16_t num_channels; + /**< @h2xmle_description {Number of channels encoded in the input stream.} + @h2xmle_rangeList {INVALID_VALUE=0,1...8} + @h2xmle_policy {Basic} */ + + uint32_t sample_rate; + /**< @h2xmle_description {Number of samples per second in Hertz.} + @h2xmle_rangeList {INVALID_VALUE=0, 11025, 16000, 22050, 32000, + 44100, 48000, 88200, 96000} + @h2xmle_policy {Basic} */ + + uint32_t avg_bytes_per_sec; + /**< @h2xmle_description {Bitrate expressed as the average bytes per second} + @h2xmle_rangeList {INVALID_VALUE=0,2000..96000} + @h2xmle_policy {Basic} */ + + uint16_t blk_align; + /**< @h2xmle_description {Size of the bit stream packet size. WMA Pro files have a payload of one + block per bit stream packet.} + @h2xmle_rangeList {"13376"=13376} + @h2xmle_default {13376} + @h2xmle_policy {Basic} */ + + uint16_t bits_per_sample; + /**< @h2xmle_description {Number of bits per sample in the encoded WMA stream.} + @h2xmle_default {16} + @h2xmle_rangeList {"16" = 16, + "24" = 24} + @h2xmle_policy {Basic} */ + + uint32_t channel_mask; + /**< @h2xmle_description {Bit-packed double word (32-bits) that indicates the recommended + speaker positions for each source channel.} + @h2xmle_policy {Basic} */ + + uint16_t enc_options; + /**< @h2xmle_description {Bit-packed word with values that indicate whether certain features of + the bit stream are used.} + @h2xmle_rangeList {"ENCOPT3_PURE_LOSSLESS" = 0x0001, + "ENCOPT3_FRM_SIZE_MOD" = 0x0006, + "ENCOPT3_SUBFRM_DIV" = 0x0038, + "ENCOPT3_WRITE_FRAMESIZE_IN_HDR" = 0x0040, + "ENCOPT3_GENERATE_DRC_PARAMS" = 0x0080, + "ENCOPT3_RTMBITS" = 0x0100, + INVALID_VALUE=0} + @h2xmle_policy {Basic} */ + + uint16_t advanced_enc_option; + /**< @h2xmle_description {Advanced encoding option. This field is ignored.} + @h2xmle_policy {Basic} */ + + uint32_t advanced_enc_options2; + /**< @h2xmle_description {Advanced encoding option 2. This field is ignored.} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pack.h" +; + +/*************************************************** WMAStd Media Format **********************************************/ +/** + * Media format ID for the WMASTD streams. + */ +#define MEDIA_FMT_ID_WMASTD 0x09001007 + +typedef struct payload_media_fmt_wmastd_t payload_media_fmt_wmastd_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the WMASTD decoder format block parameters in the + MEDIA_FMT_ID_WMASTD media format} + @h2xmlp_toolPolicy {Calibration} */ + + +#include "spf_begin_pack.h" +struct payload_media_fmt_wmastd_t +{ + uint16_t fmt_tag; + /**< @h2xmle_description {WMA format tag.} + @h2xmle_rangeList {"WMA v9 standard" = 0x161} + @h2xmle_default {0x161} + @h2xmle_policy {Basic} */ + + uint16_t num_channels; + /**< @h2xmle_description {Number of channels in the stream.} + @h2xmle_rangeList {"Mono" = 1, "Stereo" = 2, INVALID_VALUE=0} + @h2xmle_policy {Basic} */ + + uint32_t sample_rate; + /**< @h2xmle_description {Number of samples per second in Hertz.} + @h2xmle_rangeList {INVALID_VALUE=0, "8000"=8000, "11025"=11025, + "16000"=16000, "22050"=22050, "32000"=32000, + "44100"=44100, "48000"=48000} + @h2xmle_policy {Basic} */ + + uint32_t avg_bytes_per_sec; + /**< @h2xmle_description {Bitrate expressed as the average bytes per second} + @h2xmle_policy {Basic} */ + + uint16_t blk_align; + /**< @h2xmle_description {Block align. All WMA files with a maximum packet size of 13376 + are supported.} + @h2xmle_policy {Basic} */ + + uint16_t bits_per_sample; + /**< @h2xmle_description {Number of bits per sample in the output} + @h2xmle_rangeList {"16" = 16} + @h2xmle_default {16} + @h2xmle_policy {Basic} */ + + uint32_t channel_mask; + /**< @h2xmle_description {Channel mask.} + @h2xmle_rangeList {"Stereo (front left/front right)" = 3, + "Mono (centre)" = 4, INVALID_VALUE=0} + @h2xmle_policy {Basic} */ + + uint16_t enc_options; + /**< @h2xmle_description {Options used during encoding.} + @h2xmle_policy {Basic} */ + + uint16_t reserved; + /**< @h2xmle_description {Used for alignment; must be set to 0.} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pack.h" +; + +/*************************************************** SBC Media Format *************************************************/ +/** + * Media format ID for the SBC + */ +#define MEDIA_FMT_ID_SBC 0x09001008 + + +/** Enumeration for SBC channel Mono mode. */ +#define MEDIA_FMT_SBC_CHANNEL_MODE_MONO 1 + +/** Enumeration for SBC channel Stereo mode. */ +#define MEDIA_FMT_SBC_CHANNEL_MODE_STEREO 2 + +/** Enumeration for SBC channel Dual Mono mode. */ +#define MEDIA_FMT_SBC_CHANNEL_MODE_DUAL_MONO 8 + +/** Enumeration for SBC channel Joint Stereo mode. */ +#define MEDIA_FMT_SBC_CHANNEL_MODE_JOINT_STEREO 9 + +/** Enumeration for SBC bit allocation method = loudness. */ +#define MEDIA_FMT_SBC_ALLOCATION_METHOD_LOUDNESS 0 + +/** Enumeration for SBC bit allocation method = SNR. */ +#define MEDIA_FMT_SBC_ALLOCATION_METHOD_SNR 1 + +/* SBC encoder configuration structure. */ +typedef struct sbc_enc_cfg_t sbc_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the SBC encoder module} */ + +#include "spf_begin_pack.h" +struct sbc_enc_cfg_t +{ + uint32_t num_subbands; + /**< + @h2xmle_description {Number of subbands} + @h2xmle_default {4} + @h2xmle_rangeList { "4" = 4, + "8" = 8} + @h2xmle_policy {Basic} */ + + uint32_t blk_len; + /**< + @h2xmle_description {Size of the encoded block in samples} + @h2xmle_default {4} + @h2xmle_rangeList { "4" = 4, + "8" = 8, + "12" = 12, + "16" = 16} + @h2xmle_policy {Basic} */ + + int32_t channel_mode; + /**< + @h2xmle_description {Mode used to allocate bits between channels. + + -Native mode indicates that encoding must be performed with the number + of channels at the input. + + -If postprocessing outputs one-channel data, Mono mode is used. If + postprocessing outputs two-channel data, Stereo mode is used. + + -The number of channels must not change during encoding. } + @h2xmle_default {-1} + @h2xmle_rangeList { "PARAM_VAL_NATIVE" = -1, + "MEDIA_FMT_SBC_CHANNEL_MODE_MONO" = 1, + "MEDIA_FMT_SBC_CHANNEL_MODE_STEREO" = 2, + "MEDIA_FMT_SBC_CHANNEL_MODE_DUAL_MONO" = 8, + "MEDIA_FMT_SBC_CHANNEL_MODE_JOINT_STEREO" = 9} + @h2xmle_policy {Basic} */ + + uint32_t alloc_method; + /**< + @h2xmle_description {Encoder bit allocation method.} + @h2xmle_default {0} + @h2xmle_rangeList { "MEDIA_FMT_SBC_ALLOCATION_METHOD_LOUDNESS"=0, + "MEDIA_FMT_SBC_ALLOCATION_METHOD_SNR"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +/*************************************************** MP3 Media Format *************************************************/ +/** + * Media format ID for MP3 streams + */ +#define MEDIA_FMT_ID_MP3 0x09001009 +/*************************************************** MP2 Media Format *************************************************/ + +/** @ingroup asmstrm_mediafmt_mp2 + Media format ID for MP2. Following are decoder-specific details: + - Sampling rates -- 16 to 48 kHz + - Channels -- 2 + - Bitwidth -- 16/24 bits per sample + - Bitrates -- 8 to 384 kbps + - Minimum buffer required per frame -- 1728 bytes + - External bit stream support -- No + + @par MP2 format block + No format block is needed. All information is contained in the bit stream. + */ +#define MEDIA_FMT_ID_MP2 0x09001029 + +/*************************************************** AMRWB+ Media Format **********************************************/ +/** + * Media format ID for the amrwbplus streams + */ +#define MEDIA_FMT_ID_AMRWBPLUS 0x0900100A + +/** @ingroup MEDIA_FMT_ID_AMRWBPLUS + Media format ID for the AMR-WB Plus format block. + + @par AMR-WB Plus format block (payload_media_fmt_amrwbplus_t) + @table{weak__payload__amrwbplus__fmt__blk__t} +*/ +typedef struct payload_media_fmt_amrwbplus_t payload_media_fmt_amrwbplus_t; +/** @h2xmlp_subStruct +28 @h2xmlp_description {Payload of the AMRWBPLUS decoder format block parameters in the +29 MEDIA_FMT_ID_AMRWBPLUS media format} +30 @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" + +struct payload_media_fmt_amrwbplus_t +{ + uint32_t amr_frame_fmt; + /**< @h2xmle_description {Transport Interface Format (TIF)} + @h2xmle_rangeList {"contains a 2-byte header for each frame within the superframe" = 6, + "contains one header per superframe"= 0} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +/*************************************************** AMRNB Media Format *************************************************/ +/** + * Media format ID for AMRNB streams + */ +#define MEDIA_FMT_ID_EAMR 0x0900100B + +#define MEDIA_FMT_ID_AMRNB_IF2 0x0900100C + +#define MEDIA_FMT_ID_AMRNB_MODEM 0x0900100D + +#define MEDIA_FMT_ID_AMRNB_FS 0x0900100E + + +/** Enumeration for 4.75 kbps AMR-NB Encoding mode. */ +#define AMRNB_FS_ENCODE_MODE_MR475 0 + +/** Enumeration for 5.15 kbps AMR-NB Encoding mode. */ +#define AMRNB_FS_ENCODE_MODE_MR515 1 + +/** Enumeration for 5.90 kbps AMR-NB Encoding mode. */ +#define AMRNB_FS_ENCODE_MODE_MMR59 2 + +/** Enumeration for 6.70 kbps AMR-NB Encoding mode. */ +#define AMRNB_FS_ENCODE_MODE_MMR67 3 + +/** Enumeration for 7.40 kbps AMR-NB Encoding mode. */ +#define AMRNB_FS_ENCODE_MODE_MMR74 4 + +/** Enumeration for 7.95 kbps AMR-NB Encoding mode. */ +#define AMRNB_FS_ENCODE_MODE_MMR795 5 + +/** Enumeration for 10.20 kbps AMR-NB Encoding mode. */ +#define AMRNB_FS_ENCODE_MODE_MMR102 6 + +/** Enumeration for 12.20 kbps AMR-NB Encoding mode. */ +#define AMRNB_FS_ENCODE_MODE_MMR122 7 + +/** Enumeration for disabling AMR-NB DTX mode. */ +#define AMRNB_FS_DTX_MODE_OFF 0 + +/** Enumeration for enabling AMR-NB DTX mode VAD1. */ +#define AMRNB_FS_DTX_MODE_VAD1 1 + +/** Enumeration for enabling AMR-NB DTX mode VAD2. */ +#define AMRNB_FS_DTX_MODE_VAD2 2 + +/** Enumeration for enabling AMR-NB automatic DTX mode. */ +#define AMRNB_FS_DTX_MODE_AUTO 3 + + +typedef struct amrnb_enc_cfg_t amrnb_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the AMRNB encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct amrnb_enc_cfg_t +{ + uint16_t enc_mode; + /**< @h2xmle_description {AMR-NB encoding rate.} + @h2xmle_default {0} + @h2xmle_rangeList {"AMRNB_FS_ENCODE_MODE_MR475"=0, + "AMRNB_FS_ENCODE_MODE_MR515"=1, + "AMRNB_FS_ENCODE_MODE_MMR59"=2, + "AMRNB_FS_ENCODE_MODE_MMR67"=3, + "AMRNB_FS_ENCODE_MODE_MMR74"=4, + "AMRNB_FS_ENCODE_MODE_MMR795"=5, + "AMRNB_FS_ENCODE_MODE_MMR102"=6, + "AMRNB_FS_ENCODE_MODE_MMR122"=7} + @h2xmle_policy {Basic} */ + uint16_t dtx_mode; + /**< @h2xmle_description {Specifies whether DTX mode is enabled} + @h2xmle_default {0} + @h2xmle_rangeList {"Enable"=1, + "Disable"=0} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +typedef struct payload_media_fmt_eamr_t payload_media_fmt_eamr_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the EAMR decoder format block structure to indicate the decoding format} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct payload_media_fmt_eamr_t +{ + uint32_t media_format_id; + /**< @h2xmle_description {Configures the decoding format of the AMRNB decoder} + @h2xmle_default {MEDIA_FMT_ID_AMRNB_MODEM} + @h2xmle_rangeList {"MEDIA_FMT_ID_EAMR"=0x0900100B, + "MEDIA_FMT_ID_AMRNB_IF2"=0x0900100C, + "MEDIA_FMT_ID_AMRNB_MODEM"=0x0900100D, + "MEDIA_FMT_ID_AMRNB_FS"=0x0900100E} + @h2xmle_policy {Basic} */ +} + +#include "spf_end_pack.h" +; + +/*********************************************** EVRC Media format *********************************************************/ +/** + * Media format ID for EVRC streams + */ +#define MEDIA_FMT_ID_EVRC 0x0900100F +#define MEDIA_FMT_ID_EVRC_FS 0x09001024 + + +typedef struct evrc_enc_cfg_t evrc_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the EVRC encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct evrc_enc_cfg_t +{ + uint16_t max_rate; + /**< @h2xmle_description {Maximum allowed encoder frame rate.} + @h2xmle_default {VOCODER_INVALID_RATE} + @h2xmle_rangeList {"VOCODER_ONE_EIGHTH_RATE"=1, + "VOCODER_ONE_FOURTH_RATE"=2, + "VOCODER_HALF_RATE"=3, + "VOCODER_FULL_RATE"=4, + "VOCODER_INVALID_RATE"=0} + @h2xmle_policy {Basic} */ + uint16_t min_rate; + /**< @h2xmle_description {Maximum allowed encoder frame rate.} + @h2xmle_default {VOCODER_INVALID_RATE} + @h2xmle_rangeList {"VOCODER_ONE_EIGHTH_RATE"=1, + "VOCODER_ONE_FOURTH_RATE"=2, + "VOCODER_HALF_RATE"=3, + "VOCODER_FULL_RATE"=4, + "VOCODER_INVALID_RATE"=0} + @h2xmle_policy {Basic} */ + uint16_t rate_mod_cmd; + /**< @h2xmle_description {Rate modulation command + If bit 0=1, rate control is enabled. + If bit 1=1, the maximum number of consecutive full rate frames is + limited with numbers supplied in bits 2 to 10. + If bit 1=0, the minimum number of non-full rate frames in between + two full rate frames is forced to the number supplied in bits 2 to 10 + In both cases of bit 1, if necessary, half rate is used to substitute full rate. + Bits 15 to 10 are reserved and must all be set to 0.} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ + uint16_t reserved; +/**< @h2xmle_description {Clients must set this field to 0.} + @h2xmle_rangeList {"0"=0} + @h2xmle_visibility {hide} */ +} +#include "spf_end_pack.h" +; + +/************************************************************************************************************************/ + +/************************************************ HR Media format *****************************************************/ + +/** + * Media format ID for HR streams + */ +#define MEDIA_FMT_ID_HR 0x09001019 + + +/************************************************************************************************************************/ + +/************************************************ FR Media format *****************************************************/ + +/** + * Media format ID for FR streams + */ +#define MEDIA_FMT_ID_FR 0x0900101B +#define MEDIA_FMT_ID_FR_FS 0x0900101C + + +/************************************************************************************************************************/ + +/************************************************ EFR Media format *****************************************************/ + +/** + * Media format ID for EFR streams + */ +#define MEDIA_FMT_ID_EFR 0x0900101A + + +/************************************************************************************************************************/ + +/************************************************ G711 Media format *****************************************************/ + +/** + * Media format ID for G711 streams + */ +#define MEDIA_FMT_ID_G711_ALAW 0x09001032 +#define MEDIA_FMT_ID_G711_MLAW 0x09001033 +#define MEDIA_FMT_ID_G711_ALAW_V2 0x09001034 +#define MEDIA_FMT_ID_G711_MLAW_V2 0x09001035 +#define MEDIA_FMT_ID_G711_ALAW_FS 0x09001036 +#define MEDIA_FMT_ID_G711_MLAW_FS 0x09001037 + +typedef struct payload_media_fmt_g711_t payload_media_fmt_g711_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the G711 decoder format block structure} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct payload_media_fmt_g711_t +{ + uint32_t sample_rate; + /**< @h2xmle_description {Sampling rate} + @h2xmle_default {8000} + @h2xmle_rangeList {"8000" = 8000, "16000" = 16000} + @h2xmle_policy {Basic} */ +} + +#include "spf_end_pack.h" +; + +/************************************************ G722 Media format *****************************************************/ + +/** + * Media format ID for G722 streams + */ +#define MEDIA_FMT_ID_G722 + +/************************************************************************************************************************/ + + +/************************************************ G729AB Media format *****************************************************/ + +/** + * Media format ID for G729AB streams + */ +#define MEDIA_FMT_ID_G729AB 0x09001010 + + +/*********************************************** LDAC Media format *********************************************************/ +/** + * Media format ID for LDAC streams + */ +#define MEDIA_FMT_ID_LDAC 0x0900101D + +/** Enumeration for Stereo mode on the LDAC channel. */ +#define LDAC_CHANNEL_MODE_STEREO 1 + +/** Enumeration for Dual Channel mode on the LDAC channel. */ +#define LDAC_CHANNEL_MODE_DUAL_CHANNEL 2 + +/** Enumeration for Mono mode on the LDAC channel. */ +#define LDAC_CHANNEL_MODE_MONO 4 + +/* ldac encoder configuration structure. */ +typedef struct ldac_enc_cfg_t ldac_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the ldac encoder module, optional param} */ + +#include "spf_begin_pack.h" +struct ldac_enc_cfg_t +{ + uint32_t channel_mode; + /**< + @h2xmle_description {Mode used to allocate bits between channels. + The number of channels must not change during encoding } + @h2xmle_default {1} + @h2xmle_rangeList { "LDAC_CHANNEL_MODE_STEREO" = 1, + "LDAC_CHANNEL_MODE_DUAL_CHANNEL" = 2, + "LDAC_CHANNEL_MODE_MONO" = 4} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/************************************************ V13K Media format *****************************************************/ +#define MEDIA_FMT_ID_V13K 0x09001025 +#define MEDIA_FMT_ID_V13K_FS 0x09001026 + + +/** Enumeration for 14.4 kbps V13K Encoding mode. */ +#define V13K_FS_ENCODE_MODE_MR1440 0 + +/** Enumeration for 12.2 kbps V13K Encoding mode. */ +#define V13K_FS_ENCODE_MODE_MR1220 1 + +/** Enumeration for 11.2 kbps V13K Encoding mode. */ +#define V13K_FS_ENCODE_MODE_MR1120 2 + +/** Enumeration for 9.0 kbps V13K Encoding mode. */ +#define V13K_FS_ENCODE_MODE_MR90 3 + +/** Enumeration for 7.2 kbps V13K Encoding mode. */ +#define V13K_FS_ENCODE_MODE_MR720 4 + + +typedef struct v13k_enc_cfg_t v13k_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the V13K encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct v13k_enc_cfg_t +{ + uint16_t max_rate; + /**< @h2xmle_description {Maximum allowed encoder frame rate.} + @h2xmle_default {VOCODER_FULL_RATE} + @h2xmle_rangeList {"VOCODER_ONE_EIGHTH_RATE"=1, + "VOCODER_ONE_FOURTH_RATE"=2, + "VOCODER_HALF_RATE"=3, + "VOCODER_FULL_RATE"=4, + "VOCODER_INVALID_RATE"=0} + @h2xmle_policy {Basic} */ + uint16_t min_rate; + /**< @h2xmle_description {Minimum allowed encoder frame rate.} + @h2xmle_default {VOCODER_ONE_EIGHTH_RATE} + @h2xmle_rangeList {"VOCODER_ONE_EIGHTH_RATE"=1, + "VOCODER_ONE_FOURTH_RATE"=2, + "VOCODER_HALF_RATE"=3, + "VOCODER_FULL_RATE"=4, + "VOCODER_INVALID_RATE"=0} + @h2xmle_policy {Basic} */ + uint16_t reduced_rate_cmd; + /**< @h2xmle_description {Reduced rate command, used to change the average bit-rate + of the vocoder} + @h2xmle_rangeList {"V13K_FS_ENCODE_MODE_MR1440"=0, + "V13K_FS_ENCODE_MODE_MR1220"=1, + "V13K_FS_ENCODE_MODE_MR1120"=2, + "V13K_FS_ENCODE_MODE_MR90"=3, + "V13K_FS_ENCODE_MODE_MR720"=4} + @h2xmle_default {V13K_FS_ENCODE_MODE_MR1440} + @h2xmle_policy {Basic} */ + uint16_t rate_mod_cmd; + /**< @h2xmle_description {Rate modulation command + If bit 0=1, rate control is enabled. + If bit 1=1, the maximum number of consecutive full rate frames is + limited with numbers supplied in bits 2 to 10. + If bit 1=0, the minimum number of non-full rate frames in between + two full rate frames is forced to the number supplied in bits 2 to 10 + In both cases of bit 1, if necessary, half rate is used to substitute full rate. + Bits 15 to 10 are reserved and must all be set to 0.} + @h2xmle_default {0} + @h2xmle_range {0..0x03FF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/************************************************ AMRWB Media format *****************************************************/ + +/** + * Media format ID for AMRWB streams + */ +#define MEDIA_FMT_ID_AMRWB 0x09001027 +#define MEDIA_FMT_ID_AMRWB_FS 0x09001028 + + +/** Enumeration for 6.60 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR66 0 + +/** Enumeration for 8.85 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR885 1 + +/** Enumeration for 12.65 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR1265 2 + +/** Enumeration for 14.25 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR1425 3 + +/** Enumeration for 15.85 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR1585 4 + +/** Enumeration for 18.25 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR1825 5 + +/** Enumeration for 19.85 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR1985 6 + +/** Enumeration for 23.05 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR2305 7 + +/** Enumeration for 23.85 kbps AMR-WB Encoding mode. */ +#define AMRWB_FS_ENCODE_MODE_MR2385 8 + +typedef struct amrwb_enc_cfg_t amrwb_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the AMRWB encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct amrwb_enc_cfg_t +{ + uint16_t enc_mode; + /**< @h2xmle_description {AMR-WB encoding rate.} + @h2xmle_default {0} + @h2xmle_rangeList {"AMRWB_FS_ENCODE_MODE_MR66"=0, + "AMRWB_FS_ENCODE_MODE_MR885"=1, + "AMRWB_FS_ENCODE_MODE_MR1265"=2, + "AMRWB_FS_ENCODE_MODE_MR1425"=3, + "AMRWB_FS_ENCODE_MODE_MR1585"=4, + "AMRWB_FS_ENCODE_MODE_MR1825"=5, + "AMRWB_FS_ENCODE_MODE_MR1985"=6, + "AMRWB_FS_ENCODE_MODE_MR2305"=7, + "AMRWB_FS_ENCODE_MODE_MR2385"=8} + @h2xmle_policy {Basic} */ + uint16_t dtx_mode; + /**< @h2xmle_description {Specifies whether DTX mode is enabled} + @h2xmle_default {0} + @h2xmle_rangeList {"Enable"=1, + "Disable"=0} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + + +/************************************************************************************************************************/ + +/*********************************************** CELT Media format *********************************************************/ +/** + * Media format ID for the CELT + */ +#define MEDIA_FMT_ID_CELT 0x0900102A + +/* CELT encoder configuration structure. */ +typedef struct celt_enc_cfg_t celt_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the CELT encoder module} */ + +#include "spf_begin_pack.h" +struct celt_enc_cfg_t +{ + + uint16_t frame_size; + /**< + @h2xmle_description {Frame size used for encoding.} + @h2xmle_default {256} + @h2xmle_rangeList {"64" = 64, + "128" = 128, + "256" = 256, + "512" = 512} + @h2xmle_policy {Basic} */ + + + uint16_t complexity; + /**< + @h2xmle_description {Complexity of the algorithm. + - Currently, this parameter is used to enable or disable the pitch + analysis. In the future, it can be scaled to add more levels of + complexity. + - value less than 2 - Disable pitch analysis + - Value > 2 - Enable pitch analysis} + @h2xmle_default {3} + @h2xmle_range {0..10} + @h2xmle_policy {Basic} */ + + + uint16_t prediction_mode; + /**< + @h2xmle_description {Switch variable for the prediction feature. + - This parameter is used to choose between the level of interframe + predictions allowed while encoding. + - 0 -- Independent frames + - 1 -- Short-term interframe prediction allowed + - 2 -- Long-term prediction allowed} + @h2xmle_default {2} + @h2xmle_rangeList {"0" = 0, + "1" = 1, + "2" = 2} + @h2xmle_policy {Basic} */ + + uint16_t vbr_flag; + /**< + @h2xmle_description {Variable bit rate flag. + Currently, this parameter is disabled. In the future, it can be + enabled if use cases require it.} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pack.h" +; +/************************************************ FOURGV Media format *****************************************************/ + +/** + * Media format ID for FOURGV streams + */ +#define MEDIA_FMT_ID_EVRCB_FS 0x0900102B +#define MEDIA_FMT_ID_EVRCWB_FS 0x0900102C +#define MEDIA_FMT_ID_4GV_NB_MODEM 0x0900102D +#define MEDIA_FMT_ID_4GV_WB_MODEM 0x0900102E +#define MEDIA_FMT_ID_4GV_NW_MODEM 0x0900102F +#define MEDIA_FMT_ID_4GV_NW 0x09001030 +#define MEDIA_FMT_ID_EVRC_NW_2K 0x09001031 + + +/** Enumeration for 9.3 kbps EVRC-B Encoding mode. */ +#define EVRCB_FS_ENCODE_MODE_MR930 0 + +/** Enumeration for 8.5 kbps EVRC-B Encoding mode. */ +#define EVRCB_FS_ENCODE_MODE_MR850 1 + +/** Enumeration for 7.5 kbps EVRC-B Encoding mode. */ +#define EVRCB_FS_ENCODE_MODE_MR750 2 + +/** Enumeration for 7.0 kbps EVRC-B Encoding mode. */ +#define EVRCB_FS_ENCODE_MODE_MR700 3 + +/** Enumeration for 6.6 kbps EVRC-B Encoding mode. */ +#define EVRCB_FS_ENCODE_MODE_MR660 4 + +/** Enumeration for 6.2 kbps EVRC-B Encoding mode. */ +#define EVRCB_FS_ENCODE_MODE_MR620 5 + +/** Enumeration for 5.8 kbps EVRC-B Encoding mode. */ +#define EVRCB_FS_ENCODE_MODE_MR580 6 + +/** Enumeration for 4.8 kbps EVRC-B Encoding mode. */ +#define EVRCB_FS_ENCODE_MODE_MR480 7 + +/* EVCR-B encoder configuration structure. */ +//typedef struct evrcb_enc_cfg_t evrcb_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the EVRC-B encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct evrcb_enc_cfg_t +{ + uint16_t max_rate; + /**< @h2xmle_description {Maximum allowed encoder frame rate.} + @h2xmle_default {EVRCB_FS_ENCODE_MODE_MR930} + @h2xmle_rangeList {"EVRCB_FS_ENCODE_MODE_MR930"=0, + "EVRCB_FS_ENCODE_MODE_MR850"=1, + "EVRCB_FS_ENCODE_MODE_MR750"=2, + "EVRCB_FS_ENCODE_MODE_MR700"=3, + "EVRCB_FS_ENCODE_MODE_MR660"=4, + "EVRCB_FS_ENCODE_MODE_MR620"=5, + "EVRCB_FS_ENCODE_MODE_MR580"=6, + "EVRCB_FS_ENCODE_MODE_MR480"=7} + @h2xmle_policy {Basic} */ + uint16_t min_rate; + /**< @h2xmle_description {Minimum allowed encoder frame rate.} + @h2xmle_default {EVRCB_FS_ENCODE_MODE_MR480} + @h2xmle_rangeList {"EVRCB_FS_ENCODE_MODE_MR930"=0, + "EVRCB_FS_ENCODE_MODE_MR850"=1, + "EVRCB_FS_ENCODE_MODE_MR750"=2, + "EVRCB_FS_ENCODE_MODE_MR700"=3, + "EVRCB_FS_ENCODE_MODE_MR660"=4, + "EVRCB_FS_ENCODE_MODE_MR620"=5, + "EVRCB_FS_ENCODE_MODE_MR580"=6, + "EVRCB_FS_ENCODE_MODE_MR480"=7} + @h2xmle_policy {Basic} */ + uint16_t dtx_mode; + /**< @h2xmle_description {Specifies whether DTX mode is enabled} + @h2xmle_default {0} + @h2xmle_rangeList {"Enable"=1, + "Disable"=0} + @h2xmle_policy {Basic} */ + + uint16_t reduced_rate_level; + /**< @h2xmle_description {Reduced rate level for the average encoding rate} + @h2xmle_default {EVRCB_FS_ENCODE_MODE_MR480} + @h2xmle_rangeList {"EVRCB_FS_ENCODE_MODE_MR930"=0, + "EVRCB_FS_ENCODE_MODE_MR850"=1, + "EVRCB_FS_ENCODE_MODE_MR750"=2, + "EVRCB_FS_ENCODE_MODE_MR700"=3, + "EVRCB_FS_ENCODE_MODE_MR660"=4, + "EVRCB_FS_ENCODE_MODE_MR620"=5, + "EVRCB_FS_ENCODE_MODE_MR580"=6, + "EVRCB_FS_ENCODE_MODE_MR480"=7} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/** Enumeration for 8.5 kbps EVRC-WB Encoding mode. */ +#define EVRCWB_FS_ENCODE_MODE_MR850 0 + +/** Enumeration for 9.3 kbps EVRC-WB Encoding mode. */ +#define EVRCWB_FS_ENCODE_MODE_MR930 4 + +/** Enumeration for 4.8 kbps EVRC-WB Encoding mode. */ +#define EVRCWB_FS_ENCODE_MODE_MR480 7 + +/* EVRC-WB encoder configuration structure. */ +typedef struct evrcwb_enc_cfg_t evrcwb_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the EVRC-WB encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" + +struct evrcwb_enc_cfg_t +{ + uint16_t max_rate; + /**< @h2xmle_description {Maximum allowed encoder frame rate.} + @h2xmle_default {VOCODER_FULL_RATE} + @h2xmle_rangeList {"VOCODER_ONE_EIGHTH_RATE"=1, + "VOCODER_ONE_FOURTH_RATE"=2, + "VOCODER_HALF_RATE"=3, + "VOCODER_FULL_RATE"=4, + "VOCODER_INVALID_RATE"=0} + @h2xmle_policy {Basic} */ + uint16_t min_rate; + /**< @h2xmle_description {Minimum allowed encoder frame rate.} + @h2xmle_default {VOCODER_ONE_EIGHTH_RATE} + @h2xmle_rangeList {"VOCODER_ONE_EIGHTH_RATE"=1, + "VOCODER_ONE_FOURTH_RATE"=2, + "VOCODER_HALF_RATE"=3, + "VOCODER_FULL_RATE"=4, + "VOCODER_INVALID_RATE"=0} + @h2xmle_policy {Basic} */ + uint16_t dtx_enable; + /**< @h2xmle_description {Specifies whether DTX mode is enabled} + @h2xmle_default {0} + @h2xmle_rangeList {"Enable"=1, + "Disable"=0} + @h2xmle_policy {Basic} */ + uint16_t reduced_rate_level; + /**< @h2xmle_description {Reduced rate level for the average encoding rate.} + @h2xmle_default {EVRCWB_FS_ENCODE_MODE_MR850} + @h2xmle_rangeList {"EVRCWB_FS_ENCODE_MODE_MR850"=0, + "EVRCWB_FS_ENCODE_MODE_MR930"=4, + "EVRCWB_FS_ENCODE_MODE_MR480"=7} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/*********************************************** EVS Media format *********************************************************/ +/** + * Media format ID for EVRC streams + */ +#define MEDIA_FMT_ID_EVS 0x09001023 + +/** Enumeration for 06.60 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_0660 0 + +/** Enumeration for 08.85 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_0885 1 + +/** Enumeration for 12.65 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_1265 2 + +/** Enumeration for 14.25 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_1425 3 + +/** Enumeration for 15.85 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_1585 4 + +/** Enumeration for 18.25 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_1825 5 + +/** Enumeration for 19.85 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_1985 6 + +/** Enumeration for 23.05 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_2305 7 + +/** Enumeration for 23.85 kbps, AMR-WB IO (WB). */ +#define EVS_CODEC_MODE_2385 8 + +/** Enumeration for 05.90 kbps, EVS (NB, WB). */ +#define EVS_CODEC_MODE_0590 9 + +/** Enumeration for 07.20 kbps, EVS (NB, WB). */ +#define EVS_CODEC_MODE_0720 10 + +/** Enumeration for 08.00 kbps, EVS (NB, WB). */ +#define EVS_CODEC_MODE_0800 11 + +/** Enumeration for 09.60 kbps, EVS (NB, WB, SWB). */ +#define EVS_CODEC_MODE_0960 12 + +/** Enumeration for 13.20 kbps, EVS (NB, WB, SWB). */ +#define EVS_CODEC_MODE_1320 13 + +/** Enumeration for 16.40 kbps, EVS (NB, WB, SWB, FB). */ +#define EVS_CODEC_MODE_1640 14 + +/** Enumeration for 24.40 kbps, EVS (NB, WB, SWB, FB) */ +#define EVS_CODEC_MODE_2440 15 + +/** Enumeration for 32.00 kbps, EVS (WB, SWB, FB). */ +#define EVS_CODEC_MODE_3200 16 + +/** Enumeration for 48.00 kbps, EVS (WB, SWB, FB). */ +#define EVS_CODEC_MODE_4800 17 + +/** Enumeration for 64.00 kbps, EVS (WB, SWB, FB). */ +#define EVS_CODEC_MODE_6400 18 + +/** Enumeration for 96.00 kbps, EVS (WB, SWB, FB). */ +#define EVS_CODEC_MODE_9600 19 + +/** Enumeration for 128.00 kbps, EVS (WB, SWB, FB). */ +#define EVS_CODEC_MODE_12800 20 + + +typedef struct evs_enc_cfg_t evs_enc_cfg_t; +/** @h2xmlp_subStruct + @h2xmlp_description {Payload for configuring the EVS encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct evs_enc_cfg_t +{ + uint32_t bit_rate; + /**< @h2xmle_description {EVS encoding bit rate} + @h2xmle_rangeList {"EVS_CODEC_MODE_0660"=0, + "EVS_CODEC_MODE_0885"=1, + "EVS_CODEC_MODE_1265"=2, + "EVS_CODEC_MODE_1425"=3, + "EVS_CODEC_MODE_1585"=4, + "EVS_CODEC_MODE_1825"=5, + "EVS_CODEC_MODE_1985"=6, + "EVS_CODEC_MODE_2305"=7, + "EVS_CODEC_MODE_2385"=8, + "EVS_CODEC_MODE_0590"=9, + "EVS_CODEC_MODE_0720"=10, + "EVS_CODEC_MODE_0800"=11, + "EVS_CODEC_MODE_0960"=12, + "EVS_CODEC_MODE_1320"=13, + "EVS_CODEC_MODE_1640"=14, + "EVS_CODEC_MODE_2440"=15, + "EVS_CODEC_MODE_3200"=16, + "EVS_CODEC_MODE_4800"=17, + "EVS_CODEC_MODE_6400"=18, + "EVS_CODEC_MODE_9600"=19, + "EVS_CODEC_MODE_12800"=20} + @h2xmle_default {13} + @h2xmle_policy {Basic} */ + + uint32_t bandwidth; + /**< @h2xmle_description {EVS encoder bandwidth} + @h2xmle_rangeList {"SAMPLE_RATE_8K"=0, + "SAMPLE_RATE_16K"=1, + "SAMPLE_RATE_32K"=2, + "SAMPLE_RATE_48K"=3} + @h2xmle_default {2} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/*************************************************** OPUS Media Format ************************************************/ +/** + * Media format ID for OPUS streams + */ +#define MEDIA_FMT_ID_OPUS 0x09001039 + +typedef struct payload_media_fmt_opus_t payload_media_fmt_opus_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Payload of the OPUS decoder format block structure parameters in the + MEDIA_FMT_ID_OPUS media format..\n } + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct payload_media_fmt_opus_t +{ + uint16_t bitstream_format; + /**< @h2xmle_description {specifies bitstream format if its raw format + or OggOpus container format .} + @h2xmle_default {1} + @h2xmle_rangeList {"raw" = 0, "oggopus" = 1 } + @h2xmle_policy {Basic} */ + + uint16_t payload_type; + /**< @h2xmle_description {Specifies the payload type indicates OGG header parsing needed.} + @h2xmle_default {0} + @h2xmle_rangeList {"0" = 0} + @h2xmle_policy {Basic} */ + + uint8_t version; + /**< @h2xmle_description {Specifies the compatible version.} + @h2xmle_default {1} + @h2xmle_rangeList {"1" = 1} + @h2xmle_policy {Basic} */ + + uint8_t num_channels; + /**< @h2xmle_description {Number of channels present in the Opus stream.} + @h2xmle_default {1} + @h2xmle_rangeList {"Mono"=1, + "Stereo"=2, + "LinearSurround"=3, + "Quadraphonic"=4, + "5dot0Surround"=5, + "5dot1Surround"=6, + "6dot1Surround"=7, + "7dot1Surround"=8} + @h2xmle_policy {Basic} */ + + + uint16_t pre_skip; + /**< @h2xmle_description {Number of Samples at 48kHz to discard from decoder output when + starting playback.} + @h2xmle_default {0} + @h2xmle_range {0...0xFFFF} + @h2xmle_policy {Basic} */ + + + uint32_t sample_rate; + /**< @h2xmle_description {Supported sampling rates} + @h2xmle_default {0} + @h2xmle_rangeList {INVALID_VALUE=0,0,8000, 12000, 16000, 24000, 48000} + @h2xmle_policy {Basic} */ + + + uint16_t output_gain; + /**< @h2xmle_description {The gain applied when decoding, to acheive desired playback volume + in Q7.8 format.} + @h2xmle_default {0x100} + @h2xmle_rangeList {0...0xFF} + @h2xmle_policy {Basic} */ + + + uint8_t mapping_family; + /**< @h2xmle_description {Mapping family defines the order and meaning of channels} + @h2xmle_default {0} + @h2xmle_rangeList {"0" = 0, + "1" = 1, + "255" = 255} + @h2xmle_policy {Basic} */ + + + uint8_t stream_count; + /**< @h2xmle_description {Number of streams present in Opus Stream + This member is valid only if mapping_family is not 0} + @h2xmle_default {0x1} + @h2xmle_range {1...0xFF} + @h2xmle_policy {Basic} */ + + + uint8_t coupled_count; + /**< @h2xmle_description {Number of streams which needs to be configured as Stereo + This member is valid only if mapping_family is not 0} + @h2xmle_default {0x0} + @h2xmle_range {0...0xFF} + @h2xmle_policy {Basic} */ + + + uint8_t channel_map[8]; + /**< @h2xmle_description {This contains one octet per output channel, it + tells which decoded channel is to be used for + each speaker location. + This member is valid only if mapping_family is not 0} + @h2xmle_default {0x0} + @h2xmle_range {0...0xFF} + @h2xmle_policy {Basic} */ + + uint8_t reserved[3]; + /**< @h2xmle_description {Clients must set this field to 0.} + @h2xmle_rangeList {"0"=0} + @h2xmle_visibility {hide} */ + +} +#include "spf_end_pack.h" +; + +/************************************************************************************************************************/ + + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + + +#endif /* MEDIA_FMT_API_EXT_H */ diff --git a/spf/api/modules/metadata_api.h b/spf/api/modules/metadata_api.h new file mode 100644 index 0000000..ca43840 --- /dev/null +++ b/spf/api/modules/metadata_api.h @@ -0,0 +1,353 @@ +#ifndef METADATA_API_H +#define METADATA_API_H +/** + * \file metadata_api.h + * \brief + * This file contains metadata IDs. Definitions are not supposed to be here. + * definitions will be in module_cmn_metadata. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "codec_metadata_api.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/** @h2xml_title1 {Metadata IDs} + @h2xml_title_agile_rev {Metadata IDs} + @h2xml_title_date {Apr 30 2019} */ +/** + @h2xmlx_xmlNumberFormat {int} +*/ + +/** + Metadata ID for EOS. module_cmn_md_t structure + has to set the metadata_id field to this id when the metadata + is EOS. The module also should check this ID before operating on + EOS structures. + */ +#define MODULE_CMN_MD_ID_EOS 0x0A00100C + + +/** + * Metadata API to support the requirement of exchanging the metadata between the client and SPF + * + * Metadata in general can be defined as additional information associated with the stream data. + * + * Application or usage of the metadata information would be defined based on the type of + * Metadata which would be specified by the metadata ID + * + * The metadata is expected to be exchanged in the specified format for writing and reading both + * by the HLOS client and the SPF during the data command read/write operations. + * + * In general all the metadata is applicable to all the channels in the stream data + * + * Defining metadata association + * Sample associated: Metadata is applicable at the offset at which it's inserted. + * This metadata suffers both algorithmic and buffering delays. + * Buffer associated: metadata is applicable at the offset for the buffer. + * This metadata suffers buffering delays only. + * + * Defining metadata flag : The flags in the metadata payload specifies various control information. + * More details of individual controls are defined in the payload. + * + */ + + +/** Definition of a metadata client information flag bitmask. */ +#define MD_HEADER_FLAGS_BIT_MASK_CLIENT_INFO AR_NON_GUID(0x00000001) + +/** Definition of a metadata client information flag shift value. */ +#define MD_HEADER_FLAGS_SHIFT_CLIENT_INFO 0 + + +/** Definition of a metadata tracking configuration bitmask. */ +#define MD_HEADER_FLAGS_BIT_MASK_TRACKING_CONFIG AR_NON_GUID(0x00000006) + +/** Definition of a metadata tracking configuration shift value. */ +#define MD_HEADER_FLAGS_SHIFT_TRACKING_CONFIG_FLAG 1 + + +/** Definition of a metadata tracking event policy flag bitmask. */ +#define MD_HEADER_FLAGS_BIT_MASK_TRACKING_EVENT_POLICY AR_NON_GUID(0x00000008) + +/** Definition of a metadata tracking event policy flag shift value. */ +#define MD_HEADER_FLAGS_SHIFT_TRACKING_EVENT_POLICY_FLAG 3 + +/** Definition of a metadata association with data bitmask. */ +#define MD_HEADER_FLAGS_BIT_MASK_ASSOCIATION AR_NON_GUID(0x00000010) + +/** Definition of a metadata association with data flag shift value. */ +#define MD_HEADER_FLAGS_SHIFT_ASSOCIATION_FLAG 4 + + + +/** Definition of a external client of SPF */ +#define MD_HEADER_FLAGS_CLIENT_EXTERNAL 0 + +/** Definition of a internal client of SPF */ +#define MD_HEADER_FLAGS_CLIENT_INERTNAL 1 + +/** Definition of a metadata tracking configuration disable. */ +#define MD_HEADER_FLAGS_TRACKING_CONFIG_DISABLE 0 + +/** Definition of a metadata tracking configuration to enable for md drops only. */ +#define MD_HEADER_FLAGS_TRACKING_CONFIG_ENABLE_FOR_DROPS_ONLY 1 + +/** Definition of a metadata tracking configuration to enable for md drop or consume. */ +#define MD_HEADER_FLAGS_TRACKING_CONFIG_ENABLE_FOR_DROP_OR_CONSUME 2 + +/** Definition of a metadata tracking event policy last. */ +#define MD_HEADER_FLAGS_TRACKING_EVENT_POLICY_LAST 0 + +/** Definition of a metadata tracking event policy last. */ +#define MD_HEADER_FLAGS_TRACKING_EVENT_POLICY_EACH 1 + +/** Definition of a metadata sample association . */ +#define MD_HEADER_FLAGS_SAMPLE_ASSOCIATED 0 + +/** Definition of a metadata sample association . */ +#define MD_HEADER_FLAGS_BUFFER_ASSOCIATED 1 + + +/** + * Payload for Metadata + * + * struct complete_metadata_api_header_t + * { + * metadata_api_header_t base; + * uint8_t payload[payload_size]; + * } + */ +#include "spf_begin_pack.h" +struct metadata_header_t +{ + uint32_t metadata_id; + /**< Globally Unique ID of the metadata. */ + + uint32_t flags; + /**< + * Specifies the control flags for the metadata. + * + * + * BIT_0 : specifies if the metadata was from the external client or meant to be rendered to external client. + * + * @values{for bit 0} + * - 0 -- MD_HEADER_FLAGS_CLIENT_EXTERNAL (from/to external client (HLOS)) + * - 1 -- MD_HEADER_FLAGS_CLIENT_INERTNAL (internal propagation in SPF, used for MDF) + * + * This bit is specifically used for MDF to classify if the metadata is relevant + * to external client versus internally generated and propagated within SPF. + * Should be set to 0 always for HLOS + * + * + * BIT_2_to_1 : Specifies if the Metadata is trackable. + * If the metadata is dropped or consumed in SPF then the client would get an event + * with relevant information for the metadata. There is no requirement of registering for an event. + * + * @values{for bit 2_to_1} + * - 0 -- MD_HEADER_FLAGS_TRACKING_CONFIG_DISABLE + * (tracking is disabled) + * - 1 -- MD_HEADER_FLAGS_TRACKING_CONFIG_ENABLE_FOR_DROPS_ONLY + * (tracking enabled for drops only) + * - 2 -- MD_HEADER_FLAGS_TRACKING_CONFIG_ENABLE_FOR_DROP_OR_CONSUME + * (tracking enabled for all drops and consumption) + * - 3 -- reserved and ignored. + * + * For the configuration value set to 2, the event would be raised for metadata + * consumption from all the sink modules including hardware endpoints. + * + * BIT_3 : Specifies the policy for raising the event. + * For every split in the path, the metadata would be cloned to both the paths. + * This will increase the internal references for the specified metadata and can + * lead to multiple drops/consumptions. + * + * @values{for bit 3} + * - 0 -- MD_HEADER_FLAGS_TRACKING_EVENT_POLICY_LAST ( raise event for only the last drop/consumption of md in SPF) + * - 1 -- MD_HEADER_FLAGS_TRACKING_EVENT_POLICY_EACH ( raise event for every drop/consumption of md in SPF ) + * + * BIT_4: Specifies the metadata association + * + * @values{for bit 4} + * - 0 -- MD_HEADER_FLAGS_SAMPLE_ASSOCIATED + * - 1 -- MD_HEADER_FLAGS_BUFFER_ASSOCIATED + * + * Other bit fields are reserved and should be set to zero while writing the payload. + */ + + uint32_t offset; + /**< Start offset in the data buffer from which metadata is applicable. + * + * For cases where offset is a valid value, the following criteria apply for specifying the offset. + * + * For raw compressed, offset is in bytes. + * For PCM & packetized, offset in samples (per channel). + * For interleaved data (most packetized format are also interleaved), + * metadata is applicable from sample at (data buffer + (sample_offset * bytes_per_sample * num channels ) + * For deinterleaved packed data, + * metadata is applicable from sample at (data buffer + offset * bytes_per_sample) in each channel + * For deinterleaved data unpacked, + * metadata is applicable from sample at (channel data buffer + (sample_offset * bytes_per_sample)) + * Effective sample_offset in above cases must be less than buffer end + */ + + uint32_t token_lsw; + /* Unique token applicable for tracking Metadata. + * The same token will be used while raising the Metadata tracking event + * + * Lower 32 bits of the token field + */ + + uint32_t token_msw; + /* + * Higher 32 bits of the token field + */ + + uint32_t payload_size ; + /**< Total size of the payload in bytes for the specified metadata ID */ + +#if defined(__H2XML__) + uint8_t payload[0]; + /** + * Specifes the metadata payload of size defined in this API. + * This payload is specific to the metadata ID. + * + * Guideline for metadata payload : + * The metadata payload should not contain any further memory references. + * + */ +#endif +} +#include "spf_end_pack.h" +; + +/* Structure for metadata header. */ +typedef struct metadata_header_t metadata_header_t; + +/** Definition of a metadata last instance flag bitmask. */ +#define MD_TRACKING_FLAGS_BIT_MASK_LAST_INSTANCE AR_NON_GUID(0x00000001) + +/** Definition of a metadata last instance flag shift value. */ +#define MD_TRACKING_FLAGS_IS_LAST_INSTANCE_FLAG 0 + +/** tracking status of the metadata when the meta-data is consumed. */ +#define MD_TRACKING_STATUS_IS_CONSUMED AR_NON_GUID(0x00000000) + +/** tracking status of the metadata when the meta-data is dropped. */ +#define MD_TRACKING_STATUS_IS_DROPPED AR_NON_GUID(0x00000001) + +/** + * The metadata event is raised if the metadata is set as tracking metadata. + * The event will be sent to the client from SPF in the following scenarios. + * + * Metadata is dropped in the SPF and cannot be rendered to client through the data commands. + * Metadata is consumed by the the module and not propagated further. + * Note that all sink modules including the hardware end-points would consume the metadata. + */ + +#define EVENT_ID_MODULE_CMN_METADATA_TRACKING_EVENT 0x0300100C + +/** + * Payload for Metadata tracking event + */ + +#include "spf_begin_pack.h" +struct metadata_tracking_event_t +{ + uint32_t metadata_id; + /**< Globally Unique ID of the metadata. */ + + uint32_t source_module_instance; + /**< Specifies the source module of the metadata. + * + * Client Metadata: + * For metadata from the client, this is basically derived from the source port ID in the data command from + * client. + * Module metadata to client: + * If the metadata is generated by a module in SPF, then this would be the module instance ID of the module. + */ + uint32_t module_instance_id; + /**< Specifies the module instance ID of the module which is raising the event when MD is consumed/dropped. + Invalid (0) when the status is set as dropped. + */ + uint32_t flags; + /**< + * Specifies the control flags for the metadata event. + * + * + * BIT_0 : specifies if this event corresponds to the last instance of metadata in the in SPF. + * @values{for bit 0} + * - 0 -- FALSE (not last instance) + * - 1 -- TRUE ( yes, its last instance) + * + * 1. For every split in the path, the metadata would be cloned to both the paths. This will increase + * the internal reference count for the specified MD in the SPF. + * 2. If the event is generated in one path, while the MD in the other path is still active, + * this bit_field would be set as FALSE. + * This indicates that there is a possibility for more events corresponding to this MD + * 3. If the metadata tracking is set as last drop/consumption, then there will be only one event and + * this bit would be set always. + * + * Other bits are reserved for future use and should be set to zero. + */ + + uint32_t token_lsw; + /** < + * Specifies the LSW of the unique token. + * + * Client Metadata: + * For Metadata from the client, this is specified in the medata API header and the same value would be used here. + * Module metadata to client: + * If the metadata is generated by a module in SPF, the module would need to specify the token. + * It can be configured to the module by the client, if the MD needs to be trackable. * + */ + + uint32_t token_msw; + /** < + * Specifies the MSW of the unique token. + */ + + uint32_t status; + /**< + * Specifies the status information for the metadata. + * + * BIT_0 : Specifies if the metadata is consumed or dropped. + * @values{for bit 0} + * - 0 -- MD_TRACKING_STATUS_IS_CONSUMED; MD is consumed + * - 1 -- MD_TRACKING_STATUS_IS_DROPPED; MD is dropped + * + * Other values are reserved for future use. + */ + +} +#include "spf_end_pack.h" +; + +/* Structure for metadata tracking event. */ +typedef struct metadata_tracking_event_t metadata_tracking_event_t; + + +/** Metadata ID to specify the Media format + * Media format as metadata is propagated by the endpoint module in SPF to the client. + * Client should configure the end-point module with appropriate configuration + * to enable the propagation from SPF to Client in the data response. + */ +#define MODULE_CMN_MD_ID_MEDIA_FORMAT 0x0A001056 + +/** + * Payload media_format_t + * + */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + + +#endif /* METADATA_API_H */ diff --git a/spf/api/modules/miqster_api.h b/spf/api/modules/miqster_api.h new file mode 100644 index 0000000..607a1d6 --- /dev/null +++ b/spf/api/modules/miqster_api.h @@ -0,0 +1,175 @@ +#ifndef MIQSTER_API_H +#define MIQSTER_API_H + +/** + * \file miqster_api.h + * + * \brief + * + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" + +/*========================================================================== + Macros +========================================================================== */ +#define MIQSTER_STACK_SIZE_IN_BYTES 0x8000 //TODO: Profile stack + +#define MIQSTER_MIN_NUM_INPUT_PORTS 0x1 +#define MIQSTER_MAX_NUM_INPUT_PORTS 0x2 + +#define MIQSTER_MIN_NUM_OUTPUT_PORTS 0x1 +#define MIQSTER_MAX_NUM_OUTPUT_PORTS 0x1 + +#define MIQSTER_PRIMARY_IN_PORT_ID 0x2 +#define MIQSTER_SECONDARY_IN_PORT_ID 0x4 + +/** @h2xml_title1 {Audio Zoom (Miqster) Module} + @h2xml_title_agile_rev {Audio Zoom (Miqster) Module} + @h2xml_title_date {Feb 14, 2025} */ + +/*============================================================================== + Module ID and Module Supported Info +==============================================================================*/ +#define MODULE_ID_MIQSTER 0x0700117F +/** + @h2xmlm_module {"MODULE_ID_MIQSTER", MODULE_ID_MIQSTER} + @h2xmlm_displayName {MIQSTER_MODULE} + @h2xmlm_modSearchKeys {Audio zoom} + @h2xmlm_description {Audio Zoom usecase. \n + +* Supports the following parameter IDs\n +* 1. PARAM_ID_MODULE_ENABLE \n // TODO: remove PID module_enable +* 2. PARAM_ID_LIB_VERSION \n +* 3. PARAM_ID_MIQSTER_CFG \n +* 4. PARAM_ID_MIQSTER_MIX \n + + //todo: test on both GC and SC containers. +* Supported Containers: \n +* 1. APM_CONTAINER_TYPE_ID_GC \n + +* Supported Input Media Format : \n + - Data Format : FIXED_POINT \n + - fmt_id : MEDIA_FMT_ID_PCM \n + - Sample Rates : 8000, 16000, 32000, 48000, 96000 \n + - Number of input channels(0x2) : 2 \n + - Number of input channels(0x4) : 1 \n + - Number of output channels : 2 \n + - Channel type : 1 to 63 \n + - Bits per sample : 16, 32\n + - Q format : 15 for bps 16, 27 or 31 for bps 32 \n + - Interleaving : de-interleaved unpacked \n + - Signed/unsigned : Signed } + + @h2xmlm_dataMaxInputPorts {MIQSTER_MAX_NUM_INPUT_PORTS} + @h2xmlm_dataInputPorts {PRIMARY_IN = MIQSTER_PRIMARY_IN_PORT_ID ; + SECONDARY_IN = MIQSTER_SECONDARY_IN_PORT_ID} + @h2xmlm_dataMaxOutputPorts {MIQSTER_MAX_NUM_OUTPUT_PORTS} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {MIQSTER_STACK_SIZE_IN_BYTES} + @h2xmlm_ToolPolicy {Calibration} + + + @{ <-- Start of the Module --> + @h2xml_Select {"lib_version_t"} + @h2xmlm_InsertParameter + */ + +/*============================================================================== + Param miqster CAL +==============================================================================*/ +#define PARAM_ID_MIQSTER_CFG 0x08001B31 +typedef struct param_id_miqster_cfg_t param_id_miqster_cfg_t; + +/** + @h2xmlp_parameter {"PARAM_ID_MIQSTER_CFG", PARAM_ID_MIQSTER_CFG} + @h2xmlp_ToolPolicy {Calibration} + @h2xmlp_description {MIQSTER calibration/tuning parameters\n} +*/ +#include "spf_begin_pack.h" +struct param_id_miqster_cfg_t +{ + int32_t Enable; + /**< @h2xmle_description {Enables lib} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0x1} + @h2xmle_rangeList {Enable_flag=1} + */ + int32_t LowerLimit; + /**< @h2xmle_description {LowerLimit, Minimum amount of enhanced signal to be mixed} + @h2xmle_dataFormat {Q29} + @h2xmle_default {0x0} + @h2xmle_range {0x0..0x20000000} + @h2xmle_policy {Advanced} + */ + int32_t UpperLimit; + /**< @h2xmle_description {UpperLimit, Maximum amount of enhanced signal to be mixed} + @h2xmle_dataFormat {Q29} + @h2xmle_default {0x20000000} + @h2xmle_range {0x0..0x20000000} + @h2xmle_policy {Advanced} + */ + int32_t StereoInputGain; + /**< @h2xmle_description {StereoInputGain, Ratio of channels 1 and 2 to be mixed with loudness compensation. (Use + this to reduce the amount of channesl 1 and 2 in the mix without reducing the overall loudness)} + @h2xmle_dataFormat {Q29} + @h2xmle_default {0x20000000} + @h2xmle_range {0x0..0x20000000} + @h2xmle_policy {Advanced} + */ + int32_t Delay; + /**< @h2xmle_description {DelayCompensation: number of samples by which the third channel is delayed to align with channels 1 and 2.} + @h2xmle_dataFormat {Q8} + @h2xmle_default {0x100} + @h2xmle_range {0x0..0x3C000} + @h2xmle_policy {Advanced} + */ + int32_t Mode; + /**< @h2xmle_description {Mode + Mode0 = Audio Zoom additive mixing mode with loudness reduction for high SPL scenarios + Mode1 = Audio Zoom additive mixing mode without loudness reduction + Mode2 = Audio Zoom subtractive mixing mode where Mix crossfades between channel 1&2 and channel 3. Compared to Modes 0 and 1 which add channel 3 to channel 1&2.} + @h2xmle_dataFormat {Q8} + @h2xmle_default {0x0} + @h2xmle_range {0x0..0x300} + @h2xmle_policy {Advanced} + */ + int32_t Transition; + /**< @h2xmle_description {NumTransitionFrames: number of frames that channel 1&2 inputs exceed loudness threshold before applying gain reduction. } + @h2xmle_dataFormat {Q8} + @h2xmle_default {0x300} + @h2xmle_range {0x0..0x0C800} + @h2xmle_policy {Advanced} + */ +} +#include "spf_end_pack.h" +; + +#define PARAM_ID_MIQSTER_MIX 0x08001B32 +typedef struct param_id_miqster_mix_t param_id_miqster_mix_t; + +/** + @h2xmlp_parameter {"PARAM_ID_MIQSTER_MIX", PARAM_ID_MIQSTER_MIX} + @h2xmlp_ToolPolicy {Calibration, RTC} + @h2xmlp_description {MIQSTER Mix param, amount of zoom required\n} +*/ +#include "spf_begin_pack.h" +struct param_id_miqster_mix_t +{ + int32_t Mix; + /**< @h2xmle_description {Mix, Wet/Dry Mix. (Map the Camcorder Zoom level to this param)} + @h2xmle_dataFormat {Q29} + @h2xmle_default {0x0} + @h2xmle_policy {Advanced} + */ +} +#include "spf_end_pack.h" +; + +/** @} <-- End of the Module -->*/ +#endif // MIQSTER_API_H diff --git a/spf/api/modules/mma_api.h b/spf/api/modules/mma_api.h new file mode 100644 index 0000000..eb5cd2e --- /dev/null +++ b/spf/api/modules/mma_api.h @@ -0,0 +1,1146 @@ +#ifndef __MMA_API_H__ +#define __MMA_API_H__ + +/*============================================================================== + @file mma_api.h + @brief This file contains Public APIs for MMA module. + +\copyright +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +===============================================================================*/ + +/*============================================================================ +EDIT HISTORY FOR MODULE + +when who what, where, why +-------- ------ ------------------------------------------------- +10/5/24 vvenna Created File. +============================================================================*/ +#include "imcl_fwk_intent_api.h" +#include "contexts_api.h" + +/** + @h2xml_title1 {Module MMA API} + @h2xml_title_agile_rev {Module MMA API} + @h2xml_title_date {July 5, 2024} +*/ +#define MMA_RELEASE_VERSION_MSB AR_NON_GUID(0x01000100) +#define MMA_RELEASE_VERSION_LSB AR_NON_GUID(0x00000000) + +/*============================================================================== + Constants +==============================================================================*/ +#define CAPI_MMA_MAX_INPUT_PORTS 1 +#define CAPI_MMA_MAX_OUTPUT_PORTS 0 +#define CAPI_MMA_STACK_SIZE_REQUIREMENT 8192 // TODO: profile and update + +/* Global unique Module ID definition. + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_MMA 0x07001177 + +/*============================================================================== + Module definition +==============================================================================*/ +/** + @h2xml_title1 {Multi-Modal Activation Module API} + @h2xml_title_agile_rev {Multi-Modal Activation Module API} + @h2xml_title_date {July 5, 2024} */ + +/** @h2xmlm_module {"MODULE_ID_MMA",MODULE_ID_MMA} + @h2xmlm_displayName {"Multi-Modal Activation (MMA)"} + @h2xmlm_description {Supports the wakeup detection feature. \n + * - #PARAM_ID_MMA_STATIC_CFG \n + * - #PARAM_ID_MMA_MODE_BIT_CONFIG \n + * - #PARAM_ID_MMA_CONTEXT_ML_MODEL_CONFIG \n + * - #PARAM_ID_MMA_CONTEXT_THRESHOLD \n + * - #PARAM_ID_MMA_SPEECH_DYNAMIC_CFG \n + * - #PARAM_ID_MMA_CONTINUOUS_LISTEN_ENABLE_CONFIG \n + * - #PARAM_ID_MMA_CONTINUOUS_LISTEN_TIMEOUT_CONFIG \n + * - #PARAM_ID_MMA_DETECTION_TIMEOUT_CONFIG \n + * - #PARAM_ID_MMA_ENABLE_SPEECH_RESET \n + * - #PARAM_ID_MMA_SPEECH_RESET_PERIOD \n + * - #PARAM_ID_MMA_ILD_CONFIG \n + * - #PARAM_ID_MMA_CAMERA_CONFIG \n + * - #PARAM_ID_MMA_HISTORY_BUFFER_SIZE \n + * - #PARAM_ID_MMA_RESET \n + * - #PARAM_ID_MMA_ILD_RMS_CONFIG \n + * - #PARAM_ID_MMA_ILD_COH_CONFIG \n + * - #PARAM_ID_MMA_ILD_MEDFILT_CONFIG \n + * - #PARAM_ID_MMA_ILD_PND_CONFIG \n + * - #PARAM_ID_MMA_ILD_LMS_CONFIG \n + * - #PARAM_ID_MMA_LVD_CONFIG \n + * + * Supported Input Media Format: \n + * - Data Format : FIXED_POINT \n + * - fmt_id : Don't care \n + * - Sample Rates : 16Khz \n + * - Number of channels : 1 to 2 \n + * - Channel type : 1 to 63 \n + * - Bits per sample : 16 \n + * - Q format : 15 \n + * - Interleaving : Deinterleaved Unpacked \n + * - Signed/unsigned : Any } + @h2xmlm_dataMaxInputPorts {CAPI_MMA_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {CAPI_MMA_MAX_OUTPUT_PORTS} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {CAPI_MMA_STACK_SIZE_REQUIREMENT} + @h2xmlm_ctrlDynamicPortIntent { "MMA-DAM Control" = INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL, + maxPorts= 1 } + + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> +*/ + +#define PARAM_ID_MMA_STATIC_CFG 0x08001AC4 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_STATIC_CFG", PARAM_ID_MMA_STATIC_CFG} + @h2xmlp_description {Parameter for static configuration for MMA module.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_static_cfg_t +{ + + int32_t num_channel_processing; + /**< @h2xmle_description {Number of channel processing} + @h2xmle_default {1} + @h2xmle_range {1..2} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + int32_t conf_change; + /**< @h2xmle_description {Change in confidence level for sending detection update} + @h2xmle_default {1} + @h2xmle_range {0..100} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + int16_t mic_gain; + /**< @h2xmle_description {Microphone gain to be applied in Q4.11 format} + @h2xmle_default {0x0800} + @h2xmle_range {0..0x7FFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int16_t reserved; + /**< @h2xmle_description {Added for alignment} + @h2xmle_default {0} + @h2xmle_range {0x0000..0x0000} + @h2xmle_visibility {hide} + @h2xmle_readOnly {true} */ + +} param_id_mma_static_cfg_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_MODE_BIT_CONFIG 0x08001AC5 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_MODE_BIT_CONFIG", PARAM_ID_MMA_MODE_BIT_CONFIG} + @h2xmlp_description {Parameter to get MMA library version.\n + 0x00000006 TILT-N_TALK: Tilt2Talk + Speech(or mid-distance speech) Detection \n +* 0x0000000A Lift-N-Talk :Intent2Speak + NVD // CAPI doesnt expose NVD bit. So speech is enabled \n +* 0x00000026 Lift-Gaze-Talk:Tilt2Talk + Gaze Detection + Speech(or mid-distance speech) Detection \n +* 0x00000016 Lift-Face-Talk:Tilt2Talk + Face Detection + Speech(or mid-distance speech) Detection \n +* 0x00000022 Gaze-N-Talk:Gaze Detection + Speech(or mid-distance speech) Detection \n +* 0x0000002A Lift-Gaze-Talk_1 :Intent2Speak+ Gaze Detection + Speech(or mid-distance speech) Detection \n +* 0x0000001A Lift-Face-Talk_1 :Intent2Speak+ Face Detection + Speech(or mid-distance speech) Detection \n } + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_mode_bit_config_t +{ + + uint32_t mode_bit; + /**< @h2xmle_description {mode bit to enable different modalities} + + @h2xmle_bitfield {0x00000001} + @h2xmle_default {0} + @h2xmle_bitName {Bit_0} + @h2xmle_description {Reserved} + @h2xmle_visibility {hide} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x00000002} + @h2xmle_default {1} + @h2xmle_bitName {Bit_1_SPEECH_or_NVD} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {Speech detection} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x00000004} + @h2xmle_default {1} + @h2xmle_bitName {Bit_2_TILT_TO_WAKE} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {Tilt to talk} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x00000008} + @h2xmle_default {0} + @h2xmle_bitName {Bit_3_INTENT2SPEAK_ACCEL} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {Intent to talk} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x00000010} + @h2xmle_default {0} + @h2xmle_bitName {Bit_4_CAMERA_FACE} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {camera face} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x00000020} + @h2xmle_default {0} + @h2xmle_bitName {Bit_5_CAMERA_GAZE} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {camera gaze} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x00000040} + @h2xmle_default {0} + @h2xmle_bitName {Bit_6_ONOFFBODY_DETECTION} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {Onoffbody detection} + @h2xmle_visibility {hide} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x00000080} + @h2xmle_default {0} + @h2xmle_bitName {Bit_7_AMD} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {Any Motion Detection} + @h2xmle_visibility {hide} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0xFFFFFF00} + @h2xmle_bitName {Bit_30_8} + @h2xmle_description {Reserved} + @h2xmle_visibility {hide} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x80000000} + @h2xmle_default {0} + @h2xmle_bitName {Bit_31_SYNTHETIC_MODALITY_DETECTIONS_FEATURE} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {Enable synthetic modality detection feature for testing. When enabled, Module automatically generates detection events for non-audio modalities (sensors/camera) at configured intervals.} + @h2xmle_bitfieldEnd + + */ + +} param_id_mma_mode_bit_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_CONTEXT_ML_MODEL_CONFIG 0x08001AC6 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_CONTEXT_ML_MODEL_CONFIG", PARAM_ID_MMA_CONTEXT_ML_MODEL_CONFIG} + @h2xmlp_description {MMA stage1 ML MODEL} + @h2xmlp_ToolPolicy {Calibration} + @h2xmlp_isNeuralNetParam {TRUE} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_isHwAccel {TRUE} + @h2xmlp_persistType {SHARED} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +typedef struct param_id_mma_context_ml_model_config_t +{ + uint32_t model_align; + /**< @h2xmle_description {Data Alignment required for the model_data} + @h2xmle_default {256} + @h2xmle_range {0..8192} + @h2xmle_group {MODEL} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + + uint32_t model_offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of model by model_align} + @h2xmle_default {0} + @h2xmle_range {0..8191} + @h2xmle_group {MODEL} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint32_t model_size; + /**< @h2xmle_description {Size of the model in bytes} + @h2xmle_default {0} + @h2xmle_range {0x00000000..0xFFFFFFFF} + @h2xmle_group {MODEL} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint8_t model[0]; + /**< @h2xmle_description {Model data: The path to the model file on the platform} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} + @h2xmle_group {MODEL} + @h2xmle_policy {Basic} */ + +} param_id_mma_context_ml_model_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/** @h2xmlp_subStruct */ +/* Unique Parameter id */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct capi_mma_context_threshold_struct_t +{ + + uint32_t context_id; + /**< @h2xmle_description {context ID for which threshold being set. Context_id is indepedent of mode_bit and usecase designer has to tune this based on model which is being set from application} + @h2xmle_default {MODULE_CMN_CONTEXT_ID_AMBIENCE_SPEECH} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + uint32_t threshold; + /**< @h2xmle_description {Threshold confidence score value} + @h2xmle_default {50} + @h2xmle_range {0..100} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + +} capi_mma_context_threshold_struct_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_CONTEXT_THRESHOLD 0x08001AC7 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_CONTEXT_THRESHOLD", PARAM_ID_MMA_CONTEXT_THRESHOLD} + @h2xmlp_description {Parameter to set context thresholds for MMA module.} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_context_threshold_t +{ + + uint32_t num_contexts; + /**< @h2xmle_description {Number of contexts being set} + @h2xmle_default {1} + @h2xmle_range {0..18} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + +#if defined (__H2XML__) + capi_mma_context_threshold_struct_t threshold_array[0]; + /**< @h2xmle_description {pointer to context wise threshold structure} + @h2xmle_default {0x00000000} + @h2xmle_variableArraySize {num_contexts} + @h2xmle_policy {Advanced} + @h2xmle_rawData */ +#endif +} param_id_mma_context_threshold_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_SPEECH_DYNAMIC_CONFIG 0x08001AC8 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_SPEECH_DYNAMIC_CONFIG", PARAM_ID_MMA_SPEECH_DYNAMIC_CONFIG} + @h2xmlp_description {Parameter to set dynamic config for speech/NVD. Applicable if speech_or_nvd bit is set and don't care for other modes} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_speech_dynamic_config_t +{ + + uint32_t len_hangover_speech; + /**< @h2xmle_description {Number of blocks of no detected speech before vad classification goes to 0} + @h2xmle_default {10} + @h2xmle_range {0..0xFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + uint32_t max_conf_frames_speech; + /**< @h2xmle_description {Number of blocks for capping speech confidence frames} + @h2xmle_default {300} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + uint32_t min_conf_frames_speech; + /**< @h2xmle_description {Minimum confidence frames for speech detection} + @h2xmle_default {30} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + +} param_id_mma_speech_dynamic_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_CONTINUOUS_LISTEN_ENABLE_CONFIG 0x08001AC9 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_CONTINUOUS_LISTEN_ENABLE_CONFIG", PARAM_ID_MMA_CONTINUOUS_LISTEN_ENABLE_CONFIG} + @h2xmlp_description {Parameter to enable continuous listening mode.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_continuous_listen_enable_config_t +{ + + int32_t continuous_listen_enable; + /**< @h2xmle_description {Continuous listening mode enable} + @h2xmle_default {0} + @h2xmle_range {0..1} + @h2xmle_policy {Advanced} */ + +} param_id_mma_continuous_listen_enable_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_CONTINUOUS_LISTEN_TIMEOUT_CONFIG 0x08001ACA + +/** @h2xmlp_parameter {"PARAM_ID_MMA_CONTINUOUS_LISTEN_TIMEOUT_CONFIG", PARAM_ID_MMA_CONTINUOUS_LISTEN_TIMEOUT_CONFIG} + @h2xmlp_description {Timeout for continuous listening mode.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_continuous_listen_timeout_config_t +{ + + int32_t continuous_listen_timeout_in_ms; + /**< @h2xmle_description {Continuous listen timeout in ms } + @h2xmle_default {2000} + @h2xmle_range {1000..15000} + @h2xmle_policy {Advanced} */ + +} param_id_mma_continuous_listen_timeout_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_DETECTION_TIMEOUT_CONFIG 0x08001ACB + +/** @h2xmlp_parameter {"PARAM_ID_MMA_DETECTION_TIMEOUT_CONFIG", PARAM_ID_MMA_DETECTION_TIMEOUT_CONFIG} + @h2xmlp_description {Timeout for detection.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_detection_timeout_config_t +{ + + int32_t detection_timeout_in_ms; + /**< @h2xmle_description {detection listen timeout in ms} + @h2xmle_default {2000} + @h2xmle_range {1000..15000} + @h2xmle_policy {Advanced} */ + +} param_id_mma_detection_timeout_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_ENABLE_SPEECH_RESET 0x08001ACC + +/** @h2xmlp_parameter {"PARAM_ID_MMA_ENABLE_SPEECH_RESET", PARAM_ID_MMA_ENABLE_SPEECH_RESET} + @h2xmlp_description {flag to enable speech reset} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_enable_speech_reset_t +{ + + int32_t enable_reset; + /**< @h2xmle_description {flag to enable speech reset} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_policy {Advanced} */ + +} param_id_mma_enable_speech_reset_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_SPEECH_RESET_PERIOD 0x08001ACD + +/** @h2xmlp_parameter {"PARAM_ID_MMA_SPEECH_RESET_PERIOD", PARAM_ID_MMA_SPEECH_RESET_PERIOD} + @h2xmlp_description {reset period in ms } + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_speech_reset_period_t +{ + + int32_t speech_reset_period_in_ms; + /**< @h2xmle_description {reset period in microseconds} + @h2xmle_default {3000} + @h2xmle_range {0..9000} + @h2xmle_policy {Advanced} */ + +} param_id_mma_speech_reset_period_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_ILD_CONFIG 0x08001ACE + +/** @h2xmlp_parameter {"PARAM_ID_MMA_ILD_CONFIG", PARAM_ID_MMA_ILD_CONFIG} + @h2xmlp_description {ILD(interaural level difference) configuration, During multi channel processing checks the signal level difference between input channels for better detection rate } + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_ild_config_param_t +{ + + int32_t ild_enable; + /**< @h2xmle_description {Enable or disable ILD mechanism.} + @h2xmle_default {0} + @h2xmle_range {0..1} + @h2xmle_group {MMA_ILD} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t ild_threshold_Q16; + /**< @h2xmle_description {Configure an ILD threshold.} + @h2xmle_default {131072} + @h2xmle_range {65536..2147483647} + @h2xmle_group {MMA_ILD} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t ild_buff_duration_in_ms; + /**< @h2xmle_description {HIstory buffer duration for which rms value evaluation happen for successful detection} + @h2xmle_default {300} + @h2xmle_range {20..3000} + @h2xmle_group {MMA_ILD} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + +} param_id_mma_ild_config_param_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_ILD_RMS_CONFIG 0x08001BD4 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_ILD_RMS_CONFIG", PARAM_ID_MMA_ILD_RMS_CONFIG} + @h2xmlp_description {ILD RMS configuration for microphone level detection} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_ild_rms_config_param_t +{ + int32_t ild_bot_mic_dBFS; + /**< @h2xmle_description {Configure bottom microphone absolute RMS level.} + @h2xmle_default {-52} + @h2xmle_range {-70..-40} + @h2xmle_group {MMA_RMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t ild_top_mic_dBFS; + /**< @h2xmle_description {Configure top microphone absolute RMS level.} + @h2xmle_default {-70} + @h2xmle_range {-70..-40} + @h2xmle_group {MMA_RMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t ild_freq_min_bin; + /**< @h2xmle_description {Configure an ILD frequency min bin.} + @h2xmle_default {2} + @h2xmle_range {1..160} + @h2xmle_group {MMA_RMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t ild_freq_max_bin; + /**< @h2xmle_description {Configure an ILD frequency max bin.} + @h2xmle_default {120} + @h2xmle_range {1..160} + @h2xmle_group {MMA_RMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t ild_threshold_upbound_Q16; + /**< @h2xmle_description {Configure an ILD threshold upper bound.} + @h2xmle_default {20724302} + @h2xmle_range {1..207243020} + @h2xmle_group {MMA_RMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t ild_time_domain_check_enable; + /**< @h2xmle_description {Configure ild_time_domain_check_enable.} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_group {MMA_RMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t reserved; + /**< @h2xmle_description {Reserved.} + @h2xmle_default {0} + @h2xmle_group {MMA_RMS} + @h2xmle_subgroup {General} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + +} param_id_mma_ild_rms_config_param_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_ILD_COH_CONFIG 0x08001BD5 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_ILD_COH_CONFIG", PARAM_ID_MMA_ILD_COH_CONFIG} + @h2xmlp_description {ILD Coherence configuration for signal correlation analysis} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_ild_coh_config_param_t +{ + int16_t coh_1st_enable; + /**< @h2xmle_description {Enable or disable 1st coherence check.} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int16_t coh_2nd_enable; + /**< @h2xmle_description {Enable or disable 2nd coherence check.} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t coh_1st_threshold_Q16; + /**< @h2xmle_description {Configure a 1st coherence threshold. Default value 19660 corresponds to 0.3 in floating format} + @h2xmle_default {19660} + @h2xmle_range {1..65535} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t coh_1st_start_bin; + /**< @h2xmle_description {Configure a 1st coherence start bin.} + @h2xmle_default {2} + @h2xmle_range {0..160} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t coh_1st_end_bin; + /**< @h2xmle_description {Configure a 1st coherence end bin.} + @h2xmle_default {11} + @h2xmle_range {0..160} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t coh_2nd_threshold_Q16; + /**< @h2xmle_description {Configure a 2nd coherence threshold. Default value 19660 corresponds to 0.3 in floating format} + @h2xmle_default {19660} + @h2xmle_range {1..65535} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t coh_2nd_start_bin; + /**< @h2xmle_description {Configure a 2nd coherence start bin.} + @h2xmle_default {20} + @h2xmle_range {0..160} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t coh_2nd_end_bin; + /**< @h2xmle_description {Configure a 2nd coherence end bin.} + @h2xmle_default {60} + @h2xmle_range {0..160} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t reserved; + /**< @h2xmle_description {Reserved.} + @h2xmle_default {0} + @h2xmle_group {MMA_COH} + @h2xmle_subgroup {General} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + +} param_id_mma_ild_coh_config_param_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_ILD_MEDFILT_CONFIG 0x08001BD6 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_ILD_MEDFILT_CONFIG", PARAM_ID_MMA_ILD_MEDFILT_CONFIG} + @h2xmlp_description {ILD Median Filter configuration for noise reduction} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_ild_medfilt_config_param_t +{ + int16_t medfilt_enable; + /**< @h2xmle_description {Enable or disable median filter.} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_group {MMA_MEDFILT} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int16_t medfilt_kernel_width; + /**< @h2xmle_description {Configure median filter kernel width.} + @h2xmle_default {5} + @h2xmle_range {1..9} + @h2xmle_group {MMA_MEDFILT} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t reserved; + /**< @h2xmle_description {Reserved.} + @h2xmle_default {0} + @h2xmle_range {0..160} + @h2xmle_group {MMA_MEDFILT} + @h2xmle_subgroup {General} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + +} param_id_mma_ild_medfilt_config_param_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_ILD_PND_CONFIG 0x08001BD7 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_ILD_PND_CONFIG", PARAM_ID_MMA_ILD_PND_CONFIG} + @h2xmlp_description {ILD Pulsive Noise Detection configuration} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_ild_pnd_config_param_t +{ + int32_t pnd_enable; + /**< @h2xmle_description {Enable or disable pulsive noise detection.} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_group {MMA_PND} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t pnd_long_window_in_frame; + /**< @h2xmle_description {Configure long window's length in the unit of frame.} + @h2xmle_default {20} + @h2xmle_range {1..50} + @h2xmle_group {MMA_PND} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t pnd_short_window_in_frame; + /**< @h2xmle_description {Configure short window's length in the unit of frame.} + @h2xmle_default {2} + @h2xmle_range {1..10} + @h2xmle_group {MMA_PND} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t pnd_threshold_Q16; + /**< @h2xmle_description {Configure threshold for pulsive noise detection. Default value 3284580 corresponds to 17dB in floating format} + @h2xmle_default {3284580} + @h2xmle_range {0..65536000} + @h2xmle_group {MMA_PND} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t reserved; + /**< @h2xmle_description {Reserved.} + @h2xmle_default {0} + @h2xmle_group {MMA_PND} + @h2xmle_subgroup {General} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + +} param_id_mma_ild_pnd_config_param_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_ILD_LMS_CONFIG 0x08001BD8 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_ILD_LMS_CONFIG", PARAM_ID_MMA_ILD_LMS_CONFIG} + @h2xmlp_description {ILD LMS (Least Mean Squares) adaptive filter configuration} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_ild_lms_config_param_t +{ + int32_t lms_enable; + /**< @h2xmle_description {Enable or disable LMS.} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lms_tap_num; + /**< @h2xmle_description {Configure the number of taps in LMS filter.} + @h2xmle_default {40} + @h2xmle_range {1..50} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lms_delay; + /**< @h2xmle_description {Configure the number of samples to be delayed for input signal.} + @h2xmle_default {20} + @h2xmle_range {1..40} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lms_mu_Q15; + /**< @h2xmle_description {Configure the learning rate for LMS filter.} + @h2xmle_default {8192} + @h2xmle_range {1..32767} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lms_peak_index_min; + /**< @h2xmle_description {Configure the minimum peak index.} + @h2xmle_default {10} + @h2xmle_range {1..20} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lms_peak_index_max; + /**< @h2xmle_description {Configure the maximum peak index.} + @h2xmle_default {16} + @h2xmle_range {1..20} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lms_peak_value_thres_Q29; + /**< @h2xmle_description {Configure the peak threshold.} + @h2xmle_default {805306368} + @h2xmle_range {0..1610612736} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lms_p2s_ratio_Q16; + /**< @h2xmle_description {Configure the peak-to-surround ratio threshold.} + @h2xmle_default {262144} + @h2xmle_range {0..393216} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lms_erle_ratio_Q16; + /**< @h2xmle_description {Configure the erle ratio threshold.} + @h2xmle_default {26214} + @h2xmle_range {0..65536} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t reserved; + /**< @h2xmle_description {Reserved.} + @h2xmle_default {0} + @h2xmle_group {MMA_LMS} + @h2xmle_subgroup {General} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + +} param_id_mma_ild_lms_config_param_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_LVD_CONFIG 0x08001BD9 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_LVD_CONFIG", PARAM_ID_MMA_LVD_CONFIG} + @h2xmlp_description {LVD (Level Voice Detection) configuration} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_lvd_config_param_t +{ + int32_t lvd_enable; + /**< @h2xmle_description {Enable or disable LVD mechanism.} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_group {MMA_LVD} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lvd_threshold_Q20; + /**< @h2xmle_description {Configure an LVD threshold.} + @h2xmle_default {943718} + @h2xmle_range {1..1048576} + @h2xmle_group {MMA_LVD} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lvd_lookback_window_in_ms; + /**< @h2xmle_description {look back window duration in the unit of milliseconds.} + @h2xmle_default {200} + @h2xmle_range {10..3000} + @h2xmle_group {MMA_LVD} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t lvd_lookahead_window_in_ms; + /**< @h2xmle_description {look ahead window duration in the unit of milliseconds.} + @h2xmle_default {200} + @h2xmle_range {10..3000} + @h2xmle_group {MMA_LVD} + @h2xmle_subgroup {General} + @h2xmle_policy {Advanced} */ + + int32_t reserved; + /**< @h2xmle_description {Reserved.} + @h2xmle_default {0} + @h2xmle_group {MMA_LVD} + @h2xmle_subgroup {General} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + +} param_id_mma_lvd_config_param_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_SPEECH_STATE_FORGET_FACTOR 0x08001AD2 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_SPEECH_STATE_FORGET_FACTOR", PARAM_ID_MMA_SPEECH_STATE_FORGET_FACTOR} + @h2xmlp_description {state forget factor for speech model, During reset will change the current state to some intermediate state instead of restting to state 0 } + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_speech_state_forget_factor_t +{ + + int16_t state_forget_factor; + /**< @h2xmle_description {state forget factor in Q14} + @h2xmle_default {16384} + @h2xmle_range {0..16384} + @h2xmle_policy {Advanced} */ + + int16_t reserved; + /**< @h2xmle_description {reserved} + @h2xmle_default {0} + @h2xmle_range {0..0x7FFF} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + +} param_id_mma_speech_state_forget_factor_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef enum _camera_fd_delivery_mode +{ + MMA_CAMERA_FD_DELIVERY_MODE_MOTION_BASED = 0, + MMA_CAMERA_FD_DELIVERY_MODE_TIME_BASED = 1 +} camera_fd_delivery_mode; + +#define PARAM_ID_MMA_CAMERA_CONFIG 0x08001B0F + +/** @h2xmlp_parameter {"PARAM_ID_MMA_CAMERA_CONFIG", PARAM_ID_MMA_CAMERA_CONFIG} + @h2xmlp_description {CAMERA face detection config - this will be set when modality bits of camera_face or camera_gaze are set} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_camera_config_t +{ + + uint32_t delivery_mode; // delivery_mode, refer enum camera_fd_delivery_mode + /**< @h2xmle_description {delivery mode} + @h2xmle_default {0} + @h2xmle_rangeList {"MMA_CAMERA_FD_DELIVERY_MODE_MOTION_BASED"=0,"MMA_CAMERA_FD_DELIVERY_MODE_TIME_BASED"=1 } + @h2xmle_policy {Advanced} */ + uint32_t detections_per_delivery; + /**< @h2xmle_description {Number of times detections are performed per delivery(applicable for both delivery_mode - + MOTION_BASED and TIME_BASED).} + @h2xmle_default {1} + @h2xmle_range {1..100} + @h2xmle_policy {Advanced} */ + uint32_t delivery_period_in_ms; + /**< @h2xmle_description {Delivery period in ms mentions how often events will be delivered. Delivery period in ms is + applicable only when delivery_mode is set as TIME_BASED.} + @h2xmle_default {1000} + @h2xmle_range {1..10000} + @h2xmle_policy {Advanced} */ + +} param_id_mma_camera_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_HISTORY_BUFFER_SIZE 0x08001ACF + +/** @h2xmlp_parameter {"PARAM_ID_MMA_HISTORY_BUFFER_SIZE", PARAM_ID_MMA_HISTORY_BUFFER_SIZE} + @h2xmlp_description {Desired duration of history buffer in milli seconds.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_history_buffer_size_t +{ + + uint32_t history_buffer_size_in_ms; + /**< @h2xmle_description {Desired duration of history buffer in milli seconds} + @h2xmle_default {2000} + @h2xmle_range {0..0x30000}*/ + +} param_id_mma_history_buffer_size_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_SYNTHETIC_MODALITY_DETECTION_DURATION 0x08001BE8 + +/** @h2xmlp_parameter {"PARAM_ID_MMA_SYNTHETIC_MODALITY_DETECTION_DURATION", PARAM_ID_MMA_SYNTHETIC_MODALITY_DETECTION_DURATION} + @h2xmlp_description {duration of synthetic detection generation} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_mma_synthetic_modality_detection_duration_t +{ + + uint32_t synthetic_modality_detection_duration_in_ms; + /**< @h2xmle_description {Time interval in milliseconds at which synthetic detection events are automatically generated for enabled non-audio modalities (sensors/camera). Only active when bit 31 of mode_bit is enabled.} + @h2xmle_default {10000} + @h2xmle_range {5000..15000} + @h2xmle_policy {Advanced} */ + +} param_id_mma_synthetic_modality_detection_duration_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_MMA_RESET 0x08001AD0 + +/**@h2xmlp_emptyParameter {"PARAM_ID_MMA_RESET", PARAM_ID_MMA_RESET} + @h2xmlp_description {Resets the MMA module to its initial algorithm stage and begins a new detection.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#define EVENT_ID_MMA_DETECTION_EVENT 0x08001AD1 +/** @h2xmlp_parameter {"EVENT_ID_MMA_DETECTION_EVENT", + EVENT_ID_MMA_DETECTION_EVENT} + @h2xmlp_description { Detection event raised by the MMA module.} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +typedef struct event_id_mma_detection_event_t +{ + uint32_t context_id; + /**< @h2xmle_description {context ID for MMA detection?} + @h2xmle_default {0} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + uint32_t mode_mask_bits; + /**< @h2xmle_description {Mode mask bits?} + @h2xmle_default {0} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + uint32_t detection_event_bits; + /**< @h2xmle_description {Detection event bits} + @h2xmle_default {0} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + uint32_t detection_event_bits_after_mask; + /**< @h2xmle_description {Detection event bits after mask} + @h2xmle_default {0} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int32_t multi_modal_detection_flag; + /**< @h2xmle_description {multi modal detection flag} + @h2xmle_default {0} + @h2xmle_range {0..1} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int32_t curr_detection_timer_enabled_flag; + /**< @h2xmle_description {current detection timer enabled flag} + @h2xmle_default {0} + @h2xmle_range {0..1} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int32_t curr_detection_timer_counter_in_frames; + /**< @h2xmle_description {current detection timer counter in frames} + @h2xmle_default {0} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int32_t detection_timeout_in_frames; + /**< @h2xmle_description {detection timeout in frames} + @h2xmle_default {0} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int32_t continuous_listen_enabled_flag; + /**< @h2xmle_description {continuous listening mode enabled flag} + @h2xmle_default {0} + @h2xmle_range {0..1} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int32_t continuous_listen_mode_on_flag_after_detection; + /**< @h2xmle_description {continuous listening mode on flag after detection} + @h2xmle_default {0} + @h2xmle_range {0..1} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int32_t continuous_listen_timer_counter_in_frames; + /**< @h2xmle_description {continuous listening mode timer counter in frames} + @h2xmle_default {0} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + int32_t continuous_listen_timeout_in_frames; + /**< @h2xmle_description {continuous listening mode timeout in frames} + @h2xmle_default {0} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + +} event_id_mma_detection_event_t; + +/** @} <-- End of the Module -->*/ + +#endif // #ifndef __MMA_API_H__ diff --git a/spf/api/modules/module_cmn_api.h b/spf/api/modules/module_cmn_api.h new file mode 100644 index 0000000..4d27b66 --- /dev/null +++ b/spf/api/modules/module_cmn_api.h @@ -0,0 +1,185 @@ +#ifndef _MOD_CMN_API_H_ +#define _MOD_CMN_API_H_ +/** + * \file module_cmn_api.h + * \brief + * this file contains common module definitions + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "apm_graph_properties.h" +#include "media_fmt_api.h" + + +/** @ingroup ar_spf_mod_encdec_mods + Identifier for the Enable parameter used by any audio processing module. + + This generic/common parameter is used to configure or determine the + state of any audio processing module. + + @msgpayload + param_id_module_enable_t @newpage + */ +#define PARAM_ID_MODULE_ENABLE 0x08001026 + +/*# @h2xmlp_parameter {"PARAM_ID_MODULE_ENABLE", PARAM_ID_MODULE_ENABLE} + @h2xmlp_description {ID for the Enable parameter used by any audio + processing module. This generic/common parameter is + used to configure or determine the state of any audio + processing module.} + @h2xmlp_toolPolicy {Calibration; RTC} */ + +/** @ingroup ar_spf_mod_encdec_mods + Payload of the #PARAM_ID_MODULE_ENABLE parameter, which is used for any + audio processing module. +*/ +#include "spf_begin_pack.h" +struct param_id_module_enable_t +{ + uint32_t enable; + /**< Specifies whether the module is to be enabled or disabled. + + @valuesbul + - 0 -- Disable (Default) + - 1 -- Enable @tablebulletend */ + + /*#< @h2xmle_description {Specifies whether the module is to be enabled or + disabled.} + @h2xmle_rangeList {"Disable"=0; + "Enable"=1} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_module_enable_t param_id_module_enable_t; + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS // to end of file + +#define PARAM_ID_LIB_VERSION 0x00010937 + +/*# @h2xmlp_parameter {"PARAM_ID_LIB_VERSION", PARAM_ID_LIB_VERSION} + @h2xmlp_description {To query the lib version of any audio processing + module.} + @h2xmlp_toolPolicy {RTC_READONLY} + @h2xmlp_readOnly {true} */ + +/* Payload of the PARAM_ID_LIB_VERSION parameter used by + any Audio Processing module + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct lib_version_t +{ + uint32_t lib_version_low; + /*#< @h2xmle_description {Version of the module LSB.} */ + + uint32_t lib_version_high; + /*#< @h2xmle_description {Version of the module MSB} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Structure for Querying module lib version of any Audio processing modules. */ +typedef struct lib_version_t lib_version_t; + + +#define FRAME_SIZE_TYPE_NATIVE 0 +#define FRAME_SIZE_TYPE_US 1 +#define FRAME_SIZE_TYPE_SAMPLES_PER_CHANNEL 2 + +#define PARAM_ID_MODULE_FRAME_SIZE_CFG 0x08001252 + +/*# @h2xmlp_parameter {"PARAM_ID_MODULE_FRAME_SIZE_CFG", + PARAM_ID_MODULE_FRAME_SIZE_CFG} + @h2xmlp_description {Parameter for setting the module frame size.} + @h2xmlp_toolPolicy {Calibration} */ + +/* Payload of the PARAM_ID_MODULE_FRAME_SIZE_CFG parameter used by any Audio Processing module. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_module_frame_size_cfg_t +{ + uint32_t frame_size_type; + /*#< @h2xmle_description {If set to FRAME_SIZE_TYPE_NATIVE, the CAPI frame + size will be don't care and can + be selected according to the internal CAPI + implementation. (NATIVE does NOT mean the frame + size automatically follows the container frame + size. So, NATIVE mode will not work in all use + cases.) \n + Otherwise, this field specifies the units of the + frame_size_value.} + @h2xmle_rangeList {"Library Frame Size"=0; + "Microseconds"=1; + "Samples per Channel"=2} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ + + uint32_t frame_size_value; + /*#< @h2xmle_description {CAPI frame size. For FRAME_SIZE_TYPE_NATIVE, this + value is don't care. \n + FOR FRAME_SIZE_TYPE_US, this value is in + microseconds. \n + For FRAME_SIZE_TYPE_SAMPLES_PER_CHANNEL, this + value is in samples per channel.} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ + + uint32_t sample_rate; + /*#< @h2xmle_description {If frame_size_type is NOT + FRAME_SIZE_TYPE_SAMPLES_PER_CHANNEL, this value is + don't care. \n + If this value is 0, the frame size is specified in + samples that are independent of the sample rate. + Otherwise, the frame size is fixed in time based + on the specified samples (frame_size_value) at + this sample rate. \n + For FFNS, because frame_size_type is expected to + be FRAME_SIZE_TYPE_NATIVE or FRAME_SIZE_TYPE_US, + this value is don't care.} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Structure for setting the module frame size. */ +typedef struct param_id_module_frame_size_cfg_t param_id_module_frame_size_cfg_t; + + +/* Param id to Enable/Disable MLA/eNPU offloading */ +#define PARAM_ID_MLA_ENABLE 0x080011DF + +/*# @h2xmlp_parameter {"PARAM_ID_MLA_ENABLE", PARAM_ID_MLA_ENABLE} + @h2xmlp_description {ID for the parameter that enables MLA/eNPU + offloading.} + @h2xmlp_isHwAccelEnable {true} + @h2xmlp_toolPolicy {Calibration} */ + +/* Payload of the PARAM_ID_MLA_ENABLE parameter */ +#include "spf_begin_pack.h" +struct mla_enable_t +{ + uint32_t mla_enable; + /*#< @h2xmle_description {Flag that indicates whether MLA (aka NPU) is to + be invoked.} + @h2xmle_rangeList {"Disable"= 0; + "Enable"=1} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct mla_enable_t mla_enable_t; + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + + +#endif /* _MOD_CMN_API_H_ */ diff --git a/spf/api/modules/mp2_decoder_api.h b/spf/api/modules/mp2_decoder_api.h new file mode 100644 index 0000000..f4852d1 --- /dev/null +++ b/spf/api/modules/mp2_decoder_api.h @@ -0,0 +1,94 @@ +#ifndef _MP2_DECODER_API_H_ +#define _MP2_DECODER_API_H_ +/*============================================================================== + @file mp2_decoder_api.h + @brief This file contains MP2 decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + ==============================================================================*/ +// clang-format off + +/*============================================================================== + * Include files + ==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {MP2 Decoder Module API} + @h2xml_title_agile_rev {MP2 Decoder Module API} + @h2xml_title_date {April 15, 2019} */ + + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of MP2 module */ +#define MP2_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of MP2 module */ +#define MP2_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of MP2 module */ +#define MP2_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of MP2 module */ +#define MP2_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of MP2 module */ +#define MP2_STACK_SIZE 8192 + + +/*============================================================================== + Module +==============================================================================*/ + +/** + * Module ID for MP2 decoder. + * Decodes data of format-id = MEDIA_FMT_ID_MP2 + */ +#define MODULE_ID_MP2_DEC 0x0700104E +/** + @h2xmlm_module {"MODULE_ID_MP2_DEC", MODULE_ID_MP2_DEC} + @h2xmlm_displayName {"MP2 Decoder"} + @h2xmlm_description {This module is used as the decoder for MP2 use cases.\n + - This module has only one input and one output port.\n + - Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_MP2\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + -- PARAM_ID_REMOVE_INITIAL_SILENCE\n + -- PARAM_ID_REMOVE_TRAILING_SILENCE\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_MP2\n + + * Supported Input Media Format:\n + * - Data Format : FIXED_POINT\n + * - fmt_id : Don't care\n + * - Sample Rates : 16000Hz to 48000Hz \n + * - Number of channels : 2\n + * - Channel type : 1 to 63\n + * - Bits per sample : 16, 24\n + + + } + @h2xmlm_dataMaxInputPorts {MP2_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {MP2_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=MP2_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=MP2_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_stackSize {MP2_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> + */ + #endif // _MP2_DECODER_API_H_ + diff --git a/spf/api/modules/mp3_decoder_api.h b/spf/api/modules/mp3_decoder_api.h new file mode 100644 index 0000000..a132689 --- /dev/null +++ b/spf/api/modules/mp3_decoder_api.h @@ -0,0 +1,85 @@ +#ifndef _MP3_DECODER_API_H_ +#define _MP3_DECODER_API_H_ +/*============================================================================== + @file mp3_decoder_api.h + @brief This file contains MP3 decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + ==============================================================================*/ +// clang-format off + +/*============================================================================== + * Include files + ==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {MP3 Decoder Module API} + @h2xml_title_agile_rev {MP3 Decoder Module API} + @h2xml_title_date {April 15, 2019} */ + + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of MP3 module */ +#define MP3_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of MP3 module */ +#define MP3_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of MP3 module */ +#define MP3_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of MP3 module */ +#define MP3_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of MP3 module */ +#define MP3_DEC_MODULE_STACK_SIZE 8192 + + +/*============================================================================== + Module +==============================================================================*/ + +/** + * Module ID for MP3 decoder. + * Decodes data of format-id = MEDIA_FMT_ID_MP3 + */ +#define MODULE_ID_MP3_DEC 0x0700103B +/** + @h2xmlm_module {"MODULE_ID_MP3_DEC", MODULE_ID_MP3_DEC} + @h2xmlm_displayName {"MP3 Decoder"} + @h2xmlm_description {This module is used as the decoder for MP3 use cases.\n + - This module has only one input and one output port.\n + - Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_MP3\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + -- PARAM_ID_REMOVE_INITIAL_SILENCE\n + -- PARAM_ID_REMOVE_TRAILING_SILENCE\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_MP3\n + } + @h2xmlm_dataMaxInputPorts {MP3_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {MP3_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=MP3_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=MP3_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {MP3_DEC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> + */ + #endif // _MP3_DECODER_API_H_ + diff --git a/spf/api/modules/mspp_module_calibration_api.h b/spf/api/modules/mspp_module_calibration_api.h new file mode 100644 index 0000000..412a9f9 --- /dev/null +++ b/spf/api/modules/mspp_module_calibration_api.h @@ -0,0 +1,190 @@ +/*================================================== + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + ==================================================*/ + +#ifndef MSPP_MODULE_CALIBRATION_API_H +#define MSPP_MODULE_CALIBRATION_API_H + +/** @h2xml_title1 {MicroSpeaker Post Processing (MSPP)} + @h2xml_title_agile_rev {MicroSpeaker Post Processing (MSPP)} + @h2xml_title_date {March 15, 2021} */ + +#include "module_cmn_api.h" + +/* Global unique Module ID definition 0x070010DE + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_MICROSPEAKER_POST_PROCESSING 0x070010DE + +/** + @h2xmlm_module {"MODULE_ID_MICROSPEAKER_POST_PROCESSING", + MODULE_ID_MICROSPEAKER_POST_PROCESSING} + @h2xmlm_displayName {"MicroSpeaker Post Processing"} + @h2xmlm_description {ID of the MSPP module.\n + + . This module supports the following parameter IDs:\n + . #PARAM_ID_MODULE_ENABLE\n + . #PARAM_ID_MSPP_CFG\n + . #PARAM_ID_MSPP_VOLUME\n + . #PARAM_ID_MSPP_DEV_ORIENTATION\n + . #PARAM_ID_MSPP_VERSION\n + \n + . Supported Input Media Format: \n + . Data Format : FIXED_POINT \n + . fmt_id : MEDIA_FMT_ID_PCM \n + . Sample Rates : 48000 \n + . Number of channels : 2 \n + . Channel type : Supported channel mapping based on number of channels is given below. \n + . Bits per sample : 16,32 \n + . Q format : Q15 for bps = 16, Q27 for bps = 32 \n + . Interleaving : Deinterleaved Unpacked \n + . Signed/unsigned : Signed \n + \n + . Supported Input Channel Mapping based on number of input channels: \n + . 1: stereo [L, R] \n + . 2: mono [C] \n + \n + . Supported Output Channel Mapping based on number of output channels: \n + . 1: stereo [L, R] \n + . 2: mono [C] \n + \n + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC, APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + + + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter +*/ + +/* ID of the MSPP configuration parameter used by MODULE_ID_MICROSPEAKER_POST_PROCESSING.*/ +#define PARAM_ID_MSPP_CFG 0x0800137B + +/* Structure for the configuration parameters of MSPP module. */ +typedef struct mspp_param_id_config_t mspp_param_id_config_t; +/** @h2xmlp_parameter {"PARAM_ID_MSPP_CFG", PARAM_ID_MSPP_CFG} + @h2xmlp_description {Configures the MSPP module} + @h2xmlp_toolPolicy {Calibration; RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_MSPP_CONFIG parameter used by the + MSPP module. + */ +struct mspp_param_id_config_t +{ + + uint32_t cfg_size; + /**< @h2xmle_description {Specifies the length of config} + @h2xmle_range {10000..60000} + @h2xmle_default {48124} */ + + uint8_t cfg_buf[0]; + /**< @h2xmle_description {Buffer containing MSPP config} + @h2xmle_range {0x00..0xFF} + @h2xmle_variableArraySize {"cfg_size"} + @h2xmle_elementType {rawData} + @h2xmle_displayType {file} + @h2xmle_defaultFile {mspp_cfg_default.bin} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {mspp_param_id_config_t} + @h2xmlm_InsertParameter */ + + +#define MICROSPEAKER_LIN_VOLUME_QFACTOR_28 28 + +/* ID of the Multi-channel Volume Control parameters used by #MODULE_ID_MICROSPEAKER_POST_PROCESSING. */ +#define PARAM_ID_MSPP_VOLUME 0x0800137C +/** @h2xmlp_parameter {"PARAM_ID_MSPP_VOLUME", PARAM_ID_MSPP_VOLUME} + @h2xmlp_description { Payload of the volume used by the MSPP module} + @h2xmlp_toolPolicy {Calibration; RTC} + @h2xmlp_maxSize {760} */ + +/* Structure for the volume command */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct mspp_volume_ctrl_gain_t +{ + int32_t vol_lin_gain; + /**< @h2xmle_description {Device volume (linear gain) Q28 format} + @h2xmle_dataFormat {Q28} + @h2xmle_default {0x10000000} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct mspp_volume_ctrl_gain_t mspp_volume_ctrl_gain_t; + +/* @h2xml_Select {mspp_volume_ctrl_gain_t} + @h2xmlm_InsertParameter */ + + +#define PARAM_ID_MSPP_DEV_ORIENTATION 0x08001394 +/** @h2xmlp_parameter {"PARAM_ID_MSPP_DEV_ORIENTATION", PARAM_ID_MSPP_DEV_ORIENTATION} + @h2xmlp_description {Structure to set the current device orientation.} + @h2xmlp_toolPolicy {Calibration; RTC} */ + +typedef struct microspeaker_dev_orientation_t microspeaker_dev_orientation_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct microspeaker_dev_orientation_t { + uint32_t dev_orientation; + /**< @h2xmle_description {device orientation as 0, 1, 2 or 3 for portrait, inverted portrait, landscape, inverted landscape respectively} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {microspeaker_dev_orientation_t} + @h2xmlm_InsertParameter */ + + +#define MICROSPEAKER_RELEASE_VERSION_MAJOR 0x00000003 +#define MICROSPEAKER_RELEASE_VERSION_MINOR 0x00000000 + +#define PARAM_ID_MSPP_VERSION 0x0800137D +/** @h2xmlp_parameter {"PARAM_ID_MSPP_VERSION", PARAM_ID_MSPP_VERSION} + @h2xmlp_description {Structure to get the current library version.} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +typedef struct microspeaker_version_t microspeaker_version_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct microspeaker_version_t +{ + uint32_t lib_version_low; + /**< @h2xmle_description {Lower 32 bits of the 64-bit library version number} + @h2xmle_default {MICROSPEAKER_RELEASE_VERSION_MAJOR} */ + uint32_t lib_version_high; + /**< @h2xmle_description {Higher 32 bits of the 64-bit library version number} + @h2xmle_default {MICROSPEAKER_RELEASE_VERSION_MINOR} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {microspeaker_version_t} + @h2xmlm_InsertParameter */ + + +/** @} <-- End of the Module -->*/ +#endif /* MSPP_MODULE_CALIBRATION_API_H */ diff --git a/spf/api/modules/mux_demux_api.h b/spf/api/modules/mux_demux_api.h new file mode 100644 index 0000000..5e56621 --- /dev/null +++ b/spf/api/modules/mux_demux_api.h @@ -0,0 +1,223 @@ +#ifndef MUX_DEMUX_H_ +#define MUX_DEMUX_H_ +/** + * \file mux_demux_api.h + * \brief + * This file contains APIs for mux_demux module. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** @h2xml_title1 {Muxing and Demuxing Module} + @h2xml_title_agile_rev {Muxing and Demuxing Module} + @h2xml_title_date {October, 2019} */ + +/*============================================================================== + Include Files +==============================================================================*/ +#include "module_cmn_api.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Stack size of module */ +#define MUX_DEMUX_STACK_SIZE 2048 + +/*============================================================================== + Param ID +==============================================================================*/ + +#define PARAM_ID_MUX_DEMUX_CONFIG 0x080011BD + +/*============================================================================== + Param structure defintions +==============================================================================*/ +/** @h2xmlp_subStruct + @h2xmlp_description { This structure defines a connection from an input + port to an output port. } + */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct mux_demux_connection_config_t +{ + uint32_t input_port_id; + /**< @h2xmle_description {input port id.} + */ + uint32_t input_channel_index; + /**< @h2xmle_description {input channel id.} + @h2xmle_range {0..31} + */ + + uint32_t output_port_id; + /**< @h2xmle_description {output port id.} + */ + uint32_t output_channel_index; + /**< @h2xmle_description {output channel id.} + @h2xmle_range {0..31} + */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct mux_demux_connection_config_t mux_demux_connection_config_t; + + +/** @h2xmlp_parameter {"PARAM_ID_MUX_DEMUX_CONFIG", PARAM_ID_MUX_DEMUX_CONFIG} + @h2xmlp_description {This parameter is used for mux and demux configuration + at channel level across input-output streams.} + @h2xmlp_toolPolicy {Calibration; RTC} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_mux_demux_config_t +{ + uint32_t num_of_connections; + /**< @h2xmle_description {Number of connections from input to output across + all streams.} + */ +#ifdef __H2XML__ + mux_demux_connection_config_t connection_arr[0]; + /**< @h2xmle_description {An array of connections} + @h2xmlx_expandStructs {true} + @h2xmle_variableArraySize { num_of_connections } + */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_mux_demux_config_t param_id_mux_demux_config_t; + +/*============================================================================== + Param ID +==============================================================================*/ + +#define PARAM_ID_MUX_DEMUX_OUT_FORMAT 0x080011BE + +/*============================================================================== + Param structure defintions +==============================================================================*/ +/** @h2xmlp_subStruct + @h2xmlp_description { This structure sets the media format of an output port. } + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct mux_demux_out_format_t +{ + uint32_t output_port_id; + /**< @h2xmle_description {output port id.} + */ + + uint16_t bits_per_sample; + /**< @h2xmle_description {bits per sample.} + @h2xmle_default {16} + @h2xmle_rangelist {BPS16;16,BPS32;32} + */ + + uint16_t q_factor; + /**< @h2xmle_description {q factor.} + @h2xmle_default {15} + @h2xmle_rangelist {BPS16_Q15;15,BPS32_Q27;27,BPS32_Q31;31} + */ + + uint32_t num_channels; + /**< @h2xmle_description {number of channels.} + @h2xmle_default {2} + @h2xmle_range {1..32} + */ +#ifdef __H2XML__ + uint16_t channel_type[0]; + /**< @h2xmle_description {channel type, array size is even for alignment purpose.} + @h2xmlx_expandStructs {true} + @h2xmle_variableArraySize { num_channels} + @h2xmle_rangeEnum {pcm_channel_map} + @h2xmle_default {1} + */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct mux_demux_out_format_t mux_demux_out_format_t; + + +/** @h2xmlp_parameter {"PARAM_ID_MUX_DEMUX_OUT_FORMAT", PARAM_ID_MUX_DEMUX_OUT_FORMAT} + @h2xmlp_description {This parameter is used to configure the output port + media format.} + @h2xmlp_toolPolicy {Calibration; RTC} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_mux_demux_out_format_t +{ + uint32_t num_config; + /**< @h2xmle_description {Number of output port media format configuration.} + */ +#ifdef __H2XML__ + mux_demux_out_format_t out_fmt_arr[0]; + /**< @h2xmle_description {An array of output port format} + @h2xmlx_expandStructs {false} + @h2xmle_variableArraySize {num_config} + */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_mux_demux_out_format_t param_id_mux_demux_out_format_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +#define MODULE_ID_MUX_DEMUX 0x07001098 +/** + @h2xmlm_module {"MODULE_ID_MUX_DEMUX", MODULE_ID_MUX_DEMUX} + @h2xmlm_displayName {"Muxing & Demuxing"} + @h2xmlm_description { This module provides channel routing + functionality from multiple input stream + to multiple output streams.\n + Sync module is required to synchronize the inputs + if placed in CD or PP container(non timer triggered).\n + -#PARAM_ID_MUX_DEMUX_CONFIG\n + -#PARAM_ID_MUX_DEMUX_OUT_FORMAT\n + - Supported Input Media Format:\n + - Data Format : FIXED \n + - fmt_id : PCM \n + - Sample Rates : 8000...384000 \n + - Number of channels : 1...32 \n + - Channel type : Don't care \n + - Bits per sample : 16,32 \n + - Q format : Q15,Q27,Q31 \n + - Interleaving : De-interleaved unpacked \n + - Signed/unsigned : Signed \n} + @h2xmlm_dataMaxInputPorts {INFINITE} + @h2xmlm_dataMaxOutputPorts {INFINITE} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC, APM_CONTAINER_TYPE_GC} + @h2xmlm_stackSize {MUX_DEMUX_STACK_SIZE} + @h2xmlm_toolPolicy { Calibration } + + @{ <-- Start of the Module --> + + @h2xml_Select {mux_demux_out_format_t} + @h2xmlm_InsertParameter + + @h2xml_Select {mux_demux_connection_config_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_mux_demux_config_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_mux_demux_out_format_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module -->*/ + +#endif diff --git a/spf/api/modules/nmt_module_calibration_api.h b/spf/api/modules/nmt_module_calibration_api.h new file mode 100644 index 0000000..0e20570 --- /dev/null +++ b/spf/api/modules/nmt_module_calibration_api.h @@ -0,0 +1,524 @@ +/* ========================================================================= +  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + ========================================================================= */ + +#ifndef NMT_MODULE_CALIBRATION_API_H +#define NMT_MODULE_CALIBRATION_API_H + +/** @h2xml_title1 {Neural Machine Translation (NMT)} + @h2xml_title_agile_rev {Neural Machine Translation (NMT)} + @h2xml_title_date {Dec 20, 2024} */ + +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/* Global unique Module ID definition + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_NMT 0x0702C002 + +/** + @h2xmlm_module {"MODULE_ID_NMT", + MODULE_ID_NMT} + @h2xmlm_displayName {"Neural Machine Translation"} + @h2xmlm_description {ID of the NMT module.\n + + . This module supports the following parameter IDs:\n + . #PARAM_ID_NMT_CONFIG\n + . #PARAM_ID_NMT_VERSION\n + . #PARAM_ID_NMT_MODEL\n + . #PARAM_ID_NMT_FORCE_OUTPUT\n + . #PARAM_ID_NMT_OUTPUT_CONFIG\n + . #PARAM_ID_NMT_OUTPUT\n + \n + . Supported Input Media Format: \n + . Data Format : CAPI_RAW_COMPRESSED \n + . fmt_id : MEDIA_FMT_ID_ASR \n + \n + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + + @{ <-- Start of the Module --> + + +*/ + +#define NMT_NPU_RELEASE_VERSION_MAJOR 0x00000001 +#define NMT_NPU_RELEASE_VERSION_MINOR 0x00000000 + +#define PARAM_ID_NMT_VERSION 0x08001B2C +/** @h2xmlp_parameter {"PARAM_ID_NMT_VERSION", PARAM_ID_NMT_VERSION} + @h2xmlp_description {Structure to get the current library version.} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +typedef struct nmt_version_t nmt_version_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct nmt_version_t +{ + uint32_t lib_version_low; + /**< @h2xmle_description {Lower 32 bits of the 64-bit library version number} + @h2xmle_default {NMT_NPU_RELEASE_VERSION_MAJOR} */ + uint32_t lib_version_high; + /**< @h2xmle_description {Higher 32 bits of the 64-bit library version number} + @h2xmle_default {NMT_NPU_RELEASE_VERSION_MINOR} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {nmt_version_t} + @h2xmlm_InsertParameter */ + +/* + * Supported language codes + */ +namespace NMT { + typedef enum NMT_LANGUAGE_CODE_t { + en_US = 0, + zh_CN, + hi_IN, + es_US, + ko_KR, + ja_JP, + language_code_end_1 = 0xFFFFFFFF + } NMT_LANGUAGE_CODE_t; +} +/* ID of the NMT configuration parameter used by MODULE_ID_NMT.*/ +#define PARAM_ID_NMT_CONFIG 0x08001B2B + +/* Structure for the configuration parameters of NMT module. */ +typedef struct param_id_nmt_config_t param_id_nmt_config_t; +/** @h2xmlp_parameter {"PARAM_ID_NMT_CONFIG", PARAM_ID_NMT_CONFIG} + @h2xmlp_description {Configures the NMT module} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_nmt_config_t +{ + uint32_t input_language_code; // specify language of input text segment. + /**< @h2xmle_description {Code to specify NMT input language.} + @h2xmle_rangeList {"en_US"=en_US;"zh_CN"=zh_CN;"hi_IN"=hi_IN;"es_US"=es_US;"ko_KR"=ko_KR;"ja_JP"=ja_JP;"language_code_end"=language_code_end_1} + @h2xmle_default {en_US} */ + uint32_t output_language_code; // Specify language of output text segment. + /**< @h2xmle_description {Code to specify NMT output language.} + @h2xmle_rangeList {"en_US"=en_US;"zh_CN"=zh_CN;"hi_IN"=hi_IN;"es_US"=es_US;"ko_KR"=ko_KR;"ja_JP"=ja_JP;"language_code_end"=language_code_end_1} + @h2xmle_default {en_US} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_nmt_config_t} + @h2xmlm_InsertParameter */ + +namespace NMT{ + typedef enum nmt_output_mode_t + { + NON_BUFFERED = 0, /* Send NMT engine output immediately. Each buffer shall have one payload + corresponding to a partial/complete segment of speech. + Typical usage : live display of output. */ + BUFFERED, /* Buffer up NMT engine output based on configured buffer size from client. + Send the event to clients once buffer is full. + Typical usage : save transcription output in background. */ + } nmt_output_mode_t; +} +/* ID of the NMT output configuration parameter used by MODULE_ID_NMT.*/ +#define PARAM_ID_NMT_OUTPUT_CONFIG 0x08001B80 + +/* Structure for the output configuration parameter of NMT module. */ +typedef struct param_id_nmt_output_config_t param_id_nmt_output_config_t; +/** @h2xmlp_parameter {"PARAM_ID_NMT_OUTPUT_CONFIG", PARAM_ID_NMT_OUTPUT_CONFIG} + @h2xmlp_description {Param to configure required output mode and buffering for NMT engine } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_NMT_OUTPUT_CONFIG parameter used by the NMT module. + */ +struct param_id_nmt_output_config_t +{ + uint32_t output_mode; // mode of NMT output data requested by application + /**< @h2xmle_description {Configuration to specify transcription output mode depending on usecase requirement. + NON_BUFFERED - Output of each NMT algo process is immediately sent to client. + BUFFERED - Output of each NMT algo process is buffered and sent to client intermittently.} + @h2xmle_default {NON_BUFFERED} + @h2xmle_rangeList {"NON_BUFFERED"=0, "BUFFERED"=1} */ + + uint32_t out_buf_size; // size in bytes of buffer to use in different output modes, primarily in buffered mode + /**< @h2xmle_description {Configuration to specify transcription output buffer size depending on usecase requirement.} + @h2xmle_default {3072} // NMT engine controlled default if not configured + @h2xmle_range {3072.. 262144} */ + + uint32_t num_bufs; // Number of buffers + /**< @h2xmle_description {Configuration to specify number of output buffers.} + @h2xmle_default {1} // NMT engine controlled default if not configured + @h2xmle_range {1.. 16} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Maximum transcription text size of NMT output in one process call */ +#define MAX_TRANSCRIPTION_CHAR_SIZE 1024 + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct nmt_output_status_t +{ + uint32_t status; + /**<@h2xmle_description {Status of NMT output in this payload} + @h2xmle_default {0} + @h2xmle_rangeList {"NMT_SUCCESS"=0,"NMT_FAIL"=1} */ + + uint32_t is_final; + /**<@h2xmle_description {Field indicating payload is partial output of NMT or complete} + @h2xmle_default {0} + @h2xmle_rangeList {"TRUE"=1, "FALSE"=0} */ + + uint32_t segment_start_time_us_lsw; + /**< @h2xmle_description {Field indicating word start timestamp in us least significant 32 bits.} */ + + uint32_t segment_start_time_us_msw; + /**< @h2xmle_description {Field indicating word start timestamp in us most significant 32 bits.} */ + + uint32_t segment_end_time_us_lsw; + /**< @h2xmle_description {Field indicating word end timestamp in us least significant 32 bits.} */ + + uint32_t segment_end_time_us_msw; + /**< @h2xmle_description {Field indicating word end timestamp in us most significant 32 bits.} */ + + uint32_t output_text_size; + /**< @h2xmle_description {Field indicating size of valid output text including NULL Char } */ + + uint8_t output_text[MAX_TRANSCRIPTION_CHAR_SIZE]; + /**< @h2xmle_description {NMT output text } */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct nmt_output_status_t nmt_output_status_t; + +/* @h2xml_Select {nmt_output_status_t} + @h2xmlm_InsertParameter */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct nmt_input_status_t +{ + uint32_t status; + /**<@h2xmle_description {Status of NMT output in this payload} + @h2xmle_default {0} + @h2xmle_rangeList {"NMT_SUCCESS"=0,"NMT_FAIL"=1} */ + + uint32_t is_final; + /**<@h2xmle_description {Field indicating payload is partial output of NMT or complete} + @h2xmle_default {0} + @h2xmle_rangeList {"TRUE"=1, "FALSE"=0} */ + + uint32_t segment_start_time_us_lsw; + /**< @h2xmle_description {Field indicating word start timestamp in us least significant 32 bits.} */ + + uint32_t segment_start_time_us_msw; + /**< @h2xmle_description {Field indicating word start timestamp in us most significant 32 bits.} */ + + uint32_t segment_end_time_us_lsw; + /**< @h2xmle_description {Field indicating word end timestamp in us least significant 32 bits.} */ + + uint32_t segment_end_time_us_msw; + /**< @h2xmle_description {Field indicating word end timestamp in us most significant 32 bits.} */ + + uint32_t input_text_size; + /**< @h2xmle_description {Field indicating size of valid input text including NULL Char } */ + + uint8_t input_text[MAX_TRANSCRIPTION_CHAR_SIZE]; + /**< @h2xmle_description {NMT input text } */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct nmt_input_status_t nmt_input_status_t; + +/* @h2xml_Select {nmt_input_status_t} + @h2xmlm_InsertParameter */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct nmt_io_status_t +{ + uint32_t status; + /**< @h2xmle_description {Status of NMT output in this payload} + @h2xmle_default {0} + @h2xmle_rangeList {"NMT_SUCCESS"=0,"NMT_FAIL"=1} */ + + uint32_t is_final; + /**<@h2xmle_description {Field indicating payload is partial output of NMT or complete} + @h2xmle_default {0} + @h2xmle_rangeList {"TRUE"=1, "FALSE"=0} */ + + uint32_t segment_start_time_us_lsw; + /**< @h2xmle_description {Field indicating word start timestamp in us least significant 32 bits.} */ + + uint32_t segment_start_time_us_msw; + /**< @h2xmle_description {Field indicating word start timestamp in us most significant 32 bits.} */ + + uint32_t segment_end_time_us_lsw; + /**< @h2xmle_description {Field indicating word end timestamp in us least significant 32 bits.} */ + + uint32_t segment_end_time_us_msw; + /**< @h2xmle_description {Field indicating word end timestamp in us most significant 32 bits.} */ + + uint32_t output_text_size; + /**< @h2xmle_description {Field indicating size of valid output text including NULL Char } */ + + uint8_t output_text[MAX_TRANSCRIPTION_CHAR_SIZE]; + /**< @h2xmle_description {NMT output text } */ + + uint32_t input_text_size; + /**< @h2xmle_description {Field indicating size of valid input text including NULL Char } */ + + uint8_t input_text[MAX_TRANSCRIPTION_CHAR_SIZE]; + /**< @h2xmle_description {NMT input text } */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct nmt_io_status_t nmt_io_status_t; + +/* @h2xml_Select {nmt_io_status_t} + @h2xmlm_InsertParameter */ + + +/* ID of the NMT output get parameter used by MODULE_ID_NMT.*/ +#define PARAM_ID_NMT_OUTPUT 0x08001B81 + +/* Structure for the output get parameter of NMT module. */ +typedef struct param_id_nmt_output_t param_id_nmt_output_t; +/** @h2xmlp_parameter {"PARAM_ID_NMT_OUTPUT", PARAM_ID_NMT_OUTPUT} + @h2xmlp_description {Get Param to query input/output from the module based on event_payload_type in event_id_nmt_event_t} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_NMT_OUTPUT parameter used by the NMT module. + */ +struct param_id_nmt_output_t +{ + uint32_t token; + /**< @h2xmle_description {Token provided by the NMT engine corresponding to an output. + This can be used by clients to query the corresponding payload. + If not configured or invalid, Payload corresponds to output buffers + in sequential order as produced by NMT engine.Dummy token (0x7F7F7F7F) + is reserved for FORCE_OUTPUT scenario where output buffer doesn’t + have valid content but must raise event to client.} + @h2xmle_default {1} + @h2xmle_range {1..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of buffers of type nmt_output_status_t, nmt_input_status_t or nmt_io_status_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type nmt_io_status_t . + Size '0' indicates this is an event generated without any valid input/output, + for example : in response to a force output param set by client. } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ +#if defined(__H2XML__) + nmt_io_status_t transcription_payload[0]; + /*@variableArraySize {payload_size} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_nmt_output_t} + @h2xmlm_InsertParameter */ + + +/* ID of the NMT force output parameter used by MODULE_ID_NMT.*/ +#define PARAM_ID_NMT_FORCE_OUTPUT 0x08001B2E + +/* Structure for the force output parameter of NMT module. */ +typedef struct param_id_nmt_force_output_t param_id_nmt_force_output_t; +/** @h2xmlp_parameter {"PARAM_ID_NMT_FORCE_OUTPUT", PARAM_ID_NMT_FORCE_OUTPUT} + @h2xmlp_description {Forces the NMT module to produce output event irrespective of configured input threshold} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_NMT_FORCE_OUTPUT parameter used by the NMT module. + */ +struct param_id_nmt_force_output_t +{ + uint32_t force_output; // Force NMT to process and produce output + /**< @h2xmle_description {force NMT module to produce output with current data without waiting for further data accumulation.} + @h2xmle_default {1} + @h2xmle_range {0..1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_nmt_force_output_t} + @h2xmlm_InsertParameter */ + + +#define EVENT_ID_NMT_STATUS 0x08001B82 + +/* Structure definition for Parameter */ +/** @parameter {"EVENT_ID_NMT_STATUS", EVENT_ID_NMT_STATUS} + @description {Event raised by NMT to the clients; registration and event have different payload types} + @toolPolicy {NO_SUPPORT}*/ + +/** ################################ Struct definitions for event registration################### */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_nmt_reg_cfg_t +{ + uint32_t event_payload_type; + /**< @h2xmle_description {Field to configure event payload type + QUERY - Client queries the input/output via getparam upon receiving NMT event. + INBAND - NMT event has the payload inband in the event. + OPTIMAL - NMT event can be INBAND or QUERY based, flag in event + payload indicates the mode.} + @h2xmle_default {0} + @h2xmle_rangeList {"QUERY"=0, "INBAND"=1, "OPTIMAL"=2} */ + + uint32_t event_text_type; + /**< @h2xmle_description {Field to configure event text type + OUT - event payload contains output text only. + IN - event payload contains input text only. + INOUT - event payload contains combined input and output text.} + @h2xmle_default {2} + @h2xmle_rangeList {"OUT"=0, "IN"=1, "INOUT"=2} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_nmt_reg_cfg_t event_id_nmt_reg_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/* Event config to provide the info of getparam vs inband vs both */ +struct event_id_nmt_event_t +{ + uint32_t event_payload_type; + /**< @h2xmle_description {Event payload type. Default mode is Query. + QUERY = Client will query via getparam upon receiving this event, using the + output_token provided as part of this payload. + Inband = NMT output payload follows inband after the payload_size field } + @h2xmle_default {0} + @h2xmle_rangeList {"QUERY"=0, "INBAND"=1} */ + uint32_t event_text_type; + /**< @h2xmle_description {Event text type. Default type is OUT. + OUT - event payload contains output text only. + IN - event payload contains input text only. + INOUT - event payload contains combined input and output text.} + @h2xmle_default {2} + @h2xmle_rangeList {"OUT"=0, "IN"=1, "INOUT"=2} */ + uint32_t token; + /**< @h2xmle_description {Token provided by the NMT engine corresponding to an output. + This can be used by clients to query the payload param in 'QUERY' mode. + Dummy token (0x7F7F7F7F) is reserved for FORCE_OUTPUT scenario where + output buffer doesn’t have valid content but must raise event to client.} + @h2xmle_default {1} + @h2xmle_range {1..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of buffers of type nmt_ouput_status_t, nmt_input_status_t or nmt_io_status_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type nmt_io_status_t . + Size '0' indicates this is an event generated without any valid output, + for example : in response to a force output param set by client. } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ +#if defined(__H2XML__) + nmt_io_status_t transcription_payload[0]; + /*@variableArraySize {payload_size} */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_nmt_event_t event_id_nmt_event_t; + +/* @h2xml_Select {nmt_model_param_t} + @h2xmlm_InsertParameter */ +#define PARAM_ID_NMT_MODEL 0x08001B2D + +typedef struct nmt_model_param_t nmt_model_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_NMT_MODEL", PARAM_ID_NMT_MODEL} + @h2xmlp_description {NN Model related parameters} + @h2xmlp_ToolPolicy {CALIBRATION} + @h2xmlp_isHwAccel {FALSE} + @h2xmlp_isNeuralNetParam {TRUE} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct nmt_model_param_t +{ + uint32_t model_align; + /**< @h2xmle_description {Data Alignment required for the model_data} + @h2xmle_default {256} + @h2xmle_range {0..8192} + @h2xmle_group {SPF} + @h2xmle_subgroup {NNVAD} + @h2xmle_policy {Advanced} */ + + uint32_t model_offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of model by model_align} + @h2xmle_default {0} + @h2xmle_range {0..8191} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint32_t model_size; + /**< @h2xmle_description {Size of the model in bytes} + @h2xmle_default {0} + @h2xmle_range {0x00000000..0xFFFFFFFF} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint8_t model[0]; + /**< @h2xmle_description {Model data: The path to the model file on the platform} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/** @} <-- End of the Module -->*/ +#endif /* NMT_MODULE_CALIBRATION_API_H */ diff --git a/spf/api/modules/opus_decoder_api.h b/spf/api/modules/opus_decoder_api.h new file mode 100644 index 0000000..3fffe22 --- /dev/null +++ b/spf/api/modules/opus_decoder_api.h @@ -0,0 +1,87 @@ +#ifndef _OPUS_DECODER_API_H_ +#define _OPUS_DECODER_API_H_ +/*======================================================================== + @file opus_decoder_api.h + @brief This file contains OPUS decoder APIs + ========================================================================*/ + +/*======================================================================== +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==========================================================================*/ + + +/** @h2xml_title1 {OPUS Decoder Module} + @h2xml_title_agile_rev {OPUS Decoder Module} + @h2xml_title_date {March, 2023} */ + +/*======================================================================== + * Include files + =========================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/*======================================================================== + Constants +=========================================================================*/ + +/* Input port ID of OPUS module */ +#define OPUS_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of OPUS module */ +#define OPUS_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of OPUS module */ +#define OPUS_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of OPUS module */ +#define OPUS_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of OPUS module */ +#define OPUS_DEC_MODULE_STACK_SIZE 16384 + + +/*============================================================================== + Module +==============================================================================*/ + +/** + * Module ID for OPUS decoder. + * Decodes data of format-id = MEDIA_FMT_ID_OPUS + */ +#define MODULE_ID_OPUS_DEC 0x07001174 + +/** + @h2xmlm_module {"MODULE_ID_OPUS_DEC", MODULE_ID_OPUS_DEC} + @h2xmlm_displayName {"OPUS Decoder"} + @h2xmlm_description {This module is used as the decoder for OPUS Youtube offload use cases.\n + - This module has only one input and one output port.\n + - Payload for media_format_t: payload_media_fmt_opus_t\n + - Media format is not directly set on the decoder, it's set + on the EP module which propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_OPUS\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + - Supported Input Media Format\n + -- Data format: RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_OPUS\n + -- payload: payload_media_fmt_opus_t\n + } + @h2xmlm_dataMaxInputPorts {OPUS_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {OPUS_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=OPUS_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=OPUS_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {OPUS_DEC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> +*/ + +#endif //_OPUS_DECODER_API_H_ diff --git a/spf/api/modules/pcm_decoder_api.h b/spf/api/modules/pcm_decoder_api.h new file mode 100644 index 0000000..2ad8c64 --- /dev/null +++ b/spf/api/modules/pcm_decoder_api.h @@ -0,0 +1,85 @@ +#ifndef PCM_DECODER_API_H_ +#define PCM_DECODER_API_H_ +/*============================================================================== + @file pcm_decoder_api.h + @brief This file contains PCM decoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "module_cmn_api.h" +#include "common_enc_dec_api.h" + +/** + @h2xml_title1 {PCM Decoder Module API} + @h2xml_title_agile_rev {PCM Decoder Module API} + @h2xml_title_date {March 26, 2019} */ + +/*------------------------------------------------------------------------------ + Defines +------------------------------------------------------------------------------*/ +/* Input port ID of MFC module */ +#define PCM_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of MFC module */ +#define PCM_DEC_DATA_OUTPUT_PORT 0x1 + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/** + * Module ID for PCM decoder. + * Decodes data of format-id = MEDIA_FMT_ID_PCM + */ +#define MODULE_ID_PCM_DEC 0x07001005 + +/** + @h2xmlm_module {"MODULE_ID_PCM_DEC", + MODULE_ID_PCM_DEC} + @h2xmlm_displayName {"PCM Decoder"} + @h2xmlm_description { + This module is used as the decoder for PCM use cases. \n + It can be used to convert properties of PCM stream such as \n + endianness, interleaving, bit width, number of channels etc. \n + It cannot be used to convert sampling rate. \n + This module has only one input and one output port. \n + Media format for this module is propagated from \n + Write Shared Memory End Point (No need to set on this module) \n + - This module supports following parameter IDs: \n + -#PARAM_ID_PCM_OUTPUT_FORMAT_CFG \n + - \n + Supported Input Media Format: \n + - Data Format : FIXED_POINT + - fmt_id : MEDIA_FMT_ID_PCM \n + - Sample Rates : 1-384 kHz \n + - Number of channels : 1-32 \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + : 24 (bits per sample 24 and Q23, \n + bits per sample 32 and Q23 or Q27 or Q31), \n + : 32 (bits per sample 32 and Q31) \n + - Interleaving : interleaved, deinterleaved unpacked, \n + deinterleaved packed. \n + - Endianess : little, big \n + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN=PCM_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=PCM_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize { 4096 } + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + + +#endif // PCM_DECODER_API_H_ diff --git a/spf/api/modules/pcm_encoder_api.h b/spf/api/modules/pcm_encoder_api.h new file mode 100644 index 0000000..0af738c --- /dev/null +++ b/spf/api/modules/pcm_encoder_api.h @@ -0,0 +1,147 @@ +#ifndef PCM_ENCODER_API_H_ +#define PCM_ENCODER_API_H_ +/*============================================================================== + @file pcm_encoder_api.h + @brief This file contains PCM encoder APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "module_cmn_api.h" +#include "common_enc_dec_api.h" + +/** + @h2xml_title1 {PCM Encoder Module API} + @h2xml_title_agile_rev {PCM Encoder Module API} + @h2xml_title_date {March 26, 2019} */ + + +/*------------------------------------------------------------------------------ + Defines +------------------------------------------------------------------------------*/ +/* Input port ID of MFC module */ +#define PCM_ENC_DATA_INPUT_PORT 0x2 + +/* Output port ID of MFC module */ +#define PCM_ENC_DATA_OUTPUT_PORT 0x1 + +/*============================================================================== + Param ID +==============================================================================*/ + +/** + ID of the parameter used to set frame size of the pcm encoder + In general,the PCM encoder frame size is determined by the perf_mode + of the container.For Low latency it is 1 ms and for low Power it is 5 ms. + This PID can be used, if the client has the requirement to specify any + fixed frame-size for PCM encoder. +*/ + +#define PARAM_ID_PCM_ENCODER_FRAME_SIZE 0x0800136B +/** @h2xmlp_parameter {"PARAM_ID_PCM_ENCODER_FRAME_SIZE " + ,PARAM_ID_PCM_ENCODER_FRAME_SIZE } + @h2xmlp_description {Structure for PARAM_ID_PCM_ENCODER_FRAME_SIZE + used to set the encoded frame size of the pcm encoder + module.In general,the PCM encoder frame size is determined + by the perf_mode of the container.Currently,for low latency it is + 1ms and for low power it is 5ms. + This PID can be used, if the client has the requirement + to specify the frame-size for PCM encoder. + } + @h2xmlp_toolPolicy {Calibration} */ + + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** Payload of the PARAM_ID_PCM_ENCODER_FRAME_SIZE parameter. + */ +struct param_id_pcm_encoder_frame_size_t +{ + uint32_t frame_size_type; + /**< @h2xmle_description {Specifies whether the frame size of the + pcm encoder module is in samples or microsecond units.} + @h2xmle_default {0} + @h2xmle_rangeList {"frame_size_not_specified"=0; + "frame_size_in_samples"=1; + "frame_size_in_us"=2 }*/ + uint32_t frame_size_in_samples; + /**< @h2xmle_description {Specifies the frame size of pcm encoder + in samples.This parameter value will be used when the + frame_size_type is set to 1 and this value is greater than zero. + We recommend the frame size in samples to be limited to 100ms(or 384khz*100ms=38400 samples)} + @h2xmle_default {0} + @h2xmle_range {0..38400}*/ + uint32_t frame_size_in_us; + /**< @h2xmle_description {Specifies the frame size of pcm encoder + in microsecond units.This parameter value will be used + when the frame_size_type is set to 2 and this value + is greater than zero. + } + @h2xmle_default {0} + @h2xmle_range {0..100000}*/ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Type definition for the above structures. */ +typedef struct param_id_pcm_encoder_frame_size_t param_id_pcm_encoder_frame_size_t; + +/** + * Module ID for PCM encoder. + * Encodes data to format-id = MEDIA_FMT_ID_PCM + */ +#define MODULE_ID_PCM_ENC 0x07001004 +/** + @h2xmlm_module {"MODULE_ID_PCM_ENC", + MODULE_ID_PCM_ENC} + @h2xmlm_displayName {"PCM Encoder"} + @h2xmlm_description { + This module is used as the encoder for PCM use cases. \n + It can be used to convert properties of PCM stream such as \n + endianness, interleaving, bit width, number of channels etc. \n + It cannot be used to convert sampling rate. \n + This module has only one input and one output port. \n + - This module supports following parameter IDs: \n + -#PARAM_ID_PCM_OUTPUT_FORMAT_CFG \n + - \n + Doesn't support + - #PARAM_ID_ENCODER_OUTPUT_CONFIG \n + (as #PARAM_ID_PCM_OUTPUT_FORMAT_CFG covers the supported controls) \n + Supported Input Media Format: \n + - Data Format : FIXED_POINT \n + - fmt_id : Don't care \n + - Sample Rates : 1-384 kHz \n + - Number of channels : 1-32 \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + : 24 (bits per sample 24 and Q23, \n + bits per sample 32 and Q23 or Q27 or Q31), \n + : 32 (bits per sample 32 and Q31) \n + - Interleaving : interleaved, deinterleaved unpacked, \n + deinterleaved packed. \n + - Endianess : little \n + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN=PCM_ENC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=PCM_ENC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { 4096 } + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_pcm_encoder_frame_size_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + + +#endif // PCM_ENCODER_API_H_ diff --git a/spf/api/modules/pcm_tdm_api.h b/spf/api/modules/pcm_tdm_api.h new file mode 100644 index 0000000..ba8cb9e --- /dev/null +++ b/spf/api/modules/pcm_tdm_api.h @@ -0,0 +1,615 @@ +#ifndef _PCM_TDM_API_H_ +#define _PCM_TDM_API_H_ +/** + * \file pcm_tdm_api.h + * \brief + * This file contains PCM TDM module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "hw_intf_cmn_api.h" + +/** + @h2xml_title1 {PCM TDM Module API} + @h2xml_title_agile_rev {PCM TDM Module API} + @h2xml_title_date {July 12, 2018} */ + +/*============================================================================== + Macros +==============================================================================*/ +/* Input port ID of HW PCM module */ +#define PORT_ID_HW_PCM_INPUT 0x2 + +/* Output port ID of HW PCM module */ +#define PORT_ID_HW_PCM_OUTPUT 0x1 + +/* Stack size for Hw PCM and TDM Modules*/ +#define PCM_TDM_STACK_SIZE 2048 + +/*============================================================================== + Constants +==============================================================================*/ + +/* PCM interface index types */ +#define PCM_INTF_TYPE_PRIMARY 0 +#define PCM_INTF_TYPE_SECONDARY 1 +#define PCM_INTF_TYPE_TERTIARY 2 +#define PCM_INTF_TYPE_QUATERNARY 3 +#define PCM_INTF_TYPE_QUINARY 4 + +/** Enumeration for the auxiliary PCM synchronization signal provided by an + external source */ +#define PCM_SYNC_SRC_EXTERNAL 0x0 + +/** Enumeration for the auxiliary PCM synchronization signal provided by an + internal source */ +#define PCM_SYNC_SRC_INTERNAL 0x1 + +/** Enumeration for disabling the PCM/TDM configuration ctrl_data_out_enable + parameter. The PCM block is the only master */ +#define PCM_CTRL_DATA_OE_DISABLE 0x0 + +/** Enumeration for enabling the PCM/TDM configuration ctrl_data_out_enable + parameter. The PCM block shares the signal with other masters. @newpage */ +#define PCM_CTRL_DATA_OE_ENABLE 0x1 + +/** Enumeration for setting the PCM configuration frame to 16 */ +#define PCM_BITS_PER_FRAME_16 0x0 + +/** Enumeration for setting the PCM configuration frame to 32 */ +#define PCM_BITS_PER_FRAME_32 0x1 + +/** Enumeration for setting the PCM configuration frame to 64 */ +#define PCM_BITS_PER_FRAME_64 0x2 + +/** Enumeration for setting the PCM configuration frame to 128 */ +#define PCM_BITS_PER_FRAME_128 0x3 + +/** Enumeration for setting the PCM configuration frame to 256 */ +#define PCM_BITS_PER_FRAME_256 0x4 + +/** Enumeration for the PCM configuration aux_mode parameter, which configures + the auxiliary PCM interface to use short synchronization */ +#define PCM_MODE 0x0 + +/** Enumeration for the PCM configuration aux_mode parameter, which configures + the auxiliary PCM interface to use long synchronization */ +#define AUX_MODE 0x1 + +/*============================================================================== + Type definition +==============================================================================*/ +/** Param ID to configure PCM interface*/ +#define PARAM_ID_HW_PCM_INTF_CFG 0x0800101A + +/** @h2xmlp_parameter {"PARAM_ID_HW_PCM_INTF_CFG", + PARAM_ID_HW_PCM_INTF_CFG} + @h2xmlp_description {Configures the PCM interface.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" + +/** Payload for parameter PARAM_ID_HW_PCM_INTF_CFG */ +struct param_id_hw_pcm_intf_cfg_t +{ + uint32_t lpaif_type; + /**< @h2xmle_description {LPAIF types.} + @h2xmle_rangeList {"LPAIF"=0; + "LPAIF_RXTX"=1; + "LPAIF_WSA"=2; + "LPAIF_VA"=3; + "LPAIF_AXI"=4} + @h2xmle_default {0} + */ + uint32_t intf_idx; + /**< @h2xmle_description {Defines PCM interface type} + @h2xmle_rangeList {"PCM_INTF_TYPE_PRIMARY"=0; + "PCM_INTF_TYPE_SECONDARY"=1; + "PCM_INTF_TYPE_TERTIARY"=2; + "PCM_INTF_TYPE_QUATERNARY"=3; + "PCM_INTF_TYPE_QUINARY"=4} + @h2xmle_default {0} + */ + uint16_t sync_src; + /**< @h2xmle_description {Defines slave or master mode of operation.} + @h2xmle_rangeList {"PCM_SYNC_SRC_EXTERNAL"=0; + "PCM_SYNC_SRC_INTERNAL"=1} + @h2xmle_default {1} + */ + uint16_t ctrl_data_out_enable; + /**< @h2xmle_description {Specifies if PCM block shares data-out signal\n + to the driver with other masters.} + @h2xmle_rangeList {"PCM_CTRL_DATA_OE_DISABLE"=0; + "PCM_CTRL_DATA_OE_ENABLE"=1} + @h2xmle_default {1} + */ + uint32_t slot_mask; + /**< @h2xmle_description {Specifies position of the active slot} + @h2xmle_range {1..65535} + @h2xmle_default {1} + */ + uint16_t frame_setting; + /**< @h2xmle_description {Defines index for number of bits per frame} + @h2xmle_rangeList {"PCM_BITS_PER_FRAME_16"=0; + "PCM_BITS_PER_FRAME_32"=1; + "PCM_BITS_PER_FRAME_64"=2; + "PCM_BITS_PER_FRAME_128"=3; + "PCM_BITS_PER_FRAME_256"=4} + @h2xmle_default {0} + */ + uint16_t aux_mode; + /**< @h2xmle_description {PCM interface long and short sync setting.} + @h2xmle_rangeList {"PCM_MODE"=0; + "AUX_MODE"=1} + @h2xmle_default {0} + */ +} +#include "spf_end_pack.h" +; +/* Structure type def for above payload. */ +typedef struct param_id_hw_pcm_intf_cfg_t param_id_hw_pcm_intf_cfg_t; + + + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/** Module ID for PCM sink module */ + +#define MODULE_ID_HW_PCM_SINK 0x0700100C +/** @h2xmlm_module {"MODULE_ID_HW_PCM_SINK", + MODULE_ID_HW_PCM_SINK} + @h2xmlm_displayName {"HW PCM Sink"} + @h2xmlm_description {PCM Sink Module\n + - Supports following params: \n + - PARAM_ID_HW_PCM_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - PARAM_ID_HW_INTF_CLK_CFG \n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT \n + - fmt_id : Don't care \n + - Sample Rates : 8, 16, 24, 32, 48 \n + - Number of channels : 1 to 16 \n + - Bit Width : 16 (bits per sample 16 and Q15) \n + - Q format : Q15 \n + - Interleaving : HW PCM sink module needs de-interleaved unpacked} + + @h2xmlm_dataInputPorts {IN = PORT_ID_HW_PCM_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HWEP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { PCM_TDM_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::sample_rate} + @h2xmle_rangeList {"8 kHz"=8000; + "16 kHz"=16000; + "24 kHz"=24000; + "32 kHz"=32000; + "48 kHz"=48000} + @h2xmle_default {48000} + @h2xml_Select {param_id_hw_ep_mf_t::bit_width} + @h2xmle_rangeList {"16-bit"=16} + @h2xmle_default {16} + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_range {1..16} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_intf_clk_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_id} + @h2xmle_rangeList {"HW_INTF_CLK_ID_DEFAULT"=HW_INTF_CLK_ID_DEFAULT; + "CLOCK_ID_QUI_PCM_OSR"=CLOCK_ID_QUI_PCM_OSR} + @h2xmle_default {HW_INTF_CLK_ID_DEFAULT} + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_attri} + @h2xmle_rangeList {"HW_INTF_CLK_ATTRI_DEFAULT"=HW_INTF_CLK_ATTRI_DEFAULT} + @h2xmle_default {HW_INTF_CLK_ATTRI_DEFAULT} + + @h2xml_Select {param_id_hw_pcm_intf_cfg_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + +/** Module ID for PCM source module */ + +#define MODULE_ID_HW_PCM_SOURCE 0x0700100D +/** @h2xmlm_module {"MODULE_ID_HW_PCM_SOURCE", + MODULE_ID_HW_PCM_SOURCE} + @h2xmlm_displayName {"HW PCM Source"} + @h2xmlm_description {PCM Source Module \n + - Supports following params: \n + - PARAM_ID_HW_PCM_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - PARAM_ID_HW_INTF_CLK_CFG \n + - PARAM_ID_HW_EP_SRC_CHANNEL_MAP\n + - Supported Input Media Format: \n + - HW PCM source module doesn't take any inputs \n } + @h2xmlm_dataOutputPorts {OUT = PORT_ID_HW_PCM_OUTPUT} + @h2xmlm_dataMaxInputPorts {0} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { PCM_TDM_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::sample_rate} + @h2xmle_rangeList {"8 kHz"=8000; + "16 kHz"=16000; + "24 kHz"=24000; + "32 kHz"=32000; + "48 kHz"=48000} + @h2xmle_default {48000} + @h2xml_Select {param_id_hw_ep_mf_t::bit_width} + @h2xmle_rangeList {"16-bit"=16} + @h2xmle_default {16} + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_range {1..16} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_intf_clk_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_id} + @h2xmle_rangeList {"HW_INTF_CLK_ID_DEFAULT"=HW_INTF_CLK_ID_DEFAULT; + "CLOCK_ID_QUI_PCM_OSR"=CLOCK_ID_QUI_PCM_OSR} + @h2xmle_default {HW_INTF_CLK_ID_DEFAULT} + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_attri} + @h2xmle_rangeList {"HW_INTF_CLK_ATTRI_DEFAULT"=HW_INTF_CLK_ATTRI_DEFAULT} + @h2xmle_default {HW_INTF_CLK_ATTRI_DEFAULT} + + @h2xml_Select {param_id_hw_pcm_intf_cfg_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_ep_src_channel_map_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module -->*/ + + +/*============================================================================== + TDM related macros +==============================================================================*/ + +/* Input port ID of TDM module */ +#define PORT_ID_TDM_INPUT 0x2 + +/* Output port ID of TDM module */ +#define PORT_ID_TDM_OUTPUT 0x1 + +/*============================================================================== + Constants +==============================================================================*/ +/* TDM interface index types */ +#define TDM_INTF_TYPE_PRIMARY 0 +#define TDM_INTF_TYPE_SECONDARY 1 +#define TDM_INTF_TYPE_TERTIARY 2 +#define TDM_INTF_TYPE_QUATERNARY 3 +#define TDM_INTF_TYPE_QUINARY 4 + +/** Enumeration for the auxiliary TDM synchronization signal provided by an + external source */ +#define TDM_SYNC_SRC_EXTERNAL 0x0 + +/** Enumeration for the auxiliary TDM synchronization signal provided by an + internal source */ +#define TDM_SYNC_SRC_INTERNAL 0x1 + +/** Enumeration for disabling the TDM configuration ctrl_data_out_enable + parameter. The PCM block is the only master */ +#define TDM_CTRL_DATA_OE_DISABLE 0x0 + +/** Enumeration for enabling the TDM configuration ctrl_data_out_enable + parameter. The PCM block shares the signal with other masters. @newpage */ +#define TDM_CTRL_DATA_OE_ENABLE 0x1 + +/** Short (one-bit) Synchronization mode. */ +#define TDM_SHORT_SYNC_BIT_MODE 0 + +/** Long Synchronization mode. */ +#define TDM_LONG_SYNC_MODE 1 + +/** Short (one-slot) Synchronization mode. */ +#define TDM_SHORT_SYNC_SLOT_MODE 2 + +/** Normal synchronization. */ +#define TDM_SYNC_NORMAL 0 + +/** Invert the synchronization. */ +#define TDM_SYNC_INVERT 1 + +/** Zero-bit clock cycle synchronization data delay. */ +#define TDM_DATA_DELAY_0_BCLK_CYCLE 0 + +/** One-bit clock cycle synchronization data delay. */ +#define TDM_DATA_DELAY_1_BCLK_CYCLE 1 + +/** Two-bit clock cycle synchronization data delay */ +#define TDM_DATA_DELAY_2_BCLK_CYCLE 2 + +/** Max number of slots per frame supported by TDM interface */ +#define TDM_MAX_SLOTS_PER_FRAME 32 + +/** max number of channels for tdm interface */ +#define TDM_MAX_CHANNEL_CNT 32 + +/*============================================================================== + Type definition +==============================================================================*/ +/** Param ID to configure TDM interface */ +#define PARAM_ID_TDM_INTF_CFG 0x0800101B + +/** @h2xmlp_parameter {"PARAM_ID_TDM_INTF_CFG", + PARAM_ID_TDM_INTF_CFG} + @h2xmlp_description {Configures the TDM interface.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +/** Payload for parameter PARAM_ID_TDM_INTF_CFG */ +struct param_id_tdm_intf_cfg_t +{ + uint32_t lpaif_type; + /**< @h2xmle_description {LPAIF types.} + @h2xmle_rangeList {"LPAIF"=0; + "LPAIF_RXTX"=1; + "LPAIF_WSA"=2; + "LPAIF_VA"=3; + "LPAIF_AXI"=4} + @h2xmle_default {0} + */ + + uint32_t intf_idx; + /**< @h2xmle_description {Defines TDM interface type} + @h2xmle_rangeList {"TDM_INTF_TYPE_PRIMARY"=0; + "TDM_INTF_TYPE_SECONDARY"=1; + "TDM_INTF_TYPE_TERTIARY"=2; + "TDM_INTF_TYPE_QUATERNARY"=3; + "TDM_INTF_TYPE_QUINARY"=4} + @h2xmle_default {0} + */ + uint16_t sync_src; + /**< @h2xmle_description {Defines slave or master mode of operation.} + @h2xmle_rangeList {"TDM_SYNC_SRC_EXTERNAL"=0; + "TDM_SYNC_SRC_INTERNAL"=1} + @h2xmle_default {1} + */ + uint16_t ctrl_data_out_enable; + /**< @h2xmle_description {Specifies if TDM block shares data-out signal\n + to the driver with other masters.} + @h2xmle_rangeList {"TDM_CTRL_DATA_OE_DISABLE"=0; + "TDM_CTRL_DATA_OE_ENABLE"=1} + @h2xmle_default {1} + */ + uint32_t slot_mask; + /**< @h2xmle_description {Specifies position of the active slot} + @h2xmle_range {1..65535} + @h2xmle_default {1} + */ + uint16_t nslots_per_frame; + /**< @h2xmle_description {Number of slots per frame} + @h2xmle_range {1..32} + @h2xmle_default {1} + */ + uint16_t slot_width; + /**< @h2xmle_description {Width of the slot in a TDM frame} + @h2xmle_rangeList {"16-bit"=16; + "24-bit"=24; + "32-bit"=32} + @h2xmle_default {16} + */ + uint16_t sync_mode; + /**< @h2xmle_description {TDM Synchronization mode setting} + @h2xmle_rangeList {"TDM_SHORT_SYNC_BIT_MODE"=0; + "TDM_LONG_SYNC_MODE"=1; + "TDM_SHORT_SYNC_SLOT_MODE"=2} + @h2xmle_default {0} + */ + uint16_t ctrl_invert_sync_pulse; + /**< @h2xmle_description {Specifies whether to invert Synchronization} + @h2xmle_rangeList {"TDM_SYNC_NORMAL"=0; + "TDM__SYNC_INVERT"=1} + @h2xmle_default {0} + */ + uint16_t ctrl_sync_data_delay; + /**< @h2xmle_description {Specifies number of bit-clock cycles for delaying\n + data for synchronization.} + @h2xmle_rangeList {"TDM_DATA_DELAY_0_BCLK_CYCLE"=0; + "TDM_DATA_DELAY_1_BCLK_CYCLE"=1; + "TDM_DATA_DELAY_2_BCLK_CYCLE"=2} + @h2xmle_default {0} + */ + uint16_t reserved; + /**< @h2xmle_description {Client should set this field to zero.} + @h2xmle_default {0} + @h2xmle_readOnly {true} + */ +} +#include "spf_end_pack.h" +; +/* Structure type def for above payload. */ +typedef struct param_id_tdm_intf_cfg_t param_id_tdm_intf_cfg_t; + +/** Param ID to configure TDM lanes */ +#define PARAM_ID_TDM_LANE_CFG 0x0800106A + +/** @h2xmlp_parameter {"PARAM_ID_TDM_LANE_CFG", + PARAM_ID_TDM_LANE_CFG} + @h2xmlp_description {Configures TDM lanes. Optional for single lane usage, should be configured \n + if more than 1 lane is required} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +/** Payload for parameter PARAM_ID_TDM_LANE_CFG */ +struct param_id_tdm_lane_cfg_t +{ + uint16_t lane_mask; + /**< @h2xmle_description { Position of the active lanes. 1 to ((2^N)-1),\n + where N is the number of physical lanes supported\n + by the hardware interface.\n + Bits 0 to N-1 correspond to lanes 0 to N-1.\n + When a bit is set, the corresponding lane is active.\n + The number of active lanes can be inferred from \n + the number of bits set in the mask.} + @h2xmle_range {1..65535} + @h2xmle_default {1} + */ + uint16_t reserved; + /**< @h2xmle_description {Client should set this field to zero.} + @h2xmle_default {0} + @h2xmle_readOnly {true} + */ +} +#include "spf_end_pack.h" +; +/* Structure type def for above payload. */ +typedef struct param_id_tdm_lane_cfg_t param_id_tdm_lane_cfg_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/** Module ID for TDM sink module */ +#define MODULE_ID_TDM_SINK 0x0700100E +/** @h2xmlm_module {"MODULE_ID_TDM_SINK", + MODULE_ID_TDM_SINK} + @h2xmlm_displayName {"TDM Sink"} + @h2xmlm_description {- TDM Sink Module \n + - Supports following params: \n + - PARAM_ID_TDM_INTF_CFG \n + - PARAM_ID_TDM_LANE_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - PARAM_ID_HW_INTF_CLK_CFG \n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT, IEC61937_PACKETIZED, IEC60958_PACKETIZED, \n + DSD_OVER_PCM, GENERIC_COMPRESSED, RAW_COMPRESSED \n + - fmt_id : Don't care \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1 to 32 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15) \n + - \n : 24 (bits per sample 24 and Q27) \n + - \n : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q27, Q31 \n + - Interleaving : TDM sink module needs de-interleaved unpacked} + @h2xmlm_dataInputPorts {IN = PORT_ID_TDM_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HWEP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { PCM_TDM_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_intf_clk_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_id} + @h2xmle_rangeList {"HW_INTF_CLK_ID_DEFAULT"=HW_INTF_CLK_ID_DEFAULT; + "CLOCK_ID_PRI_TDM_IBIT"=CLOCK_ID_PRI_TDM_IBIT; + "CLOCK_ID_SEC_TDM_IBIT"=CLOCK_ID_SEC_TDM_IBIT; + "CLOCK_ID_TER_TDM_IBIT"=CLOCK_ID_TER_TDM_IBIT; + "CLOCK_ID_QUAD_TDM_IBIT"=CLOCK_ID_QUAD_TDM_IBIT; + "CLOCK_ID_QUI_TDM_IBIT"=CLOCK_ID_QUI_TDM_IBIT; + "CLOCK_ID_QUI_TDM_OSR"=CLOCK_ID_QUI_TDM_OSR; + "CLOCK_ID_SEN_TDM_IBIT"=CLOCK_ID_SEN_TDM_IBIT} + @h2xmle_default {HW_INTF_CLK_ID_DEFAULT} + + @h2xml_Select {param_id_tdm_intf_cfg_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_tdm_lane_cfg_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module -->*/ + + + +/** Module ID for TDM source module */ +#define MODULE_ID_TDM_SOURCE 0x0700100F +/** @h2xmlm_module {"MODULE_ID_TDM_SOURCE", + MODULE_ID_TDM_SOURCE} + @h2xmlm_displayName {"TDM Source"} + @h2xmlm_description {TDM Source Module \n + - Supports following params: \n + - PARAM_ID_TDM_INTF_CFG \n + - PARAM_ID_TDM_LANE_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - PARAM_ID_HW_INTF_CLK_CFG \n + - PARAM_ID_HW_EP_SRC_CHANNEL_MAP\n + - Supported Input Media Format: \n + - TDM source module doesn't take any inputs} + @h2xmlm_dataOutputPorts {OUT = PORT_ID_TDM_OUTPUT} + @h2xmlm_dataMaxInputPorts {0} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HWEP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { PCM_TDM_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_intf_clk_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_intf_clk_cfg_t::clock_id} + @h2xmle_rangeList {"HW_INTF_CLK_ID_DEFAULT"=HW_INTF_CLK_ID_DEFAULT; + "CLOCK_ID_PRI_TDM_IBIT"=CLOCK_ID_PRI_TDM_IBIT; + "CLOCK_ID_SEC_TDM_IBIT"=CLOCK_ID_SEC_TDM_IBIT; + "CLOCK_ID_TER_TDM_IBIT"=CLOCK_ID_TER_TDM_IBIT; + "CLOCK_ID_QUAD_TDM_IBIT"=CLOCK_ID_QUAD_TDM_IBIT; + "CLOCK_ID_QUI_TDM_IBIT"=CLOCK_ID_QUI_TDM_IBIT; + "CLOCK_ID_QUI_TDM_OSR"=CLOCK_ID_QUI_TDM_OSR; + "CLOCK_ID_SEN_TDM_IBIT"=CLOCK_ID_SEN_TDM_IBIT} + @h2xmle_default {HW_INTF_CLK_ID_DEFAULT} + + @h2xml_Select {param_id_tdm_intf_cfg_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_tdm_lane_cfg_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_ep_src_channel_map_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module -->*/ + +#endif // _PCM_TDM_API_H_ diff --git a/spf/api/modules/pop_suppressor_api.h b/spf/api/modules/pop_suppressor_api.h new file mode 100644 index 0000000..06402ad --- /dev/null +++ b/spf/api/modules/pop_suppressor_api.h @@ -0,0 +1,154 @@ +#ifndef _POP_SUPPRESSOR_API_H_ +#define _POP_SUPPRESSOR_API_H_ + +/*============================================================================== + @file pop_suppressor_api.h + @brief This file contains pop suppressor parameters +==============================================================================*/ + +/*======================================================================= +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +=========================================================================*/ +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "module_cmn_api.h" + +/** @h2xml_title1 {Pop Suppressor Module} + @h2xml_title_agile_rev {Pop Suppressor} + @h2xml_title_date {Jul 5, 2019} + */ +/** + @h2xmlx_xmlNumberFormat {int} + */ + +/*============================================================================== + Constants +==============================================================================*/ +#define CAPI_POP_SUPPRESSOR_STACK_SIZE 1024 +#define CAPI_POP_SUPPRESSOR_MAX_IN_PORTS 1 +#define CAPI_POP_SUPPRESSOR_MAX_OUT_PORTS 1 + +/* Global unique Module ID definition + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_POP_SUPPRESSOR 0x07001072 +/** + @h2xmlm_module {"MODULE_ID_POP_SUPPRESSOR", + MODULE_ID_POP_SUPPRESSOR} + @h2xmlm_displayName {"Pop Suppressor"} + @h2xmlm_toolPolicy {Calibration} + @h2xmlm_description {This module takes care of the unwanted + and annoying pops happening due to data discontinuity arising + because of the handovers and device switches during a voice call. + Pop suppressor module smoothens out the sudden discontinuity + and sudden rise of the speech in scenarios like when handover + occurs or just after handover is completed. For smoothing + the algorithm uses a sigmoid curve. The module supports both mono + and stereo channel input. \n + + - This module supports the following parameter IDs: \n + - #PARAM_ID_POP_SUPPRESSOR_CONFIG \n + - #PARAM_ID_POP_SUPPRESSOR_MUTE_CONFIG \n + - #PARAM_ID_MODULE_ENABLE \n + + - Supported Input Media Format:\n + - Data Format : FIXED_POINT\n + - fmt_id : PCM\n + - Sample Rates : 8000, 16000, 32000, 48000, 96000 Hz \n + - Number of channels(Max) : 2 \n + - Channel type : Don't care\n + - Bits per sample : 16 \n + - Q format : Q15\n + - Interleaving : de-interleaved unpacked\n + - Signed/unsigned : Signed } + + @h2xmlm_dataMaxInputPorts {CAPI_POP_SUPPRESSOR_MAX_IN_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {CAPI_POP_SUPPRESSOR_MAX_OUT_PORTS} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {CAPI_POP_SUPPRESSOR_STACK_SIZE} + @{ <-- Start of the Module --> */ + + +/* ID of the POP_SUPPRESSOR Configuration parameter used by MODULE_ID_POP_SUPPRESSOR.*/ +#define PARAM_ID_POP_SUPPRESSOR_CONFIG 0x0800117F + +/* ID of the POP_SUPPRESSOR Configuration parameter to MUTE the Output of POP_SUPPRESSOR MODULE */ +#define PARAM_ID_POP_SUPPRESSOR_MUTE_CONFIG 0x0800134F + +/*============================================================================== + Type Definitions +==============================================================================*/ + +/* Structure for pop suppressor configuration parameters */ +typedef struct param_id_pop_suppressor_params_t param_id_pop_suppressor_params_t; +/** @h2xmlp_parameter {"PARAM_ID_POP_SUPPRESSOR_CONFIG", PARAM_ID_POP_SUPPRESSOR_CONFIG} + @h2xmlp_description {This is used to configure pop suppressor module} */ + +#include "spf_begin_pack.h" + +/* Payload of the PARAM_ID_POP_SUPPRESSOR_CONFIG parameters in the POP Suppressor module. + */ +struct param_id_pop_suppressor_params_t +{ + uint16_t ramp_duration_in_ms; + /**< @h2xmle_description {Input ramp duration in ms} + @h2xmle_default {0x1} + @h2mle_dataFormat {Q0} + */ + + int16_t reserved; + /**< @h2xmle_description {Client must set this field to zero.} + @h2xmle_default {0} + @h2xmle_policy {Advanced} + */ +} +#include "spf_end_pack.h" +; +/* Structure for pop suppressor configuration parameters */ +typedef struct param_id_pop_suppressor_mute_config_t param_id_pop_suppressor_mute_config_t; +/** @h2xmlp_parameter {"PARAM_ID_POP_SUPPRESSOR_MUTE_CONFIG ", PARAM_ID_POP_SUPPRESSOR_MUTE_CONFIG} + @h2xmlp_description {This parameter is used to mute the output of pop suppressor module during a device switch usecase. + The mute would happen with a duration set in PID PARAM_ID_POP_SUPPRESSOR_CONFIG. + This parameter can be set to enable/disable by + the client. + POP_SUPPRESSOR module will reset to unmute (disable) when GRAPH_STOP(or algo reset) command is issued} + @h2xmlp_toolPolicy {Calibration; RTC} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_pop_suppressor_mute_config_t +{ + uint32_t mute_enable; + /**< Specifies whether the Pop_suppressor mute parameter is to be enabled(1) or disabled(0) + + @valuesbul + - 0 -- Disabled (Default) + - 1 -- Enabled @tablebulletend */ + /*#< @h2xmle_description {Specifies whether the Pop_suppressor mute parameter is to be enabled or + disabled.} + @h2xmle_rangeList {"Disable"=0; + "Enable"=1} + @h2xmle_default {0} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/** + @h2xml_Select {param_id_module_enable_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_pop_suppressor_params_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_pop_suppressor_mute_config_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + +#endif /* _POP_SUPPRESSOR_API_H_ */ diff --git a/spf/api/modules/priority_sync_api.h b/spf/api/modules/priority_sync_api.h new file mode 100644 index 0000000..11e6d9f --- /dev/null +++ b/spf/api/modules/priority_sync_api.h @@ -0,0 +1,79 @@ +#ifndef _PRIORITY_SYNC_API_H_ +#define _PRIORITY_SYNC_API_H_ +/** + * \file priority_sync_api.h + * \brief + * This file contains Priority Sync module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "apm_graph_properties.h" + +/** @h2xml_title1 {Priority Sync Module API} + @h2xml_title_agile_rev {Priority Sync Module API} + @h2xml_title_date {July 12, 2018} */ + +/*============================================================================== + Defines +==============================================================================*/ + +#define PRIORITY_SYNC_MAX_IN_PORTS 2 +#define PRIORITY_SYNC_MAX_OUT_PORTS 2 + +#define PRIORITY_SYNC_PRIMARY_IN_PORT_ID 0x2 +#define PRIORITY_SYNC_PRIMARY_OUT_PORT_ID 0x1 + +#define PRIORITY_SYNC_SECONDARY_IN_PORT_ID 0x4 +#define PRIORITY_SYNC_SECONDARY_OUT_PORT_ID 0x3 + +#define PRIORITY_SYNC_MAX_CHANNELS 32 +#define PRIORITY_SYNC_STACK_SIZE 4096 + +/*============================================================================== + API definitions +==============================================================================*/ + +#define MODULE_ID_EC_SYNC 0x07001028 +#define MODULE_ID_PRIORITY_SYNC MODULE_ID_EC_SYNC + +/** @h2xmlm_module {"MODULE_ID_PRIORITY_SYNC", MODULE_ID_PRIORITY_SYNC} + @h2xmlm_displayName {"Priority Sync"} + @h2xmlm_description {- This module is used to synchronize the secondary input signal with respect to primary(priority) input signal. + - Use cases are :- + - To synchronize Echo reference signal with Mic data. ECNS and other similar use cases. + - To synchronize music Rx signal with voice Tx signal for ICMD use case. + - Supported Input Media Format: \n + - Data Format : FIXED_POINT, \n + - fmt_id : MEDIA_FMT_ID_PCM \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1 to 32 \n + - Channel type : Don't care \n + - Bit Width : 16, 24, 32 + - Q format : Don't care \n + - Interleaving : Deinterleaved unpacked. \n + - Endianess : little, big \n + - Primary and secondary ports are allowed to have different media formats. The only \n + - restriction is that if one port runs at a fractional rate, the other port must also \n + - run at a fractional rate (use cases where ports have variable input frame sizes are \n + - not supported).} + + @h2xmlm_dataMaxInputPorts {PRIORITY_SYNC_MAX_IN_PORTS} + @h2xmlm_dataInputPorts {PRIMARY_IN = PRIORITY_SYNC_PRIMARY_IN_PORT_ID; + SECONDARY_IN = PRIORITY_SYNC_SECONDARY_IN_PORT_ID} + @h2xmlm_dataMaxOutputPorts {PRIORITY_SYNC_MAX_OUT_PORTS} + @h2xmlm_dataOutputPorts {PRIMARY_OUT = PRIORITY_SYNC_PRIMARY_OUT_PORT_ID; + SECONDARY_OUT = PRIORITY_SYNC_SECONDARY_OUT_PORT_ID} + + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize { PRIORITY_SYNC_STACK_SIZE } + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + +#endif //_PRIORITY_SYNC_API_H_ diff --git a/spf/api/modules/prm_api.h b/spf/api/modules/prm_api.h new file mode 100644 index 0000000..62573f7 --- /dev/null +++ b/spf/api/modules/prm_api.h @@ -0,0 +1,180 @@ +#ifndef _PRM_API_H_ +#define _PRM_API_H_ +/** + * \file prm_api.h + * \brief + * This file contains Proxy Resource Manager module interface + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +/** + Instance ID of the Proxy Resource Manager module + + This module instance supports the following command IDs: + - #PRM_CMD_REQUEST_HW_RSC + - #PRM_CMD_RELEASE_HW_RSC + - #PRM_CMD_RSP_REQUEST_HW_RSC + - #PRM_CMD_RSP_RELEASE_HW_RSC + + @calibration_hdr_field + module_id -- PRM_MODULE_INSTANCE_ID + */ +#define PRM_MODULE_INSTANCE_ID 0x00000002 + +/** @ingroup EVENT_ID_MBHC_INTR_DETECTION + - EVENT_ID_MBHC_INTR_DETECTION is sent when a mbhc interrupt has been received to notify the client + - This event has no payload attached + - This event is registered using the APM_CMD_REGISTER_MODULE_EVENTS command sent against the PRM module static + instance ID, and deregistered the + same way. The payload for the reg/dereg is apm_module_register_events_t, using the PRM as the module ID + + @gpr_hdr_fields + Opcode -- EVENT_ID_MBHC_INTR_DETECTION + + @return + None + */ +#define EVENT_ID_MBHC_INTR_DETECTION 0x0800115E + +/** @ingroup prm_cmd_request_hw_rsc + - This API is used by client for requesting the single h/w resource ID + - Command payload depends upon the resource ID and it may vary for + different resource types + - A single resource ID may encompass multiple instances of that resource + - From client perspective, it is possible to request multiple such instances + using a single command + - Multiple resources ID request cannot be clubbed together in a single command. + Individual command must be sent for requesting each individual resource ID + - Depending upon resource type, a resource ID may be requested multiple number + of times as long as the resource configuration is not changed. This is possible + if there are multiple unique clients on HLOS side requesting for the same resource ID + - Multiple request for same resource ID may not be supported for all resources + - PRM module keeps track of reference counter for each such request + + @gpr_hdr_fields + Opcode -- PRM_CMD_REQUEST_HW_RSC + + @structure + apm_cmd_header_t + apm_module_param_data_t + <>Param ID payload<> + <8 byte alignment if any, but not mandatory> + + @return + Opcode -- PRM_CMD_RSP_REQUEST_HW_RSC + + */ +#define PRM_CMD_REQUEST_HW_RSC 0x0100100F + +/** @ingroup prm_cmd_release_hw_rsc + - This API is used by client for releasing the h/w resource requested + using the PRM_CMD_REQUEST_HW_RSC command + - This command results in failure if command issued for releasing a + resource which was not previously requested + - Number of release commands for a given resource ID must match with + the number of request commands + - If the number of release is lesser than number of request, it may result + in h/w resource to remain ON + - For resources with multiple instances, release command need not be symmetric + to release request. For example, client may request 3 clock ID's under a single + REQUEST command but release maybe be done across 2 or more commands + + @gpr_hdr_fields + Opcode -- PRM_CMD_RELEASE_HW_RSC + + @structure + apm_cmd_header_t + apm_module_param_data_t + <>Param ID payload<> + <8 byte alignment if any, but not mandatory> + + @return + Opcode -- PRM_CMD_RSP_RELEASE_HW_RSC + + */ +#define PRM_CMD_RELEASE_HW_RSC 0x01001010 + +/** @ingroup prm_cmd_rsp_request_hw_rsc + - PRM_CMD_RSP_REQUEST_HW_RSC is sent in response to PRM_CMD_REQUEST_HW_RSC + - The response payload depends upon the resource type and it varies for + different resource ID's + + @gpr_hdr_fields + Opcode -- PRM_CMD_RSP_REQUEST_HW_RSC + + @structure + - prm_cmd_rsp_hw_rsc_cfg_t + + @return + None + */ +#define PRM_CMD_RSP_REQUEST_HW_RSC 0x02001002 + +/** @ingroup prm_cmd_rsp_release_hw_rsc + - PRM_CMD_RSP_RELEASE_HW_RSC is sent in response to PRM_CMD_RELEASE_HW_RSC + - The response payload depends upon the resource type and it varies for + different resource ID's + + @gpr_hdr_fields + Opcode -- PRM_CMD_RSP_RELEASE_HW_RSC + + @structure + - prm_cmd_rsp_hw_rsc_cfg_t + + @return + None + */ +#define PRM_CMD_RSP_RELEASE_HW_RSC 0x02001003 + +/** + This structure is the common payload structure used by + resource request and release response API's. + If there are no failures, only the success code is returned + back to the client. + In case of partial or complete failure, the response payload + may contain more information depending upon the resource ID. + + Immediately following this structure is a variable length + array of structure objects corresponding to each status of + resource requested. Length of the array is determined by + number of resources being requested + */ + +#include "spf_begin_pack.h" + +struct prm_cmd_rsp_hw_rsc_cfg_t +{ + uint32_t param_id; + /**< @ PARAM_ID_RSC_LPASS_CORE + * @ PARAM_ID_RSC_AUDIO_HW_CLK + */ + + uint32_t status; + /**< Status representing of request/release cmd + * @ 0 - Success + * @ Non-Zero - Failure + * */ +} + +#include "spf_end_pack.h" +; + +typedef struct prm_cmd_rsp_hw_rsc_cfg_t prm_cmd_rsp_hw_rsc_cfg_t; + +#ifdef CSMD_COSIM +/* These are private commands used in the OTTP CSMD simulator setup to +to perform cosim reset. +OPEN is used to write 1 to the RESET register and CLOSE is used to write 0. +The sequence is - CLOSE -> Write to dma_io_dynamic.cfg -> OPEN --> usecase*/ + +#define PRM_PVT_CMD_COSIM_OPEN 0x01001024 +#define PRM_PVT_CMD_COSIM_CLOSE 0x01001025 + +#endif // CSMD_COSIM + +#endif /* _PRM_API_H_ */ diff --git a/spf/api/modules/quasar_module_api.h b/spf/api/modules/quasar_module_api.h new file mode 100644 index 0000000..cff5ee0 --- /dev/null +++ b/spf/api/modules/quasar_module_api.h @@ -0,0 +1,508 @@ +/* ========================================================================= + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + ========================================================================= */ + +#ifndef QUASAR_MODULE_API_H +#define QUASAR_MODULE_API_H + +/** @h2xml_title1 {Qualcomm Spatial Audio Renderer (QUASAR_Module)} + @h2xml_title_agile_rev {Qualcomm Spatial Audio Renderer (QUASAR_Module)} + @h2xml_title_date {August 05, 2025} */ + +#include "module_cmn_api.h" +#include "imcl_spm_intent_api.h" +#include "imcl_fwk_intent_api.h" + + +#define MODULE_ID_QUASAR 0x07001186 +#define VERSION_MAJOR 0x00000004 +#define VERSION_MINOR 0x00000001 + +/** + @h2xmlm_module {"MODULE_ID_QUASAR", + MODULE_ID_QUASAR} + @h2xmlm_displayName {"Qualcomm Spatial Audio Renderer"} + @h2xmlm_modSearchKeys {Audio} + @h2xmlm_description {- ID of the QUASAR module.\n + - This module dynamically registers for HDT data via IMCL.\n + - It can register for either:\n + - INTENT_ID_SA_HDT_ORIENTATION_DATA (preferred - pre-processed)\n + - INTENT_ID_SA_HDT_RAW_DATA (fallback - requires conversion)\n + - This module supports the following parameter IDs:\n + - PARAM_ID_QUASAR_MODULE_DYNAMICS_CONFIG\n + - PARAM_ID_QUASAR_MODULE_REVERB_CONFIG\n + - PARAM_ID_QUASAR_MODULE_REFLECTIONS_CONFIG\n + - PARAM_ID_QUASAR_MODULE_USER_POSITION\n + - PARAM_ID_QUASAR_MODULE_N_SOURCES_METADATA\n + - PARAM_ID_QUASAR_MODULE_RESET\n + - PARAM_ID_QUASAR_MODULE_OBJ_BINAURALIZER_CONFIG\n + - PARAM_ID_QUASAR_MODULE_OUTPUT_MODE\n + - PARAM_ID_QUASAR_MODULE_VERSION\n + - Supported Input Media Format:\n + - Data Format : FIXED_POINT\n + - fmt_id : MEDIA_FMT_ID_PCM\n + - Sample Rates : 48000\n + - Number of channels : 12\n + - Channel type : Supported channel mapping based on number of channels\n + - Bits per sample : 16\n + - Q format : Q15 for bps = 16\n + - Interleaving : Deinterleaved Unpacked\n + - Signed/unsigned : Signed\n + - Supported Input Channel Mapping:\n + - TBD: Channel default order as per Android framework is supported. Final supported channel map and order will be updated later.} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN = 2} + @h2xmlm_dataOutputPorts {OUT = 1} + @h2xmlm_ctrlDynamicPortIntent { "HDT Raw Data In" = INTENT_ID_SA_HDT_RAW_DATA, + maxPorts= 1 } + @h2xmlm_ctrlDynamicPortIntent { "HDT Orientation Data In" = INTENT_ID_SA_HDT_ORIENTATION_DATA, + maxPorts= 1 } + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC, APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + + @{ <-- Start of the Module --> **/ + + +#define PARAM_ID_QUASAR_MODULE_DYNAMICS_CONFIG 0x08001BB5 + +typedef struct dynamics_config_t dynamics_config_t; +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_DYNAMICS_CONFIG", + PARAM_ID_QUASAR_MODULE_DYNAMICS_CONFIG} + @h2xmlp_description {Configures QuaSAR's dynamics sub-module} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct dynamics_config_t +{ + uint32_t enable; + /** < @h2xmle_default {1} + @h2xmle_description {Dynamics enable/disable} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {disableDynamics=0;enableDynamics=1} */ + uint32_t comp_enable; + /** < @h2xmle_default {1} + @h2xmle_description {Compressor enable/disable} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {disableCompressor=0;enableCompressor=1} */ + float comp_gain; + /** < @h2xmle_default {6.0} + @h2xmle_description {Make-up gain applied in dB applied by compressor} + @h2xmle_range {-12.0,12.0} */ + float comp_threshold; + /** < @h2xmle_default {-18.0} + @h2xmle_description {Threshold for compression in dB(FS)} + @h2xmle_range {-60.0,0.0} */ + float comp_ratio; + /** < @h2xmle_default {1.3} + @h2xmle_description {Compression ratio applied above threshold} + @h2xmle_range {1.0,10.0} */ + uint32_t os_enable; + /** < @h2xmle_default {1} + @h2xmle_description {Overshoot control enable/disable} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {disableOS=0;enableOS=1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* @h2xml_Select {dynamics_config_t} + @h2xmlm_InsertParameter */ + +#define PARAM_ID_QUASAR_MODULE_REVERB_CONFIG 0x08001BB6 + +typedef struct reverb_config_t reverb_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_REVERB_CONFIG", + PARAM_ID_QUASAR_MODULE_REVERB_CONFIG} + @h2xmlp_description {Configures QuaSAR's late reverb sub-module} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct reverb_config_t +{ + uint32_t enable; + /** < @h2xmle_default {1} + @h2xmle_description {Reverb enable/disable} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {disableReverb=0;enableReverb=1} */ + float duration; + /** < @h2xmle_default {0.165} + @h2xmle_description {Duration of reverb tail in seconds} + @h2xmle_range {0.001,0.165} */ + uint32_t pulse_period; + /** < @h2xmle_default {15} + @h2xmle_description {Density of reverb tail pulses (lower = more dense)} + @h2xmle_dataFormat {Q0} + @h2xmle_range {2,6000} */ + float scale; + /** < @h2xmle_default {0.09} + @h2xmle_description {Scale factor applied to reverb tail} + @h2xmle_range {0.0,1.0} */ + uint32_t predelay; + /** < @h2xmle_default {15} + @h2xmle_description {Pre-delay between direct path and reverb start in miliseconds} + @h2xmle_dataFormat {Q0} + @h2xmle_range {0,100} */ + uint32_t stereo; + /** < @h2xmle_default {1} + @h2xmle_description {Enable stereo decorrelation of reverb} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {disableStereo=0;enableStereo=1} */ + uint32_t tone_enable; + /** < @h2xmle_default {1} + @h2xmle_description {Enable reverb tone control} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {disableTone=0;enableTone=1} */ + uint32_t tone_cutoff; + /** < @h2xmle_default {10000} + @h2xmle_description {Cutoff frequency of tone control high-shelf in Hz} + @h2xmle_dataFormat {Q0} + @h2xmle_range {100,12000} */ + float tone_balance; + /** < @h2xmle_default {0.5} + @h2xmle_description {Relative level high shelf (-1.0 = -12 dB, 1.0 = 0 dB)} + @h2xmle_range {-1.0,1.0} */ + float tone_slope; + /** < @h2xmle_default {1.0} + @h2xmle_description {Slope of shelving filter (higher value = steeper slope)} + @h2xmle_range {0.1,1.0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* @h2xml_Select {reverb_config_t} + @h2xmlm_InsertParameter */ + +#define PARAM_ID_QUASAR_MODULE_REFLECTIONS_CONFIG 0x08001BB7 + +typedef struct reflections_config_t reflections_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_REFLECTIONS_CONFIG", + PARAM_ID_QUASAR_MODULE_REFLECTIONS_CONFIG} + @h2xmlp_description {Configures QuaSAR's early reflections sub-module} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct reflections_config_t +{ + uint32_t mode; + /** < @h2xmle_default {0} + @h2xmle_description {Early reflections processing mode} + @h2xmle_range {0,6} */ + float room_l; + /** < @h2xmle_default {5.0} + @h2xmle_description {Room length} + @h2xmle_range {1.0,14.0} */ + float room_w; + /** < @h2xmle_default {4.0} + @h2xmle_description {Room width} + @h2xmle_range {1.0,14.0} */ + float room_h; + /** < @h2xmle_default {3.0} + @h2xmle_description {Room height} + @h2xmle_range {1.0,14.0} */ + uint32_t use_materials; + /** < @h2xmle_default {0} + @h2xmle_description {Flag to use materials (1) or absorption coefficients (0)} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {useAbsCoeff=0;useMaterial=1} */ + float abs_front; + /** < @h2xmle_default {0.2} + @h2xmle_description {Absorption coefficient of front wall} + @h2xmle_range {0.0,1.0} */ + float abs_back; + /** < @h2xmle_default {0.2} + @h2xmle_description {Absorption coefficient of back wall} + @h2xmle_range {0.0,1.0} */ + float abs_left; + /** < @h2xmle_default {0.2} + @h2xmle_description {Absorption coefficient of left wall} + @h2xmle_range {0.0,1.0} */ + float abs_right; + /** < @h2xmle_default {0.2} + @h2xmle_description {Absorption coefficient of right wall} + @h2xmle_range {0.0,1.0} */ + float abs_ceiling; + /** < @h2xmle_default {0.11} + @h2xmle_description {Absorption coefficient of ceiling} + @h2xmle_range {0.0,1.0} */ + float abs_floor; + /** < @h2xmle_default {0.63} + @h2xmle_description {Absorption coefficient of floor} + @h2xmle_range {0.0,1.0} */ + uint32_t material_front; + /** < @h2xmle_default {2} + @h2xmle_description {Front wall material} + @h2xmle_range {1,27} */ + uint32_t material_back; + /** < @h2xmle_default {2} + @h2xmle_description {Front wall material} + @h2xmle_range {1,27} */ + uint32_t material_left; + /** < @h2xmle_default {2} + @h2xmle_description {Front wall material} + @h2xmle_range {1,27} */ + uint32_t material_right; + /** < @h2xmle_default {2} + @h2xmle_description {Front wall material} + @h2xmle_range {1,27} */ + uint32_t material_ceiling; + /** < @h2xmle_default {27} + @h2xmle_description {Front wall material} + @h2xmle_range {1,27} */ + uint32_t material_floor; + /** < @h2xmle_default {25} + @h2xmle_description {Front wall material} + @h2xmle_range {1,27} */ + float user_x; + /** < @h2xmle_default {0.0} + @h2xmle_description {User X position (front-back) in meters} + @h2xmle_range {-7.0,7.0} */ + float user_y; + /** < @h2xmle_default {0.0} + @h2xmle_description {User Y position (left-right) in meters} + @h2xmle_range {-7.0,7.0} */ + float user_height; + /** < @h2xmle_default {1.6} + @h2xmle_description {User height in meters} + @h2xmle_range {0.1,14.0} */ + uint32_t auto_reverb; + /** < @h2xmle_default {0} + @h2xmle_description {Flag to use automatic late reverb (1) or manual reverb parameters (0)} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {disableAutoreverb=0,enableAutoreverb=1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {reflections_config_t} + @h2xmlm_InsertParameter */ + +#define PARAM_ID_QUASAR_MODULE_SCREEN_ORIENTATION 0x08001BB8 + +typedef struct screen_orientation_t screen_orientation_t; + +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_SCREEN_ORIENTATION", + PARAM_ID_QUASAR_MODULE_SCREEN_ORIENTATION} + @h2xmlp_description {Set QuaSAR screen orientation} + @h2xmlp_toolPolicy {RTC; CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct screen_orientation_t { + /* h2xml does not support enum, so use int32_t when h2xml is defined */ + uint32_t rotation_mode; + /** < @h2xmle_default {0} + @h2xmle_description {Rotation mode} + @h2xmle_range {0,2} */ + + float orientation[3]; + /** < @h2xmle_defaultList {0.0,0.0,1.0} + @h2xmle_description {User orientation 3 vector} + @h2xmle_range {-360.0,360.0} */ + int64_t timestamp; + /** < @h2xmle_default {0} + @h2xmle_description {Current screen orientation timestamp} + @h2xmle_range {0..1000000000000000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {screen_orientation_t} + @h2xmlm_InsertParameter */ + +#define PARAM_ID_QUASAR_MODULE_USER_POSITION 0x08001BB9 + +typedef struct user_position_t user_position_t; + +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_USER_POSITION", + PARAM_ID_QUASAR_MODULE_USER_POSITION} + @h2xmlp_description {Set QuaSAR user position} + @h2xmlp_toolPolicy {RTC; CALIBRATION} */ + +/** +User position is defined using the following right-handed cartesian coordinate system: + position[0] (X-axis): Positive forwards, negative backwards + position[1] (Y-axis): Positive left, negative right + position[2] (Z-axis): Positive up, negative down */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct user_position_t { + float position[3]; + /** < @h2xmle_defaultList {0.0,0.0,0.0} + @h2xmle_description {User position 3 vector} + @h2xmle_range {-100.0,100.0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {user_position_t} + @h2xmlm_InsertParameter */ + +typedef struct source_metadata_t source_metadata_t; +/** + @h2xmlp_subStruct + @h2xmlp_description {Set QuaSAR source metadata} */ + +/** +Source position is defined using the following right-handed cartesian coordinate system: + position[0] (X-axis): Positive forwards, negative backwards + position[1] (Y-axis): Positive left, negative right + position[2] (Z-axis): Positive up, negative down */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct source_metadata_t { + uint16_t index; + /** < @h2xmle_default {0} + @h2xmle_description {Source index} + @h2xmle_dataFormat {Q0} + @h2xmle_range {0,63} */ + float position[3]; + /** < @h2xmle_defaultList {0.0,0.0,0.0} + @h2xmle_description {Source position 3 vector} + @h2xmle_range {-100.0,100.0} */ + uint32_t type; + /** < @h2xmle_default {0} + @h2xmle_description {Rotation mode} + @h2xmle_range {0,4} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +#define PARAM_ID_QUASAR_MODULE_N_SOURCES_METADATA 0x08001BBB + +typedef struct n_sources_metadata_t n_sources_metadata_t; +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_N_SOURCES_METADATA", + PARAM_ID_QUASAR_MODULE_N_SOURCES_METADATA} + @h2xmlp_description {Set QuaSAR source metadata for N sources} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct n_sources_metadata_t { + uint32_t n_sources; + /** < @h2xmle_default {1} + @h2xmle_description {Number of sources} + @h2xmle_range {1,64} */ + source_metadata_t source_metadata[]; + /** < @h2xmle_variableArraySize {n_sources} + @h2xmle_default {0} + @h2xmle_description {Source metadata} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {n_sources_metadata_t} + @h2xmlm_InsertParameter */ + +#define PARAM_ID_QUASAR_MODULE_RESET 0x08001BBC +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_RESET", + PARAM_ID_QUASAR_MODULE_RESET} + @h2xmlp_description {Resets QuaSAR library} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +// DOES NOT REQUIRE ANY PARAM STRUCTURE PTR / SIZE + +#define PARAM_ID_QUASAR_MODULE_OUTPUT_MODE 0x08001BBD + +typedef struct output_mode_t output_mode_t; + +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_OUTPUT_MODE", + PARAM_ID_QUASAR_MODULE_OUTPUT_MODE} + @h2xmlp_description {Set QuaSAR output mode} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct output_mode_t { + uint32_t output_mode; + /** < @h2xmle_default {0} + @h2xmle_description {QuaSAR output mode} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {twoSided=0;oneSidedLeft=1;oneSidedRight=2} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* @h2xml_Select {output_mode_t} + @h2xmlm_InsertParameter */ + +#define PARAM_ID_QUASAR_MODULE_OBJ_BINAURALIZER_CONFIG 0x08001BBE + +typedef struct obj_binauralizer_config_t obj_binauralizer_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_OBJ_BINAURALIZER_CONFIG", + PARAM_ID_QUASAR_MODULE_OBJ_BINAURALIZER_CONFIG} + @h2xmlp_description {Configuration params for QUASAR_MODULE_OBJECT_BINAURALIZE render mode} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct obj_binauralizer_config_t { + uint32_t activity_detect; + /** < @h2xmle_default {1} + @h2xmle_description {Enable / disable activity detector} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {disableActivityDetect=0;enableActivityDetect=1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {obj_binauralizer_config_t} + @h2xmlm_InsertParameter */ + +#define PARAM_ID_QUASAR_MODULE_VERSION 0x08001BBF + +typedef struct quasar_module_version_t quasar_module_version_t; + +/** @h2xmlp_parameter {"PARAM_ID_QUASAR_MODULE_VERSION", + PARAM_ID_QUASAR_MODULE_VERSION} + @h2xmlp_description {Structure to get the current library version.} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct quasar_module_version_t +{ + uint32_t version_major; + /**< @h2xmle_description {Lower 32 bits of the 64-bit library version number} + @h2xmle_default {VERSION_MAJOR} */ + uint32_t version_minor; + /**< @h2xmle_description {Higher 32 bits of the 64-bit library version number} + @h2xmle_default {VERSION_MINOR} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {QUASAR_MODULE_module_version_t} + @h2xmlm_InsertParameter */ + + +/*============================================================================== + Insert Common parameters +==============================================================================*/ + +/** + @h2xml_Select {param_id_module_enable_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module -->*/ + +#endif diff --git a/spf/api/modules/rate_adapted_timer_api.h b/spf/api/modules/rate_adapted_timer_api.h new file mode 100644 index 0000000..286a1b9 --- /dev/null +++ b/spf/api/modules/rate_adapted_timer_api.h @@ -0,0 +1,161 @@ +#ifndef _RATE_ADAPTED_TIMER_API_H_ +#define _RATE_ADAPTED_TIMER_API_H_ +/** + * \file rate_adapted_timer_api.h + * \brief + * This file contains RATE_ADAPTED_TIMER module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/**@h2xml_title1 {RATE_ADAPTED_TIMER Module API} + @h2xml_title_agile_rev {RATE_ADAPTED_TIMER Module API} + @h2xml_title_date {April 8, 2019} */ + +/*============================================================================== + Constants +==============================================================================*/ +/* IMCL static port id's to receive drifts*/ +#define QT_REFCLK_TIMING_INPUT AR_NON_GUID(0xC0000001) +#define REFCLK_REMOTE_TIMING_INPUT AR_NON_GUID(0xC0000002) +#define QT_REMOTE_TIMING_INPUT AR_NON_GUID(0xC0000003) + +/* RAT module stack size*/ +#define RATE_ADAPTED_TIMER_STACK_SIZE 4096 + +/* Input port ID of Rate Adapted Timer module */ +#define PORT_ID_RATE_ADAPTED_TIMER_INPUT 0x2 + +/* Output port ID of Rate Adapted Timer module */ +#define PORT_ID_RATE_ADAPTED_TIMER_OUTPUT 0x1 + +/** ID of the parameter used to configure the RAT media format */ +#define PARAM_ID_RAT_MEDIA_FORMAT 0x080010D0 + +/** @h2xmlp_parameter {"PARAM_ID_RAT_MEDIA_FORMAT", + PARAM_ID_RAT_MEDIA_FORMAT} + @h2xmlp_description {Configures the media format of the Rate Adapted Timer Module and is mandatory} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_rat_mf_t +{ + uint32_t sample_rate; + /**< @h2xmle_description {Defines sample rate.} + @h2xmle_rangelist {"8 kHz"=8000; + "11.025 kHz"=11025; + "12 kHz"=12000; + "16 kHz"=16000; + "22.05 kHz"=22050; + "24 kHz"=24000; + "32 kHz"=32000; + "44.1 kHz"=44100; + "48 kHz"=48000; + "88.2 kHz"=88200; + "96 kHz"=96000; + "176.4 kHz"=176400; + "192 kHz"=192000; + "352.8 kHz"=352800; + "384 kHz"=384000} + @h2xmle_default {48000} + */ + + uint16_t bits_per_sample; + /**< @h2xmle_description {bits per sample.} + @h2xmle_rangeList {"16-bit"=16; + "32-bit"=32} + @h2xmle_default {16} + */ + + uint16_t q_factor; + /**< @h2xmle_description {q factor \n + -> If bits per sample is 16, q_factor should be 15 \n + -> If bits per sample is 32, q_factor can be 27 or 31} + @h2xmle_rangeList {"q15"=15; + "q27"=27; + "q31"=31} + @h2xmle_default {15} + */ + + uint32_t data_format; + /**< @h2xmle_description {Format of the data} + @h2xmle_rangeList {"DATA_FORMAT_FIXED_POINT"=1} + @h2xmle_default {1} + */ + + uint32_t num_channels; + /**< @h2xmle_description {Number of channels.} + @h2xmle_range {1..32} + @h2xmle_default {1} + */ + + uint16_t channel_map[0]; + /**< @h2xmle_description {Channel mapping array. \n + ->Specify a channel mapping for each output channel \n + ->If the number of channels is not a multiple of four, zero padding must be added + to the channel type array to align the packet to a multiple of 32 bits} + @h2xmle_variableArraySize {num_channels} + @h2xmle_rangeEnum {pcm_channel_map} + @h2xmle_default {1} */ + + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_rat_mf_t param_id_rat_mf_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/** Module ID for Rate Adapted Timer module */ +#define MODULE_ID_RATE_ADAPTED_TIMER 0x07001041 +/** @h2xmlm_module {"MODULE_ID_RATE_ADAPTED_TIMER", + MODULE_ID_RATE_ADAPTED_TIMER} + @h2xmlm_displayName {"Rate Adapted Timer "} + @h2xmlm_description {- Rate Adapted Timer \n + - Supports following params: \n + - PARAM_ID_RAT_MEDIA_FORMAT \n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT, IEC61937_PACKETIZED, IEC60958_PACKETIZED, \n + - DSD_OVER_PCM, GENERIC_COMPRESSED, RAW_COMPRESSED \n + - fmt_id : Don't care \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1 to 16 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 24 (bits per sample 24 and Q27) \n + - : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q23, Q27, Q31 \n + - Interleaving : Module needs de-interleaved unpacked } + + @h2xmlm_dataInputPorts {IN = PORT_ID_RATE_ADAPTED_TIMER_INPUT} + @h2xmlm_dataOutputPorts {OUT = PORT_ID_RATE_ADAPTED_TIMER_OUTPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlStaticPort {"QT_REFCLK_TIMING_INPUT" = 0xC0000001, + "Qtimer HW-EP drift info" = INTENT_ID_TIMER_DRIFT_INFO} + @h2xmlm_ctrlStaticPort {"REFCLK_REMOTE_TIMING_INPUT" = 0xC0000002, + "HWEP BT drift info" = INTENT_ID_TIMER_DRIFT_INFO} + @h2xmlm_ctrlStaticPort {"QT_REMOTE_TIMING_INPUT" = 0xC0000003, + "Qtimer Remote drift info" = INTENT_ID_TIMER_DRIFT_INFO} + @h2xmlm_ctrlDynamicPortIntent {"Qtimer to Adapted Rate drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { RATE_ADAPTED_TIMER_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_rat_mf_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + +#endif //_RATE_ADAPTED_TIMER_API_H_ diff --git a/spf/api/modules/rd_sh_mem_client_api.h b/spf/api/modules/rd_sh_mem_client_api.h new file mode 100644 index 0000000..4d890c7 --- /dev/null +++ b/spf/api/modules/rd_sh_mem_client_api.h @@ -0,0 +1,71 @@ +/** + * \file rd_sh_mem_client_api.h + * \brief + * This file contains Shared mem Client module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RD_SH_MEM_CLIENT_API_H_ +#define RD_SH_MEM_CLIENT_API_H_ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "apm_graph_properties.h" + +/** + @h2xml_title1 {APIs of Read Shared Memory Client Module} + @h2xml_title_agile_rev {APIs of Read Shared Memory Client Module} + @h2xml_title_date {May 23, 2019} + */ + +/** + @h2xmlx_xmlNumberFormat {int} +*/ + + +/** + * Input port ID of the Read Shared Memory CLIENT + */ +#define PORT_ID_RD_SHARED_MEM_CLIENT_INPUT 0x2 + +/** + * Output port ID of the Read Shared Memory CLIENT + */ +#define PORT_ID_RD_SHARED_MEM_CLIENT_OUTPUT 0x1 + +/** + * ID of the Read Shared Memory Client Module + * + * This module has only one static input port with ID 2 and one output port with ID 1 + * + * Supported Input Media Format: + * - Any + */ +#define MODULE_ID_RD_SHARED_MEM_CLIENT 0x0700105D +/** + @h2xmlm_module {"MODULE_ID_RD_SHARED_MEM_CLIENT", MODULE_ID_RD_SHARED_MEM_CLIENT} + @h2xmlm_displayName {"Read Shared Memory Client"} + @h2xmlm_description { + This module is used by the SPF in master process domain to read data from spf + in Satellite process domain through packet exchange mechanism. + This module has only one static input port with ID 2 and one output port with ID 1. + } + @h2xmlm_offloadInsert { RD_CLIENT } + @h2xmlm_dataInputPorts { IN = PORT_ID_RD_SHARED_MEM_CLIENT_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataOutputPorts { OUT = PORT_ID_RD_SHARED_MEM_CLIENT_OUTPUT} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_OLC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { 1024 } + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + + +#endif // RD_SH_MEM_CLIENT_API_H_ diff --git a/spf/api/modules/rd_sh_mem_ep_api.h b/spf/api/modules/rd_sh_mem_ep_api.h new file mode 100644 index 0000000..95f3120 --- /dev/null +++ b/spf/api/modules/rd_sh_mem_ep_api.h @@ -0,0 +1,597 @@ +/** + * \file rd_sh_mem_ep_api.h + * \brief + * This file contains Shared mem module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RD_SH_MEM_EP_API_H_ +#define RD_SH_MEM_EP_API_H_ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "common_enc_dec_api.h" + +/** + @h2xml_title1 {APIs of Read Shared Memory End Point Module} + @h2xml_title_agile_rev {APIs of Read Shared Memory End Point Module} + @h2xml_title_date {August 13, 2018} + */ + +/** + @h2xmlx_xmlNumberFormat {int} +*/ + +/** + * Data command to send an empty buffer to the shared memory end point module. + * RD_SHARED_MEM_EP writes to this buffer & client reads. + * + * This command can be used to read PCM, raw compressed as well as packetized streams. + * + * Once buffer is filled, DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_DONE event is raised. + */ +#define DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER 0x04001003 + +#include "spf_begin_pack.h" +struct data_cmd_rd_sh_mem_ep_data_buffer_t +{ + uint32_t buf_addr_lsw; + /**< Lower 32 bits of the address of the buffer */ + + uint32_t buf_addr_msw; + /**< Upper 32 bits of the address of the buffer . + + The buffer address for each frame must be a valid address + that was mapped via #APM_CMD_SHARED_MEM_MAP_REGIONS. + The 64-bit number formed by buf_addr_lsw and buf_addr_msw must be + aligned to the cache-line of the processor where spf runs (64-byte alignment for Hexagon). + + @tblsubhd{For a 32-bit shared memory address} This buf_addr_msw field + must be set to 0. + + @tblsubhd{For a 36-bit address} Bits 31 to 4 of this + buf_addr_msw field must be set to 0. */ + + uint32_t mem_map_handle; + /**< Unique identifier for the shared memory address. + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t buf_size; + /**< Number of bytes available for the spf to write. The + first byte starts at the buffer address. + + @values @ge 0 */ + +} +#include "spf_end_pack.h" +; + +/** Structure for DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER */ +typedef struct data_cmd_rd_sh_mem_ep_data_buffer_t data_cmd_rd_sh_mem_ep_data_buffer_t; + +/** + * Indicates that the referenced buffer has been filled and + * is available to the client for reading. + * + * This is response to DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER + * + The referenced buffer contains an optional array of metadata if the client + requested it in an open command. The buffer is followed by a variable + amount of empty space, assuming metadata is present, followed by an integer + number of encoded frames. Metadata presence is indicated by bit 30 of the + flags field in the flags + + Buffer format + A multiframe buffer becomes an array of frame metadata + information structures, and then an array of audio frames. Data + frames start with offset. + @verbatim + MetaData 0 (optional) + MetaData 1 (optional) + . . . + MetaData n (optional) + Extra space (optional) + Frame 0 Payload (this always starts at an offset from buf_addr) + Frame 1 Payload + . . . + Frame n-1 Payload + + */ +#define DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_DONE 0x05001002 + +/** Definition of a timestamp valid flag bitmask. */ +#define RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG AR_NON_GUID(0x80000000) + +/** Definition of a timestamp valid flag shift value. */ +#define RD_SH_MEM_EP_SHIFT_TIMESTAMP_VALID_FLAG 31 + +/** Definition of the frame metadata bitmask. +*/ +#define RD_SH_MEM_EP_BIT_MASK_FRAME_METADATA_FLAG AR_NON_GUID(0x60000000) + +/** Definition of the frame metadata shift value. +*/ +#define RD_SH_MEM_EP_SHIFT_FRAME_METADATA_FLAG 29 + +#include "spf_begin_pack.h" +/** + * Complete payload struct + * struct of memory at (buf_addr_msw|buf_addr_lsw) + * { + * + * if metadata_enabled: + * { + * data_event_rd_sh_mem_ep_metadata_t metadata[num_frames]; + * uint8_t padding1[if_any]; + * } + * uint8_t frames[data_size]; + * uint8_t padding2[if_any]; + * } + */ +struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_t +{ + uint32_t status; + /**< Status message (error code). + + @values Refer to @xrefcond{Q5,80-NF774-4,80-NA610-4} */ + + uint32_t buf_addr_lsw; + /**< Lower 32 bits of the address of the buffer being returned. */ + + uint32_t buf_addr_msw; + /**< Upper 32 bits of the address of the buffer being returned. + + The valid, mapped, 64-bit address is the same address that + the client provides in #DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER. */ + + uint32_t mem_map_handle; + /**< Unique identifier for the shared memory address. + + The spf returns this handle through #DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER. */ + + uint32_t data_size; + /**< Total size of the data frames in bytes. + + @values @ge 0 */ + + uint32_t offset; + /**< Offset from the buffer address to the first byte of the data frame. + * All frames are consecutive, starting from this offset. + + @values > 0 */ + + uint32_t timestamp_lsw; + /**< Lower 32 bits of the 64-bit session time in microseconds of the + first sample in the buffer. */ + + uint32_t timestamp_msw; + /**< Upper 32 bits of the 64-bit session time in microseconds of the + first sample in the buffer. + + the 64bit timestamp must be interpreted as a signed number. + + Source of the timestamp depends on the source feeding data to this module. + */ + + uint32_t flags; + /**< Bit field of flags. + + @values{for bit 31} + - 1 -- Timestamp is valid + - 0 -- Timestamp is invalid + - To set this bit, use #RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG and + RD_SH_MEM_EP_SHIFT_TIMESTAMP_VALID_FLAG + + @values{for bit 29-30} + - 00 -- frame metadata absent + - 01 -- Frame metadata is present as data_event_rd_sh_mem_ep_metadata_t + - 10 -- Reserved + - 11 -- Reserved + - To set these bits, use #RD_SH_MEM_EP_BIT_MASK_FRAME_METADATA_FLAG and + #RD_SH_MEM_EP_SHIFT_FRAME_METADATA_FLAG + + All other bits are reserved; the spf sets them to 0. + + When frame metadata is available, num_frames of consecutive instances of + %data_event_rd_sh_mem_ep_metadata_t + start at the buffer address + (see Buffer format). */ + + uint32_t num_frames; + /**< Number of data frames in the buffer. */ +} +#include "spf_end_pack.h" +; + +/* Structure DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_DONE */ +typedef struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_t data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_t; + +#include "spf_begin_pack.h" + +/* Payload of the metadata that can be put in the data read buffer. +*/ +struct data_event_rd_sh_mem_ep_metadata_t +{ + uint32_t offset; + /**< Offset from the buffer address in %data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_t to + the frame associated with the metadata. + + @values > 0 */ + + uint32_t frame_size; + /**< Size of each frame in bytes (E.g. encoded frame size). + + @values > 0 */ + + uint32_t pcm_length; + /**< Number of PCM samples per channel corresponding to each frame_size + * (E.g. number of PCM samples per channel used for encoding a frame). + + This field is always set to zero as there's no use case that needs it. + + @values = 0 */ + + uint32_t timestamp_lsw; + /**< Lower 32 bits of the 64-bit session time in microseconds of the + first sample in the frame. */ + + uint32_t timestamp_msw; + /**< Upper 32 bits of the 64-bit session time in microseconds of the + first sample in the frame. + */ + + uint32_t flags; + /**< Frame flags. + + @values{for bit 31} + - 1 -- Timestamp is valid + - 0 -- Timestamp is not valid + - To set this bit, use #RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG and + RD_SH_MEM_EP_SHIFT_TIMESTAMP_VALID_FLAG + + All other bits are reserved; the spf sets them to 0. */ +} +#include "spf_end_pack.h" +; + +/* Structure for metadata that can be put in the data read buffer. */ +typedef struct data_event_rd_sh_mem_ep_metadata_t data_event_rd_sh_mem_ep_metadata_t; + +/** + * Data command to send an empty buffer to the shared memory end point module. + * RD_SHARED_MEM_EP writes data and metadata to this buffer & client reads. + * + * This command can be used to read PCM, raw compressed as well as packetized streams. + * + * DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_DONE_V2 command response, once buffer is filled + */ +#define DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2 0x0400100B + +#include "spf_begin_pack.h" +struct data_cmd_rd_sh_mem_ep_data_buffer_v2_t +{ + uint32_t data_buf_addr_lsw; + /**< Lower 32 bits of the address of the data buffer */ + + uint32_t data_buf_addr_msw; + /**< Upper 32 bits of the address of the data buffer . + + The data buffer address for each frame must be a valid address + that was mapped via #APM_CMD_SHARED_MEM_MAP_REGIONS. + The 64-bit number formed by data_buf_addr_lsw and data_buf_addr_msw must be + aligned to the cache-line of the processor where spf runs (64-byte alignment for Hexagon). + + @tblsubhd{For a 32-bit shared memory address} This data_buf_addr_msw field + must be set to 0. + + @tblsubhd{For a 36-bit address} Bits 31 to 4 of this + data_buf_addr_msw field must be set to 0. */ + + uint32_t data_mem_map_handle; + /**< Unique identifier for the shared memory address corresponding to data buffer. + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t data_buf_size; + /**< Number of bytes available for the spf to write data. The + first byte starts at the specified data buffer address. + + @values @ge 0 */ + + uint32_t md_buf_addr_lsw; + /**< Lower 32 bits of the address of the metadata buffer */ + + uint32_t md_buf_addr_msw; + /**< Upper 32 bits of the address of the metadata buffer . + + The metadata buffer address for each frame must be a valid address + that was mapped via #APM_CMD_SHARED_MEM_MAP_REGIONS. + The 64-bit number formed by md_buf_addr_lsw and md_buf_addr_msw must be + aligned to the cache-line of the processor where spf runs (64-byte alignment for Hexagon). + + @tblsubhd{For a 32-bit shared memory address} This md_buf_addr_msw field + must be set to 0. + + @tblsubhd{For a 36-bit address} Bits 31 to 4 of this + md_buf_addr_msw field must be set to 0. */ + + uint32_t md_mem_map_handle; + /**< Unique identifier for the shared memory address corresponding to metadata buffer. + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t md_buf_size; + /**< Number of bytes available for the spf to write metadata. The + first byte starts at the specified metadata buffer address. + + @values @ge 0 */ + +} +#include "spf_end_pack.h" +; + +/** Structure for DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2 */ +typedef struct data_cmd_rd_sh_mem_ep_data_buffer_v2_t data_cmd_rd_sh_mem_ep_data_buffer_v2_t; + +/** + * Indicates that the referenced buffer has been filled and + * is available to the client for reading. + * + * This is response to DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2 + * + */ +#define DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_DONE_V2 0x05001005 + + +#include "spf_begin_pack.h" +struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t +{ + uint32_t data_status; + /**< Status message for data buffer (error code). + + @values Refer to @xrefcond{Q5,80-NF774-4,80-NA610-4} */ + + uint32_t data_buf_addr_lsw; + /**< Lower 32 bits of the address of the data buffer being returned. */ + + uint32_t data_buf_addr_msw; + /**< Upper 32 bits of the data address of the buffer being returned. + + The valid, mapped, 64-bit address is the same address that + the client provides in #DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2. */ + + uint32_t data_mem_map_handle; + /**< Unique identifier for the shared memory address corresponding to data buffer + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t data_size; + /**< Total size of the data frames in bytes. + + @values @ge 0 */ + + uint32_t timestamp_lsw; + /**< Lower 32 bits of the 64-bit session time in microseconds of the + first sample in the data buffer. */ + + uint32_t timestamp_msw; + /**< Upper 32 bits of the 64-bit session time in microseconds of the + first sample in the data buffer. + + the 64bit timestamp must be interpreted as a signed number. + + Source of the timestamp depends on the source feeding data to this module. + */ + + uint32_t flags; + /**< Bit field of flags. + + @values{for bit 31} + - 1 -- Timestamp is valid + - 0 -- Timestamp is invalid + - To set this bit, use #RD_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG and + RD_SH_MEM_EP_SHIFT_TIMESTAMP_VALID_FLAG + + All other bits are reserved; the spf sets them to 0. + */ + + uint32_t num_frames; + /**< Number of data frames in the data buffer. */ + + uint32_t md_status; + /**< Status message for metadata buffer(error code). + + @values Refer to @xrefcond{Q5,80-NF774-4,80-NA610-4} */ + + uint32_t md_buf_addr_lsw; + /**< Lower 32 bits of the address of the metadata buffer being returned. */ + + uint32_t md_buf_addr_msw; + /**< Upper 32 bits of the data address of the metadata buffer being returned. + + The valid, mapped, 64-bit address is the same address that + the client provides in #DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2. */ + + uint32_t md_mem_map_handle; + /**< Unique identifier for the shared memory address corresponding to metadata buffer + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t md_size; + /**< Total size of the metadata frames in bytes. + + @values @ge 0 */ +} +#include "spf_end_pack.h" +; + +/* Structure DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_DONE_V2 */ +typedef struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2_t; + +/** + * Media format sent from this module to the client. + * + * Payload media_format_t + * + * Event must be registered with APM_CMD_REGISTER_MODULE_EVENTS + */ +#define DATA_EVENT_ID_RD_SH_MEM_EP_MEDIA_FORMAT 0x06001000 + +/** + EOS event sent from this module to the client. + This serves as a discontinuity marker. + + Event must be registered with APM_CMD_REGISTER_MODULE_EVENTS +*/ +#define DATA_EVENT_ID_RD_SH_MEM_EP_EOS 0x06001001 + +#include "spf_begin_pack.h" +struct data_event_rd_sh_mem_ep_eos_t +{ + uint32_t eos_reason; + /**< EoS raised due to one of the following discontinuities + * - pause + * - other */ +} +#include "spf_end_pack.h" +; + +typedef struct data_event_rd_sh_mem_ep_eos_t data_event_rd_sh_mem_ep_eos_t; + +/** + * Input port ID of the Read Shared Memory EP + */ +#define PORT_ID_RD_SHARED_MEM_EP_INPUT 0x2 + +/** + * Output port ID of the Read Shared Memory EP + * This Port is connected only in OFFLOAD(MDF) use-cases + */ +#define PORT_ID_RD_SHARED_MEM_EP_OUTPUT 0x1 + +/** + * ID of the Read Shared Memory End-Point Module + * + * This module has only one static input port with ID 2 + * + * + * Supported Input Media Format: + * - Any + */ +#define MODULE_ID_RD_SHARED_MEM_EP 0x07001001 +/** + @h2xmlm_module {"MODULE_ID_RD_SHARED_MEM_EP", MODULE_ID_RD_SHARED_MEM_EP} + @h2xmlm_displayName {"Read Shared Memory EndPoint"} + @h2xmlm_description { + This module is used to read data from spf into the host through packet exchange mechanism. + For regular use-case, this module has only one static input port with ID 2. + For MDF use-cases where the module is automatically inserted by the ARCT, + this module support one static output port with ID 1 and one static input port with ID 2. + } + @h2xmlm_offloadInsert { RD_EP } + @h2xmlm_dataInputPorts { IN = PORT_ID_RD_SHARED_MEM_EP_INPUT} + @h2xmlm_dataOutputPorts { OUT = PORT_ID_RD_SHARED_MEM_EP_OUTPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { 1024 } + @{ <-- Start of the Module --> + +*/ + +/** + * Special value of num_frames_per_buffer to indicate that as many buffer need to be filled as possible. + */ +#define RD_SH_MEM_NUM_FRAMES_IN_BUF_AS_MUCH_AS_POSSIBLE 0 + +/*============================================================================== + Param ID +==============================================================================*/ + +/** + Configuration of the Read Shared Memory Module. +*/ +#define PARAM_ID_RD_SH_MEM_CFG 0x08001007 + +/** Definition of a metadata control flags, encoder frame info flag bitmask. */ +#define RD_EP_CFG_MD_CNTRL_FLAGS_BIT_MASK_ENABLE_ENCODER_FRAME_MD AR_NON_GUID(0x00000001) + +/** Definition of a metadata control flags, encoder frame info shift value. */ +#define RD_EP_CFG_MD_CNTRL_FLAGS_SHIFT_ENABLE_ENCODER_FRAME_MD 0 + +/** Definition of a metadata control flags, enable media format metadata flag bitmask. */ +#define RD_EP_CFG_MD_CNTRL_FLAGS_BIT_MASK_ENABLE_MEDIA_FORMAT_MD AR_NON_GUID(0x00000002) + +/** Definition of a metadata control flags, enable media format metadata shift value. */ +#define RD_EP_CFG_MD_CNTRL_FLAGS_SHIFT_ENABLE_MEDIA_FORMAT_MD 1 + +/*============================================================================== + Param structure definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"PARAM_ID_RD_SH_MEM_CFG", PARAM_ID_RD_SH_MEM_CFG} + @h2xmlp_description {Parameter for setting the configuration of read shared memory end point module.\n } + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +struct param_id_rd_sh_mem_cfg_t +{ + uint32_t num_frames_per_buffer; + /**< @h2xmle_description {The number of frames per buffer that need to be populated in the Read buffers. + It's an error if even one frame cannot be filled. + If zero, then as many frames are filled as possible (only integral number of frames). + If N frames cannot be filled but M can be (where M < N), then buffer is released after M.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} + */ + + uint32_t metadata_control_flags; + /**< @h2xmle_description {Specifies the control flags for the metadata for the read shared memory + end-point module.} + @h2xmle_default {0} + @h2xmle_range {0..3} + @h2xmle_policy {Basic} + + + @h2xmle_bitfield {0x00000001} + @h2xmle_default {0} + @h2xmle_bitName {Bit_0_ENABLE_ENCODER_FRAME_MD} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_description {Specifies the control to enable/disable the per frame encoder information + which is communicated using the metadata ID MODULE_CMN_MD_ID_ENCODER_FRAME_INFO } + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0x00000002} + @h2xmle_default {1} + @h2xmle_bitName {Bit_1_ENABLE_MEDIA_FORMAT_MD} + @h2xmle_description { Specifies the control to enable/disable the media format communication from SPF to + Client as metatdata, which is communicated using the metadata ID + MODULE_CMN_MD_ID_MEDIA_FORMAT If enabled, the media format would be communicated + as metadata in the read buffer.} + @h2xmle_bitfieldEnd + + @h2xmle_bitfield {0xfffffffC} + @h2xmle_bitName {Bit_31_2_Reserved} + @h2xmle_description {Reserved Bit[31:2]} + @h2xmle_visibility {hide} + @h2xmle_bitfieldEnd + */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_rd_sh_mem_cfg_t param_id_rd_sh_mem_cfg_t; + + +/** @} <-- End of the Module --> */ + + +#endif // RD_SH_MEM_EP_API_H_ diff --git a/spf/api/modules/rt_proxy_api.h b/spf/api/modules/rt_proxy_api.h new file mode 100644 index 0000000..e4490e0 --- /dev/null +++ b/spf/api/modules/rt_proxy_api.h @@ -0,0 +1,122 @@ +#ifndef __RT_PROXY_H +#define __RT_PROXY_H +/** + * \file rt_proxy_api.h + * \brief + * This file contains module published by RT Proxy CAPI intialization. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/** + @h2xml_title1 {Real Time Proxy Module} + @h2xml_title_agile_rev {Real Time Proxy Module} + @h2xml_title_date {Jun 4, 2019} +*/ + +// Max number of ports supported by RT proxy module. +#define CAPI_RT_PROXY_MAX_INPUT_PORTS (1) +#define CAPI_RT_PROXY_MAX_OUTPUT_PORTS (1) +#define CAPI_RT_PROXY_MAX_CTRL_PORTS (1) + +/*============================================================================== + Constants +==============================================================================*/ + +/* Parameter description */ +#define PARAM_ID_RT_PROXY_CONFIG 0x08001157 + +/*============================================================================== + Type Definitions +==============================================================================*/ + + +/** @h2xmlp_parameter {"PARAM_ID_RT_PROXY_CONFIG", + PARAM_ID_RT_PROXY_CONFIG} + @h2xmlp_description { This param ID is used to configure RT proxy module. } */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_rt_proxy_config_t +{ + uint32_t jitter_allowance_in_ms; + /**< @h2xmle_description { It defines the range of jitter for client buffers. + Rang is considered as +/- jitter_allowance_in_ms } + @h2xmle_default { 1 } */ + + uint32_t client_frame_size_in_ms; + /**< @h2xmle_description { Its read/write client buffer frame size.} + @h2xmle_default { 0 } */ + + uint32_t low_watermark_in_ms; + /**< @h2xmle_description { Low watermark event is sent to the client if the buffer size + reaches less than this threshold. } + @h2xmle_default { 0 } */ + + uint32_t high_watermark_in_ms; + /**< @h2xmle_description { High watermark event is sent to the client if the buffer size + crosses this threshold. } + @h2xmle_default { 0xFFFFFFFF } */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure to define the RT proxy configuration.*/ +typedef struct param_id_rt_proxy_config_t param_id_rt_proxy_config_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** Module ID of the Real Time Proxy Module. */ +#define MODULE_ID_RT_PROXY_RX 0x07001065 + +/** + @h2xmlm_module {"MODULE_ID_RT_PROXY_RX", MODULE_ID_RT_PROXY_RX} + @h2xmlm_displayName {"Real Time Proxy RX"} + @h2xmlm_description { This module acts a bridge RT source and RT sink. } + @h2xmlm_dataMaxInputPorts { 1 } + @h2xmlm_dataMaxOutputPorts { 1 } + @h2xmlm_ctrlDynamicPortIntent { "RT proxy - RAT" = INTENT_ID_TIMER_DRIFT_INFO, + maxPorts= 1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { 1024 } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_rt_proxy_config_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module --> */ + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** Module ID of the Real Time Proxy Module. */ +#define MODULE_ID_RT_PROXY_TX 0x0700106B + +/** + @h2xmlm_module {"MODULE_ID_RT_PROXY_TX", MODULE_ID_RT_PROXY_TX} + @h2xmlm_displayName {"Real Time Proxy TX"} + @h2xmlm_description { This module acts a bridge RT client sink and RT source on DSP. } + @h2xmlm_dataMaxInputPorts { 1 } + @h2xmlm_dataMaxOutputPorts { 1 } + @h2xmlm_ctrlDynamicPortIntent { "RT proxy - RAT" = INTENT_ID_TIMER_DRIFT_INFO, + maxPorts= 1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { 1024 } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_rt_proxy_config_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module --> */ + +#endif /*__RT_PROXY_H*/ diff --git a/spf/api/modules/rtm_logging_api.h b/spf/api/modules/rtm_logging_api.h new file mode 100644 index 0000000..444e5af --- /dev/null +++ b/spf/api/modules/rtm_logging_api.h @@ -0,0 +1,160 @@ +#ifndef __RTM_LOGGING_API_H__ +#define __RTM_LOGGING_API_H__ +/** + * \file rtm_logging_api.h + * \brief + * This file contains audio rtm logging parameters. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +/*============================================================================== + Param ID +==============================================================================*/ + +#define PARAM_ID_RTM_LOGGING_ENABLE 0x080010A6 + +/*============================================================================== + Param structure defintions +==============================================================================*/ + +/** @h2xmlp_parameter {"PARAM_ID_RTM_LOGGING_ENABLE", PARAM_ID_RTM_LOGGING_ENABLE} + @h2xmlp_description {Parameter used to enable/disable RTM logging in audio modules.} + @h2xmlp_toolPolicy {Calibration; RTC} */ + +#include "spf_begin_pack.h" +struct rtm_logging_enable_payload_t +{ + uint32_t enable_rtm_logging; + /**< @h2xmle_description {Param to enable RTM logging for any Audio module} + @h2xmle_rangeList {"Disable" = 0; + "Enable" = 1} + @h2xmle_policy {Basic} + @h2xmle_default {0} */ + + uint32_t log_code; + /**< @h2xmle_description {logging code} + @h2xmle_default {0x184B} + @h2xmle_rangeList {"VoiceProc_RTM_Log_Code" = 0x184B; + "AudProc_RTM_Log_Code" = 0x19B3} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +/* Type definition for the above structure.*/ +typedef struct rtm_logging_enable_payload_t rtm_logging_enable_payload_t; + +/* Currently no RTM header is logged as part of RTM data blob, hence a default value is + * used for RTM header version. */ +#define RTM_HEADER_VERSION_0 0 + +/** @h2xmlp_description { Common structure used for RTM logging of all monitoring parameters} + @h2xmlp_toolPolicy {RTM} + @h2xmlp_readOnly {true}*/ +#include "spf_begin_pack.h" +struct rtm_logging_param_data_t +{ + uint32_t module_instance_id; + /**< @h2xmle_description {instance ID of the module that logs the RTM data} + @h2xmle_default {0x0} + @h2xmle_range {0..4294967295} */ + + uint32_t param_id; + /**< @h2xmle_description {param ID of the parameter that is being logged} + @h2xmle_default {0x0} + @h2xmle_range {0..4294967295} */ + + uint16_t param_size; + /**< @h2xmle_description {size of the param data which is followed by this structure} + @h2xmle_default {0x0} + @h2xmle_range {0..65536} */ + + uint16_t reserved; + /**< @h2xmle_description {reserved parameter} + @h2xmle_default {0x0} + @h2xmle_range {0..65536} */ +} +#include "spf_end_pack.h" +; +/* Type definition for the above structure.*/ +typedef struct rtm_logging_param_data_t rtm_logging_param_data_t; + +/*============================================================================== + Param ID +==============================================================================*/ + +#define PARAM_ID_RTM_PCM_LOGGING 0x080010A7 + +/*============================================================================== + Param structure defintions +==============================================================================*/ + +/** @h2xmlp_description { To query RTM PCM logging.\n + Payload size of this parameter is dynamic and depends on pcm_size. + The header size for version 0 param is 48 bytes \n. + payload size -- (48 + pcm_size) bytes} + @h2xmlp_toolPolicy {RTM} + @h2xmlp_readOnly {true}*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct rtm_pcm_logging_payload_t +{ + + uint32_t pcm_size; + /**< @h2xmle_description {total size of PCM data in Bytes} + @h2xmle_default {0x0} + @h2xmle_range {0..4294967295} */ + + uint32_t log_tap_id; + /**< @h2xmle_description {tap ID for PCM data} + @h2xmle_default {0x0} + @h2xmle_range {0..4294967295} */ + + uint32_t sampling_rate; + /**< @h2xmle_description {sampling rate of the PCM data} + @h2xmle_default {0x1f40} + @h2xmle_range {0..384000} */ + + uint16_t num_channels; + /**< @h2xmle_description {Number of channels in the PCM stream getting logged} + @h2xmle_default {0x1} + @h2xmle_range {1..32} */ + + uint8_t pcm_width; + /**< @h2xmle_description {pcm width of the PCM data} + @h2xmle_rangeList {"bitwidth 16bit"=16; + "bitwidth 24bit"=24; + "bitwidth 24bit"=32} + @h2xmle_default {0x10} */ + + uint8_t interleaved; + /**< @h2xmle_description {specifies whether PCM data packing is interleaved or deinterleaved} + @h2xmle_rangeList {"INTERLEAVED"=0; + "DEINTERLEAVED_PACKED"=1; + "DEINTERLEAVED_UNPACKED"=2} + @h2xmle_default {0x0} */ + + uint8_t channel_map[32]; + /**< @h2xmle_description {Channel map of each channel in the PCM stream getting logged} + @h2xmle_default {0x1} + @h2xmle_range {1..63} */ +#if defined(__H2XML__) + int8_t payload[0]; + /**< @h2xmle_description {Array of PCM data} + + @h2xmle_variableArraySize {"pcm_size"} + @h2xmle_policy {Basic} */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Type definition for the above structure.*/ +typedef struct rtm_pcm_logging_payload_t rtm_pcm_logging_payload_t; + +#endif // __RTM_LOGGING_PARAM_CALIB_H__ diff --git a/spf/api/modules/rx_haptics_api.h b/spf/api/modules/rx_haptics_api.h new file mode 100644 index 0000000..895a096 --- /dev/null +++ b/spf/api/modules/rx_haptics_api.h @@ -0,0 +1,3059 @@ +#ifndef __RX_HAPTICS_API_H__ +#define __RX_HAPTICS_API_H__ + +/*============================================================================== + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + + @file rx_haptics_api.h + @brief This file contains APIs for Haptics Module +==============================================================================*/ + +/*============================================================================== + Edit History + + when who what, where, why + -------- --- ------------------------------------------------------ + 06/21/2022 deepjind Haptics + 02/28/2025 shyap Haptics v2.3 +==============================================================================*/ + +/** @h2xml_title1 {Haptics-RX} + @h2xml_title_date {June 21, 2022} */ +#include "module_cmn_api.h" +#include "ar_defs.h" +#include "imcl_spm_intent_api.h" +#include "rtm_logging_api.h" + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ +#define HAPTICS_MAX_INPUT_PORTS 1 +#define HAPTICS_MAX_OUTPUT_PORTS 1 +#define HAPTICS_STACK_SIZE 4096 + +/* Unique Module ID */ +#define MODULE_ID_HAPTICS 0x070010E6 + +/** @h2xmlm_module {"MODULE_ID_HAPTICS", + MODULE_ID_HAPTICS} + @h2xmlm_displayName {"HAPTICS-RX"} + @h2xmlm_rtmLogcode {0x184B} + @h2xmlm_toolPolicy {Calibration;CALIBRATION} + @h2xmlm_description {ID of the HAPTICS module.\n + This module includes Haptics waveform designer block, Excursion control and + CPS processing. + + This module supports the following parameter IDs:\n + - #PARAM_ID_MODULE_ENABLE \n + - #PARAM_ID_RTM_LOGGING_ENABLE\n + - #PARAM_ID_HAPTICS_STATIC_CFG\n + - #PARAM_ID_HAPTICS_OP_MODE\n + - #PARAM_ID_HAPTICS_DYNAMIC_CFG\n + - #PARAM_ID_HAPTICS_WAVE_DESIGNER_CFG\n + - #PARAM_ID_HAPTICS_WAVE_DESIGNER_CFG_V2\n + - #PARAM_ID_HAPTICS_WAVE_DESIGNER_STOP_PARAM\n + - #PARAM_ID_HAPTICS_WAVE_DESIGNER_UPDATE_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_0_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_1_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_2_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_3_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_4_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_5_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_6_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_7_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_8_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_9_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_10_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_11_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_12_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_13_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EFFECT_14_DATA_PARAM\n + - #PARAM_ID_HAPTICS_CPS_PARAM\n + - #PARAM_ID_HAPTICS_CPS_DATA_PARAM\n + - #PARAM_ID_HAPTICS_EX_CPS_DEMO_PKT_PARAM\n + - #PARAM_ID_HAPTICS_EX_CPS_DEMO_PARAM\n + - #PARAM_ID_HAPTICS_RX_RTCL_LOGGING_PARAM_V3\n + - #PARAM_ID_HAPTICS_EX_DEMO_PARAM\n + - #PARAM_ID_HAPTICS_VERSION\n + - #PARAM_ID_HAPTICS_WAVE_DESIGNER_STATE\n + - #PARAM_ID_HAPTICS_RX_EFFECTS_CONFIG_PARAM\n + - #PARAM_ID_HAPTICS_RX_FTM_DATA_PARAM\n + - #PARAM_ID_HAPTICS_RX_CALIB_DATA_PARAM\n + - #PARAM_ID_HAPTICS_RX_PERSISTENT_DATA_PARAM\n + - #PARAM_ID_HAPTICS_RX_PCMV_PLAYBACK\n + - #PARAM_ID_HAPTICS_RX_FTM_CFG\n + - #PARAM_ID_HAPTICS_LPASS_SWR_HW_REG_CFG\n + - #PARAM_ID_HAPTICS_RX_TUNING_DATA_0_PARAM\n + - #PARAM_ID_HAPTICS_RX_TUNING_DATA_1_PARAM\n + - #PARAM_ID_HAPTICS_RX_TUNING_DATA_2_PARAM\n + - #PARAM_ID_HAPTICS_RX_TUNING_DATA_3_PARAM\n + - #PARAM_ID_HAPTICS_RX_TUNING_DATA_4_PARAM\n + - #PARAM_ID_HAPTICS_RX_VISENSE_CFG\n + - #PARAM_ID_HAPTICS_RX_THERMAL_GAIN_CFG\n + - #PARAM_ID_HAPTICS_RX_LRA_PARAM_RANGE_CFG\n + - #PARAM_ID_HAPTICS_RX_TEST_MODE_CFG\n + + All parameter IDs are device independent.\n + + Supported Input Media Format:\n +* - Data Format : FIXED_POINT\n +* - fmt_id : Don't care\n +* - Sample Rates : 48000\n +* - Number of channels : 1 and 2\n +* - Channel type : 1 to 63\n +* - Bits per sample : 16, 32\n +* - Q format : 15 for bps = 16 and 31 for bps = 32\n +supported bps +* - Interleaving : de-interleaved unpacked\n +* - Signed/unsigned : Signed } + + @h2xmlm_toolPolicy {Calibration} + + @h2xmlm_dataMaxInputPorts {HAPTICS_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {HAPTICS_MAX_OUTPUT_PORTS} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {HAPTICS_STACK_SIZE} + @h2xmlm_ctrlDynamicPortIntent { "Haptics VI intent id for communicating Vsens and Isens data" = 0x0800136E, maxPorts= +1 } + @h2xmlm_ToolPolicy {Calibration} + + + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + + @h2xml_Select {"rtm_logging_enable_payload_t"} + @h2xmlm_InsertParameter +*/ +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ + +/* Number of plotting samples in one excursion Rx output packet. */ +#define HAPTICS_EX_RX_DEMO_SMPL_PER_PKT 10*8 + +#define HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT 10 + +/* Max number of vbatt resistance table */ +#define NVBATT_DISCRETE (9) + +/* Max number of die temp resistance table */ +#define NDTEMP_DISCRETE (14) + +/* Max number of vbatt fine resistance table */ +#define NVBATT_DISCRETE_FINE (13) + +/* Max number of resistance table */ +#define NRE_DISCRETE (3) + +// Maximum output channels +#define HAPTICS_MAX_OUT_CHAN (2) + +// Maximum number of entries for thermal compensation +#define HAPTICS_THERMAL_GAIN_COUNT (11) + +/*typedef enum WAVE_DSN_MODE_T { + MIN_WAVE_DSN_MODE = 0, + PARAMETRIC = 0, // Parametric waveform designer mode + PWL = 1, // Piece-wise linear waveform designer mode + SINUSOIDAL = 2, // Sinusoidal waveform designer mode + PCMV_RINGTONE = 3, // Pre-canned haptics waveform mode for ringtone haptics + PCMV_EFFECTS = 4, // Pre-canned haptics waveform mode for pre-defined effects + PCMV_PLAYBACK = 5, // Pre-canned haptics waveform mode for pcmv playback from HLOS + MAX_WAVE_DSN_MODE = 0xFFFFFFFF // max 32-bit unsigned value. tells the compiler to use 32-bit data type +} WAVE_DSN_MODE_T; */ + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_STATIC_CFG 0x080014E7 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_static_config_t param_id_haptics_static_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_STATIC_CFG", + PARAM_ID_HAPTICS_STATIC_CFG} + @h2xmlp_description {Parameters used to configure the static configuration of + WSA smart haptics Rx processing.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_static_config_t +{ + uint32_t sampling_rate; // PCM signal sampling rate + /**< @h2xmle_description {Sampling rate of Rx signal.} + @h2xmle_rangeList {"48kHz"=48000} + @h2xmle_default {48000} */ + uint32_t bits_per_sample; // Number of bits for input and output samples, (per channel) + /**< @h2xmle_description {Bits per sample for Rx signal.} + @h2xmle_rangeList {"16"=16;"32"=32} + @h2xmle_default {16} */ + uint32_t num_channels; // Number of LRAs/ number of channels for Rx signal. + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + uint32_t frame_size_ms; // processing frame size in ms + /**< @h2xmle_description {Frame size for Rx processing in ms.} + @h2xmle_rangeList {"1ms"=1} + @h2xmle_default {1} */ + uint32_t features; // what sub-features are on + /**< @h2xmle_description {Features enabled in the WSA smart haptics + algorithm.} + @h2xmle_range {0..0x07} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Thermal tracking"} + @h2xmle_description {Thermal tracking} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Excursion control"} + @h2xmle_description {Excursion control} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000004} + @h2xmle_bitName {"Excursion control static gain support"} + @h2xmle_description {Excursion control static gain support} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd */ + uint32_t pt_lvl_switch_en; // dynamic pilot tone level switch enable/disable flag + /**< @h2xmle_description {Flag to enable/disable the dynamic pilot tone level switch.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} */ + int32_t pt_masking_thr_q27; // Rated Voltage of the LRA in peak Volts + /**< @h2xmle_description {Rated Voltage of the LRA in peak Volts. Default = 1.3, Range: 0 to 15.99} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728} */ + uint32_t ex_block_size; + /**< @h2xmle_description {excursion control block size - number of frames used for excursion control} + @h2xmle_range {3..3} + @h2xmle_default {3} */ + int32_t Mu_gram_q20; + /**< @h2xmle_description {Mechanical mass of the handset in grams. Default value: 200g, Range: 0 to 2048g} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q20} + @h2xmle_default {209715200} */ + uint32_t fpilot_Hz; // Pilot tone frequency [40] 40 Hz. + // Note: Pilot tone frequency values MUST be the same for the RX/TH/EX modules. + /**< @h2xmle_description {Pilot tone frequency in Hz. Pilot tone frequency values MUST be the same for the RX/TH/EX modules} + @h2xmle_rangeList {"40"=40} Hz + @h2xmle_default {40} */ + int32_t fpilot_amplitude_db; // Pilot tone amplitude [-37] -37dB. + // Note: Pilot tone amplitude values MUST be the same for the RX/TH/EX modules. + /**< @h2xmle_description {Pilot tone amplitude relative to 0 dbFS (for example, -37 dB from the full scale), in dB. Pilot tone amplitude values MUST be the same for the RX/TH/EX modules} + @h2xmle_range {-40..-30} dB + @h2xmle_default {-37} */ + int32_t tracked_freq_warmup_time_ms; // Time delay before enabling resonance frequency tracking (in ms). + /**< @h2xmle_description {Time delay before enabling resonance frequency tracking, in ms.} + @h2xmle_range {0..10000} ms + @h2xmle_default {50} */ + int32_t settling_time_ms; // Maximum time delay for the haptics waveform to settle to zero, after actuation ends (in ms). + /**< @h2xmle_description {Maximum time delay for the haptics waveform to settle to zero after actuation ends, in ms.} + @h2xmle_range {5..100} ms + @h2xmle_default {30} */ + + // Waveform designer parameters + int32_t rise_fall_time_max_ms; // Waveform designer parametric mode parameter. Defines time taken for the LRA to reach specified accelaration at 0% sharpness (in ms). + /**< @h2xmle_description {Waveform designer parametric mode parameter. Defines time taken for the LRA to reach specified accelaration at 0% sharpness, in ms.} + @h2xmle_range {20..100} ms + @h2xmle_default {100} */ + int32_t delay_time_ms; // Waveform designer parametric mode parameter. Time delay at the start and end of the pulse acceleration waveform (in ms). + /**< @h2xmle_description {Waveform designer parametric mode parameter. Time delay at the start and end of the parametric waveform, in ms} + @h2xmle_range {0..100} ms + @h2xmle_default {0} */ + int32_t pwl_max_pulse_points; // Maximum no. of pulse points supported in PWL mode, waveform designer + /**< @h2xmle_description {Maximum no. of pulse points supported in PWL mode by the waveform designer} + @h2xmle_range {50..500} + @h2xmle_default {100} */ + int32_t wave_dsgn_max_pulse_duration_ms; // Maximum continuous haptics pulse duration supported, to prevent thermal damage (in ms). + /**< @h2xmle_description {Maximum continuous haptics pulse duration supported to prevent thermal damage, in ms} + @h2xmle_range {1000..3000} ms + @h2xmle_default {3000} */ + int32_t wave_dsgn_max_duty_cycle; // Maximum duty cycle supported, to prevent thermal damage in % + /**< @h2xmle_description {Maximum duty cycle supported, to prevent thermal damage in %} + @h2xmle_range {40..100} + @h2xmle_default {50} */ + int32_t phase_index; // Initial phase index + /**< @h2xmle_description {Initial phase index.} + @h2xmle_range {0..100} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_OP_MODE 0x0800136D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_op_mode param_id_haptics_op_mode; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_OP_MODE", + PARAM_ID_HAPTICS_OP_MODE} + @h2xmlp_description {Parameter used to select the operation mode of WSA + smart haptics RX processing.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_op_mode { + uint32_t operation_mode; // normal running or thermal calibration + /**< @h2xmle_description {Operation mode of RX module.} + @h2xmle_rangeList {"Normal Running mode"=0; + "Calibration mode"=1; + "Factory Test Mode"=2}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_PCMV_PLAYBACK 0x08001AE3 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_pcmv_playback param_id_haptics_rx_pcmv_playback; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_PCMV_PLAYBACK", + PARAM_ID_HAPTICS_RX_PCMV_PLAYBACK} + @h2xmlp_description {PCMV Playback mode buffer ptr, size set param} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_rx_pcmv_playback { + uint32_t channel_mask; // Mask to indicate to which channel(s) the buffer is being set, for mono set this to 1 + /**< @h2xmle_description {Mask to indicate which channel(s) have a valid UPDATE command.} + @h2xmle_range {0..0x02} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Channel 1"} + @h2xmle_description {Enabling this bit will indicate a valid PCMV Playback buffer set to Channel 1.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Channel 2"} + @h2xmle_description {Enabling this bit will indicate a valid PCMV Playback buffer set to Channel 2.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd */ + int32_t buffer_size; // Buffer size in bytes + /**< @h2xmle_description {Length of the effect PCM buffer in bytes, (48kHz, 16-bit mono, Q15 format), Max duration supported is 10 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x000EA600} */ +#ifdef __H2XML__ + uint8_t buffer_ptr[0]; // PCMV Playback mode buffer pointer + /**< @h2xmle_description {Haptics PCMV playback data buffer. PCM data format: 48kHz, 16-bit mono, Q15 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_FTM_CFG 0x08001B1C + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_ftm_cfg_t param_id_haptics_rx_ftm_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_FTM_CFG", + PARAM_ID_HAPTICS_RX_FTM_CFG} + @h2xmlp_description {Parameter to set FTM configuration} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_rx_ftm_cfg_t { + uint32_t non_linearity_compensation; // Enable/Disable duffing non linearity compensation + /**< @h2xmle_description {Enable/Disable duffing non linearity compensation} + @h2xmle_rangeList {"Disabled"=0; + "Enabled"=1} + @h2xmle_default {0} */ + int32_t ftm_amplitude_q24[HAPTICS_MAX_OUT_CHAN]; // FTM playback amplitude level in Volts + /**< @h2xmle_description {FTM playback amplitude level in Volts} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t f0_tracking_duration_ms[HAPTICS_MAX_OUT_CHAN]; // f0 tracking duration in ms + /**< @h2xmle_description {FTM f0 tracking duration in ms} + @h2xmle_range {0..1000} + @h2xmle_default {250} */ + int32_t f0_duffing_duration_ms[HAPTICS_MAX_OUT_CHAN]; // FTM f0 tracking non linearity compensation max duration in ms + /**< @h2xmle_description {FTM f0 tracking non linearity compensation max duration in ms} + @h2xmle_range {0..8000} + @h2xmle_default {6000} */ + int32_t rtcl_gain_k_0_q27[HAPTICS_MAX_OUT_CHAN]; // RTCL gain_k[0] + /**< @h2xmle_description {RTCL gain_k[0]} + @h2xmle_range {-7..7} + @h2xmle_dataFormat {Q27} + @h2xmle_default {0} */ + int32_t rtcl_gain_k_1_q27[HAPTICS_MAX_OUT_CHAN]; // RTCL gain_k[1] + /**< @h2xmle_description {RTCL gain_k[1]} + @h2xmle_range {-7..7} + @h2xmle_dataFormat {Q27} + @h2xmle_default {0} */ + int32_t rtcl_gain_l_0_q27[HAPTICS_MAX_OUT_CHAN]; // RTCL gain_l[0] + /**< @h2xmle_description {RTCL gain_l[0]} + @h2xmle_range {-7..7} + @h2xmle_dataFormat {Q27} + @h2xmle_default {0} */ + int32_t rtcl_gain_l_1_q27[HAPTICS_MAX_OUT_CHAN]; // RTCL gain_l[1] + /**< @h2xmle_description {RTCL gain_l[1]} + @h2xmle_range {-7..7} + @h2xmle_dataFormat {Q27} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_DYNAMIC_CFG 0x08001398 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct haptics_ex_ctrl_param_h haptics_ex_ctrl_param_h; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +// Structure encapsulating LRA parameters for RX excursion control block +/** @h2xmlp_subStruct */ +struct haptics_ex_ctrl_param_h +{ + int32_t amp_gain_q24; // Amplifier gain that will be used in scaling Tx vsense signal to rx signal + /**< @h2xmle_description {WSA peak voltage for a digitally full-scale signal. Default = 10, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {167772160} */ + int32_t max_excursion_mm_q27; // LRA xmax value + /**< @h2xmle_description {maximum permissible excursoin, in mm. Default = 0.3mm, Range: 0.05 to 16mm} + @h2xmle_range {6710886..2147483647} + @h2xmle_dataFormat {Q27} + @h2xmle_default {40265318} */ + int32_t max_acceleration_q27; // LRA maximum acceleration value + /**< @h2xmle_description {LRA maximum acceleration value in linear scale, in Gs. Default = 1G, Range: 0.1 to 16G} + @h2xmle_range {13421773..2147483647} + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728} */ + int32_t trace_resistance_rx_q24; + /**< @h2xmle_description {trace resistance from amp output to LRA, in Ohms. Default = 0Ohm, Range: 0 to 128Ohms} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Re_ohm_q24; + /**< @h2xmle_description {DC resistance of LRA coil at room temperature, in Ohms. Default = 8Ohm, Range: 2 to 128Ohms} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Le_mH_q24; + /**< @h2xmle_description {Inductance of LRA coil at room temperature, in mH. Default = 0.04mH, Range: 0.001mH to 128mH} + @h2xmle_range {16777..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {671088} */ + int32_t Bl_q24; + /**< @h2xmle_description {Force factor (Bl product). Default = 1, Range: 0.01 to 128} + @h2xmle_range {167772..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Mms_gram_q24; + /**< @h2xmle_description {Mass of LRA moving mass, in grams. Default = 1g, Range: 0.05 to 128g} + @h2xmle_range {838860..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Rms_KgSec_q24; + /**< @h2xmle_description {Mechanical damping or resistance of LRA, in kg/s. Default = 0.0945kg/s, Range = 0.0001 to 20kg/s} + @h2xmle_range {16777..335544320} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1585446} */ + int32_t Kms_Nmm_q24; + /**< @h2xmle_description {Mechanical stiffness of driver suspension, in N/mm. Default = 1.838N/mm, Range = 0.1 to 50N/mm} + @h2xmle_range {1677721..838860800} + @h2xmle_dataFormat {Q24} + @h2xmle_default {30836523} */ + int32_t Fres_Hz_q20; + /**< @h2xmle_description {Resonance frequency, in Hz. Default = 160Hz, Range = 50 to 400Hz} + @h2xmle_range {52428800..419430400} + @h2xmle_dataFormat {Q20} + @h2xmle_default {167772160} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_dynamic_cfg param_id_haptics_dynamic_cfg; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_DYNAMIC_CFG", + PARAM_ID_HAPTICS_DYNAMIC_CFG} + @h2xmlp_description {Parameters used to configure the dynamic configuration of + WSA smart haptics Rx processing.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_dynamic_cfg +{ + uint32_t num_channels; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ +#ifdef __H2XML__ + haptics_ex_ctrl_param_h haptics_ex_ctrl_param[0]; + /**< @h2xmle_description {Structure encapsulating LRA parameters for RX excursion control block} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_FTM_DATA_PARAM 0x08001ADE + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_ftm_data_param_t param_id_haptics_rx_ftm_data_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_FTM_DATA_PARAM", PARAM_ID_HAPTICS_RX_FTM_DATA_PARAM} + @h2xmlp_description {Parameter for registering haptics ftm data to lib} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_ftm_data_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for FTM data file} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of ftm data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the FTM data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00000064} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics FTM data: The path to the FTM cal file} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_CALIB_DATA_PARAM 0x08001ADF + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_calib_data_param_t param_id_haptics_rx_calib_data_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_CALIB_DATA_PARAM", PARAM_ID_HAPTICS_RX_CALIB_DATA_PARAM} + @h2xmlp_description {Parameter for registering haptics calibration data to lib.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_calib_data_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for Calibration data file} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of calibration data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the calibration data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00000064} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics calibration data: The path to the calibration cal file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_PERSISTENT_DATA_PARAM 0x08001B1A + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_persistent_data_param_t param_id_haptics_rx_persistent_data_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_PERSISTENT_DATA_PARAM", + PARAM_ID_HAPTICS_RX_PERSISTENT_DATA_PARAM} + @h2xmlp_description {Parameter for registering haptics persistent data to lib.} + @h2xmlp_toolPolicy {RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_persistent_data_param_t { + int32_t Re_ohm_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {DC resistance of LRA coil at room temperature, in Ohms. Default = 8Ohm, Range: 2 to 128Ohms} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Le_mH_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Inductance of LRA coil at room temperature, in mH. Default = 0.04mH, Range: 0.001mH to 128mH} + @h2xmle_range {16777..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {671088} */ + int32_t Bl_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Force factor (Bl product). Default = 1, Range: 0.01 to 128} + @h2xmle_range {167772..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Rms_KgSec_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Mechanical damping or resistance of LRA, in kg/s. Default = 0.0945kg/s, Range = 0.0001 to 20kg/s} + @h2xmle_range {16777..335544320} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1585446} */ + int32_t Kms_Nmm_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Mechanical stiffness of driver suspension, in N/mm. Default = 1.838N/mm, Range = 0.1 to 50N/mm} + @h2xmle_range {1677721..838860800} + @h2xmle_dataFormat {Q24} + @h2xmle_default {30836523} */ + int32_t Fres_Hz_q20[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Resonance frequency, in Hz. Default = 160Hz, Range = 50 to 400Hz} + @h2xmle_range {52428800..419430400} + @h2xmle_dataFormat {Q20} + @h2xmle_default {167772160} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_WAVE_DESIGNER_CFG 0x08001399 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct rx_wave_designer_config_h rx_wave_designer_config_h; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_subStruct */ +struct rx_wave_designer_config_h { + // Waveform designer mode parameters + uint32_t wave_design_mode; // Waveform designer mode parameter + /**< @h2xmle_description {Waveform designer mode parameter. Lower 16b represents the wave designer mode. + When mode is Pre-canned (Effects), upper 16b represents the effect ID; for all other modes these bits are ignored.} + @h2xmle_rangeList {"Parametric" = 0x00000000; + "Piece-wise Linear" = 0x00000001; + "Sinusoidal" = 0x00000002; + "PCMV Ringtone" = 0x00000003; + "Pre-canned Effect 0" = 0x00000004; + "Pre-canned Effect 1" = 0x00010004; + "Pre-canned Effect 2" = 0x00020004; + "Pre-canned Effect 3" = 0x00030004; + "Pre-canned Effect 4" = 0x00040004; + "Pre-canned Effect 5" = 0x00050004; + "Pre-canned Effect 6" = 0x00060004; + "Pre-canned Effect 7" = 0x00070004; + "Pre-canned Effect 8" = 0x00080004; + "Pre-canned Effect 9" = 0x00090004; + "Pre-canned Effect10" = 0x000A0004; + "Pre-canned Effect11" = 0x000B0004; + "Pre-canned Effect12" = 0x000C0004; + "Pre-canned Effect13" = 0x000D0004; + "Pre-canned Effect 14" = 0x000E0004; + "PCMV Playback" = 0x00000005} + @h2xmle_default {0} */ + + int32_t auto_overdrive_brake_en; // Flag to enable/ disable auto overdrive and brake + /**< @h2xmle_description {Flag to enable/ disable auto overdrive and brake. Considered in Sinusoidal mode only.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} */ + int32_t f0_tracking_en; // Flag to enable/ disable resonance frequency tracking + /**< @h2xmle_description {Flag to enable/ disable resonance frequency tracking. Considered in Sinusoidal mode only.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} */ + int32_t f0_tracking_param_reset_flag; // If this flag is enabled and f0 tracking is disabled, LRA parameters will be reset to calibration parameters (instead of cached parameters). + /**<@h2xmle_description {If this flag is enabled and f0 tracking is disabled, LRA parameters will be reset to calibration parameters (instead of cached parameters). Considered in all modes.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} */ + + uint32_t override_flag; // Mask to indicate the parameters for which default value will be overridden. + /**< @h2xmle_description {Mask to indicate the parameters for which default value will be overridden. Considered in all modes.} + @h2xmle_range {0..0x0f} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Tracked frequency warmup time"} + @h2xmle_description {If this bit is enabled, tracked_freq_warmup_time_ms field will be considered.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Settling time"} + @h2xmle_description {If this bit is enabled, settling_time_ms field will be considered.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000004} + @h2xmle_bitName {"Delay time"} + @h2xmle_description {If this bit is enabled, delay_time_ms field will be considered.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000008} + @h2xmle_bitName {"Waveform generator fstart"} + @h2xmle_description {If this bit is enabled, wavegen_fstart_hz_q20 field will be considered.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd */ + + int32_t tracked_freq_warmup_time_ms; // Time delay before enabling resonance frequency tracking (in ms). + /**< @h2xmle_description {Time delay before enabling resonance frequency tracking, in ms. Considered only if corresponding bit is enabled in `override_flag`.} + @h2xmle_range {0..10000} ms + @h2xmle_default {0}*/ + int32_t settling_time_ms; // Maximum time delay for the haptics waveform to settle to zero, after actuation ends (in ms). + /**< @h2xmle_description {Maximum time delay for the haptics waveform to settle to zero after actuation ends, in ms. Considered only if corresponding bit is enabled in `override_flag`.} + @h2xmle_range {5..100} ms + @h2xmle_default {30}*/ + int32_t delay_time_ms; // Waveform designer parametric mode parameter. Time delay at the start and end of the pulse acceleration waveform (in ms). Considered only when corresponding bit is enabled in override_flag. + /**< @h2xmle_description {Waveform designer parametric mode parameter. Time delay at the start and end of the parametric waveform, in ms. Considered only if corresponding bit is enabled in `override_flag`.} + @h2xmle_range {0..100} ms + @h2xmle_default {0}*/ + int32_t wavegen_fstart_hz_q20; // Starting frequency in Hz. + /**< @h2xmle_description {Starting frequency for the waveform designer, in Hz. Considered only if corresponding bit is enabled in `override_flag`.} + @h2xmle_range {52428800..419430400} Hz + @h2xmle_default {157286400} + @h2xmle_dataFormat {Q20} */ + + int32_t repetition_count; // No. of repetitions of the haptics waveform + /**< @h2xmle_description {No. of repetitions of the haptics waveform. Considered in Parametric, PWL, Sinusoidal modes only.} */ + int32_t repetition_period_ms; // Time period of one repetition + /**< @h2xmle_description {Time period of one repetition, in ms. Considered in Parametric, PWL, Sinusoidal modes only.} */ + uint32_t pilot_tone_en; // Flag to enable/disable pilot tone + /**< @h2xmle_description {Flag to enable/disable pilot tone. Considered in all modes.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0}*/ + int32_t pulse_intensity; // Pulse intensity as percentage of maximum acceleration + /**< @h2xmle_description {Pulse intensity as percentage of maximum acceleration, in %. Considered in Parametric, Sinusoidal modes only.} + @h2xmle_range {0..100} + @h2xmle_default {0}*/ + int32_t pulse_width_ms; // Haptics waveform duration + /**< @h2xmle_description {Haptics waveform duration, in ms. Considered in Parametric, Sinusoidal modes only.} */ + int32_t pulse_sharpness; // Pulse sharpness as percentage of maximum rise/fall time + /**< @h2xmle_description {Pulse sharpness as percentage of maximum rise/fall time, in %. Considered in Parametric mode only.} + @h2xmle_range {0..100} + @h2xmle_default {0}*/ + int32_t num_pwl; // No. of waveform points in piece-wise linear waveform + /**< @h2xmle_description {No. of waveform points in piece-wise linear waveform. Considered in PWL mode only.} */ +#ifdef __H2XML__ + int32_t pwl_time[0]; // Time indices for piece-wise linear waveform + /**< @h2xmle_description {Time indices for piece-wise linear waveform, in ms. Considered in PWL mode only.} + @h2xmle_variableArraySize {num_pwl} */ + int32_t pwl_acc[0]; // Acceleration values corresponding to piece-wise linear waveform, as percentage of max acceleration + /**< @h2xmle_description {Acceleration values corresponding to piece-wise linear waveform, as percentage of max acceleration, in %. Considered in PWL mode only.} + @h2xmle_variableArraySize {num_pwl} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_wave_designer_config_t param_id_haptics_wave_designer_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_WAVE_DESIGNER_CFG", + PARAM_ID_HAPTICS_WAVE_DESIGNER_CFG} + @h2xmlp_description {Waveform designer configuration.} + @h2xmlp_toolPolicy {RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_wave_designer_config_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of valid channel configurations that are sent. num_channels= 1 supports channel_mask 1 and 2, num_channels= 2 supports channel_mask 3} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + uint32_t channel_mask; + /**< @h2xmle_description {Mask to indicate which channel(s) have a valid waveform designer configuration.} + @h2xmle_range {0..0x03} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Channel 1"} + @h2xmle_description {Enabling this bit will indicate a valid configuration for Channel 1.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Channel 2"} + @h2xmle_description {Enabling this bit will indicate a valid configuration for Channel 2.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd */ +#ifdef __H2XML__ + rx_wave_designer_config_h rx_wave_designer_config[0]; // Wave designer configuration for each channel + /**< @h2xmle_description {Wave designer configuration for each channel.} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_WAVE_DESIGNER_CFG_V2 0x08001B1B + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct rx_wave_designer_config_v2_h rx_wave_designer_config_v2_h; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_subStruct */ +struct rx_wave_designer_config_v2_h { + // Waveform designer mode parameters + uint32_t wave_design_mode; // Waveform designer mode parameter + /**< @h2xmle_description {Waveform designer mode parameter. Lower 16b represents the wave designer mode. + When mode is Pre-canned (Effects), upper 16b represents the effect ID; for all other modes these bits are ignored.} + @h2xmle_rangeList {"Parametric" = 0x00000000; + "Piece-wise Linear" = 0x00000001; + "Sinusoidal" = 0x00000002; + "PCMV Ringtone" = 0x00000003; + "Pre-canned Effect 0" = 0x00000004; + "Pre-canned Effect 1" = 0x00010004; + "Pre-canned Effect 2" = 0x00020004; + "Pre-canned Effect 3" = 0x00030004; + "Pre-canned Effect 4" = 0x00040004; + "Pre-canned Effect 5" = 0x00050004; + "Pre-canned Effect 6" = 0x00060004; + "Pre-canned Effect 7" = 0x00070004; + "Pre-canned Effect 8" = 0x00080004; + "Pre-canned Effect 9" = 0x00090004; + "Pre-canned Effect10" = 0x000A0004; + "Pre-canned Effect11" = 0x000B0004; + "Pre-canned Effect12" = 0x000C0004; + "Pre-canned Effect13" = 0x000D0004; + "Pre-canned Effect 14" = 0x000E0004; + "PCMV Playback" = 0x00000005} + @h2xmle_default {0} */ + + int32_t auto_overdrive_brake_en; // Flag to enable/ disable auto overdrive and brake + /**< @h2xmle_description {Flag to enable/ disable auto overdrive and brake. Considered in Sinusoidal mode only.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} */ + int32_t f0_tracking_en; // Flag to enable/ disable resonance frequency tracking + /**< @h2xmle_description {Flag to enable/ disable resonance frequency tracking. Considered in Sinusoidal mode only.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} */ + int32_t rtcl_mode; // Real-time closed loop mode + /**< @h2xmle_description {Choose real time closed loop mode. Considered in all waveform designer modes.} + @h2xmle_rangeList {disabled=0;tracking=1;braking=2;ltf_mode=3} + @h2xmle_default {0} */ + int32_t pmic_autobrake_en; // Flag to enable/disable PMIC autobraking + /**< @h2xmle_description {Flag to enable/disable PMIC autobraking. Considered in all modes except PCMV Ringtone.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} */ + int32_t f0_tracking_param_reset_flag; // If this flag is enabled and f0 tracking is disabled, LRA parameters will be reset to calibration parameters (instead of cached parameters). + /**<@h2xmle_description {If this flag is enabled and f0 tracking is disabled, LRA parameters will be reset to calibration parameters (instead of cached parameters). Considered in all modes.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} */ + + uint32_t override_flag; // Mask to indicate the parameters for which default value will be overridden. + /**< @h2xmle_description {Mask to indicate the parameters for which default value will be overridden. Considered in all modes.} + @h2xmle_range {0..0x0f} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Tracked frequency warmup time"} + @h2xmle_description {If this bit is enabled, tracked_freq_warmup_time_ms field will be considered.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Settling time"} + @h2xmle_description {If this bit is enabled, settling_time_ms field will be considered.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000004} + @h2xmle_bitName {"Delay time"} + @h2xmle_description {If this bit is enabled, delay_time_ms field will be considered.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000008} + @h2xmle_bitName {"Waveform generator fstart"} + @h2xmle_description {If this bit is enabled, wavegen_fstart_hz_q20 field will be considered.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd */ + + int32_t tracked_freq_warmup_time_ms; // Time delay before enabling resonance frequency tracking (in ms). + /**< @h2xmle_description {Time delay before enabling resonance frequency tracking, in ms. Considered only if corresponding bit is enabled in `override_flag`.} + @h2xmle_range {0..10000} ms + @h2xmle_default {0}*/ + int32_t settling_time_ms; // Maximum time delay for the haptics waveform to settle to zero, after actuation ends (in ms). + /**< @h2xmle_description {Maximum time delay for the haptics waveform to settle to zero after actuation ends, in ms. Considered only if corresponding bit is enabled in `override_flag`.} + @h2xmle_range {5..100} ms + @h2xmle_default {30}*/ + int32_t delay_time_ms; // Waveform designer parametric mode parameter. Time delay at the start and end of the pulse acceleration waveform (in ms). Considered only when corresponding bit is enabled in override_flag. + /**< @h2xmle_description {Waveform designer parametric mode parameter. Time delay at the start and end of the parametric waveform, in ms. Considered only if corresponding bit is enabled in `override_flag`.} + @h2xmle_range {0..100} ms + @h2xmle_default {0}*/ + int32_t wavegen_fstart_hz_q20; // Starting frequency in Hz. + /**< @h2xmle_description {Starting frequency for the waveform designer, in Hz. Considered only if corresponding bit is enabled in `override_flag`.} + @h2xmle_range {52428800..419430400} Hz + @h2xmle_default {157286400} + @h2xmle_dataFormat {Q20} */ + + int32_t repetition_count; // No. of repetitions of the haptics waveform + /**< @h2xmle_description {No. of repetitions of the haptics waveform. Considered in Parametric, PWL, Sinusoidal modes only.} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_default {1}*/ + int32_t repetition_period_ms; // Time period of one repetition + /**< @h2xmle_description {Time period of one repetition, in ms. Considered in Parametric, PWL, Sinusoidal modes only.} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_default {0}*/ + uint32_t pilot_tone_en; // Flag to enable/disable pilot tone + /**< @h2xmle_description {Flag to enable/disable pilot tone. Considered in all modes.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0}*/ + int32_t pulse_intensity; // Pulse intensity as percentage of maximum acceleration + /**< @h2xmle_description {Pulse intensity as percentage of maximum acceleration, in %. Considered in Parametric, Sinusoidal, PWL, PCMV Playback modes only.} + @h2xmle_range {0..1000} + @h2xmle_default {0}*/ + int32_t pulse_width_ms; // Haptics waveform duration + /**< @h2xmle_description {Haptics waveform duration, in ms. Considered in Parametric, Sinusoidal modes only.} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_default {100}*/ + int32_t pulse_sharpness; // Pulse sharpness as percentage of maximum rise/fall time + /**< @h2xmle_description {Pulse sharpness as percentage of maximum rise/fall time, in %. Considered in Parametric mode only.} + @h2xmle_range {0..100} + @h2xmle_default {0}*/ + int32_t num_pwl; // No. of waveform points in piece-wise linear waveform + /**< @h2xmle_description {No. of waveform points in piece-wise linear waveform. Considered in PWL mode only.} + @h2xmle_range {0..500} + @h2xmle_default {0}*/ +#ifdef __H2XML__ + int32_t pwl_time[0]; // Time indices for piece-wise linear waveform + /**< @h2xmle_description {Time indices for piece-wise linear waveform, in ms. Considered in PWL mode only.} + @h2xmle_variableArraySize {num_pwl} */ + int32_t pwl_acc[0]; // Acceleration values corresponding to piece-wise linear waveform, as percentage of max acceleration + /**< @h2xmle_description {Acceleration values corresponding to piece-wise linear waveform, as percentage of max acceleration, in %. Considered in PWL mode only.} + @h2xmle_variableArraySize {num_pwl} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_wave_designer_config_v2_t param_id_haptics_wave_designer_config_v2_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_WAVE_DESIGNER_CFG_V2", + PARAM_ID_HAPTICS_WAVE_DESIGNER_CFG_V2} + @h2xmlp_description {Waveform designer configuration v2.} + @h2xmlp_toolPolicy {RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_wave_designer_config_v2_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of valid channel configurations that are sent. num_channels= 1 supports channel_mask 1 and 2, num_channels= 2 supports channel_mask 3} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + uint32_t channel_mask; + /**< @h2xmle_description {Mask to indicate which channel(s) have a valid waveform designer configuration.} + @h2xmle_range {0..0x03} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Channel 1"} + @h2xmle_description {Enabling this bit will indicate a valid configuration for Channel 1.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Channel 2"} + @h2xmle_description {Enabling this bit will indicate a valid configuration for Channel 2.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd */ +#ifdef __H2XML__ + rx_wave_designer_config_v2_h rx_wave_designer_config_v2[0]; // Wave designer configuration for each channel + /**< @h2xmle_description {Wave designer configuration for each channel.} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_WAVE_DESIGNER_STOP_PARAM 0x0800139A + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_wave_designer_stop_param_t param_id_haptics_wave_designer_wave_designer_stop_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_WAVE_DESIGNER_STOP_PARAM", + PARAM_ID_HAPTICS_WAVE_DESIGNER_STOP_PARAM} + @h2xmlp_description {Waveform designer stop command.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_wave_designer_stop_param_t { + uint32_t channel_mask; // Mask to indicate to which channel(s) a valid STOP command was sent. + /**< @h2xmle_description {Mask to indicate to which channel(s) a valid STOP command was sent.} + @h2xmle_range {0..0x03} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Channel 1"} + @h2xmle_description {Enabling this bit will indicate a valid STOP command for Channel 1.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Channel 2"} + @h2xmle_description {Enabling this bit will indicate a valid STOP command for Channel 2.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_WAVE_DESIGNER_UPDATE_PARAM 0x0800139B + +/*============================================================================== + Type definitions +==============================================================================*/ +/* Structure definition for Parameter */ +typedef struct rx_wave_designer_update_config_t rx_wave_designer_update_config_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +// Wave designer parameters - update +struct rx_wave_designer_update_config_t { + int32_t pulse_intensity; // Pulse intensity as percentage of maximum acceleration + /**< @h2xmle_description {Pulse intensity as percentage of maximum acceleration, in %. Valid in Parametric, Sinusoidal modes only.} + @h2xmle_range {0..100} + @h2xmle_default {100} */ + int32_t pulse_sharpness; // Pulse sharpness as percentage of maximum rise/fall time + /**< @h2xmle_description {Pulse sharpness as percentage of maximum rise/fall time, in %. Valid in Parametric mode only.} + @h2xmle_range {0..100} + @h2xmle_default {100} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_wave_designer_update_param_t param_id_haptics_wave_designer_update_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_WAVE_DESIGNER_UPDATE_PARAM", + PARAM_ID_HAPTICS_WAVE_DESIGNER_UPDATE_PARAM} + @h2xmlp_description {This parameter is used to update configuration of haptics Waveform.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_wave_designer_update_param_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of valid channel UPDATE commands that are sent. num_channels = 1 supports channel_mask 1 and 2, num_channels = 2 supports channel_mask 3} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + uint32_t channel_mask; + /**< @h2xmle_description {Mask to indicate which channel(s) have a valid UPDATE command.} + @h2xmle_range {0..0x03} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Channel 1"} + @h2xmle_description {Enabling this bit will indicate a valid UPDATE command for Channel 1.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Channel 2"} + @h2xmle_description {Enabling this bit will indicate a valid UPDATE command for Channel 2.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} + @h2xmle_bitFieldEnd */ + + // Wave designer parameters - update +#ifdef __H2XML__ + rx_wave_designer_update_config_t rx_wave_designer_update_config[0]; // Wave designer update parameters for each channel + /**< @h2xmle_description {Wave designer update parameters for each channel.} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_0_DATA_PARAM 0x08001522 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_0_data_t param_id_haptics_effect_0_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_0_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_0_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 0'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_0_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 0': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_1_DATA_PARAM 0x08001523 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_1_data_t param_id_haptics_effect_1_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_1_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_1_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 1'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_1_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 1': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_2_DATA_PARAM 0x08001524 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_2_data_t param_id_haptics_effect_2_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_2_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_2_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 2'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_2_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 2': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_3_DATA_PARAM 0x08001525 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_3_data_t param_id_haptics_effect_3_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_3_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_3_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 3'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_3_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..7} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 3': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_4_DATA_PARAM 0x08001526 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_4_data_t param_id_haptics_effect_4_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_4_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_4_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 4'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_4_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 4': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_5_DATA_PARAM 0x08001527 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_5_data_t param_id_haptics_effect_5_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_5_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_5_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 5'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_5_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 5': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_6_DATA_PARAM 0x08001528 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_6_data_t param_id_haptics_effect_6_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_6_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_6_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 6'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_6_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 6': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_7_DATA_PARAM 0x08001529 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_7_data_t param_id_haptics_effect_7_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_7_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_7_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 7'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_7_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 7': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_8_DATA_PARAM 0x0800152A + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_8_data_t param_id_haptics_effect_8_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_8_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_8_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 8'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_8_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 8': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_9_DATA_PARAM 0x0800152B + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_9_data_t param_id_haptics_effect_9_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_9_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_9_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 9'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_9_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 9': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_10_DATA_PARAM 0x0800152C + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_10_data_t param_id_haptics_effect_10_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_10_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_10_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 10'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_10_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 10': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_11_DATA_PARAM 0x0800152D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_11_data_t param_id_haptics_effect_11_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_11_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_11_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 11'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_11_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 11': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_12_DATA_PARAM 0x0800152E + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_12_data_t param_id_haptics_effect_12_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_12_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_12_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 12'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_12_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 12': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_13_DATA_PARAM 0x0800152F + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_13_data_t param_id_haptics_effect_13_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_13_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_13_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 13'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_13_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 13': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EFFECT_14_DATA_PARAM 0x08001530 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_effect_14_data_t param_id_haptics_effect_14_data_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EFFECT_14_DATA_PARAM", PARAM_ID_HAPTICS_EFFECT_14_DATA_PARAM} + @h2xmlp_description {Parameter for registering the pre-canned effects haptics waveform data for 'Effect 14'.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_effect_14_data_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for the effect data} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of effect data by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the effect PCM data in bytes, (48kHz, 32-bit mono, Q31 format), Max duration supported is 2 sec} + @h2xmle_default {0} + @h2xmle_range {0x0..0x0005DC00} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics PCM data for 'Effect 14': The path to the effect file in the file system (PCM data format: 48kHz, 32-bit mono, Q31 format)} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_EFFECTS_CONFIG_PARAM 0x08001ADA + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_effects_config_param_t param_id_haptics_rx_effects_config_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_EFFECTS_CONFIG_PARAM", PARAM_ID_HAPTICS_RX_EFFECTS_CONFIG_PARAM} + @h2xmlp_description {Parameter for setting f0, R used to generate PCMV Effects waveforms.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_effects_config_param_t { + int32_t Fres_Hz_q20[HAPTICS_MAX_OUT_CHAN]; // Resonance frequency used to generate PCMV Effects waveforms + /**< @h2xmle_description {Resonance frequency used to generate PCMV Effects waveforms, in Hz. Default = 0Hz, Range = 0 to 400Hz} + @h2xmle_range {0..419430400} + @h2xmle_dataFormat {Q20} + @h2xmle_default {0} */ + int32_t Re_ohm_q24[HAPTICS_MAX_OUT_CHAN]; // DC resistance of LRA coil used to generate PCMV Effects waveforms + /**< @h2xmle_description {DC resistance of LRA coil used to generate PCMV Effects waveforms, in Ohms. Default = 0 Ohm, Range: 0 to 128Ohms} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_TUNING_DATA_0_PARAM 0x08001B36 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_tuning_data_0_param_t param_id_haptics_rx_tuning_data_0_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_TUNING_DATA_0_PARAM", PARAM_ID_HAPTICS_RX_TUNING_DATA_0_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 0 to RX module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_tuning_data_0_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for RX module tuning data file for LRA 0} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of RX module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the RX module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {RX module tuning data for LRA 0: path to the RX module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_TUNING_DATA_1_PARAM 0x08001B37 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_tuning_data_1_param_t param_id_haptics_rx_tuning_data_1_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_TUNING_DATA_1_PARAM", PARAM_ID_HAPTICS_RX_TUNING_DATA_1_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 1 to RX module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_tuning_data_1_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for RX module tuning data file for LRA 1} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of RX module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the RX module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {RX module tuning data for LRA 1: path to the RX module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_TUNING_DATA_2_PARAM 0x08001B38 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_tuning_data_2_param_t param_id_haptics_rx_tuning_data_2_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_TUNING_DATA_2_PARAM", PARAM_ID_HAPTICS_RX_TUNING_DATA_2_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 2 to RX module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_tuning_data_2_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for RX module tuning data file for LRA 2} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of RX module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the RX module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {RX module tuning data for LRA 2: path to the RX module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_TUNING_DATA_3_PARAM 0x08001B39 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_tuning_data_3_param_t param_id_haptics_rx_tuning_data_3_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_TUNING_DATA_3_PARAM", PARAM_ID_HAPTICS_RX_TUNING_DATA_3_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 3 to RX module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_tuning_data_3_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for RX module tuning data file for LRA 3} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of RX module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the RX module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {RX module tuning data for LRA 3: path to the RX module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_TUNING_DATA_4_PARAM 0x08001B3A + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_tuning_data_4_param_t param_id_haptics_rx_tuning_data_4_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_TUNING_DATA_4_PARAM", PARAM_ID_HAPTICS_RX_TUNING_DATA_4_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 4 to RX module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_tuning_data_4_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for RX module tuning data file for LRA 4} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of RX module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the RX module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {RX module tuning data for LRA 4: path to the RX module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_VISENSE_CFG 0x08001B3B + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_visense_t param_id_haptics_rx_visense_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_VISENSE_CFG", + PARAM_ID_HAPTICS_RX_VISENSE_CFG} + @h2xmlp_description {VI sense scaling factors.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ +struct param_id_haptics_rx_visense_t { + int32_t vsens_scale_q24[HAPTICS_MAX_OUT_CHAN]; // Vsense scaling constant + /**< @h2xmle_description {conversion factor from Vsens digital to Volts. Default = 10.48, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {175849472} */ + int32_t isens_scale_q24[HAPTICS_MAX_OUT_CHAN]; // Isense scaling constant + /**< @h2xmle_description {conversion factor from Isens digital to Amperes. Default = 6.90, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {115859456} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_THERMAL_GAIN_CFG 0x08001B7D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_thermal_gain_cfg_t param_id_haptics_rx_thermal_gain_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_THERMAL_GAIN_CFG", + PARAM_ID_HAPTICS_RX_THERMAL_GAIN_CFG} + @h2xmlp_description {Parameter defining gains for different temperature variations to compensate for vibration intensity change.} + @h2xmlp_toolPolicy {CALIBRATION}*/ +struct param_id_haptics_rx_thermal_gain_cfg_t { + int32_t delta_r_percent_q24[HAPTICS_THERMAL_GAIN_COUNT]; // Percentage change in R + /**< @h2xmle_description {Percentage change in LRA Resistance. Default = 0.0, Range: -100.0 to 100.0} + @h2xmle_range {-1677721600..1677721600} + @h2xmle_dataFormat {Q24} + @h2xmle_defaultList {-335544320,-268435456,-201326592,-134217728,-67108864,0,67108864,134217728,201326592,268435456,335544320} */ + int32_t gain_q27[HAPTICS_THERMAL_GAIN_COUNT]; // Gain corresponding to LRA resistance change + /**< @h2xmle_description {Gain corresponding to LRA resistance change. Default = 1.0, Range: 0 to 10.0} + @h2xmle_range {0..1342177280} + @h2xmle_dataFormat {Q27} + @h2xmle_defaultList {134217728,134217728,134217728,134217728,134217728,134217728,134217728,134217728,134217728,134217728,134217728} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_LRA_PARAM_RANGE_CFG 0x08001B8D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct haptics_rx_lra_param_range_cfg_h haptics_rx_lra_param_range_cfg_h; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +// Structure encapsulating valid ranges for different LRA parameters +/** @h2xmlp_subStruct */ +struct haptics_rx_lra_param_range_cfg_h +{ + int32_t Re_min_percent_q20; + /**< @h2xmle_description {Minimum valid DC resistance of LRA coil as a percentage of manufacturer spec. Default = -60%, Range: -100% to +100%} + @h2xmle_range {-104857600..104857600} + @h2xmle_dataFormat {Q20} + @h2xmle_default {-62914560} */ + int32_t Re_max_percent_q20; + /**< @h2xmle_description {Maximum valid DC resistance of LRA coil as a percentage of manufacturer spec. Default = +60%, Range: -100% to +100%} + @h2xmle_range {-104857600..104857600} + @h2xmle_dataFormat {Q20} + @h2xmle_default {62914560} */ + int32_t Le_min_percent_q20; + /**< @h2xmle_description {Minimum valid inductance of LRA coil as a percentage of manufacturer spec. Default = -30%, Range: -100% to +100%} + @h2xmle_range {-104857600..104857600} + @h2xmle_dataFormat {Q20} + @h2xmle_default {-31457280} */ + int32_t Le_max_percent_q20; + /**< @h2xmle_description {Maximum valid inductance of LRA coil as a percentage of manufacturer spec. Default = +30%, Range: -100% to +100%} + @h2xmle_range {-104857600..104857600} + @h2xmle_dataFormat {Q20} + @h2xmle_default {31457280} */ + int32_t Bl_min_percent_q20; + /**< @h2xmle_description {Minimum valid force factor (Bl product) of LRA as a percentage of manufacturer spec. Default = -50%, Range: -100% to +100%} + @h2xmle_range {-104857600..104857600} + @h2xmle_dataFormat {Q20} + @h2xmle_default {-52428800} */ + int32_t Bl_max_percent_q20; + /**< @h2xmle_description {Maximum valid force factor (Bl product) of LRA as a percentage of manufacturer spec. Default = +50%, Range: -100% to +100%} + @h2xmle_range {-104857600..104857600} + @h2xmle_dataFormat {Q20} + @h2xmle_default {52428800} */ + int32_t Rms_min_percent_q20; + /**< @h2xmle_description {Minimum valid mechanical damping of LRA as a percentage of manufacturer spec. Default = -80%, Range: -1000% to +1000%} + @h2xmle_range {-1048576000..1048576000} + @h2xmle_dataFormat {Q20} + @h2xmle_default {-83886080} */ + int32_t Rms_max_percent_q20; + /**< @h2xmle_description {Maximum valid mechanical damping of LRA as a percentage of manufacturer spec. Default = +200%, Range: -1000% to +1000%} + @h2xmle_range {-1048576000..1048576000} + @h2xmle_dataFormat {Q20} + @h2xmle_default {209715200} */ + int32_t Fres_min_percent_q20; + /**< @h2xmle_description {Minimum valid resonance frequency of LRA as a percentage of manufacturer spec. Default = -20%, Range: -50% to +50%} + @h2xmle_range {-52428800..52428800} + @h2xmle_dataFormat {Q20} + @h2xmle_default {-20971520} */ + int32_t Fres_max_percent_q20; + /**< @h2xmle_description {Maximum valid resonance frequency of LRA as a percentage of manufacturer spec. Default = +20%, Range: -50% to +50%} + @h2xmle_range {-52428800..52428800} + @h2xmle_dataFormat {Q20} + @h2xmle_default {20971520} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_lra_param_range_cfg_t param_id_haptics_rx_lra_param_range_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_LRA_PARAM_RANGE_CFG", + PARAM_ID_HAPTICS_RX_LRA_PARAM_RANGE_CFG} + @h2xmlp_description {Parameter defining valid ranges for different LRA parameters.} + @h2xmlp_toolPolicy {CALIBRATION}*/ +struct param_id_haptics_rx_lra_param_range_cfg_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of channels for RX signal.} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ +#ifdef __H2XML__ + haptics_rx_lra_param_range_cfg_h rx_lra_param_range_cfg[0]; + /**< @h2xmle_description {Structure encapsulating valid ranges for different LRA parameters} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_TEST_MODE_CFG 0x08001B8E + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_rx_test_mode_cfg_t param_id_haptics_rx_test_mode_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_TEST_MODE_CFG", + PARAM_ID_HAPTICS_RX_TEST_MODE_CFG} + @h2xmlp_description {Parameter used to enable/disable test mode.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_rx_test_mode_cfg_t { + uint32_t test_mode; // Enable/Disable test mode + /**< @h2xmle_description {Enable/Disable test mode.} + @h2xmle_rangeList {"Disabled"=0;"Enabled"=1} + @h2xmle_default {0} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_CPS_FINE_PARAM 0x0800139D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_cps_fine_param_t param_id_haptics_cps_fine_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_CPS_FINE_PARAM", + PARAM_ID_HAPTICS_CPS_FINE_PARAM} + @h2xmlp_description {This parameter is used for getting finer resolution of gain to be applied at Vbatt/DieTemps.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ +struct param_id_haptics_cps_fine_param_t { + uint16_t cps_fine_tbl_en_flag; + /**< @h2xmle_description {Flag to enable/disable fine-VBAT resolution CPS gain tables} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {0} */ + + uint16_t reserved; + /**< @h2xmle_description {Reserved} + @h2xmle_default {0} */ + + int32_t FourOhmTable_fine_GaindB_q24[NDTEMP_DISCRETE * NVBATT_DISCRETE_FINE]; + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp. Range: -9dB to 21dB} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmle_defaultList {-53285485, 68153209, 140261762, 149830710, 172158254, 179529886, 196730361, 196730361, 201136445, 211417309, 222963712, 224388279, 234465433, + -53501694, 71474774, 143619166, 152180893, 172158254, 179529886, 196730361, 196730361, 201004748, 210978319, 218850334, 223483143, 236126715, + -61867454, 71578604, 137847344, 148140617, 172158254, 179529886, 196730361, 196730361, 200987512, 210920864, 220936046, 223623129, 235966854, + -52962369, 71188477, 137480805, 147884040, 172158254, 179529886, 196730361, 196730361, 199593251, 206273327, 217477288, 220887257, 233383879, + -52908655, 70401900, 136689101, 147329847, 172158254, 179529886, 196730361, 196730361, 199611622, 206334564, 216755019, 220142936, 232609941, + -49090800, 69633385, 135888699, 146769565, 172158254, 179529886, 196730361, 196730361, 199371583, 205534433, 215815743, 219316788, 232008960, + -52801347, 68802805, 135079406, 146203061, 172158254, 179529886, 196730361, 196730361, 199110096, 204662812, 212190708, 218300850, 231207999, + -52908655, 67894469, 134206137, 145591772, 172158254, 179529886, 196730361, 196730361, 198845444, 203780637, 211302130, 217362043, 230212812, + -52854981, 67057511, 133377831, 145011958, 172158254, 179529886, 196730361, 196730361, 198603204, 202973170, 210496804, 216441856, 229391747, + -52747752, 66294546, 132596157, 144464786, 172158254, 179529886, 196730361, 196730361, 195301930, 191968925, 200327519, 202503216, 217012474, + -53016122, 65297664, 125651617, 139603608, 172158254, 179529886, 196730361, 196730361, 194781369, 190233721, 199236742, 201411199, 214936993, + -53123748, 64815411, 118521597, 134612594, 172158254, 179529886, 196730361, 196730361, 192310557, 181997682, 190067202, 192417852, 204348176, + -54922914, 64186542, 102687156, 123528485, 172158254, 179529886, 196730361, 196730361, 188500630, 169297925, 175702957, 177144954, 189897145, + -56597988, 34772406, 59808743, 93513596, 172158254, 179529886, 196730361, 196730361, 177321044, 132032639, 143752379, 145289306, 153312524} */ + + int32_t SixOhmTable_fine_GaindB_q24[NDTEMP_DISCRETE * NVBATT_DISCRETE_FINE]; + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp. Range: -9dB to 21dB} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmle_defaultList {-52640680, 85752586, 147025038, 155761153, 178102761, 190540773, 207818747, 207818747, 216194267, 225950438, 240078195, 253359903, 268795636, + -52801347, 84943464, 146287806, 154863101, 176829465, 189412052, 207027370, 207027370, 215376840, 225072228, 239850956, 252790449, 266373698, + -52720969, 83409460, 144689660, 153414376, 175729389, 188360566, 206089262, 206089262, 214527575, 224430263, 239476089, 252339879, 265943161, + -52640680, 98530836, 156460474, 164467385, 185107520, 197199964, 213671616, 213671616, 222225715, 232398569, 248009020, 258834803, 272751212, + -52320404, 97923645, 156115970, 163984123, 184300490, 196365681, 212773743, 212773743, 221345863, 231560765, 247131676, 258218333, 272002190, + -52400341, 97618141, 155596140, 163515655, 183951865, 195848921, 211864668, 211864668, 220382051, 230469236, 246049797, 257123593, 271181965, + -52400341, 97106104, 155116349, 162986748, 183308354, 195161040, 211073257, 211073257, 219506256, 229396545, 244951610, 256168259, 270459286, + -52560479, 90099877, 154677417, 162449121, 182540440, 194500571, 210663492, 210663492, 218973574, 228577056, 244097803, 255252888, 269837167, + -52560479, 89531967, 154280104, 161938175, 181764347, 193729031, 209902576, 209902576, 218159648, 227639441, 243280414, 254498926, 269046529, + -52720969, 89143244, 153657724, 161121083, 180492929, 192515394, 208823763, 208823763, 217114012, 226671214, 242076305, 253508313, 268247218, + -52801347, 88452162, 153029981, 160377231, 179478157, 191184140, 206754050, 206754050, 214815839, 223839972, 237269725, 248183228, 263139965, + -52962369, 87964475, 152487578, 158438297, 174280651, 185845259, 201085292, 201085292, 209309272, 218711849, 233820783, 243031842, 257187693, + -58139204, 87285590, 129657571, 136098972, 153086249, 165174839, 181637497, 181637497, 189085073, 196676041, 208405479, 216700429, 228434673, + -58390588, 7753521, 38934541, 46872245, 67350897, 82467561 , 105995727, 105995727, 116189971, 130189831, 142920003, 151330973, 164524018} */ + + int32_t EightOhmTable_fine_GaindB_q24[NDTEMP_DISCRETE * NVBATT_DISCRETE_FINE]; + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp. Range: -9dB to 21dB} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmle_defaultList {-37005097, 117034173, 155598710, 164684872, 211051742, 198962287, 217729765, 255946043, 255946043, 255946043, 255946043, 275433571, 276824064, + -37005097, 108914168, 152561295, 162855954, 212042649, 199474744, 228869887, 255104773, 255104773, 255104773, 255104773, 273260021, 276824064, + -36918818, 112073979, 154961924, 164536395, 212042649, 199312425, 228328826, 254475288, 254475288, 254475288, 254475288, 273615448, 276824064, + -41915024, 131132697, 168073936, 202165453, 202165453, 202165453, 202165453, 260392457, 260392457, 260392457, 260392457, 276824064, 276824064, + -40271438, 126146996, 164795830, 202165453, 202165453, 202165453, 202165453, 260246586, 260246586, 260246586, 260246586, 276824064, 276824064, + -40271438, 122767259, 163494679, 202165453, 202165453, 202165453, 202165453, 259453797, 259453797, 259453797, 259453797, 276824064, 276824064, + -40271438, 134614203, 166579267, 202165453, 202165453, 202165453, 202165453, 261978054, 261978054, 261978054, 261978054, 276824064, 276824064, + -40181206, 126250128, 164838804, 202165453, 202165453, 202165453, 202165453, 261117463, 261117463, 261117463, 261117463, 276824064, 276824064, + -40091086, 124582243, 163187704, 202165453, 202165453, 202165453, 202165453, 260290378, 260290378, 260290378, 260290378, 276824064, 276824064, + -40181206, 122875283, 162303439, 171361255, 217661982, 205525916, 235928683, 259365174, 259365174, 259365174, 259365174, 276824064, 276824064, + -40181206, 121016723, 161408311, 170459597, 216745088, 203972396, 232889703, 254633170, 254633170, 254633170, 254633170, 276824064, 276824064, + -40091086, 119336498, 160502049, 169218616, 214723095, 200145992, 224853007, 247913808, 247913808, 247913808, 247913808, 266049143, 276824064, + -40271438, 117616611, 159538184, 165589641, 204875531, 190670985, 216247301, 239818783, 239818783, 239818783, 239818783, 255903548, 269202447, + -40361783, 84567719, 104703048, 112262886, 155068332, 142438733, 171689925, 185056341, 185056341, 185056341, 185056341, 206022448, 215241475} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_CPS_DATA_PARAM 0x0800139E + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_cps_data_param_t param_id_haptics_cps_data_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_CPS_DATA_PARAM", + PARAM_ID_HAPTICS_CPS_DATA_PARAM} + */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_cps_data_param_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRAs} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + uint8_t Vbatt_rt[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {battery voltage - register reading} + @h2xmle_range {0..255} + @h2xmle_default {0} + @h2xmle_dataFormat {Q0} */ + uint8_t DieTemp_rt[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {temperature of the die - register reading} + @h2xmle_range {0..255} + @h2xmle_default {0} + @h2xmle_dataFormat {Q0} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_CPS_DEMO_PKT_PARAM 0x080013A0 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct haptics_ex_cps_param_t haptics_ex_cps_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_subStruct */ +struct haptics_ex_cps_param_t { + // CPS params + int32_t Vbatt_rt_q24[HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Battery Voltage in volts} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ + int32_t DieTemp_rt_q20[HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {die temperature in degree C} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q20} */ + int32_t dB_cps_Gain_rt_q24[HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {cps gain in dB} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_cps_demo_pkt_param_t param_id_haptics_ex_cps_demo_pkt_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_CPS_DEMO_PKT_PARAM", + PARAM_ID_HAPTICS_EX_CPS_DEMO_PKT_PARAM} + */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_cps_demo_pkt_param_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRAs} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {2} */ +#ifdef __H2XML__ + // demo packet for CPS + haptics_ex_cps_param_t ex_cps_demo_param[0]; + /**< @h2xmle_description {structure containing LRA params for CPS in Rx Excursion Control block} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_CPS_DEMO_PARAM 0x080013A1 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_cps_demo_param_t param_id_haptics_ex_cps_demo_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_CPS_DEMO_PARAM", + PARAM_ID_HAPTICS_EX_CPS_DEMO_PARAM} + @h2xmlp_description {Parameter used for setting the algorithm internal variables related to ex cps demo rtm configuration.} + @h2xmlp_toolPolicy {CALIBRATION}*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_cps_demo_param_t +{ + uint16_t dsr; // downsample ratio from internal values to output + /**< @h2xmle_description {downsample ratio from internal values to output.} + @h2xmle_range {0..65535} + @h2xmle_default {10} + @h2xmle_dataFormat {Q24} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_DEMO_PKT_PARAM 0x080013A2 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct haptics_ex_param_t haptics_ex_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_subStruct */ +struct haptics_ex_param_t +{ + int32_t Re_rt_q24[HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Resistance of the LRA, in ohm. Default = 8Ohm, Range: 2 to 128Ohms} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Bl_rt_q24[HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Force factor (Bl product). Default = 1, Range: 0.01 to 128} + @h2xmle_range {167772..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Rms_rt_q24[HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Mechanical damping or resistance of LRA, in kg/s. Default = 0.0945kg/s, Range = 0.0001 to 20kg/s} + @h2xmle_range {16777..335544320} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1585446} */ + int32_t Kms_rt_q24[HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Mechanical stiffness of driver suspension, in N/mm. Default = 1.838N/mm, Range = 0.1 to 50N/mm} + @h2xmle_range {1677721..838860800} + @h2xmle_dataFormat {Q24} + @h2xmle_default {30836523} */ + int32_t Fres_rt_q20[HAPTICS_CPS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Resonance frequency, in Hz. Default = 160Hz, Range = 50 to 400Hz} + @h2xmle_range {52428800..419430400} + @h2xmle_dataFormat {Q20} + @h2xmle_default {167772160} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_demo_pkt_param_t param_id_haptics_ex_demo_pkt_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_DEMO_PKT_PARAM", + PARAM_ID_HAPTICS_EX_DEMO_PKT_PARAM} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_demo_pkt_param_t +{ + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + int32_t demo_out_valid; + /**< @h2xmle_description {flag to indicate signals output contains meaningful data} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {0} */ + uint32_t demo_out_pkt_cnt; + /**< @h2xmle_description {output counter, keep track of repeated or lost output} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ + int32_t demo_out_samp_dist_ms; + /**< @h2xmle_description {distance in time between samples (msec)} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ + +#ifdef __H2XML__ + haptics_ex_param_t ex_demo_param[0]; + /**< @h2xmle_description {structure containing LRA params for RX excursion control block.} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_RX_RTCL_LOGGING_PARAM_V3 0x08001BA8 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct haptics_v3_rtcl_lra_param_t haptics_v3_rtcl_lra_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_subStruct */ +struct haptics_v3_rtcl_lra_param_t +{ + int32_t tracked_Param_1[HAPTICS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Tracked parameter 1 for RTCL tuning. Default = 0, Range: -127.99 to +127.99} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t tracked_Param_2[HAPTICS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Tracked parameter 2 for RTCL tuning. Default = 0, Range: -127.99 to +127.99} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t tracked_Param_3[HAPTICS_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Tracked parameter 3 for RTCL tuning. Default = 0, Range: -127.99 to +127.99} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_v3_rx_rtcl_logging_param_t param_id_haptics_v3_ex_rx_demo_pkt_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_RX_RTCL_LOGGING_PARAM_V3", + PARAM_ID_HAPTICS_RX_RTCL_LOGGING_PARAM_V3} + @h2xmlp_description {Parameter used to plot tracked RTCL tuning parameters in Tuning Tool.} + @h2xmlp_toolPolicy {RTM} + @h2xmlp_readOnly {true} */ + + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_v3_rx_rtcl_logging_param_t +{ + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + int32_t demo_out_valid; + /**< @h2xmle_description {flag to indicate signals output contains meaningful data} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {0} */ + +#ifdef __H2XML__ + haptics_v3_rtcl_lra_param_t rx_demo_param[0]; + /**< @h2xmle_description {structure containing LRA params for RX RTCL block.} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_DEMO_PARAM 0x080013A3 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_demo_param_t param_id_haptics_ex_demo_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_DEMO_PARAM", + PARAM_ID_HAPTICS_EX_DEMO_PARAM} + @h2xmlp_description {Parameter used for setting the algorithm internal variables related to demo configuration of excursion.} + @h2xmlp_toolPolicy {CALIBRATION}*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_demo_param_t +{ + uint16_t dsr; // downsample ratio from internal values to output + /**< @h2xmle_description {downsample ratio from internal values to output.} + @h2xmle_range {0..65535} + @h2xmle_default {10} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VERSION 0x0800139F + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_version_t param_id_haptics_version_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VERSION", + PARAM_ID_HAPTICS_VERSION} + @h2xmlp_description {parameter used to get the version of the HAPTICS Library.} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_version_t +{ + uint32_t lib_version_low; + /**< @h2xmle_description {Lower 32 bits of the 64-bit + library version number.} */ + + uint32_t lib_version_high; + /**< @h2xmle_description {Higher 32 bits of the 64-bit + library version number.} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ + +#define PARAM_ID_HAPTICS_GLOBAL_SHMEM_MSG 0x08001BC2 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_global_shmem_msg_t param_id_haptics_global_shmem_msg_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_GLOBAL_SHMEM_MSG", + PARAM_ID_HAPTICS_GLOBAL_SHMEM_MSG} + @h2xmlp_description {Parameter used to set global msg} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_global_shmem_msg_t +{ + uint32_t shmem_id; + /**< @h2xmle_description {shared memory ID} + @h2xmle_default {0} */ + uint32_t reserved; + /**< @h2xmle_description {reserved field for future use} + @h2xmle_default {0} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ + +#define PARAM_ID_HAPTICS_WAVE_DESIGNER_STATE 0x080013D7 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_wave_designer_state param_id_haptics_wave_designer_state; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_WAVE_DESIGNER_STATE", + PARAM_ID_HAPTICS_WAVE_DESIGNER_STATE} + @h2xmlp_description {Parameter used to get waveform state} + @h2xmlp_toolPolicy {CALIBRATION}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_wave_designer_state +{ + uint16_t state[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Wave Designer State} + @h2xmle_rangeList {"Ideal"=0;"In_Progress"=1;"Complete"=2} + @h2xmle_default {0} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ +#define PARAM_ID_HAPTICS_LPASS_SWR_HW_REG_CFG \ + 0x08001AE1 // we get hardware register addresses + +/* LPASS SWR HW register dependent sub structure payload */ + +typedef struct pkd_reg_addr_t pkd_reg_addr_t; +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct haptics_pkd_reg_addr_t { + uint32_t ab_initialize_pkd_reg_addr; + /**< @h2xmle_description {Per channel write initialized value to register + * address .} */ + uint32_t ab_trigger_pkd_reg_addr; + /**< @h2xmle_description {Per channel write values to register to trigger + * autobraking.} */ + uint32_t ab_stop_pkd_reg_addr; + /**< @h2xmle_description {Per channel write values to register to stop + * autobraking} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* LPASS SWR HW register structure payload */ +typedef struct param_id_haptics_lpass_swr_hw_reg_cfg_t + param_id_haptics_lpass_swr_hw_reg_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_LPASS_SWR_HW_REG_CFG", + PARAM_ID_HAPTICS_LPASS_SWR_HW_REG_CFG} + @h2xmlp_description {PMIC autobraking register details.} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct param_id_haptics_lpass_swr_hw_reg_cfg_t { + uint32_t num_channel; + /**< @h2xmle_description {Number of channels.} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {2} */ + + uint32_t lpass_wr_cmd_reg_phy_addr; + /**< @h2xmle_description {LPASS HW write register physical address.} */ + + uint32_t lpass_rd_cmd_reg_phy_addr; + /**< @h2xmle_description {LPASS HW read register physical address} */ + + uint32_t lpass_rd_fifo_reg_phy_addr; + /**< @h2xmle_description {LPASS HW register physical address to read + * autobreaking soundwire register values.} */ + + haptics_pkd_reg_addr_t haptics_pkd_reg_addr[0]; + /**< @h2xmle_description {Per channel packed register address written to LPASS + RD CMD register.} + @h2xmle_variableArraySize {num_channel} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define EVENT_ID_WAVEFORM_STATE 0x080013B2 +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_WAVEFORM_STATE", + EVENT_ID_WAVEFORM_STATE} + @h2xmlp_description { For Getting update of waveform state as “Complete", event raised by the Haptics Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + +/** @} <-- End of the Module --> */ +#endif /* __HAPTICS_RX_H__ */ diff --git a/spf/api/modules/rx_haptics_shmem_api.h b/spf/api/modules/rx_haptics_shmem_api.h new file mode 100644 index 0000000..d230b1c --- /dev/null +++ b/spf/api/modules/rx_haptics_shmem_api.h @@ -0,0 +1,108 @@ +#ifndef _RX_HAPTCIS_SHMEM_API_H_ +#define _RX_HAPTCIS_SHMEM_API_H_ + +/** + * \file rx_haptics_shmem_api.h + * + * \brief + * + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" + +/*============================================================================== + Shared memory communication protocol for haptics +==============================================================================*/ + +/* Type of configuration which client specifies to communicate with the module*/ +typedef enum rx_haptics_shmem_config_type +{ + /* client wants to set the configuration from shared memory. */ + SET_CFG = 0, + + /* client wants to get the configuration in shared memory. */ + GET_CFG = 1, + +} rx_haptics_shmem_config_type_t; + +typedef enum rx_haptics_shmem_msg_mode +{ + // specifies global message would be sent once after that client + // will only write data in shared memory and module needs to poll + POLLING_BASED = 0, + + // specifies global message would be trigger based, meaning + // every message will be sent via PARAM_ID_HAPTICS_GLOBAL_SHMEM_MSG + TRIGGER_BASED = 1, +} rx_haptics_shmem_msg_mode_t; + +typedef enum rx_haptics_shmem_rsp_type +{ + // specifies synchronization mechanism is polling based + RSP_POLLING = 0, + + // specifies synchronization mechanism is event based + RSP_EVENT_TRIGGER = 1, +} rx_haptics_shmem_rsp_type_t; + +/* per config structure specified by the client to the module. */ +typedef struct rx_haptics_shmem_config +{ + //config_type_t: set_cfg, get_cfg + rx_haptics_shmem_config_type_t config_type; + + //pid for set_cfg or get_cfg + uint32_t pid; + + //address offset from the base virtual base where this config data is provided or requested + uint32_t config_addr_offset; + + //size of the memory block for the config data from config_addr_offset + uint32_t config_size; + + // result code for the corresponding set/get param + uint32_t err_code; +} rx_haptics_shmem_config_t; + +typedef struct rx_haptics_shmem_payload_hdr +{ + // num of configurations part of payload, when set to 0 it indicates + // that only global message header is passed for configuring module + uint32_t num_config; + + //mode of response (event/polling) + rx_haptics_shmem_rsp_type_t shmem_config_rsp_mode; + + // mode of msg (Trigger/polling) + rx_haptics_shmem_msg_mode_t shmem_msg_mode; + + //Bit 0 is the client msg flag that indicates client has written msg if set + // module needs to reset it once read is complete + //Bit 1 is the module msg flag that indicates module has written msg if set + // client needs to reset it once read is complete + uint32_t shmem_property_flag; + +} rx_haptics_shmem_payload_hdr_t; + +/*header structure placed in the shared memory by the client to specifies one of multiple configuration to the module.*/ +typedef struct rx_haptics_shmem_ipc_protocol +{ + uint32_t version; + + uint32_t payload_header_size; +#ifdef __H2XML__ + // payload header pointer which is of type rx_haptics_shmem_payload_hdr_t + uint32_t payload_header[0]; + // config_ptr which is array of type rx_haptics_shmem_config_t + uint32_t config_ptr[0]; +#endif + +} rx_haptics_shmem_ipc_protocol_t; + +#endif //_RX_HAPTCIS_SHMEM_API_H_ diff --git a/spf/api/modules/sa_hdt_api.h b/spf/api/modules/sa_hdt_api.h new file mode 100644 index 0000000..b3672dd --- /dev/null +++ b/spf/api/modules/sa_hdt_api.h @@ -0,0 +1,375 @@ +#ifndef SA_HDT_API_H +#define SA_HDT_API_H + +/*============================================================================== + @file sa_hdt_api.h + @brief This file contains spatial audio head tracking module APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/* ========================================================================= + Edit History + + + when who what, where, why + -------- ------- ---------------------------------------------------- + + ======================================================================== */ +// clang-format on + +/** @h2xml_title1 {SA Head Tracking} + @h2xml_title_agile_rev {SA Head Tracking} + @h2xml_title_date {Sep 16 2025} */ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "imcl_spm_intent_api.h" +#include "imcl_fwk_intent_api.h" + +/*============================================================================== + Constants +==============================================================================*/ +/* SA HDT module stack size*/ +#define SA_HDT_STACK_SIZE 4096 + +/* Input ports of SA HDT module */ +#define SA_HDT_MAX_IN_PORTS 0x1 + +/* Ouput ports of SA HDT module */ +#define SA_HDT_MAX_OUT_PORTS 0x0 + +/* Input port ID of SA HDT module */ +#define PORT_ID_SA_HDT_INPUT 0x2 + +/* Output port ID of SA HDT module */ +#define PORT_ID_SA_HDT_OUTPUT 0x1 + +/* Max number of intent per control port of SA HDT module */ +#define SA_HDT_MAX_INTENTS_PER_CTRL_PORT 2 + +/* Static output control port ID's of SA HDT module */ +#define SA_HDT_OUT_RAW_DATA AR_NON_GUID(0xC0000001) + +/* Static output control port for orientation data */ +#define SA_HDT_OUT_ORIENTATION_DATA AR_NON_GUID(0xC0000002) + +/* Direction of Stream Information for SA HDT module */ +#define SA_HDT_FROM_AIR 1 +#define SA_HDT_TO_AIR 0 + +/*============================================================================== + Param ID +==============================================================================*/ +/** Parameter ID of SA HDT Stream Info */ +#define PARAM_ID_SA_HDT_STREAM_INFO 0x08001B95 + +/** @h2xmlp_subStruct */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct sa_hdt_stream_info_map_t +{ + uint32_t stream_id; + /**< + @h2xmle_description {Stream ID} + @h2xmle_default {0} */ + uint32_t direction; + /**< + @h2xmle_description {1 -> from air || 0 -> to air } + @h2xmle_default {0} + @h2xmle_rangeList {"FROMAIR"=1; + "TOAIR"=0} */ + uint32_t channel_mask_lsw; + /**< + @h2xmle_description {Channel Mask LSW} + @h2xmle_default {0x00000008} */ + uint32_t channel_mask_msw; + /**< + @h2xmle_description {Channel Mask MSW} + @h2xmle_default {0x00000000} */ +} sa_hdt_stream_info_map_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" + ; + +/** @h2xmlp_parameter {"PARAM_ID_SA_HDT_STREAM_INFO", PARAM_ID_SA_HDT_STREAM_INFO} + @h2xmlp_description {Structure for the param_id_sa_hdt_stream_info_t parameter used by the SA HDT module. + It is a mandatory param for SA HDT module to work } + @h2xmlp_toolPolicy {NO_SUPPORT} + @h2xmlx_expandStructs {false} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sa_hdt_stream_info_t +{ + uint32_t num_streams; + /**< + @h2xmle_description {Number of Streams of HDT data} + @h2xmle_default {1} + @h2xmle_policy {Basic} + */ + +#if defined(__H2XML__) + sa_hdt_stream_info_map_t stream_map[0]; + /**< @h2xmle_description {Channel mapping -> sa_hdt_stream_info_map_t structures} + @h2xmle_variableArraySize {num_streams} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_sa_hdt_stream_info_t param_id_sa_hdt_stream_info_t; + +/** Parameter ID of SA HDT OP Mode */ +#define PARAM_ID_SA_HDT_OP_MODE 0x08001B96 + +/** @h2xmlp_parameter {"PARAM_ID_SA_HDT_OP_MODE", PARAM_ID_SA_HDT_OP_MODE} + @h2xmlp_description {Structure for the param_id_sa_hdt_op_mode_t parameter used by the SA HDT module. + It is an optional param for SA HDT module } + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlx_expandStructs {false} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sa_hdt_op_mode_t +{ + uint32_t hdt_op_mode; + /**< + @h2xmle_description {Operation mode of HDT Module} + @h2xmle_rangeList {"Default RAW Mode"=0; + "Processed HDT Data"=1} + @h2xmle_default {0} + @h2xmle_policy {Basic} + */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_sa_hdt_op_mode_t param_id_sa_hdt_op_mode_t; + +/** Parameter ID for SA HDT Tracking Configuration */ +#define PARAM_ID_SA_HDT_TRACKING_CONFIG 0x08010007 + +/** @h2xmlp_parameter {"PARAM_ID_SA_HDT_TRACKING_CONFIG", PARAM_ID_SA_HDT_TRACKING_CONFIG} + @h2xmlp_description {Structure for tracking configuration parameters} + @h2xmlp_toolPolicy {CALIBRATION} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sa_hdt_tracking_config_t +{ + uint32_t target_tracking_mode; + /**< + @h2xmle_description {Target tracking mode} + @h2xmle_rangeList {"Static (No tracking)"=0; + "World-locked (Head tracking)"=1; + "Screen-locked"=2} + @h2xmle_default {1} + @h2xmle_policy {Basic} + */ + + uint32_t stillness_detect; + /**< + @h2xmle_description {Enable stillness detection for auto-recenter} + @h2xmle_rangeList {"Disabled"=0; + "Enabled"=1} + @h2xmle_default {1} + @h2xmle_policy {Basic} + */ + + uint32_t stillness_timer; + /**< + @h2xmle_description {Stillness timer in milliseconds} + @h2xmle_range {500..15000} + @h2xmle_default {7000} + @h2xmle_policy {Basic} + */ + + float stillness_threshold; + /**< + @h2xmle_description {Stillness threshold (quaternion dot product)} + @h2xmle_range {0.001..0.1} + @h2xmle_default {0.0175} + @h2xmle_policy {Basic} + */ + + float max_rotational_velocity; + /**< + @h2xmle_description {Maximum rotational velocity in rad/s} + @h2xmle_range {0.0..20} + @h2xmle_default {10} + @h2xmle_policy {Basic} + */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_sa_hdt_tracking_config_t param_id_sa_hdt_tracking_config_t; + +/** Parameter ID for SA HDT Tracking Recenter */ +#define PARAM_ID_SA_HDT_TRACKING_RECENTER 0x08F013DB + +/** @h2xmlp_parameter {"PARAM_ID_SA_HDT_TRACKING_RECENTER", PARAM_ID_SA_HDT_TRACKING_RECENTER} + @h2xmlp_description {Command to recenter head tracking} + @h2xmlp_toolPolicy {RTC} + @h2xmlx_expandStructs {false} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sa_hdt_tracking_recenter_t +{ + uint32_t force_update; + /**< + @h2xmle_description {Force immediate update bypassing velocity limiting} + @h2xmle_rangeList {"Normal recenter"=0; + "Force immediate"=1} + @h2xmle_default {0} + @h2xmle_policy {Basic} + */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_sa_hdt_tracking_recenter_t param_id_sa_hdt_tracking_recenter_t; + +/** Parameter ID for SA HDT Tracking Status (Read-only) */ +#define PARAM_ID_SA_HDT_TRACKING_STATUS 0x08F013E0 + +/** @h2xmlp_parameter {"PARAM_ID_SA_HDT_TRACKING_STATUS", PARAM_ID_SA_HDT_TRACKING_STATUS} + @h2xmlp_description {Read-only tracking status information} + @h2xmlp_toolPolicy {RTC_READONLY} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sa_hdt_tracking_status_t +{ + uint32_t current_tracking_mode; + /**< + @h2xmle_description {Current active tracking mode} + @h2xmle_rangeList {"Static"=0; + "World-locked"=1; + "Screen-locked"=2} + @h2xmle_default {1} + @h2xmle_policy {Basic} + */ + + uint32_t head_to_stage_rotation_mode; + /**< + @h2xmle_description {Rotation mode of head-to-stage output} + @h2xmle_rangeList {"YPR"=0; + "RPY"=1; + "Axis-Angle"=2} + @h2xmle_default {2} + @h2xmle_policy {Basic} + */ + + float head_to_stage_x; + /**< + @h2xmle_description {Head-to-stage rotation X component} + @h2xmle_default {0.0} + @h2xmle_policy {Basic} + */ + + float head_to_stage_y; + /**< + @h2xmle_description {Head-to-stage rotation Y component} + @h2xmle_default {0.0} + @h2xmle_policy {Basic} + */ + + float head_to_stage_z; + /**< + @h2xmle_description {Head-to-stage rotation Z component} + @h2xmle_default {0.0} + @h2xmle_policy {Basic} + */ + + uint32_t head_is_still; + /** < @h2xmle_default {0} + @h2xmle_description {Current head stillness status} + @h2xmle_dataFormat {Q0} + @h2xmle_rangeList {moving=0;still=1} */ + + int64_t stillness_countdown; + /** < @h2xmle_default {7000} + @h2xmle_description {Stillness time until recenter in ms} + @h2xmle_dataFormat {Q0} + @h2xmle_range {500,15000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Type definition for the above structure. */ +typedef struct param_id_sa_hdt_tracking_status_t param_id_sa_hdt_tracking_status_t; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/** @h2xml_title1 {SA HDT Module API} */ + +/** + * Module ID for SA HDT Module + */ + +#define MODULE_ID_SA_HDT 0x0702C005 +/** + @h2xmlm_module {"MODULE_ID_SA_HDT", + MODULE_ID_SA_HDT} + @h2xmlm_displayName {"Spatial Audio HDT"} + @h2xmlm_modSearchKeys {Spatial Audio, HDT} + @h2xmlm_description {- SA HDT\n + - This module handles headtracking data from BT controller as deinterleaved raw + bitstream\n + - Supports following params: \n + - PARAM_ID_SA_HDT_STREAM_INFO + - PARAM_ID_SA_HDT_OP_MODE + - PARAM_ID_SA_HDT_TRACKING_CONFIG + - PARAM_ID_SA_HDT_TRACKING_RECENTER + - PARAM_ID_SA_HDT_TRACKING_STATUS + - Supported Input Media Format: \n + - Data Format : CAPI_DEINTERLEAVED_RAW_COMPRESSED + - fmt_id : Don't care \n} + @h2xmlm_dataInputPorts {IN = PORT_ID_SA_HDT_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlStaticPort {"SA_HDT_OUT_RAW_DATA" = 0xC0000001, + "HDT Raw Data Out" = INTENT_ID_SA_HDT_RAW_DATA} + @h2xmlm_ctrlStaticPort {"SA_HDT_OUT_ORIENTATION_DATA" = 0xC0000002, + "HDT Orientation Data Out" = INTENT_ID_SA_HDT_ORIENTATION_DATA} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {SA_HDT_STACK_SIZE} + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_sa_hdt_op_mode_t} + @h2xmlm_InsertParameter + @h2xml_Select {sa_hdt_stream_info_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_sa_hdt_stream_info_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_sa_hdt_tracking_config_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_sa_hdt_tracking_recenter_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_sa_hdt_tracking_status_t} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ +#endif // SA_HDT_API_H diff --git a/spf/api/modules/sbc_decoder_api.h b/spf/api/modules/sbc_decoder_api.h new file mode 100644 index 0000000..465ab96 --- /dev/null +++ b/spf/api/modules/sbc_decoder_api.h @@ -0,0 +1,46 @@ +/*============================================================================== + @file sbc_decoder_api.h + @brief This file contains SBC decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _SBC_DECODER_H_ +#define _SBC_DECODER_H_ + +#include "common_enc_dec_api.h" +#include "ar_defs.h" + +/** @h2xml_title1 {SBC Decoder} + @h2xml_title_agile_rev {SBC Decoder} + @h2xml_title_date {October 15, 2018} +*/ + +#define MODULE_ID_SBC_DEC 0x07001039 +/** + @h2xmlm_module {"MODULE_ID_SBC_DEC", MODULE_ID_SBC_DEC} + @h2xmlm_displayName {"SBC Decoder"} + @h2xmlm_description {This module is used as the decoder for SBC use cases.\n + - This module has only one input and one output port.\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> +*/ + +#endif //_SBC_DECODER_API_H diff --git a/spf/api/modules/sbc_encoder_api.h b/spf/api/modules/sbc_encoder_api.h new file mode 100644 index 0000000..2473f75 --- /dev/null +++ b/spf/api/modules/sbc_encoder_api.h @@ -0,0 +1,61 @@ +/*============================================================================== + @file sbc_encoder_api.h + @brief This file contains SBC encoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ + +#ifndef _SBC_ENCODER_API_H_ +#define _SBC_ENCODER_API_H_ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {SBC Encoder} + @h2xml_title_agile_rev {SBC Encoder} + @h2xml_title_date {March 13, 2019} +*/ +#define MODULE_ID_SBC_ENC 0x0700103A +/** + @h2xmlm_module {"MODULE_ID_SBC_ENC", MODULE_ID_SBC_ENC} + @h2xmlm_displayName {"SBC Encoder"} + @h2xmlm_description {This module is used as the encoder for SBC use cases.\n + - This module has only one input and one output port.\n + - Payload for param_id_encoder_output_config_t : sbc_enc_cfg_t\n + - Encodes data to format-id = MEDIA_FMT_ID_SBC\n + - Supports following params:\n + -- PARAM_ID_ENCODER_OUTPUT_CONFIG\n + -- PARAM_ID_ENC_BITRATE\n + - Supported Input Media Format:\n + -- Data Format : FIXED_POINT\n + -- fmt_id : Don't care\n + -- Sample Rates: 0 (native mode), 16, 32, 44.1, 48 \n + -- Number of channels : 1, 2\n + -- Bit Width : 16\n + -- Bits Per Sample : 16\n + -- Q format : Q15\n + -- Interleaving : interleaved\n + - Supported bit rates in each configuration :\n + -- maximum bit rates in bps:\n + --- mono : 320kbps \n + --- stereo : 512kbps \n } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN0=2} + @h2xmlm_dataOutputPorts {OUT0=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_encoder_output_config_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"sbc_enc_cfg_t"} + @h2xmlm_InsertStructure + @h2xml_Select {"param_id_enc_bitrate_param_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif //_SBC_ENCODER_API_H_ diff --git a/spf/api/modules/sdz_api.h b/spf/api/modules/sdz_api.h new file mode 100644 index 0000000..fc27aa9 --- /dev/null +++ b/spf/api/modules/sdz_api.h @@ -0,0 +1,872 @@ +/* ========================================================================= +*  Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +*  SPDX-License-Identifier: BSD-3-Clause + ========================================================================= */ + +#ifndef SDZ_API_H +#define SDZ_API_H + +/* ========================================================================= +@file sdz_api.h + + API header file for Speaker Diarization Module. +========================================================================= */ + +/** @h2xml_title1 {Speaker Diarization (SDZ)} + @h2xml_title_agile_rev {Speaker Diarization (SDZ)} + @h2xml_title_date {Feb 18, 2025} */ + +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/*SDZ module only supports one input port.*/ +#define CAPI_SDZ_MAX_INPUT_PORTS 1 +#define CAPI_SDZ_MAX_OUTPUT_PORTS 0 + +/* Stack memory size used by SDZ module library */ +#define SDZ_STACK_SIZE 2048 + +/*sdz_speaker_segment_t structure speaker_name and speaker_uuid sizes */ +#define SDZ_SPEAKER_INFO_SPEAKER_NAME_SIZE 64 +#define SDZ_SPEAKER_INFO_SPEAKER_UUID_SIZE 40 + +/* SDZ client id definitions - Public API enum + * These values are exposed to external clients and should not be changed + * for backward compatibility */ +typedef enum sdz_client_id_t +{ + SDZ_CLIENT_INVALID = 0, + SDZ_CLIENT_HLOS = 1, + SDZ_CLIENT_SENSOR = 2, + SDZ_CLIENT_MAX = SDZ_CLIENT_SENSOR +} sdz_client_id_t; + +/* Global unique Module ID definition + Module library is independent of this number, it is defined here for static + loading purpose only */ +#define MODULE_ID_SDZ 0x0702C000 + +/** + @h2xmlm_module {"MODULE_ID_SDZ", + MODULE_ID_SDZ} + @h2xmlm_displayName {"Speaker Diarization"} + @h2xmlm_description {SDZ (Speaker Diarization) module identifies a speaker ID and gives out an unique + identification number for further consumption and processing by applications which + require the speaker identification from single MIC stream\n + + . This module supports the following parameter IDs:\n + . #PARAM_ID_SDZ_VERSION\n + . #PARAM_ID_SDZ_INPUT_THRESHOLD\n + . #PARAM_ID_SDZ_INPUT_THRESHOLD_V2\n + . #PARAM_ID_SDZ_OUTPUT_CONFIG\n + . #PARAM_ID_SDZ_OUTPUT_CONFIG_V2\n + . #PARAM_ID_SDZ_FORCE_OUTPUT\n + . #PARAM_ID_SDZ_FORCE_OUTPUT_V2\n + . #PARAM_ID_SDZ_MODEL\n + . #PARAM_ID_SDZ_OUTPUT\n + . #PARAM_ID_SDZ_OUTPUT_V2\n + . #PARAM_ID_SDZ_VOICE_PROFILE\n + . #PARAM_ID_SDZ_TIMESTAMP_FORMAT\n + . #EVENT_ID_SDZ_OUTPUT\n + . #EVENT_ID_SDZ_OUTPUT_V2\n + \n + . Supported Input Media Format: \n + . Data Format : FIXED_POINT \n + . fmt_id : MEDIA_FMT_ID_PCM \n + . Sample Rates : 16000 \n + . Number of channels : 1 \n + . Channel type : C \n + . Bits per sample : 16 \n + . Q format : Q15 for bps = 16 \n + . Interleaving : Deinterleaved Unpacked \n + . Signed/unsigned : Signed \n + } + @h2xmlm_dataMaxInputPorts {CAPI_SDZ_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {CAPI_SDZ_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {FALSE} + @h2xmlm_stackSize {SDZ_STACK_SIZE} + @h2xmlm_ctrlDynamicPortIntent { "DAM-SDZ Control" = INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL, + maxPorts= 1 } + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + +*/ + +/* ID of the SDZ version parameter used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_VERSION 0x08001B08 + +/* Structure for the SDZ version parameter of SDZ module. */ +typedef struct sdz_version_t sdz_version_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_VERSION", PARAM_ID_SDZ_VERSION} + @h2xmlp_description {Structure to get the current library version.} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_SDZ_VERSION parameter used by the + SDZ module. + */ + +struct sdz_version_t +{ + uint32_t lib_version_low; + /**< @h2xmle_description {Lower 32 bits of the 64-bit library version number} */ + uint32_t lib_version_high; + /**< @h2xmle_description {Higher 32 bits of the 64-bit library version number} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {sdz_version_t} + @h2xmlm_InsertParameter */ + +/* ID of the SDZ input threshold parameter used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_INPUT_THRESHOLD 0x08001B09 + +/* Structure for the input threshold parameter of SDZ module. */ +typedef struct param_id_sdz_input_threshold_t param_id_sdz_input_threshold_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_INPUT_THRESHOLD", PARAM_ID_SDZ_INPUT_THRESHOLD} + @h2xmlp_description {Param to control wakeup threshold for SDZ engine based on input buffering i.e., + to control the frequency at which SDZ engine should be woken up periodically } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_SDZ_INPUT_THRESHOLD parameter used by the + SDZ module. + */ +struct param_id_sdz_input_threshold_t +{ + uint32_t buf_duration_ms; + /**< @h2xmle_description {Duration of input threshold in milli seconds, used to create input buffering and wakeup control.} + @h2xmle_range {200..30000} ms + @h2xmle_default {200} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_input_threshold_t} + @h2xmlm_InsertParameter */ + +/* ID of the SDZ input threshold parameter V2 used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_INPUT_THRESHOLD_V2 0x08001BC7 + +/* Structure for the input threshold parameter V2 of SDZ module with client ID support. */ +typedef struct param_id_sdz_input_threshold_v2_t param_id_sdz_input_threshold_v2_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_INPUT_THRESHOLD_V2", PARAM_ID_SDZ_INPUT_THRESHOLD_V2} + @h2xmlp_description {Param to control wakeup threshold for SDZ engine based on input buffering with client ID support} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_SDZ_INPUT_THRESHOLD_V2 parameter used by the + SDZ module. + */ +struct param_id_sdz_input_threshold_v2_t +{ + uint32_t client_id; + /**< @h2xmle_description {Client ID for this input threshold configuration. + This API provide the input threshold requirement of each client. The lowest threshold will be chosen as the operating threshold.} + @h2xmle_default {1} + @h2xmle_rangeList {"SDZ_CLIENT_HLOS"=1, "SDZ_CLIENT_SENSOR"=2} */ + uint32_t buf_duration_ms; + /**< @h2xmle_description {Duration of input threshold in milli seconds, used to create input buffering and wakeup control.} + @h2xmle_range {200..30000} ms + @h2xmle_default {200} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_input_threshold_v2_t} + @h2xmlm_InsertParameter */ + +/* ID of the SDZ output configuration parameter used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_OUTPUT_CONFIG 0x08001B0D + +/* Enums defining the mode of output used by param_id_sdz_output_config_t */ +typedef enum sdz_output_mode_t +{ + SDZ_NON_BUFFERED = 0, /* Send SDZ engine output immediately. Each buffer shall have one payload + corresponding to a partial/complete segment of speech. + Typical usage : live display of output. */ + + SDZ_BUFFERED, /* Buffer up SDZ engine output based on configured buffer size from client. + Send the event to clients once buffer is full. + Typical usage : save transcription output in background. */ +}sdz_output_mode_t; + +/* Structure for the output configuration parameter of SDZ module. */ +typedef struct param_id_sdz_output_config_t param_id_sdz_output_config_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_OUTPUT_CONFIG", PARAM_ID_SDZ_OUTPUT_CONFIG} + @h2xmlp_description {Param to configure required output mode and buffering mode for SDZ engine } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_SDZ_OUTPUT_CONFIG parameter used by the + SDZ module. + */ + +struct param_id_sdz_output_config_t +{ + uint32_t output_mode; + /**< @h2xmle_description {Configuration to specify transcription output mode depending on usecase requirement. + SDZ_NON_BUFFERED - Output of each SDZ algo process is immediately sent to client. + SDZ_BUFFERED - Output of each SDZ algo process is buffered and sent to client intermittently.} + @h2xmle_default {SDZ_NON_BUFFERED} + @h2xmle_rangeList {"SDZ_NON_BUFFERED"=0, "SDZ_BUFFERED"=1} */ + uint32_t out_buf_size; + /**< @h2xmle_description {Configuration to specify transcription output buffer size, 0 for SDZ_NON_BUFFERED output mode.} + @h2xmle_default {0} + @h2xmle_range {0.. 262144} */ + uint32_t num_bufs; + /**< @h2xmle_description {Configuration to specify number of output buffers, 0 for SDZ_NON_BUFFERED output mode.} + @h2xmle_default {0} + @h2xmle_range {0.. 16} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_output_config_t} + @h2xmlm_InsertParameter */ + +/* Base structure for client-specific output configuration of SDZ module. */ +typedef struct param_id_sdz_output_config_v2_base_t param_id_sdz_output_config_v2_base_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Sub structure for client-specific output configuration of SDZ module} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sdz_output_config_v2_base_t +{ + uint32_t client_id; + /**< @h2xmle_description {Client ID (sdz_client_id_t) for this configuration. + This API allow multiple clients to have unique configurations.} + @h2xmle_default {1} + @h2xmle_rangeList {"SDZ_CLIENT_HLOS"=1, "SDZ_CLIENT_SENSOR"=2} */ + uint32_t output_mode; + /**< @h2xmle_description {Configuration to specify transcription output mode depending on usecase requirement. + SDZ_NON_BUFFERED - Output of each SDZ algo process is immediately sent to client. + SDZ_BUFFERED - Output of each SDZ algo process is buffered and sent to client intermittently.} + @h2xmle_default {SDZ_NON_BUFFERED} + @h2xmle_rangeList {"SDZ_NON_BUFFERED"=0, "SDZ_BUFFERED"=1} */ + uint32_t out_buf_size; + /**< @h2xmle_description {Configuration to specify transcription output buffer size depending on usecase requirement.} + @h2xmle_default {0} + @h2xmle_range {0..262144} */ + uint32_t num_bufs; + /**< @h2xmle_description {Configuration to specify number of output buffers.} + @h2xmle_default {1} + @h2xmle_range {1..16} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* ID of the SDZ output configuration V2 parameter used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_OUTPUT_CONFIG_V2 0x08001BDA + +/* Structure for the multi-client output configuration parameter of SDZ module. */ +typedef struct param_id_sdz_output_config_v2_t param_id_sdz_output_config_v2_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_OUTPUT_CONFIG_V2", PARAM_ID_SDZ_OUTPUT_CONFIG_V2} + @h2xmlp_description {Param to configure output mode and buffering for multiple SDZ clients simultaneously} + @h2xmlp_toolPolicy {CALIBRATION} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sdz_output_config_v2_t +{ + uint32_t num_clients; + /**< @h2xmle_description {Number of client configurations provided} + @h2xmle_default {1} + @h2xmle_range {1..2} */ + param_id_sdz_output_config_v2_base_t client_configs[0]; + /**< @h2xmle_description {Variable array of client-specific output configurations} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_output_config_v2_t} + @h2xmlm_InsertParameter */ + +/* ID of the SDZ force output parameter used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_FORCE_OUTPUT 0x08001B0E + +/* Structure for the force output parameter of SDZ module. */ +typedef struct param_id_sdz_force_output_t param_id_sdz_force_output_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_FORCE_OUTPUT", PARAM_ID_SDZ_FORCE_OUTPUT} + @h2xmlp_description {Forces the SDZ module to produce output event irrespective of configured input threshold and current buffering state} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_SDZ_FORCE_OUTPUT parameter used by the + SDZ module. + */ +struct param_id_sdz_force_output_t +{ + uint32_t force_output; + /**< @h2xmle_description {forces SDZ module to produce output with current data without waiting for further data accumulation.} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_force_output_t} + @h2xmlm_InsertParameter */ + +/* ID of the SDZ force output V2 parameter used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_FORCE_OUTPUT_V2 0x08001BDB + +/* Structure for the force output V2 parameter of SDZ module with client ID support. */ +typedef struct param_id_sdz_force_output_v2_t param_id_sdz_force_output_v2_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_FORCE_OUTPUT_V2", PARAM_ID_SDZ_FORCE_OUTPUT_V2} + @h2xmlp_description {Forces the SDZ module to produce output event for a specific client irrespective of configured input threshold and current buffering state} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_SDZ_FORCE_OUTPUT_V2 parameter used by the + SDZ module. + */ +struct param_id_sdz_force_output_v2_t +{ + uint32_t client_id; + /**< @h2xmle_description {Client ID (sdz_client_id_t) for which to force output. + This allows forcing output for a specific client independently.} + @h2xmle_default {1} + @h2xmle_rangeList {"SDZ_CLIENT_HLOS"=1, "SDZ_CLIENT_SENSOR"=2} */ + uint32_t force_output; + /**< @h2xmle_description {forces SDZ module to produce output for the specified client with current data without waiting for further data accumulation.} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_force_output_v2_t} + @h2xmlm_InsertParameter */ + +/* ID of the SDZ output event configuration used by MODULE_ID_SDZ.*/ +#define EVENT_ID_SDZ_OUTPUT 0x08001B0A + +/** @h2xmlp_parameter {"EVENT_ID_SDZ_OUTPUT", + EVENT_ID_SDZ_OUTPUT} + @h2xmlp_description {Event raised by SDZ to the clients; registration and event have different payload types} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/* Structure for the event registration payload of the EVENT_ID_SDZ_OUTPUT. */ +typedef struct event_id_sdz_output_reg_cfg_t event_id_sdz_output_reg_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_sdz_output_reg_cfg_t +{ + uint32_t event_payload_type; + /**< @h2xmle_description {Field to configure event payload type} + QUERY - Client queries the output via getparam upon receiving SDZ output event. + INBAND - SDZ output event has the output payload inband in the event.} + DONT_CARE - SDZ output event can be INBAND or QUERY based, flag in event + payload indicates the mode.} + @h2xmle_default {0} + @h2xmle_rangeList {"QUERY"=0, "INBAND"=1, "DONT_CARE"=2} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define EVENT_ID_SDZ_OUTPUT_V2 0x08001BC8 + +/** @h2xmlp_parameter {"EVENT_ID_SDZ_OUTPUT_V2", + EVENT_ID_SDZ_OUTPUT_V2} + @h2xmlp_description {Event raised by SDZ to the clients with client ID support; registration and event have different payload types.} + Registering to this event will mean using PARAM_ID_SDZ_OUTPUT_V2. PARAM_ID_SDZ_OUTPUT should not be expected.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/* V2 event registration configuration with client ID */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_sdz_output_reg_cfg_v2_t +{ + uint32_t client_id; + /**< @h2xmle_description {Client ID (sdz_client_id_t) to identify the client.} + @h2xmle_default {1} + @h2xmle_rangeList {"SDZ_CLIENT_HLOS"=1, "SDZ_CLIENT_SENSOR"=2} */ + uint32_t event_payload_type; + /**< @h2xmle_description {Field to configure event payload type} + QUERY - Client queries the output via getparam upon receiving SDZ output event. + INBAND - SDZ output event has the output payload inband in the event. + DONT_CARE - SDZ output event can be INBAND or QUERY based, flag in event + payload indicates the mode.} + @h2xmle_default {0} + @h2xmle_rangeList {"QUERY"=0, "INBAND"=1, "DONT_CARE"=2} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_sdz_output_reg_cfg_v2_t event_id_sdz_output_reg_cfg_v2_t; + +/* Sub Structure for the event/param payload used for containing timestamp associated with each speaker ID.*/ +/** @h2xmlp_subStruct + @h2xmlp_description {Sub Structure for the event/param payload used for containing timestamp associated with each speaker ID} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct sdz_speaker_info_t +{ + uint32_t speaker_id; + /**< @h2xmle_description {speaker ID detected by the algorithm} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t start_ts_lsw; + /**< @h2xmle_description {Field indicating the least-significant 32 bits of the start timestamp for + above speaker id.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t start_ts_msw; + /**< @h2xmle_description {Field indicating the most-significant 32 bits of the start timestamp for + above speaker id.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t end_ts_lsw; + /**< @h2xmle_description {Field indicating the least-significant 32 bits of the end timestamp for + above speaker id.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t end_ts_msw; + /**< @h2xmle_description {Field indicating the most-significant 32 bits of the end timestamp for + above speaker id.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sdz_speaker_info_t sdz_speaker_info_t; + +/* Sub Structure for speaker segment information - used when voice profile mode is enabled */ +/** @h2xmlp_subStruct + @h2xmlp_description {Sub Structure for speaker segment information with UUID, speaker name, and confidence scores} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + + +struct sdz_speaker_segment_t +{ + uint32_t time_stamp_start_lsw; + /**< @h2xmle_description {Field indicating the least-significant 32 bits of the start timestamp in microseconds} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t time_stamp_start_msw; + /**< @h2xmle_description {Field indicating the most-significant 32 bits of the start timestamp in microseconds} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t time_stamp_end_lsw; + /**< @h2xmle_description {Field indicating the least-significant 32 bits of the end timestamp in microseconds} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t time_stamp_end_msw; + /**< @h2xmle_description {Field indicating the most-significant 32 bits of the end timestamp in microseconds} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + float diarization_score; + /**< @h2xmle_description {Confidence value for diarization, reserved for future planned functionalities(reserved for future planned functionalities)} + @h2xmle_default {0.0} + @h2xmle_range {0.0..100.0} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + + float identification_score; + /**< @h2xmle_description {Confidence value for speaker identification/persistence, reserved for future planned functionalities(reserved for future planned functionalities)} + @h2xmle_default {0.0} + @h2xmle_range {0.0..100.0} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + + uint8_t speaker_name[SDZ_SPEAKER_INFO_SPEAKER_NAME_SIZE]; + /**< @h2xmle_description {Name of the speaker from profile} + @h2xmle_default {0} */ + + uint8_t speaker_uuid[SDZ_SPEAKER_INFO_SPEAKER_UUID_SIZE]; + /**< @h2xmle_description {Unique ID associated with a speaker who has an existing profile} + @h2xmle_default {0} */ + + int32_t speaker_id; + /**< @h2xmle_description {Speaker label (e.g., 'talker 1', 'talker 2'), -1 for unidentified speaker} + @h2xmle_default {0} + @h2xmle_range {-1..0x7FFFFFFF} */ + + uint32_t speaker_is_owner; + /**< @h2xmle_description {Flag indicating if the current speaker is device owner (from profile)} + @h2xmle_default {0} + @h2xmle_rangeList {"FALSE"=0, "TRUE"=1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sdz_speaker_segment_t sdz_speaker_segment_t; + +typedef struct sdz_output_status_t sdz_output_status_t; + +/* Sub Structure for the event/param payload used for containing information about number of detected spakers and each speaker info.*/ +/** @h2xmlp_subStruct + @h2xmlp_description {Sub Structure for the event/param payload used for containing information about number of detected spakers and each speaker info} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct sdz_output_status_t +{ + uint32_t num_speakers; + /**< @h2xmle_description {Field indicating the number of sdz_speaker_info_t present in + the speakers_info_list buf} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t overlap_detected; + /**< @h2xmle_description {Field indicating if the overlapping detected in the given inference + result.} + @h2xmle_default {0} + @h2xmle_rangeList {"FALSE"=0, "TRUE"=1} */ +#if defined(__H2XML__) + sdz_speaker_info_t speakers_info_list[0]; + /*@variableArraySize {num_speakers} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Sub Structure V2 for the event/param payload - used when voice profile mode is enabled */ +typedef struct sdz_output_status_v2_t sdz_output_status_v2_t; + +/** @h2xmlp_subStruct + @h2xmlp_description {Sub Structure V2 for the event/param payload containing speaker segments with UUID and speaker name} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct sdz_output_status_v2_t +{ + uint32_t num_segments; + /**< @h2xmle_description {Field indicating the number of sdz_speaker_segment_t present in + the segments buffer} + @h2xmle_default {0} + @h2xmle_range {0x0..0xFFFFFFFF} */ + +#if defined(__H2XML__) + sdz_speaker_segment_t segments[0]; + /*@variableArraySize {num_segments} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* ID of the SDZ output get parameter used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_OUTPUT 0x08001B0C + + +/* Structure for the event payload of EVENT_ID_SDZ_OUTPUT. */ +typedef struct event_id_sdz_output_event_t event_id_sdz_output_event_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct event_id_sdz_output_event_t +{ + uint32_t event_payload_type; + /**< @h2xmle_description {event type of SDZ event. + Query = Client will query via getparam upon receiving this event, using the + output_token provided as part of this payload. + Inband = SDZ output payload follows inband after the payload_size field } + @h2xmle_default {0} + @h2xmle_rangeList {"Query"=0, "Inband"=1} */ + uint32_t output_token; + /**< @h2xmle_description {Token provided by the SDZ engine corresponding to an output. + This is used to query the corresponding output payload. + If not configured or invalid, Payload corresponds to next output buffer + is sent.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of outputs of type sdz_output_status_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type sdz_output_status_t} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ +#if defined(__H2XML__) + sdz_output_status_t buf[0]; + /**< @h2xmle_description {Inband Payload, This will be filled if event_payload_type is Inband} + /*@variableArraySize {payload_size} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure for the PARAM_ID_SDZ_OUTPUT parameter. */ + +/** @h2xmlp_parameter {"PARAM_ID_SDZ_OUTPUT", PARAM_ID_SDZ_OUTPUT} + @h2xmlp_description {Get Param to query output from the module in response to the QUERY based event.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ +typedef event_id_sdz_output_event_t param_id_sdz_output_t; + +/* @h2xml_Select {param_id_sdz_output_t} + @h2xmlm_InsertParameter */ + +/* Structure for the event payload of EVENT_ID_SDZ_OUTPUT_V2. */ +typedef struct event_id_sdz_output_event_v2_t event_id_sdz_output_event_v2_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct event_id_sdz_output_event_v2_t +{ + uint32_t client_id; + /**< @h2xmle_description {Client ID (sdz_client_id_t) to identify which client's output buffer to query. + This must match the client_id used in PARAM_ID_SDZ_OUTPUT_CONFIG_V2. + Allows multiple clients to independently query their own output buffers.} + @h2xmle_default {1} + @h2xmle_rangeList {"SDZ_CLIENT_HLOS"=1, "SDZ_CLIENT_SENSOR"=2} */ + uint32_t event_payload_type; + /**< @h2xmle_description {event type of SDZ event. + Query = Client will query via getparam upon receiving this event, using the + output_token provided as part of this payload. + Inband = SDZ output payload follows inband after the payload_size field } + @h2xmle_default {0} + @h2xmle_rangeList {"Query"=0, "Inband"=1} */ + uint32_t output_token; + /**< @h2xmle_description {Token provided by the SDZ engine corresponding to an output. + This is used to query the corresponding output payload. + If not configured or invalid, Payload corresponds to next output buffer + is sent.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of outputs of type sdz_output_status_v2_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type sdz_output_status_v2_t} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ +#if defined(__H2XML__) + sdz_output_status_v2_t buf[0]; + /**< @h2xmle_description {Inband Payload, This will be filled if event_payload_type is Inband} + /*@variableArraySize {payload_size} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* ID of the SDZ output V2 get parameter used by MODULE_ID_SDZ (with voice profile mode enabled).*/ +#define PARAM_ID_SDZ_OUTPUT_V2 0x08001BA7 + +/* Structure for the PARAM_ID_SDZ_OUTPUT_V2 parameter. */ +typedef struct param_id_sdz_output_v2_t param_id_sdz_output_v2_t; + +/** @h2xmlp_parameter {"PARAM_ID_SDZ_OUTPUT_V2", PARAM_ID_SDZ_OUTPUT_V2} + @h2xmlp_description {Get Param to query output from the module in response to the QUERY based event.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_sdz_output_v2_t +{ + uint32_t client_id; + /**< @h2xmle_description {Client ID (sdz_client_id_t) to identify which client's output buffer to query. + This must match the client_id used in PARAM_ID_SDZ_OUTPUT_CONFIG_V2. + Allows multiple clients to independently query their own output buffers.} + @h2xmle_default {1} + @h2xmle_rangeList {"SDZ_CLIENT_HLOS"=1, "SDZ_CLIENT_SENSOR"=2} */ + uint32_t output_token; + /**< @h2xmle_description {Token provided by the SDZ engine corresponding to an output. + This is used to query the corresponding output payload. + If not configured or invalid, Payload corresponds to next output buffer + is sent.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t num_outputs; + /**< @h2xmle_description {Number of outputs of type sdz_output_status_v2_t in the payload } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint32_t payload_size; + /**< @h2xmle_description {Payload size in bytes. Following this field is the payload of + this size. Payload is variable array of type sdz_output_status_v2_t} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ +#if defined(__H2XML__) + sdz_output_status_v2_t buf[0]; + /*@variableArraySize {payload_size} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_output_v2_t} + @h2xmlm_InsertParameter */ + +#define PARAM_ID_SDZ_MODEL 0x08001B0B + +/* Structure for the model parameter of SDZ module. */ +typedef struct param_id_sdz_model_t param_id_sdz_model_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_MODEL", PARAM_ID_SDZ_MODEL} + @h2xmlp_description {NN Model related parameters} + @h2xmlp_ToolPolicy {NO_SUPPORT} + @h2xmlp_isHwAccel {FALSE} + @h2xmlp_isNeuralNetParam {TRUE} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Structure for the PARAM_ID_SDZ_OUTPUT parameter. */ +struct param_id_sdz_model_t +{ + uint32_t model_align; + /**< @h2xmle_description {Data Alignment required for the model_data} + @h2xmle_default {256} + @h2xmle_range {0..8192} + @h2xmle_group {SPF} + @h2xmle_subgroup {NNVAD} + @h2xmle_policy {Advanced} */ + + uint32_t model_offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of model by model_align} + @h2xmle_default {0} + @h2xmle_range {0..8191} + @h2xmle_policy {Basic} */ + + uint32_t model_size; + /**< @h2xmle_description {Size of the model in bytes} + @h2xmle_default {0} + @h2xmle_range {0x00000000..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +#if defined(__H2XML__) + uint8_t model[0]; + /**< @h2xmle_description {Model data: The path to the model file on the platform} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} + @h2xmle_policy {Basic} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_model_t} + @h2xmlm_InsertParameter */ + +/* ID of the SDZ voice profile parameter used by MODULE_ID_SDZ.*/ +#define PARAM_ID_SDZ_VOICE_PROFILE 0x08001BA5 + +/* Structure for the voice profile parameter of SDZ module. */ +typedef struct param_id_sdz_voice_profile_t param_id_sdz_voice_profile_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_VOICE_PROFILE", PARAM_ID_SDZ_VOICE_PROFILE} + @h2xmlp_description {Param to set voice profile/voiceprint data for speaker identification} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_SDZ_VOICE_PROFILE parameter used by the + SDZ module. + */ +struct param_id_sdz_voice_profile_t +{ + uint32_t client_id; + /**< @h2xmle_description {Client ID for input voice profile.(reserved for future use, currently not being utilized)} + @h2xmle_default {1} + @h2xmle_rangeList {"SDZ_CLIENT_HLOS"=1} */ + uint32_t voiceprint_size; + /**< @h2xmle_description {Size of the voiceprint data in bytes} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} */ + uint8_t voiceprint_data[0]; + /**< @h2xmle_description {Voiceprint/voice profile data blob} + @h2xmle_variableArraySize {voiceprint_size} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_sdz_voice_profile_t} + @h2xmlm_InsertParameter */ + +/* ID of set SDZ timestamp fmt.*/ +#define PARAM_ID_SDZ_TIMESTAMP_FORMAT 0x08001B84 +/* Structure to enable timestamp based on qtimer or UTC converted. */ +typedef struct param_id_sdz_ts_fmt_t param_id_sdz_ts_fmt_t; +/** @h2xmlp_parameter {"PARAM_ID_SDZ_TIMESTAMP_FORMAT", PARAM_ID_SDZ_TIMESTAMP_FORMAT} + @h2xmlp_description {Set Param to set the timestamp format associated with text. } + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_SDZ_TIMESTAMP_FORMAT parameter used by the + SDZ module. + */ +struct param_id_sdz_ts_fmt_t +{ + uint32_t ts_fmt; + /**< @h2xmle_description {Indicates the timestamp associated with speakers} + @h2xmle_default {0} + @h2xmle_rangeList {"UTC_FMT"=0, "QTIMER_FMT"=1} */ + uint32_t reset_period; + /**< @h2xmle_description {Indicates the period to read reference UTC time. Note: '0' means module latches to UTC time only at the beginning of the usecase and doesn't + periodically sync to UTC time for dynamic changes. For non-zero values say 'x' seconds, the module will dynamically sync and update the UTC time at every x seconds. + The maximum reset period allowed is a day.} + @h2xmle_default {0} + @h2xmle_range {0..86400} */ + uint32_t timestamp_unit; + /**< @h2xmle_description {Indicates the unit of timestamp. Currently only TIME_USEC is supported} + @h2xmle_default {1} + @h2xmle_rangeList {"TIME_USEC"=1} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* @h2xml_Select {param_id_sdz_ts_fmt_t} + @h2xmlm_InsertParameter */ +/** @} <-- End of the Module -->*/ +#endif /* SDZ_API_H */ diff --git a/spf/api/modules/sh_mem_pull_push_mode_api.h b/spf/api/modules/sh_mem_pull_push_mode_api.h new file mode 100644 index 0000000..46d656a --- /dev/null +++ b/spf/api/modules/sh_mem_pull_push_mode_api.h @@ -0,0 +1,638 @@ +/** + * \file sh_mem_pull_push_mode_api.h + * \brief + * This file contains CAPI pull mode and push mode module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _PULL_PUSH_MODE_API_H_ +#define _PULL_PUSH_MODE_API_H_ + +/*------------------------------------------------------------------------ + Include files + -----------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "apm_container_api.h" +#include "module_cmn_api.h" +#include "media_fmt_api.h" + +/*# @h2xml_title1 {Shared Memory Pull and Push Modules} + @h2xml_title_agile_rev {Shared Memory Pull and Push Modules} + @h2xml_title_date {March 29, 2019} */ + + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Enumerates the maximum number of input ports for Pull mode. */ +#define SH_MEM_PULL_MODE_MAX_INPUT_PORTS 0x0 + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Enumerates the maximum number of output ports for Pull mode. */ +#define SH_MEM_PULL_MODE_MAX_OUTPUT_PORTS 0x1 + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Enumerates the stack size of the module for Pull mode. */ +#define SH_MEM_PULL_MODE_STACK_SIZE_REQUIREMENT 4096 + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Enumerates the maximum number of input ports for Push mode. */ +#define SH_MEM_PUSH_MODE_MAX_INPUT_PORTS 0x1 + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Enumerates the maximum number of output ports for Push mode. */ +#define SH_MEM_PUSH_MODE_MAX_OUTPUT_PORTS 0x0 + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Enumerates the stack size of the module for Push mode. @newpage */ +#define SH_MEM_PUSH_MODE_STACK_SIZE_REQUIREMENT 4096 + +/*# @h2xmlx_xmlNumberFormat {int} */ + +/*============================================================================== + Event ID +==============================================================================*/ + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Identifier of the watermark event from the #MODULE_ID_SH_MEM_PULL_MODE and + #MODULE_ID_SH_MEM_PUSH_MODE modules to the client. + + @msgpayload + Payload of the configuration that the client is to register with the module + through APM_CMD_REGISTER_MODULE_EVENTS . \n + event_cfg_sh_mem_pull_push_mode_watermark_t + @par + @indent{12pt} Payload of the event raised by the module to the client + through \n + @indent{12pt} APM_CMD_REGISTER_MODULE_EVENTS. \n + @indent{12pt} event_sh_mem_pull_push_mode_watermark_level_t + @par + @note1hang For information about the APM events, see the AudioReach SPF + API Reference (80-VN500-5). + */ +#define EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK 0x0800101C + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Payload of the #EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK event. +*/ +#include "spf_begin_pack.h" +struct event_cfg_sh_mem_pull_push_mode_watermark_level_t +{ + uint32_t watermark_level_bytes; + /**< Watermark level in the circular buffer, in bytes. + + When data in the buffer reaches this level, the module informs the + client by raising a watermark event. */ + + /*#< @h2xmle_description {Watermark level in the circular buffer, in bytes. + When data in the buffer reaches this level, the + module informs the client by raising a watermark + event.} + @h2xmle_policy {Basic} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct event_cfg_sh_mem_pull_push_mode_watermark_level_t event_cfg_sh_mem_pull_push_mode_watermark_level_t; + + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Immediately following this structure are watermark level structures of type + sh_mem_pull_push_mode_watermark_level_t. + + Following is the overall structure: + + @code + { + event_cfg_sh_mem_pull_push_mode_watermark_t a; + event_cfg_sh_mem_pull_push_mode_watermark_level_t[num_water_mark_levels]; + } + @endcode @vertspace{6} +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_cfg_sh_mem_pull_push_mode_watermark_t +{ + uint32_t num_water_mark_levels; + /**< Number of watermark levels in the array. + + If set to zero, no watermark levels are specified, and hence no + watermark events are supported. */ + + /*#< @h2xmle_description {Number of watermark level structures in the array. + If set to zero, no watermark levels are specified, + and hence no watermark events are supported.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + +#if defined(__H2XML__) + event_cfg_sh_mem_pull_push_mode_watermark_level_t levels[0]; + /**< Array of watermark levels of size num_water_mark_levels. */ + + /*#< @h2xmle_description {Array of watermark levels of size + num_water_mark_levels.} + @h2xmle_variableArraySize {num_water_mark_levels} + @h2xmle_policy {Basic} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_cfg_sh_mem_pull_push_mode_watermark_t event_cfg_sh_mem_pull_push_mode_watermark_t; + + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Payload of the #EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK event. +*/ +#include "spf_begin_pack.h" +struct event_sh_mem_pull_push_mode_watermark_level_t +{ + uint32_t watermark_level_bytes; + /**< Watermark level in the circular buffer in bytes. + + When data in the buffer reaches this level, the module informs the + client by raising a watermark event. @newpagetable */ + + /*#< h2xmle_description {Watermark level in the circular buffer in bytes. + When data in the buffer reaches this level, the + module informs the client by raising a watermark + event.} + h2xmle_policy {Basic} + h2xmle_default {0} + h2xmle_range {0..0xFFFFFFFF} + h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct event_sh_mem_pull_push_mode_watermark_level_t event_sh_mem_pull_push_mode_watermark_level_t; + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Identifier of the EOS marker event from the #MODULE_ID_SH_MEM_PUSH_MODE modules to the client. + EOS marker payload has the timestamp info when the Push mode module receives end of the stream, which + inturn indicates the TS till which client can read the current stream from circular buffer. + + The client must exercise this event with caution and cannot assume has absolutely ended here. + Event only indicates that the stream momentarily ended at this timestamp. The data flow can always resume + if the upstream graph of the push mode graph remains started. So there is no synchronization promised with + respect to the data flow and EOS event. + + @msgpayload + Client needs to register with the module through APM_CMD_REGISTER_MODULE_EVENTS. No + payload required for this event's registration.\n + + @par + @indent{12pt} Payload of the event raised by the module to the client + through \n + @indent{12pt} APM_CMD_REGISTER_MODULE_EVENTS. \n + @indent{12pt} event_sh_mem_push_mode_eos_marker_t + @par + @note1hang For information about the APM events, see the AudioReach SPF + API Reference (80-VN500-5). + */ +#define EVENT_ID_SH_MEM_PUSH_MODE_EOS_MARKER 0x080013DD + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Payload of the event EVENT_ID_SH_MEM_PUSH_MODE_EOS_MARKER, contains the timestamp of the EOS marker. */ +#include "spf_begin_pack.h" +struct event_sh_mem_push_mode_eos_marker_t +{ + uint32_t index; + /**< Index of the sample in the circular buffer at which EOS marker is set. + + Range for the index: + 0 @ge index \> shared_circ_buf_size - 1 */ + + /*#< @h2xmle_description {Index of the sample in the circular buffer at which EOS marker is set. \n + Range for the index: 0 ≥ index > shared_circ_buf_size - 1} + @h2xmle_default {0} + @h2xmle_rangeList {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t timestamp_us_lsw; + /**< Lower 32 bits of Timestamp at which push mode module received EOS. */ + + /*#< @h2xmle_description {Lower 32 bits of Timestamp at which push mode module gets EOS. } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t timestamp_us_msw; + /**< Higher 32 bits of Timestamp at which push mode module received EOS. */ + + /*#< @h2xmle_description {Higher 32 bits of Timestamp at which push mode module gets EOS. } + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct event_sh_mem_push_mode_eos_marker_t event_sh_mem_push_mode_eos_marker_t; + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Common structure definition for the shared circular buffer between the SPF + and clients. Both Pull mode and Push mode modules support this structure. */ +#include "spf_begin_pack.h" +struct sh_mem_pull_push_mode_position_buffer_t +{ + volatile uint32_t frame_counter; + /**< Counter used to handle interprocessor synchronization issues associated + with reading write_index, wall_clock_us_lsw, and wall_clock_us_msw. + These fields are invalid when frame_counter=0. + + Read the frame_counter value both before and after reading these values + to ensure that the SPF did not update them while the client was reading + them. */ + + /*#< @h2xmle_description {Counter used to handle interprocessor + synchronization issues associated with reading + write_index, wall_clock_us_lsw, and + wall_clock_us_msw. These fields are invalid when + frame_counter=0. \n + Read the frame_counter value both before and after + reading these values to ensure that the SPF did + not update them while the client was reading + them.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + volatile uint32_t index; + /**< Index (in bytes) to the buffer where the SPF is writing (Push mode) or + reading (Pull mode). + + Range for the index: + 0 @ge index \> sh_mem_pull_push_mode_cfg_t::shared_circ_buf_size - 1 */ + + /*#< @h2xmle_description {Index (in bytes) to the buffer where the SPF is + writing (Push mode) or reading (Pull mode). \n + Range for the index: 0 ≥ index > + sh_mem_pull_push_mode_cfg_t:: + shared_circ_buf_size - 1} + @h2xmle_default {0} + @h2xmle_rangeList {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + volatile uint32_t timestamp_us_lsw; + /**< Upper 32 bits of the 64-bit timestamp, in microseconds. + + For Pull mode, the timestamp is the timestamp at which the index was + updated. For Push mode, the timestamp is the buffer or capture + timestamp of the sample at the index. */ + + /*#< @h2xmle_description {Upper 32 bits of the 64-bit timestamp, in + microseconds. \n + For Pull mode, the timestamp is the timestamp at + which the index was updated. \n + For Push mode, the timestamp is the buffer or + capture timestamp of the sample at the index.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + volatile uint32_t timestamp_us_msw; + /**< Upper 32 bits of the 64-bit timestamp, in microseconds. + + For Pull mode, the timestamp is the timestamp at which the index was + updated. For Push mode, the timestamp is the buffer or the capture + timestamp of the sample at the index. */ + + /*#< @h2xmle_description {Upper 32 bits of the 64-bit timestamp, in + microseconds. \n + For Pull mode, the timestamp is the timestamp at + which the index was updated. \n + For Push mode, the timestamp is the buffer or the + capture timestamp of the sample at the index.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct sh_mem_pull_push_mode_position_buffer_t sh_mem_pull_push_mode_position_buffer_t; + +/*============================================================================== + Param ID +==============================================================================*/ + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Identifier of the parameter that configures shared memory information for + Pull mode and Push mode. + + Before issuing this Set parameter: + - APM_CMD_SHARED_MEM_MAP_REGIONS must be issued (see the AudioReach SPF + API Reference (80-VN500-5)) + - Memory for the position buffer must be mapped as uncached + - Memory for the shared circular buffer must be mapped as uncached for + Push mode and cached for Pull mode + + @msgpayload + sh_mem_pull_push_mode_cfg_t @newpage + */ +#define PARAM_ID_SH_MEM_PULL_PUSH_MODE_CFG 0x0800100A + +/*============================================================================== + Param structure definitions +==============================================================================*/ + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Payload of the #PARAM_ID_SH_MEM_PULL_PUSH_MODE_CFG parameter. +*/ +#include "spf_begin_pack.h" +struct sh_mem_pull_push_mode_cfg_t +{ + uint32_t shared_circ_buf_addr_lsw; + /**< Lower 32 bits of the address of the shared circular buffer. */ + + /*#< @h2xmle_description {Lower 32 bits of the address of the shared + circular buffer.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t shared_circ_buf_addr_msw; + /**< Upper 32 bits of the address of the shared circular buffer. */ + + /*#< @h2xmle_description {Upper 32 bits of the address of the shared + circular buffer.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t shared_circ_buf_size; + /**< Number of bytes in the shared circular buffer. + + The value must be an integral multiple of the number of (bits per + sample * number of channels). */ + + /*#< @h2xmle_description {Number of bytes in the shared circular buffer. + The value must be an integral multiple of the + number of (bits per sample * number of channels).} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t circ_buf_mem_map_handle; + /**< Unique identifier for the shared memory address of shared circular + buffer. + + The SPF returns this handle through APM_CMD_RSP_SHARED_MEM_MAP_REGIONS + (see the AudioReach SPF CAPI API Reference (80-VN500-6)). */ + + /*#< @h2xmle_description {Unique ID of the shared memory address of shared + circular buffer. The SPF returns this handle + through APM_CMD_RSP_SHARED_MEM_MAP_REGIONS + (see the AudioReach SPF CAPI API Reference + (80-VN500-6)).} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t shared_pos_buf_addr_lsw; + /**< Lower 32 bits of the address of the shared position buffer. */ + + /*#< @h2xmle_description {Lower 32 bits of the address of the shared + position buffer.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t shared_pos_buf_addr_msw; + /**< Upper 32 bits of the address of the shared position buffer. */ + + /*#< @h2xmle_description {Upper 32 bits of the address of the shared + position buffer.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t pos_buf_mem_map_handle; + /**< Unique identifier for the shared memory address of position buffer. + + The SPF returns this handle through APM_CMD_RSP_SHARED_MEM_MAP_REGIONS + (see the AudioReach SPF CAPI API Reference (80-VN500-6)). */ + + /*#< @h2xmle_description {Unique ID of the shared memory address of position + buffer. The SPF returns this handle through + APM_CMD_RSP_SHARED_MEM_MAP_REGIONS (see the + AudioReach SPF CAPI API Reference + (80-VN500-6)).} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct sh_mem_pull_push_mode_cfg_t sh_mem_pull_push_mode_cfg_t; + +/*============================================================================== + Param ID +==============================================================================*/ + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Identifier of the parameter that configures header information for Push mode. + This parameter enables timestamp information to be written alongside PCM data + in the shared circular buffer. + + @msgpayload + sh_mem_push_mode_header_cfg_t + */ +#define PARAM_ID_SH_MEM_PUSH_MODE_HEADER_CFG 0x08001BDF +/** @h2xmlp_parameter {"PARAM_ID_SH_MEM_PUSH_MODE_HEADER_CFG", PARAM_ID_SH_MEM_PUSH_MODE_HEADER_CFG} + @h2xmlp_description {Configures the header info.\n} + @h2xmlp_toolPolicy {Calibration} */ + +/*============================================================================== + Param structure definitions +==============================================================================*/ +#include "spf_begin_pack.h" +struct sh_mem_push_mode_header_cfg_t +{ + uint32_t header_type; + /**< Bit field to enable/disable additional information to be sent along with + the audio data in the buffer. + + Bit 0: Include UTC timestamp (0=disabled, 1=enabled) + Bits 1-31: Reserved for future use*/ + + /*#< @h2xmle_description {Bit field to enable/disable additional header information. + Bit 0: UTC timestamp + Bits 1-31: Reserved} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct sh_mem_push_mode_header_cfg_t sh_mem_push_mode_header_cfg_t; + +/*============================================================================== + Header Structure Definitions +==============================================================================*/ + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Sync word for header validation. Value is ASCII "SPFM" (0x5350464D). */ +#define SH_MEM_PUSH_MODE_HEADER_SYNC_WORD 0x5350464D + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Batch header structure that appears at the start of each batch in shared memory. + Contains sync word for validation. */ +struct sh_mem_push_mode_batch_header_t +{ + uint32_t sync_word; + /**< Sync word for validation. Must be 0x5350464D ("SPFM"). */ +}; + +typedef struct sh_mem_push_mode_batch_header_t sh_mem_push_mode_batch_header_t; + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Parameter header type information structure (PARAM_ID + SIZE). + This header precedes each header type data/payload in the batch header. */ +struct sh_mem_push_mode_param_header_t +{ + uint32_t param_id; + /**< Parameter ID identifying the type of data that follows. */ + + uint32_t actual_size; + /**< Actual size of the payload in bytes */ + + uint32_t padding_size; + /**< Size of the padded bytes in param payload, to make next header SYNC_WORD 4-byte aligned. */ +}; + +typedef struct sh_mem_push_mode_param_header_t sh_mem_push_mode_param_header_t; + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Header Parameter ID for UTC timestamp. */ +#define PARAM_ID_HEADER_TYPE_UTC_TIMESTAMP 0x08001BE0 + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Timestamp parameter payload structure. + Can be used for both Propagated timestamp and UTC timestamp parameters. */ +struct sh_mem_push_mode_timestamp_payload_t +{ + uint32_t timestamp_us_lsw; + /**< Lower 32 bits of the 64-bit timestamp, in microseconds*/ + + uint32_t timestamp_us_msw; + /**< Upper 32 bits of the 64-bit timestamp, in microseconds*/ +}; + +typedef struct sh_mem_push_mode_timestamp_payload_t sh_mem_push_mode_timestamp_payload_t; + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Header Parameter ID for PCM data. */ +#define PARAM_ID_HEADER_TYPE_PCM_DATA 0x08001BE1 + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Identifier for the Shared Memory Pull mode module, which writes data to the + SPF from the host through a shared circular buffer. + + This module has only one static output port with ID 1. + + The module does not work unless it receives #PARAM_ID_MEDIA_FORMAT. + + @subhead4{Supported input media format ID} + - Data format : #DATA_FORMAT_FIXED_POINT @lstsp1 + - fmt_id : #MEDIA_FMT_ID_PCM @lstsp1 + - Sample rates : 1..384 kHz @lstsp1 + - Number of channels: 1 to 128 (for certain products this module supports only 32 channels) @lstsp1 + - Bit width: @lstsep + - 16 bits per sample in Q15 format @lstsp2 + - 24 bits per sample in Q23 format; 32 bits per sample in Q23, Q27, or + Q31 format @lstsp2 + - 32 bits per sample in Q31 format @lstsp1 + - Interleaving: @lstsep + - Interleaved @lstsp2 + - De-interleaved unpacked @lstsp2 + - De-interleaved packed @lstsp1 + - Endianness: little, big + */ +#define MODULE_ID_SH_MEM_PULL_MODE 0x07001006 + +/*# @h2xmlm_module {"MODULE_ID_SH_MEM_PULL_MODE", + MODULE_ID_SH_MEM_PULL_MODE} + @h2xmlm_displayName {"Shared Memory Pull Mode Endpoint"} + @h2xmlm_modSearchKeys {software, source} + @h2xmlm_description {ID for the module that writes data to the SPF + from the host through a shared circular + buffer. \n + This module has only one static output port + with ID 1. For more details, see the + AudioReach Module User Guide + (80-VN500-4).} + @h2xmlm_dataMaxInputPorts {SH_MEM_PULL_MODE_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {SH_MEM_PULL_MODE_MAX_OUTPUT_PORTS} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC, APM_CONTAINER_TYPE_GC,APM_CONTAINER_TYPE_PTC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {SH_MEM_PULL_MODE_STACK_SIZE_REQUIREMENT} + @h2xmlm_toolPolicy {Calibration} + + @{ <-- Start of the Module --> + @h2xml_Select {"sh_mem_pull_push_mode_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"event_cfg_sh_mem_pull_push_mode_watermark_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"media_format_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"param_id_module_data_interleaving_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + + +/** @ingroup ar_spf_mod_ep_shmempp_mods + Identifier for the shared memory Push mode module, which reads data from + the SPF to the host through a shared circular buffer. + + This module has only one static input port with ID 2. + + @subhead4{Supported input media format ID} + - Data format : #DATA_FORMAT_FIXED_POINT @lstsp1 + - fmt_id : Don't care @lstsp1 + - Sample rates : 1..384 kHz @lstsp1 + - Number of channels: @lstsep + - 16 bits per sample in Q15 format @lstsp2 + - 24 bits per sample in Q23 format; 32 bits per sample in Q23, Q27, or + Q31 format @lstsp2 + - 32 bits per sample in Q31 format @lstsp1 + - Interleaving: @lstsep + - Interleaved @lstsp2 + - De-interleaved unpacked @lstsp2 + - De-interleaved packed @lstsp1 + - Endianness: little, big @newpage + */ +#define MODULE_ID_SH_MEM_PUSH_MODE 0x07001007 + +/*# @h2xmlm_module {"MODULE_ID_SH_MEM_PUSH_MODE", + MODULE_ID_SH_MEM_PUSH_MODE} + @h2xmlm_displayName {"Shared Memory Push-Mode Endpoint"} + @h2xmlm_modSearchKeys {software} + @h2xmlm_description {ID for the shared memory Push mode module, + which reads data from the SPF to the host + through a shared circular buffer. \n + This module has only one static input port + with ID 2. For more details, see the + AudioReach Module User Guide + (80-VN500-4).} + @h2xmlm_dataMaxInputPorts {SH_MEM_PUSH_MODE_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {SH_MEM_PUSH_MODE_MAX_OUTPUT_PORTS} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC, APM_CONTAINER_TYPE_GC,APM_CONTAINER_TYPE_PTC} + @h2xmlm_stackSize {SH_MEM_PUSH_MODE_STACK_SIZE_REQUIREMENT} + @h2xmlm_toolPolicy {Calibration} + + @{ <-- Start of the Module --> + @h2xml_Select {"sh_mem_pull_push_mode_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"event_cfg_sh_mem_pull_push_mode_watermark_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"sh_mem_push_mode_header_cfg_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> */ + + +#endif // _PULL_PUSH_MODE_API_H_ diff --git a/spf/api/modules/slimbus_api.h b/spf/api/modules/slimbus_api.h new file mode 100644 index 0000000..b3a1932 --- /dev/null +++ b/spf/api/modules/slimbus_api.h @@ -0,0 +1,175 @@ +/** + * \file slimbus_api.h + * \brief + * This file contains slimbus module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _SLIMBUS_API_H_ +#define _SLIMBUS_API_H_ + + /*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "hw_intf_cmn_api.h" + +/** @h2xml_title1 {SLIMBUS Module API} + @h2xml_title_agile_rev {SLIMBUS Module API} + @h2xml_title_date {29 Jan, 2019} */ + +/*============================================================================== + Constants +==============================================================================*/ +/** Sets SLIMbus device ID 1. */ +#define SLIMBUS_DEVICE_1 0x0 + +/** Sets SLIMbus device ID 2. */ +#define SLIMBUS_DEVICE_2 0x1 + +/** Enumeration for setting the maximum number of channels per device @newpage */ +#define SB_MAX_CHAN_CNT 8 + +#define CAPI_SLIMBUS_STACK_SIZE 4096 + +#define PARAM_ID_SLIMBUS_CONFIG 0x08001068 + + /** @h2xmlp_parameter {"PARAM_ID_SLIMBUS_CONFIG", + PARAM_ID_SLIMBUS_CONFIG} + @h2xmlp_description {Configures the SLIMBUS interface.} + @h2xmlp_toolPolicy {Calibration} + */ +/* Payload of the PARAM_ID_SLIMBUS_CONFIG parameter + */ +#include "spf_begin_pack.h" +struct param_id_slimbus_cfg_t +{ + uint32_t slimbus_dev_id; + /**< @h2xmle_description {ID of the SLIMbus hardware device. This ID is required to handle + multiple SLIMbus hardware blocks.} + @h2xmle_rangeList {"SLIMBUS_DEVICE_1"=0; + "SLIMBUS_DEVICE_2"=1} + @h2xmle_default {0} + */ + uint8_t shared_channel_mapping[SB_MAX_CHAN_CNT]; + /**< @h2xmle_description {Shared_channel_mapping[i] represents the shared channel assigned for + audio channel i in multichannel audio data. + Array of shared channel IDs (128 to 255) to which the master port + is connected.} + @h2xmle_range {128..255} + @h2xmle_default {128} + */ + +} +#include "spf_end_pack.h" +; +typedef struct param_id_slimbus_cfg_t param_id_slimbus_cfg_t; + + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/** Module ID for SLIMBUS sink module */ +/* + +*/ +#define MODULE_ID_SLIMBUS_SINK 0x07001029 +/** @h2xmlm_module {"MODULE_ID_SLIMBUS_SINK", + MODULE_ID_SLIMBUS_SINK} + @h2xmlm_displayName {"SLIMBus Sink"} + @h2xmlm_description {SLIMBUS Sink Module \n +* - Supports following params: \n +* - PARAM_ID_SLIMBUS_CONFIG \n +* - PARAM_ID_HW_EP_MF_CFG \n +* - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n +* +* Supported Input Media Format:\n +* - Data Format : SB_DATA_FORMAT_NOT_INDICATED, FIXED_POINT,\n +* - COMPR_OVER_PCM_PACKETIZED, GENERIC_COMPRESSED \n +* - fmt_id : Don't care\n +* - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n +* 88.2, 96, 176.4, 192, 352.8, 384 kHz\n +* - Number of channels : 1 to 8\n +* - Channel type : Don't care\n +* - Bit Width : 16 (bits per sample 16 and Q15),\n +* : 24 (bits per sample 24 and Q27)\n +* : 32 (bits per sample 32 and Q31) \n +* - Q format : Q15, Q27, Q31\n +* - Interleaving : Deinterleaved unpacked \n + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {CAPI_SLIMBUS_STACK_SIZE} + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_range {1..SB_MAX_CHAN_CNT} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"FIXED POINT"=1; + "COMPR OVER PCM PACKETIZED"=7; + "GENERIC COMPRESSED"=5} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_slimbus_cfg_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ +/** Module ID for SLIMBUS source module */ +#define MODULE_ID_SLIMBUS_SOURCE 0x0700102A +/** @h2xmlm_module {"MODULE_ID_SLIMBUS_SOURCE", + MODULE_ID_SLIMBUS_SOURCE} + @h2xmlm_displayName {"SLIMBus Source"} + @h2xmlm_description {SLIMBUS Source Module\n +* - Supports following params: \n +* - PARAM_ID_SLIMBUS_CONFIG \n +* - PARAM_ID_HW_EP_MF_CFG \n +* - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n +* - PARAM_ID_HW_EP_SRC_CHANNEL_MAP\n +- # Slimbus source doesn't take any inputs} + @h2xmlm_dataMaxInputPorts {0} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_stackSize {CAPI_SLIMBUS_STACK_SIZE} + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_range {1..8} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"FIXED POINT"=1; + "COMPR OVER PCM PACKETIZED" = 7; + "GENERIC COMPRESSED"=5} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_slimbus_cfg_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_ep_src_channel_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_src_channel_map_t::num_channels} + @h2xmle_range {0..8} + @} <-- End of the Module -->*/ + + +#endif // _SLIMBUS_API_H_ diff --git a/spf/api/modules/smart_sync_api.h b/spf/api/modules/smart_sync_api.h new file mode 100644 index 0000000..6516836 --- /dev/null +++ b/spf/api/modules/smart_sync_api.h @@ -0,0 +1,118 @@ +#ifndef _SMART_SYNC_API_H_ +#define _SMART_SYNC_API_H_ +/** + * \file smart_sync_api.h + * \brief + * This file contains Smart Sync module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "apm_graph_properties.h" + +/** @h2xml_title1 {Smart Sync Module API} + @h2xml_title_agile_rev {Smart Sync Module API} + @h2xml_title_date {June 06, 2018} */ + +/*============================================================================== + Defines +==============================================================================*/ + +#define SMART_SYNC_MAX_IN_PORTS 2 +#define SMART_SYNC_MAX_OUT_PORTS 2 + +#define SMART_SYNC_PRIMARY_IN_PORT_ID 0x2 +#define SMART_SYNC_PRIMARY_OUT_PORT_ID 0x1 + +#define SMART_SYNC_SECONDARY_IN_PORT_ID 0x4 +#define SMART_SYNC_SECONDARY_OUT_PORT_ID 0x3 + +#define SMART_SYNC_MAX_CHANNELS 8 + +#define SMART_SYNC_STACK_SIZE 4096 + +/*============================================================================== + API definitions +==============================================================================*/ + +/*============================================================================== + Param ID +==============================================================================*/ + +/* Custom param id to be sent by VCPM to set voice processing info of smart sync + * module. Voice processing info includes voc proc start tick, proc start samples and + * vfr cycle duration */ +#define PARAM_ID_SMART_SYNC_VOICE_PROC_INFO 0x08001027 + +/*============================================================================== + Type definitions +==============================================================================*/ +/* Structure defined for above Property */ +#include "spf_begin_pack.h" +struct smart_sync_voice_proc_info_t +{ + uint32_t is_subscribe; + /**< Flag to indicate whether to subscribe/unsubscribe with Voice Timer. */ + + uint32_t voice_proc_start_offset_us; + /**< voice processing start tick in microseconds */ + + uint32_t voice_proc_start_samples_us; + /**< minimum number of samples (in microseconds) required to start processing at + * voice processing start tick */ + + uint32_t vfr_cycle_duration_ms; + /**< vfr cycle duration in milliseconds + @values : {20, 40} */ + + uint32_t vsid; + /* TODO(CG): add comments for vsid and vfr mode */ + + uint32_t vfr_mode; + + uint32_t path_delay_us; +} +#include "spf_end_pack.h" +; + +typedef struct smart_sync_voice_proc_info_t smart_sync_voice_proc_info_t; + +#define MODULE_ID_SMART_SYNC 0x0700103C +/** @h2xmlm_module {"MODULE_ID_SMART_SYNC", MODULE_ID_SMART_SYNC} + @h2xmlm_displayName {"Smart Sync"} + @h2xmlm_description {- Voice call Synchronziation Module\n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT, \n + - fmt_id : MEDIA_FMT_ID_PCM \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1 to 8 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q31 \n + - Interleaving : Deinterleaved unpacked \n + - Endianess : little, big \n + - Primary and secondary ports are allowed to have different media formats. The only \n + - restriction is that if one port runs at a fractional rate, the other port must also \n + - run at a fractional rate (use cases where ports have variable input frame sizes are \n + - not supported).} + + @h2xmlm_dataMaxInputPorts {SMART_SYNC_MAX_IN_PORTS} + @h2xmlm_dataInputPorts {PRIMARY_IN = SMART_SYNC_PRIMARY_IN_PORT_ID; + SECONDARY_IN = SMART_SYNC_SECONDARY_IN_PORT_ID} + @h2xmlm_dataMaxOutputPorts {SMART_SYNC_MAX_OUT_PORTS} + @h2xmlm_dataOutputPorts {PRIMARY_OUT = SMART_SYNC_PRIMARY_OUT_PORT_ID; + SECONDARY_OUT = SMART_SYNC_SECONDARY_OUT_PORT_ID} + + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { SMART_SYNC_STACK_SIZE } + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + +#endif //_SMART_SYNC_API_H_ diff --git a/spf/api/modules/soft_pause_api.h b/spf/api/modules/soft_pause_api.h new file mode 100644 index 0000000..07a805a --- /dev/null +++ b/spf/api/modules/soft_pause_api.h @@ -0,0 +1,372 @@ +#ifndef _SOFT_PAUSE_API_H_ +#define _SOFT_PAUSE_API_H_ + +/*============================================================================== + @file soft_pause_api.h + @brief This file contains Soft pause module APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/* ========================================================================= + Edit History + + $Header: //components/rel/avs.spm_pp/1.0.15/volume_control/capi/soft_pause/api/soft_pause_api.h#1 $ + + when who what, where, why + -------- ------- ---------------------------------------------------- + 7/15/18 np Created file + ======================================================================== */ +// clang-format on + +/*------------------------------------------------------------------------ + Include files + -----------------------------------------------------------------------*/ +#include "module_cmn_api.h" + +/*# @h2xml_title1 {Soft Pause Module API} + @h2xml_title_agile_rev {Soft Pause Module API} + @h2xml_title_date {July 15, 2018} */ + +/*============================================================================== + Defines +==============================================================================*/ + +/** @ingroup ar_spf_mod_soft_pause_mod + Soft stepping linear ramping curve. */ +#define PARAM_PAUSE_RAMPINGCURVE_LINEAR 0 + +/** @ingroup ar_spf_mod_soft_pause_mod + Exponential ramping curve. */ +#define PARAM_PAUSE_RAMPINGCURVE_EXP 1 + +/** @ingroup ar_spf_mod_soft_pause_mod + Logarithmic ramping curve. */ +#define PARAM_PAUSE_RAMPINGCURVE_LOG 2 + +/** @ingroup ar_spf_mod_soft_pause_mod + Fractional exponent ramping curve. */ +#define PARAM_PAUSE_RAMPINGCURVE_FRAC_EXP 3 + +/** @ingroup ar_spf_mod_soft_pause_mod + Input port ID for the Soft Pause module. */ +#define PAUSE_DATA_INPUT_PORT 2 + +/** @ingroup ar_spf_mod_soft_pause_mod + Output port ID for the Soft Pause module. @newpage */ +#define PAUSE_DATA_OUTPUT_PORT 1 + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the Soft Pause module. + + @subhead4{Supported parameter IDs} + - #PARAM_ID_SOFT_PAUSE_RAMP_PARAMETERS @lstsp1 + - #PARAM_ID_SOFT_PAUSE_START @lstsp1 + - #PARAM_ID_SOFT_PAUSE_RESUME @lstsp1 + - #PARAM_ID_SOFT_PAUSE_RESUME_THRESHOLD @lstsp1 + - #PARAM_ID_SOFT_PAUSE_DOWNSTREAM_DELAY @lstsp1 + - #PARAM_ID_SOFT_PAUSE_RESUME_DEFERRED_RAMPUP + + @subhead4{Supported input media format ID} + - Data format : #DATA_FORMAT_FIXED_POINT @lstsp1 + - fmt_id : Don't care @lstsp1 + - Sample rates : Don't care @lstsp1 + - Number of channels: 1..128 (for certain products this module supports only 32 channels)@lstsp1 + - Channel type : 0..128 @lstsp1 + - Bits per sample : 16, 32 @lstsp1 + - Q format : Don't care @lstsp1 + - Interleaving : De-interleaved unpacked @lstsp1 + - Signed/unsigned : Signed +*/ +#define MODULE_ID_SOFT_PAUSE 0x07001019 + +/*# @h2xmlm_module {"MODULE_ID_SOFT_PAUSE", MODULE_ID_SOFT_PAUSE} + @h2xmlm_displayName {"Soft Pause"} + @h2xmlm_modSearchKeys {Audio} + @h2xmlm_description {ID for the Soft Pause module. For more + details, see AudioReach Signal Processing Framework (SPF) API Reference.} + @h2xmlm_dataInputPorts {IN = PAUSE_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT = PAUSE_DATA_OUTPUT_PORT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC,APM_CONTAINER_TYPE_SC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {4096} + + @{ <-- Start of the Module --> */ + +/*============================================================================== + API definitions +==============================================================================*/ + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the parameter that configures the ramp curve parameters for + pause, where: + - Period is the duration of the ramp. + - Step is the duration for which same gain is applied before + calculating next gain in the curve. + - Ramping curve is the shape of the curve (linear, exponential, + logarithmic, fractional exponent). + + This parameter is used to set ramp parameters or get ramp parameters. + + @msgpayload + pause_ramp_params_t +*/ +#define PARAM_ID_SOFT_PAUSE_RAMP_PARAMETERS 0x0800102D + +/*# @h2xmlp_parameter {"PARAM_ID_SOFT_PAUSE_RAMP_PARAMETERS", + PARAM_ID_SOFT_PAUSE_RAMP_PARAMETERS} + @h2xmlp_description {ID for the parameter that configures the ramp curve + parameters for pause. This parameter is used to set + ramp parameters or get ramp parameters. For more + details, see AudioReach Signal Processing Framework (SPF) API Reference.} + @h2xmlp_toolPolicy {RTC; Calibration} */ + +/** @ingroup ar_spf_mod_soft_pause_mod + Payload for the #PARAM_ID_SOFT_PAUSE_RAMP_PARAMETERS parameter. +*/ +#include "spf_begin_pack.h" +struct pause_ramp_params_t +{ + uint32_t period_ms_ramp_up; + /**< Duration of the up ramp. + + @values 0 through 15000 milliseconds */ + + /*#< @h2xmle_description {Duration of the up ramp specified in + milliseconds.} + @h2xmle_range {0..15000} + @h2xmle_default {0} */ + + uint32_t step_us_ramp_up; + /**< Duration for which a constant gain is applied before calculating the + next gain in the ramp up curve. + + @values 0 through 15000000 microseconds */ + + /*#< @h2xmle_description {Duration (in microseconds) for which a constant + gain is applied before calculating the next gain + in the ramp up curve.} + @h2xmle_range {0..15000000} + @h2xmle_default {0} */ + + uint32_t ramping_curve_ramp_up; + /**< Specifies ramp up of the ramping curve. + + @valuesbul + - #PARAM_PAUSE_RAMPINGCURVE_LINEAR (Default) + - #PARAM_PAUSE_RAMPINGCURVE_EXP + - #PARAM_PAUSE_RAMPINGCURVE_LOG + - #PARAM_PAUSE_RAMPINGCURVE_FRAC_EXP @tablebulletend */ + + /*#< @h2xmle_description {Specifies the ramp up of the ramping curve.} + @h2xmle_rangeList {"PARAM_PAUSE_RAMPINGCURVE_LINEAR" = 0; + "PARAM_PAUSE_RAMPINGCURVE_EXP" = 1; + "PARAM_PAUSE_RAMPINGCURVE_LOG" = 2; + "PARAM_PAUSE_RAMPINGCURVE_FRAC_EXP" = 3} + @h2xmle_default {0} */ + + uint32_t period_ms_ramp_down; + /**< Duration of the down ramp. + + @values 0 through 15000 milliseconds */ + + /*#< @h2xmle_description {Duration of the down ramp specified in + milliseconds.} + @h2xmle_range {0..15000} + @h2xmle_default {0} */ + + uint32_t step_us_ramp_down; + /**< Duration for which the same gain is applied before calculating the next + gain in the ramp down curve. + + @values 0 through 15000000 microseconds */ + + /*#< @h2xmle_description {Duration (in microseconds) for which the same gain + is applied before calculating the next gain in the + ramp down curve.} + @h2xmle_range {0..15000000} + @h2xmle_default {0} */ + + uint32_t ramping_curve_ramp_down; + /**< Specifies the ramp down of the ramping curve. + + @valuesbul + - #PARAM_PAUSE_RAMPINGCURVE_LINEAR (Default) + - #PARAM_PAUSE_RAMPINGCURVE_EXP + - #PARAM_PAUSE_RAMPINGCURVE_LOG + - #PARAM_PAUSE_RAMPINGCURVE_FRAC_EXP @tablebulletend */ + + /*#< @h2xmle_description {Specifies the ramp down of the ramping curve.} + @h2xmle_rangeList {"PARAM_PAUSE_RAMPINGCURVE_LINEAR" = 0; + "PARAM_PAUSE_RAMPINGCURVE_EXP" = 1; + "PARAM_PAUSE_RAMPINGCURVE_LOG" = 2; + "PARAM_PAUSE_RAMPINGCURVE_FRAC_EXP" = 3} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct pause_ramp_params_t pause_ramp_params_t; + + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the parameter used to signal a pause to start. */ +#define PARAM_ID_SOFT_PAUSE_START 0x0800102E + +/*# @h2xmlp_emptyParameter {"PARAM_ID_SOFT_PAUSE_START", + PARAM_ID_SOFT_PAUSE_START} + @h2xmlp_description {ID for the parameter used to signal a pause to + start.} + @h2xmlp_toolPolicy {Calibration} */ + + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the parameter used to signal a resume to start. @newpage */ +#define PARAM_ID_SOFT_PAUSE_RESUME 0x0800102F + +/*# @h2xmlp_emptyParameter {"PARAM_ID_SOFT_PAUSE_RESUME", + PARAM_ID_SOFT_PAUSE_RESUME} + @h2xmlp_description {ID for the parameter used to signal a resume to start.} + @h2xmlp_toolPolicy {Calibration} */ + + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the parameter that configures the threshold required for + a pause to resume. + + The threshold is an amplitude value in Q15 format. It is the minimum value + a sample should have to notify the module to start ramp up when it is in + the Pause state. + + @msgpayload + pause_resume_threshold_t +*/ +#define PARAM_ID_SOFT_PAUSE_RESUME_THRESHOLD 0x08001030 + +/*# @h2xmlp_parameter {"PARAM_ID_SOFT_PAUSE_RESUME_THRESHOLD", + PARAM_ID_SOFT_PAUSE_RESUME_THRESHOLD} + @h2xmlp_description {ID for the parameter that configures the threshold + required for a pause to resume. \n + The threshold is an amplitude value in Q15 format. It + is the minimum value a sample should have to notify + the module to start ramp up when it is in the Pause + state.} + @h2xmlp_toolPolicy {RTC; Calibration} */ + +/** @ingroup ar_spf_mod_soft_pause_mod + Payload of the #PARAM_ID_SOFT_PAUSE_RESUME_THRESHOLD parameter. +*/ +#include "spf_begin_pack.h" +struct pause_resume_threshold_t +{ + uint16_t threshold_Q15; + /**< Specifies the set or get resume threshold (in Q15 format). + + @values 0 through 32767 (Default = 0) @newpagetable */ + + /*#< @h2xmle_description {Specifies the set or get resume threshold (in Q15 + format).} + @h2xmle_range {0..32767} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct pause_resume_threshold_t pause_resume_threshold_t; + + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the parameter used to configure the downstream delay from + the stream to a device leg. + + @msgpayload + pause_downstream_delay_t +*/ +#define PARAM_ID_SOFT_PAUSE_DOWNSTREAM_DELAY 0x0800103E + +/*# @h2xmlp_parameter {"PARAM_ID_SOFT_PAUSE_DOWNSTREAM_DELAY", + PARAM_ID_SOFT_PAUSE_DOWNSTREAM_DELAY} + @h2xmlp_description {ID for the parameter used to configure the downstream + delay from the stream to a device leg.} + @h2xmlp_toolPolicy {RTC; Calibration} */ + +/** @ingroup ar_spf_mod_soft_pause_mod + Payload of the #PARAM_ID_SOFT_PAUSE_DOWNSTREAM_DELAY parameter. +*/ +#include "spf_begin_pack.h" +struct pause_downstream_delay_t +{ + uint32_t delay_ms; + /**< Specifies the downstream delay from the stream to the device leg. + + @values 0 through 65535 milliseconds (Default = 25) */ + + /*#< @h2xmle_description {Specifies the downstream delay from the stream to + the device leg (in milliseconds).} + @h2xmle_range {0..65535} + @h2xmle_default {25} */ +} +#include "spf_end_pack.h" +; +typedef struct pause_downstream_delay_t pause_downstream_delay_t; + + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the parameter that configures the ramp up delay. + + The module mutes the signal for delay_ms time before ramping up during + resume. + + @msgpayload + pause_rampup_delay_t +*/ +#define PARAM_ID_SOFT_PAUSE_RESUME_DEFERRED_RAMPUP 0x08001170 + +/*# @h2xmlp_parameter {"PARAM_ID_SOFT_PAUSE_RESUME_DEFERRED_RAMPUP", + PARAM_ID_SOFT_PAUSE_RESUME_DEFERRED_RAMPUP} + @h2xmlp_description {ID for the parameter that configures the ramp up + delay. The module mutes the signal for delay_ms time + before ramping up during resume.} + @h2xmlp_toolPolicy {RTC; Calibration} */ + +/** @ingroup ar_spf_mod_soft_pause_mod + Payload of the #PARAM_ID_SOFT_PAUSE_RESUME_DEFERRED_RAMPUP parameter. +*/ +#include "spf_begin_pack.h" +struct pause_rampup_delay_t +{ + uint32_t delay_ms; + /**< Specifies the time that the module mutes before ramping up during + resume. + + @values 0 through 1000 milliseconds */ + + /*#< @h2xmle_description {Specifies the time (in milliseconds) that the + module mutes before ramping up during resume.} + @h2xmle_range {0..1000} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct pause_rampup_delay_t pause_rampup_delay_t; + +/*# @} <-- End of the Module --> */ + + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the Pause Complete event that the Soft Pause module sends to + the client. */ +#define EVENT_ID_SOFT_PAUSE_PAUSE_COMPLETE 0x0800103F + +/** @ingroup ar_spf_mod_soft_pause_mod + Identifier for the Resume Complete event that the Soft Pause module sends + to the client. @newpage */ +#define EVENT_ID_SOFT_PAUSE_RESUME_COMPLETE 0x08001043 + + +#endif //_SOFT_PAUSE_API_H_ diff --git a/spf/api/modules/sound_dose_api.h b/spf/api/modules/sound_dose_api.h new file mode 100644 index 0000000..bdd43de --- /dev/null +++ b/spf/api/modules/sound_dose_api.h @@ -0,0 +1,211 @@ +#ifndef API_SOUND_DOSE_H +#define API_SOUND_DOSE_H +/*============================================================================== + @file sounddose_api.h + @brief This file contains SOUND DOSE API +==============================================================================*/ + +/*======================================================================= +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +* SPDX-License-Identifier: BSD-3-Clause +=========================================================================*/ +/*======================================================================== + Edit History + + when who what, where, why + -------- --- ------------------------------------------------------- + 22/08/2024 sreegr Created File. + ========================================================================== */ + + /*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "module_cmn_api.h" +/*============================================================================== + Constants +==============================================================================*/ +#define CAPI_SOUND_DOSE_STACK_SIZE 2048 +#define MODULE_ID_SOUND_DOSE 0x17030FFF +/** + @h2xml_title1 {Sound Dose API} + @h2xml_title_agile_rev {Sound Dose API} + @h2xml_title_date {August 01 , 2024} + */ + +/** + @h2xmlm_module {"MODULE_ID_SOUND_DOSE", + MODULE_ID_SOUND_DOSE} + @h2xmlm_displayName {"Sound Dose"} + @h2xmlm_toolPolicy {Calibration} + @h2xmlm_description {Mel Value calculation from the audio input to control the sound pressure exposure\n +* - This module supports the following parameter IDs: \n +* - #PARAM_ID_SOUND_DOSE_MEL_EVENTS_CONFIG \n +* - #PARAM_ID_SOUND_DOSE_RS2_UPPER_BOUND \n +* - #PARAM_ID_SOUND_DOSE_MEL_TIMESTAMP_INFO \n +* +* Supported Input Media Format:\n +* - Data Format : FIXED_POINT\n +* - fmt_id : Don't care\n +* - Sample Rates : 44100,48000\n +* - Number of channels : 1 , 2 \n +* - Channel type : 1 to 63\n +* - Bits per sample : 16, 32\n +* - Q format : 15, 27, 31\n +* - Interleaving : de-interleaved unpacked\n +* - Signed/unsigned : Signed } + + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC, APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {CAPI_SOUND_DOSE_STACK_SIZE} + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> +*/ + +/** Param ID of the time interval in which mel values to be raised to client */ +#define PARAM_ID_SOUND_DOSE_MEL_EVENTS_CONFIG 0x18030FFA +/** @h2xmlp_parameter {"PARAM_ID_SOUND_DOSE_MEL_EVENTS_CONFIG", + PARAM_ID_SOUND_DOSE_MEL_EVENTS_CONFIG} + @h2xmlp_description {This parameter used to configure the time interval + in which event to be raised to client.} + @h2xmlp_toolPolicy {CALIBRATION}*/ + + +typedef struct param_id_sounddose_mel_events_config{ + uint32_t mel_event_interval_in_sec; + /**< @h2xmle_description {The period in which the new MEL values will be communicated to the client. + } + @h2xmle_default {0xA} + @h2xmle_range {0x1..0xA} */ +}param_id_sounddose_mel_events_config; + +/** Param ID of RS2 Upper bound used for momentary exposure detection */ +#define PARAM_ID_SOUND_DOSE_RS2_UPPER_BOUND 0x18030FFB +/** @h2xmlp_parameter {"PARAM_ID_SOUND_DOSE_RS2_UPPER_BOUND", + PARAM_ID_SOUND_DOSE_RS2_UPPER_BOUND} + @h2xmlp_description {parameter used to configure the RS2 upper bound for momentary exposure.} + @h2xmlp_toolPolicy {CALIBRATION,RTC}*/ + +typedef struct param_id_sounddose_rs2_upper_bound{ + uint32_t rs2_upper_bound; + /**< @h2xmle_description {RS2 upper bound value above which the momentary exposure warning to be raised } + @h2xmle_dataFormat {Q22} + @h2xmle_default {0x19000000} */ +}param_id_sounddose_rs2_upper_bound; + +/** Param ID related to the timestamp info attached to the mel values */ +#define PARAM_ID_SOUND_DOSE_MEL_TIMESTAMP_INFO 0x18030FFC +/** @h2xmlp_parameter {"PARAM_ID_SOUND_DOSE_MEL_TIMESTAMP_INFO", + PARAM_ID_SOUND_DOSE_MEL_TIMESTAMP_INFO} + @h2xmlp_description {parameter used to configure the timestamp info attached to event. + Absolute TS is used when the module is in the real time section of the graph and + Relative TS is to be used if the module is kept in the non RT section} + @h2xmlp_toolPolicy {CALIBRATION}*/ + +typedef struct param_id_sounddose_mel_timestamp_info{ + uint32_t timestamp_info; + /**< @h2xmle_description {This field is regarding the timestamp value + * attached to the mel values. The client can communicate whether it is expecting + * absolute or relative timestamp. + } + @h2xmle_rangeList { "Absolute TS" = 0 ; "Relative TS " = 1} + @h2xmle_default {0x0} */ +}param_id_sounddose_mel_timestamp_info; + + +/** Event ID of the events raised to client for momentary exposure or new mel values*/ +#define EVENT_ID_SOUND_DOSE_MEL_VALUES 0x18030FFE +/** @h2xmlp_parameter {"EVENT_ID_SOUND_DOSE_MEL_VALUES", + EVENT_ID_SOUND_DOSE_MEL_VALUES} + @h2xmlp_description {New Mel Values or Momentary exposure event raised by sound dose module} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +#include "spf_begin_pragma.h" +typedef struct event_id_sound_dose_mel_values{ + uint32_t is_momentary_exposure_raised; + /**< @h2xmle_description {Flag to indicate whether the event is related to momentary exposure or new mel values + 1 means the event is related to momentary exposure and 0 indicates the event is related to new mel values} + */ + + uint32_t num_mel_values; + /**< @h2xmle_description {The number of mel values included in the event raised to HLOS + } + @h2xmle_default {0xA} */ + + float mel_value[0]; + /**< @h2xmle_description {The mel values calculated in the ADSP is kept in this section} + * @h2xmle_variableArraySize {max_num_mel_values} + */ + + uint32_t timestamp_mel_value[0]; + /**< @h2xmle_description {The timestamp associated with mel value are kept in this section + * The timestamp at which each mel value is generated is captured. + * The 64 bit timestamp value is split into two 32 bit values and stored consecutively. + * For example, the first item in this section is the LSB of the 64 bit timestamp associated with first mel value + * The second item is the MSB of the 64 bit timestamp associated with first mel value. + * Timestamp for the other mel values will be in the same order} + * @h2xmle_variableArraySize {max_num_mel_values} + */ +}event_id_sound_dose_mel_values; +#include "spf_end_pragma.h" + + +#define PARAM_ID_SOUND_DOSE_FLUSH_MEL_VALUES 0x18030FFD +/** @h2xmlp_parameter {"PARAM_ID_SOUND_DOSE_FLUSH_MEL_VALUES", + PARAM_ID_SOUND_DOSE_FLUSH_MEL_VALUES} + @h2xmlp_description {This get param is used to get the accumulated mel values at the end of the use case} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ +#include "spf_begin_pragma.h" +typedef struct param_id_sounddose_flush_mel_values{ + uint32_t num_mel_values; + /**< @h2xmle_description {The number of mel values included in the get param + } + @h2xmle_default {0xA} */ + + float mel_value[0]; + /**< @h2xmle_description {The mel values accumulated in the ADSP + * after the last event has been raised} + * @h2xmle_variableArraySize {num_mel_values} + */ + + uint32_t timestamp_mel_value[0]; + /**< @h2xmle_description {The timestamp associated with mel value are kept in this section + * The timestamp at which each mel value is generated is captured. + * The 64 bit timestamp value is split into two 32 bit values and stored consecutively. + * For example, the first item in this section is the LSB of the 64 bit timestamp associated with first mel value + * The second item is the MSB of the 64 bit timestamp associated with first mel value. + * Timestamp for the other mel values will be in the same order} + * @h2xmle_variableArraySize {num_mel_values} + */ +}param_id_sounddose_flush_mel_values; +#include "spf_end_pragma.h" + + +/** + @h2xml_Select {param_id_module_enable_t} + @h2xmlm_InsertParameter +*/ +/** + @h2xml_Select {param_id_sounddose_mel_events_config} + @h2xmlm_InsertParameter +*/ + +/** + @h2xml_Select {param_id_sounddose_rs2_upper_bound} + @h2xmlm_InsertParameter +*/ + +/** + @h2xml_Select {param_id_sounddose_mel_timestamp_info} + @h2xmlm_InsertParameter +*/ + +/** + @h2xml_Select {param_id_sounddose_flush_mel_values} + @h2xmlm_InsertParameter +*/ + +/** @} <-- End of the Module -->*/ +#endif //API_SOUND_DOSE_H diff --git a/spf/api/modules/sp_dc_api.h b/spf/api/modules/sp_dc_api.h new file mode 100644 index 0000000..2916b77 --- /dev/null +++ b/spf/api/modules/sp_dc_api.h @@ -0,0 +1,27 @@ +/** + * \file sp_dc_api.h + * \brief + * This file contains DTMF Detection Event api + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SP_API_H +#define SP_API_H + +#include "ar_defs.h" + +#define EVENT_ID_SP_DC_DETECTION 0x0800119C + +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_SP_DC_DETECTION", + EVENT_ID_SP_DC_DETECTION} + @h2xmlp_description { Direct Current Detection event raised by the Speaker Protection Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + +#endif diff --git a/spf/api/modules/sp_rx.h b/spf/api/modules/sp_rx.h new file mode 100644 index 0000000..1888798 --- /dev/null +++ b/spf/api/modules/sp_rx.h @@ -0,0 +1,3122 @@ +#ifndef __SP_RX_H__ +#define __SP_RX_H__ + +/*============================================================================== + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + + @file sp_rx.h + @brief This file contains APIs for Speaker Protection Module +==============================================================================*/ + +/** @h2xml_title1 {Speaker Protection} + @h2xml_title_date {January 7, 2022} */ +#include "module_cmn_api.h" +#include "ar_defs.h" +#include "imcl_spm_intent_api.h" +#include "rtm_logging_api.h" + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ +#define SP_MAX_INPUT_PORTS 1 +#define SP_MAX_OUTPUT_PORTS 1 +#define SP_STACK_SIZE 16384 + +/* Unique Module ID */ +#define MODULE_ID_SPEAKER_PROTECTION_V7 0x0701000F + +/** @h2xmlm_module {"MODULE_ID_SPEAKER_PROTECTION_V5", + MODULE_ID_SPEAKER_PROTECTION_V5} + @h2xmlm_displayName {"Speaker Protection v5"} + @h2xmlm_toolPolicy {Calibration;CALIBRATION} + @h2xmlm_description {ID of the Speaker Protection v5 module.\n + this module implements algorithms to ensure that speakers arent + damaged when some music is played. + + This module supports the following parameter IDs:\n + - #PARAM_ID_MODULE_ENABLE \n + - #PARAM_ID_SP_STATIC_CFG\n + - #PARAM_ID_SP_OP_MODE\n + - #PARAM_ID_SP_TRANSITION_ASP_ENABLE\n + - #PARAM_ID_SP_TRANSITION_ASP_CALIB_PARAM\n + - #PARAM_ID_SPv5_SP_DYNAMIC_CFG\n \\Todo: rename this and also in VI + - #PARAM_ID_SP_TH_DEMO_CFG\n + - #PARAM_ID_SP_EX_DEMO_CFG\n + - #PARAM_ID_SP_TH_STATS\n + - #PARAM_ID_SP_EX_STATS\n + - #PARAM_ID_SP_STATS\n + - #PARAM_ID_SP_TMAX_XMAX_LOGGING\n + - #PARAM_ID_SP_VERSION\n + - #PARAM_ID_RTM_LOGGING_ENABLE\n + - #PARAM_ID_SP_TH_PI_DERV_CTRL_CFG\n + - #PARAM_ID_SP_CPS_STATIC_CFG\n + - #PARAM_ID_SPKR_PROT_EX_CPS_DEMO_CFG\n + - #PARAM_ID_SPKR_PROT_RX_EX_CPS2_BATTCONFIG_LFATTEN_PARAM\n + - #PARAM_ID_SPKR_PROT_EX_RX_CPS2_PARAM\n + - #PARAM_ID_SPKR_PROT_EX_RX_CPS_BOOSTOPERATION_PARAM\n + - #PARAM_ID_SPKR_PROT_CPSBASIC_CFG\n + - #PARAM_ID_CPS_LPASS_HW_INTF_CFG\n + - #PARAM_ID_CPS_LPASS_SWR_THRESHOLDS_CFG\n + - #PARAM_ID_RX_CPS_FINE_PARAM\n + - #PARAM_ID_SP_EX_CPS_STATS\n + - #PARAM_ID_SPKR_PROT_EX_RX_CPS2_DEMO_PKT_PARAM\n + - #PARAM_ID_SPKR_PROT_EX_RX_CPS2_DEMO_PARAM\n + - #PARAM_ID_SPKR_PROT_EX_RX_CPS3_DEMO_PKT_PARAM\n + - #PARAM_ID_SPKR_PROT_EX_RX_CPS3_DEMO_PARAM\n + - #PARAM_ID_SPKR_PROT_T0_CALI_PARAM\n + - #PARAM_ID_SPKR_PROT_EX_RX_BATTTEMP_DATA_PARAM\n + - #PARAM_ID_SPKR_PROT_DYNAMIC_NOTCH_PARAM\n + - #PARAM_ID_SPKR_PROT_LIN_RX_DYNAMIC_CFG\n + - #PARAM_ID_SPKR_PROT_SPEAKERS_LINK_MODE_PARAM\n + - #PARAM_ID_SP_EX_RX_POWLIM_MODE2_CFG_PARAM\n + - #PARAM_ID_SPv5_SP_TMAX_XMAX_LOGGING_EXTN\n + + + + All parameter IDs are device independent.\n + + Supported Input Media Format:\n +* - Data Format : FIXED_POINT\n +* - fmt_id : Don't care\n +* - Sample Rates : 48000\n +* - Number of channels : 1 to 8\n +* - Channel type : 1 to 63\n +* - Bits per sample : 16, 24 \n +* - Q format : 15 for bps = 16 and 27 for bps = 24\n +supported bps +* - Interleaving : de-interleaved unpacked\n +* - Signed/unsigned : Signed } + + @h2xmlm_toolPolicy {Calibration} + + @h2xmlm_dataMaxInputPorts {SP_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {SP_MAX_OUTPUT_PORTS} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {SP_STACK_SIZE} + @h2xmlm_ctrlDynamicPortIntent { "SP VI intent id for communicating Vsens and Isens data" = INTENT_ID_SP, +maxPorts= 1 } + @h2xmlm_ctrlDynamicPortIntent { "SP CPS intent id for communicating CPS data" = INTENT_ID_CPS, maxPorts= 1 } + @h2xmlm_ToolPolicy {Calibration} + + + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + + @h2xml_Select {"rtm_logging_enable_payload_t"} + @h2xmlm_InsertParameter +*/ +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ + +/* Maximum number of speakers supported in speaker protection Rx + processing. */ +#define SP_NUM_MAX_SPKRS 8 + +/* Maximum number of stages in the notch filter. */ +#define SP_NCH_FILT_STAGES_MAX 5 + +/* Number of plotting samples in one thermal Rx output packet. */ +#define SP_TH_RX_DEMO_SMPL_PER_PKT 10 + +/* Number of plotting samples in one excursion Rx output packet. */ +#define SP_EX_RX_DEMO_SMPL_PER_PKT 10 + +/* Maximum number of stages in the IIR filter. */ +#define SP_IIR_TDF2_STAGES_MAX 5 + +/* Number of numerators per stage in the IIR filter. */ +#define SP_IIR_TDF2_NUM_NUM_PER_STAGE 3 + +/* Number of denominators per stage in the IIR filter. */ +#define SP_IIR_TDF2_NUM_DEN_PER_STAGE 2 + +/* Maximum number of samples per packet. */ +#define MAX_SAMPLES_IN_PACKET 480 + +/* Max number of vbatt resistance table */ +#define SP_NVBATT_DISCRETE 9 + +/* Max number of die temp resistance table */ +#define SP_NDTEMP_DISCRETE 14 + +/* Max number of vbatt fine resistance table */ +#define SP_NVBATT_DISCRETE_FINE (13) + +/* LPASS CPS HW INTF TYPE*/ +#define SOUNDWIRE_MODE 1 + +/* LPASS CPS HW INTF TYPE*/ +#define DMA_MODE 2 + +#define MAX_CPS_BOOST_INDUCTOR_CURRENT_SAMPLES_IN_PACKET_48K (4800) +#define MAX_CPS_BOOST_INDUCTOR_CURRENT_SAMPLES_IN_PACKET_96K (9600) +#define MAX_CPS_BOOST_INDUCTOR_CURRENT_SAMPLES_IN_PACKET_192K (19200) + +#define SP_NILIM_DISCRETE (11) + +#define FIR_LEN_MAX (385) + +#define N_VPH_RANGE (25) + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_STATIC_CFG 0x08001B3C + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_static_cfg_t param_id_sp_static_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_STATIC_CFG", + PARAM_ID_SP_STATIC_CFG} + @h2xmlp_description {parameter used to configure the static configuration of + speaker protection processing.} + @h2xmlp_toolPolicy {CALIBRATION; RTC_READONLY}*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_static_cfg_t +{ + uint32_t sampling_rate; // PCM signal sampling rate + /**< @h2xmle_description {Sampling rate of Rx signal.} + @h2xmle_rangeList {"48kHz"=48000} + @h2xmle_default {48000} */ + uint32_t bits_per_sample; // Number of bits for input and output samples, (per channel) + /**< @h2xmle_description {Bits per sample for Rx signal.} + @h2xmle_rangeList {"16"=16;"24"=24} + @h2xmle_default {16} */ + uint32_t num_speakers; // Number of speakers + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + uint32_t frame_size_ms; // processing frame size in ms + /**< @h2xmle_description {Frame size for Rx processing.} + @h2xmle_rangeList {"1ms"=1} + @h2xmle_default {1} */ + uint32_t features; // what sub-features are on + /**< @h2xmle_description {Features enabled in the speaker protection + algorithm.} + @h2xmle_range {0..0x1f} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Notch high-pass filter"} + @h2xmle_description {Notch high-pass filter} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_group {HPF} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Thermal protection"} + @h2xmle_description {Thermal protection} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000004} + @h2xmle_bitName {"Feedback excursion control"} + @h2xmle_description {Feedback excursion control} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_group {Excursion_Control} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000008} + @h2xmle_bitName {"Account for dc in excursion prediction/control"} + @h2xmle_description {Feedback voice-coil offset control} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {1} + @h2xmle_group {Excursion_Control} //todo: check once on this grouping field. + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000010} + @h2xmle_bitName {"Feedback dc control"} + @h2xmle_description {Feedback voice-coil offset control} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_group {DC} + @h2xmle_default {1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000020} + @h2xmle_bitName {"Reserved bits"} + @h2xmle_description {any bit field from 0x00000020 to 0xfffffff8 is reserved for future use.} + @h2xmle_default {0} + @h2xmle_visibility {hide} + @h2xmle_readOnly {true} + @h2xmle_bitFieldEnd*/ + + + uint32_t tuning_mode_en_flag; // indicates whether tuning mode is enabled (1) or disabled (0) + /**< @h2xmle_description {Specifies whether RTM tuning mode is enabled.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} */ + uint32_t ctrl_rate; // thermal control rate (Hz) + /**< @h2xmle_description {Thermal control rate.} + @h2xmle_rangeList {"1000Hz"=1000} + @h2xmle_default {1000} */ + uint32_t num_nch_filter_stages; // number of NOTCH filter stages + /**< @h2xmle_description {Number of notch filter stages.} + @h2xmle_range {0..SP_NCH_FILT_STAGES_MAX} + @h2xmle_default {2} */ + + int16_t temp_loop_dly_ms; // loop delay from predicted temp to temp info coming back + /**< @h2xmle_description {Loop delay from the predicted temperature to the + temperature information coming back.} + @h2xmle_range {0..1000} + @h2xmle_default {120} */ + int16_t pow_est_smooth_flag; // indicates whether or not do IIR filtering, to smooth out power estimation + /**< @h2xmle_description {Specifies whether to use IIR filtering to smooth the + power estimation.} + @h2xmle_rangeList {"Do not use IIR filtering"=0; + "Use IIR filtering"=1} + @h2xmle_default {1} */ + + uint16_t pt_lvl_switch_en; // dynamic pilot tone level switch enable/disable flag + /**< @h2xmle_description {Specifies whether to enable the dynamic pilot tone + level switch.} + @h2xmle_rangeList {disabled=0;enabled=1} + @h2xmle_default {0} */ + uint16_t pt_masking_delay_ms; // delay in ramping down pilot tone in ms + /**< @h2xmle_description {Delay in ramping down the pilot tone.} + @h2xmle_range {0..1000} + @h2xmle_default {13} */ + int32_t pt_masking_thr_q27; // when input level is below this threshold, pilot tone is disabled + /**< @h2xmle_description {Specifies the input level threshold below which the + pilot tone is disabled.} + @h2xmle_range {0..134217727} + @h2xmle_dataFormat {Q27} + @h2xmle_default {189813} */ + int32_t hist_buf_length; + /**< @h2xmle_description {history buffer length in msec for excursion and power control} + @h2xmle_range {4..12} + @h2xmle_default {8} */ + int32_t rx_static_gain_q27; + /**< @h2xmle_description {Gain to be applied to RX signal before speaker protection in linear scale} + @h2xmle_range {33713968..534330399} + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728} */ + int32_t dyn_proc_delay_ms; // dyn_proc delay in millisecond (Q0) + /**< @h2xmle_description {delay in dynamic processing in msec to compensate analysis filter delay} + @h2xmle_range {0..10} ms + @h2xmle_default {0} */ + uint32_t log_dump_en_flag; // indicates whether dumping maximum excursion and temperature data or not; enable(1)/disable(0); enforce to enable tuning_mode_en_flag if this flag is enabled. + /**< @h2xmle_description {Flag to enable/disable logging maximum excursion and temperature data} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {0} */ + uint32_t logging_count_period; // duration of monitoring Xmax/Tmax to increase counter in msec + /**< @h2xmle_description {Duration of monitoring Xmax/Tmax to increase counter in msec} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {2000} */ + uint32_t fpilot; // Pilot tone frequencies [16, 40] 16Hz or 40 Hz. + // Note: Pilot tone frequency values MUST be the same for the RX/TH/EX modules. + /**< @h2xmle_description {Pilot tone frequencies. Pilot tone frequency values MUST be the same for the RX/TH/EX modules} + @h2xmle_rangeList {"16"=16; "40"=40} + @h2xmle_default {40} */ + + uint32_t cps_sampling_rate; + /**< @h2xmle_description {CPS sampling rate for DMA/Pandeiro} + @h2xmle_rangeList {"24000"=24000; "48000"=48000} + @h2xmle_default {48000} */ + + uint32_t chip; + /**< @h2xmle_description {attached WSA 88xx} + @h2xmle_rangeList {"884x"=0; "885x"=1} + @h2xmle_default {0} */ + + uint32_t cps_mode_flag; //reserved for future + /**< @h2xmle_description {Flag to enable/disable limiter based on Vbatt/DieTemp} + @h2xmle_rangeList {"disabled"=0; "enabled"=1; "LFSN bass shelf"=2; "6dB attenuation at low-die-temperature"=3; "CPSv2.0 with Predictive boost"=4; "CPSv2.0 without Predictive boost"=5; "CPS-bypass"=6; "Phy model single"=7; "Phy model shared"=8; "CPS-basic-single"=9; "CPS-basic-stereo"=10} + @h2xmle_default {0}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_CPS_STATIC_CFG 0x08001B3D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_cps_static_cfg_t param_id_sp_cps_static_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_CPS_STATIC_CFG", + PARAM_ID_SP_CPS_STATIC_CFG} + @h2xmlp_description {parameter used to configure the static cps configuration of + speaker protection processing.} + @h2xmlp_toolPolicy {Calibration;RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_cps_static_cfg_t +{ + uint16_t limiter_cps_en_flag; // flag that activates the limiter based on the Vbatt/Die Temp values. enable (1)/disable(0)/ LFSNshelf (2)/fullband Attenuation at low die temp (3). + /**< @h2xmle_description {Flag to enable/disable limiter based on Vbatt/DieTemp} + @h2xmle_rangeList {"disabled"=0; "enabled"=1; "LFSN bass shelf"=2; "6dB attenuation at low-die-temperature"=3; "CPSv2.0" = 4} + @h2xmle_default {0} + @h2xmle_group {Limiter}*/ + + uint16_t limiter_cps_smooth_VbDT_en_flag; // flag that activates the smoothing operator on the CPS limiter applied to Vbatt/DieTemp. enable (1)/disable(0). + /**< @h2xmle_description {Flag that activates the smoothing operator on the CPS limiter applied to Vbatt/DieTemp} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {0} */ + + + int32_t limiter_cps_margin_dB_q15; // dB margin about the limiter gain based on the Vbatt/Die Temp values. //{-3dB to 3dB} + /**< @h2xmle_description {margin in dB about the limiter gain based on Vbatt/DieTemp} + @h2xmle_range {-98304..98304} + @h2xmle_dataFormat {Q15} + @h2xmle_default {0} */ + + int32_t FourOhmTable_GaindB_q24[SP_NDTEMP_DISCRETE * SP_NVBATT_DISCRETE]; //{-9dB to 21dB} + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp.} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmlx_expandArray {true} + @h2xmle_defaultFile {sp_fourOhmGain.bin} + @h2xmle_policy {Advanced} */ + + int32_t SixOhmTable_GaindB_q24[SP_NDTEMP_DISCRETE * SP_NVBATT_DISCRETE];//{-9dB to 21dB} + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp.} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmlx_expandArray {true} + @h2xmle_defaultFile {sp_sixOhmGain.bin} + @h2xmle_policy {Advanced} */ + + int32_t EightOhmTable_GaindB_q24[SP_NDTEMP_DISCRETE * SP_NVBATT_DISCRETE];//{-9dB to 21dB} + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp.} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmlx_expandArray {true} + @h2xmle_defaultFile {sp_eightOhmGain.bin} + @h2xmle_policy {Advanced} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +#define CPS_NUM_VBATT_THRESHOLD_VALUES 3 + + + +/* Unique Parameter id */ +#define PARAM_ID_SP_EX_CPS_DEMO_CFG 0x08001B3E + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_cps_demo_cfg_t param_id_sp_ex_cps_demo_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_CPS_DEMO_CFG", + PARAM_ID_SP_EX_CPS_DEMO_CFG} + @h2xmlp_description {parameter used for setting the algorithm internal + variables related to ex cps demo rtm configuration.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_cps_demo_cfg_t +{ + uint16_t dsr; + /**< @h2xmle_description {downsample ratio from internal values to output.} + @h2xmle_default {10} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_CPS_STATS 0x08001B3F //todo:ms13 update this in ccb as well +/*============================================================================== + Type definitions +==============================================================================*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_ex_rx_cps_param_t +{ + int32_t Vbatt_rt_q24[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Battery Voltage in volts} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ + int32_t DieTemp_rt_q20[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {die temperature in degree C} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q20} */ + int32_t dB_cps_Gain_rt_q24[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {cps gain in dB} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sp_ex_rx_cps_param_t sp_ex_rx_cps_param_t; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_cps_stats_t param_id_sp_ex_cps_stats_t; +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_CPS_STATS", + PARAM_ID_SP_EX_CPS_STATS} + @h2xmlp_description {parameter used for RTM of the algorithm internal + variables related to ex cps processing.} + @h2xmlp_toolPolicy {RTM} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_cps_stats_t +{ + uint32_t frame_duration_in_ms; + /**< @h2xmle_description {Frame duration in milliseconds for Excursion cps Rx + statistics.} */ + + uint32_t frame_num; + /**< @h2xmle_description {Frame number of the Excursion Rx statistics.} */ + // CPS params + + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ +#ifdef __H2XML__ + // demo packet for CPS + sp_ex_rx_cps_param_t ex_rx_cps_demo_param[0]; + /**< @h2xmle_description {structure containing speaker params for CPS in Rx Excursion Control block} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_OP_MODE 0x08001B40 +/* unique param id for spv5 */ +#define PARAM_ID_SP_OP_MODE_V5 0x080011E9 + + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_op_mode_t param_id_sp_op_mode_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_OP_MODE", + PARAM_ID_SP_OP_MODE} + @h2xmlp_description {parameter used to configure the mode of feedback + speaker protection processing} + @h2xmlp_toolPolicy {NO_SUPPORT} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_op_mode_t +{ + uint32_t operation_mode; // normal running or thermal calibration + /**< @h2xmle_description {Operation mode of thermal VI module.} + @h2xmle_rangeList {"Normal Running mode"=0; + "Calibration mode"=1; + "Factory Test Mode"=2; + "V-Validation Mode"=3} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TRANSITION_ASP_ENABLE 0x08001B41 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_transition_asp_enable_t param_id_sp_transition_asp_enable_t; +/** @h2xmlp_parameter {"PARAM_ID_SP_TRANSITION_ASP_ENABLE", + PARAM_ID_SP_TRANSITION_ASP_ENABLE} + @h2xmlp_description {parameter used to enable transition acoustic shock protection + feature.} + @h2xmlp_toolPolicy {CALIBRATION; RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_transition_asp_enable_t +{ + uint32_t trans_asp_mode; // transition acoustic shock protection mode (0-disable, 1-enable) + /**< @h2xmle_description {flag for transition acoustic shock protection mode} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TRANSITION_ASP_CALIB_PARAM 0x08001B42 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_transition_asp_calib_param_t param_id_sp_transition_asp_calib_param_t; +/** @h2xmlp_parameter {"PARAM_ID_SP_TRANSITION_ASP_CALIB_PARAM", + PARAM_ID_SP_TRANSITION_ASP_CALIB_PARAM} + @h2xmlp_description {parameter used for logging the algorithm internal + variables.} + @h2xmlp_toolPolicy {CALIBRATION; RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_transition_asp_calib_param_t +{ + uint32_t initial_target_gain; // initial linear target gain in Q28 + /**< @h2xmle_description {Initial linear target gain in Q28 + default: 7.199 (in decimal) + Range: 0 - 7.999 (in decimal)} + @h2xmle_range {0..2147483647} + @h2xmle_default {1932735283} + @h2xmle_dataFormat {Q28} */ + uint32_t initial_target_gain_period_in_msec; // time period in which target gain remain still as initial target gain in milisecond (Q0) + /**< @h2xmle_description {Time period in which target gain remain still as initial target gain in millisecond (Q0)} + @h2xmle_range {0..2147483647} + @h2xmle_default {2000} + @h2xmle_dataFormat {Q0} */ + uint32_t rampup_transition_time_in_msec; // ramp up transition time from initial linear gain to gain 0dB in milisecond (Q0) + /**< @h2xmle_description {Ramp up transition time from initial linear gain to gain 0dB in millisecond (Q0)} + @h2xmle_range {0..2147483647} + @h2xmle_default {1000} + @h2xmle_dataFormat {Q0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPv5_SP_DYNAMIC_CFG 0x08001B43 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Notch Dyanmic Config structure payload */ +typedef struct sp_rx_nch_filt_param_t sp_rx_nch_filt_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_rx_nch_filt_param_t +{ + int32_t num[SP_NCH_FILT_STAGES_MAX * SP_IIR_TDF2_NUM_NUM_PER_STAGE]; + /**< @h2xmle_description {Numerator coefficients for notch filter + configuration.} + @h2xmle_defaultList {1055533754, -2111067576, 1055533762, + 1073741824, -2147483582, 1073741815, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0} */ + + int32_t den[SP_NCH_FILT_STAGES_MAX * SP_IIR_TDF2_NUM_DEN_PER_STAGE]; + /**< @h2xmle_description {Denominator coefficients for notch filter + configuration.} + @h2xmle_defaultList {-2121642205, 1048082161, + -2136597088, 1063038326, + 0, 0, + 0, 0, + 0, 0} */ + + int16_t num_q[SP_NCH_FILT_STAGES_MAX]; + /**< @h2xmle_description {Q factor of numerator coefficients for notch filter + configuration.} + @h2xmle_defaultList {1, 1, 0, 0, 0} */ + + int16_t den_q[SP_NCH_FILT_STAGES_MAX]; + /**< @h2xmle_description {Q factor of denominator coefficients for notch + filter configuration.} + @h2xmle_defaultList {1, 1, 0, 0, 0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* tdf2 configuration structure for RX_EX Dynamic config. */ +typedef struct sp_tdf2_cfg_t sp_tdf2_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_tdf2_cfg_t +{ + int16_t numCh; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {2} */ + int16_t stages; + /**< @h2xmle_description {Number of stages.} + @h2xmle_range {1..5} + @h2xmle_default {1} */ + int32_t num[SP_IIR_TDF2_STAGES_MAX*SP_IIR_TDF2_NUM_NUM_PER_STAGE]; // numerator coefficients + /**< @h2xmle_description {Numerator coefficients.} + @h2xmle_defaultList {1073741824,0,0, + 0,0,0, + 0,0,0, + 0,0,0, + 0,0,0} */ + int32_t den[SP_IIR_TDF2_STAGES_MAX*SP_IIR_TDF2_NUM_DEN_PER_STAGE]; // denominator coefficients + /**< @h2xmle_description {Denominator coefficients.} + @h2xmle_defaultList {0,0,0,0,0, + 0,0,0,0,0} */ + int16_t numQ[SP_IIR_TDF2_STAGES_MAX]; // numerator coefficients' Q-Factor + /**< @h2xmle_description {Q factor of numerator coefficients} + @h2xmle_defaultList {1,0,0,0,0} */ + int16_t denQ[SP_IIR_TDF2_STAGES_MAX]; // denominator coefficients' Q-Factor + /**< @h2xmle_description {Q factor of denominator coefficients.} + @h2xmle_defaultList {1,0,0,0,0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +typedef struct sp_th_ctrl_param_t sp_th_ctrl_param_t; + +struct sp_th_ctrl_param_t +{ +// Top-level + uint32_t pi_scale_u16q18; // scale down a full-scale 40Hz pilot tone by this much. + /**< @h2xmle_description {scale down a full scale 40 Hz pilot + tone by this value.} + @h2xmle_dataFormat {Q18} + @h2xmle_range {0..65535} + @h2xmle_default {3775} */ + uint32_t rx_scale_u16q16; // scale outgoing signal down by this much, so that when pilot tone is added, the signal won't exceed full-scale + /**< @h2xmle_description {scale down the outgoing signal by this + value so when the pilot tone is added, the signal + does not exceed full scale.} + @h2xmle_dataFormat {Q16} + @h2xmle_range {32768..65535} + @h2xmle_default {64592} */ + // Th Rx Ch 0 params + int32_t r_spk_coil_q8; // typical resistnace of speaker + /**< @h2xmle_description {typical resistance.} + @h2xmle_range {512..16384} + @h2xmle_dataFormat {Q8} + @h2xmle_default {2048} */ + int32_t v_full_scale_q10; // Speaker voltage for digitially full scale signal + /**< @h2xmle_description {voltage for a digitally full scale + signal.} + @h2xmle_range {512..16384} + @h2xmle_dataFormat {Q10} + @h2xmle_default {5477} */ + int32_t thermal_resistance_q6; // total thermal resistance (voice coil + magnet etc) + /**< @h2xmle_description {Ch 0: total thermal resistance (such as + voice coil + magnet).} + @h2xmle_range {0..32767} + @h2xmle_dataFormat {Q6} + @h2xmle_default {3200} */ + int32_t thermal_time_constant_low_q10; // low estimate of voice coil thermal time constant (sec) + /**< @h2xmle_description {low estimate of the voice coil thermal + time constant. (in seconds)} + @h2xmle_range {51..32767} + @h2xmle_dataFormat {Q10} + @h2xmle_default {1024} */ + int32_t thermal_time_constant_high_q10; // high estimate of voice coil thermal time constant (sec) + /**< @h2xmle_description {high estimate of voice coil thermal + time constant. (in seconds)} + @h2xmle_range {51..32767} + @h2xmle_dataFormat {Q10} + @h2xmle_default {3482} */ + int32_t temp_tgt_q6; // target temperature (deg C) + /**< @h2xmle_description {target temperature.(in degrees C)} + @h2xmle_range {-1920..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {5120} */ + int32_t pi_ctrl_prop_value_q12; // value of the P term in the PI controller + /**< @h2xmle_description {value of the proportional term in the + PI controller.} + @h2xmle_range {0..32767} + @h2xmle_dataFormat {Q12} + @h2xmle_default {2100} */ + int32_t pi_ctrl_intg_value_q12; // value of the I term in the PI controller + /**< @h2xmle_description {value of the integral term in the PI + controller.}s + @h2xmle_range {0..32767} + @h2xmle_dataFormat {Q12} + @h2xmle_default {75} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sp_fir_cfg_t sp_fir_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_fir_cfg_t +{ + int16_t numTaps; + /**< @h2xmle_description {Number of fir filter coefficients} + @h2xmle_range {1...385} + @h2xmle_default {49} */ + int16_t Q; // Q-Factor + /**< @h2xmle_description {Q factor of numerator coefficients} + @h2xmle_default {0} */ + int32_t taps[FIR_LEN_MAX]; // numerator coefficients + /**< @h2xmle_description {FIR filter coefficients.} + @h2xmle_defaultList {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +typedef struct sp_ex_ctrl_param_t sp_ex_ctrl_param_t; + +struct sp_ex_ctrl_param_t +{ + // Ex Rx Ch 0 params + int32_t amp_gain_q24; // Amplifier gain that will be used in scaling Tx vsense signal to rx signal + /**< @h2xmle_description {speaker peak voltage for a digitally full-scale signal} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t ptone_excursion_mm_q27; // excursion in mm for pilot tone, will be added to peak excursion computed + /**< @h2xmle_description {excursion for the pilot tone. This + excursion is added to the computed peak excursion.} + @h2xmle_range {0..134217728} + @h2xmle_dataFormat {Q27} + @h2xmle_default {0} + @h2xmle_group {Exc_Control}*/ + int32_t dc_excursion_mm_q27; // excursion in mm for pilot tone, will be added to peak excursion computed + /**< @h2xmle_description {DC excursion margin} + @h2xmle_range {0..134217728} + @h2xmle_dataFormat {Q27} + @h2xmle_default {0} + @h2xmle_group {Exc_Control}*/ + int32_t max_excursion_mm_q27; // speaker xmax value + /**< @h2xmle_description {maximum permissible excursoin} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q27} + @h2xmle_default {40265318} + @h2xmle_group {Exc_Control}*/ + int32_t max_amplitude_q27; // speaker xmax value + /**< @h2xmle_description {amplitude limiter threshold in linear scale} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728} + @h2xmle_group {Limiter}*/ + int32_t max_power_W_q27; + /**< @h2xmle_description {maximum power that amplifier can handle} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q27} + @h2xmle_default {536870912} + @h2xmle_group {Power_Limiter}*/ + int32_t trace_resistance_rx_q24; + /**< @h2xmle_description {trace resistance from amp output to speakers in Ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t exc_model_tuning_factor_q27; + /**< @h2xmle_description {Tuning coefficient to compensation for ex-rx linear model over-prediction} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728} */ + int32_t Re_ohm_q24; + /**< @h2xmle_description {DC resistance of voice coil at room temperature or small signal level in Ohm} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Bl_q24; + /**< @h2xmle_description {Force factor (Bl product)} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Mms_gram_q24; + /**< @h2xmle_description {Ch 0: Mechanical mass of loudspeaker diaphragm in gram} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2722896} */ + int32_t Rms_KgSec_q24; + /**< @h2xmle_description {Mechanical damping or resistance of loudspeaker in Kg/sec} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {5056765} */ + int32_t Kms_Nmm_q24; + /**< @h2xmle_description {Mechanical stiffness of driver suspension in N/mm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {68155531} */ + int32_t Qms_q24; + /**< @h2xmle_description {Mechanical Q-factor} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {50331648} */ + int32_t Fres_Hz_q20; + /**< @h2xmle_description {Resonance frequency in Hz} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q20} + @h2xmle_default {838860800} */ + int32_t dc_sensitivity_Vmm_q24; + /**< @h2xmle_description {Speaker DC voltage sensitivity in Volt/mm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q20} + @h2xmle_default {838860800} */ + sp_tdf2_cfg_t band_splitting_even_filter_cfg; // band splitting even config + /**< @h2xmle_description {Band splitting even config} + */ + sp_tdf2_cfg_t band_splitting_odd_filter_cfg; // band splitting odd config + sp_fir_cfg_t band_splitting_linear_phase_filter_cfg;// band splitting using linear-phase filters + /**< @h2xmle_description {Band splitting odd config} + */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/* Structure definition for Parameter */ +typedef struct param_id_sp_dynamic_cfg_t param_id_sp_dynamic_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPv5_SP_DYNAMIC_CFG", + PARAM_ID_SPv5_SP_DYNAMIC_CFG} + @h2xmlp_description {Parameter used to configure dynamic parameters for + Feedback Speaker Protection module processing} + @h2xmlp_toolPolicy {Calibration;RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_dynamic_cfg_t +{ + /* Common params (common to both speakers) */ + // Top-level + sp_rx_nch_filt_param_t rx_notch_filter_cfg; // notch filter configuration (coefficients and coefficient q-factors) + /**< @h2xmle_description {Payload to configure dynamic + notch filter configuration} */ + + uint32_t link_all_channels_gain; // Specifies whether the gains applied to the two speakers are linked or unlinked. + /**< @h2xmle_description {Specifies whether the gains applied to the two + speakers are linked.} + @h2xmle_rangeList {"Unlinked"=0; "Linked"=1} + @h2xmle_default {0} */ + // Th Rx + uint32_t temp_control_mthd; // Use feedback temp only (0), feedback with lowpass (1), or use feedforward est temp (2) + /**< @h2xmle_description {Temperature control method.} + @h2xmle_rangeList {"Use feedback temperature only"=0; + "Feedback with low pass"=1; + "Use feedforward estimated temperature"=2} + @h2xmle_default {2} */ + int32_t temp_nominal_q6; // assumed voice coil temp, at startup + /**< @h2xmle_description {Assumed voice coil temperature at startup. (in + degree C)} + @h2xmle_range {-1920..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {3200} */ + int32_t temp_min_q6; // min reasonable meas'd temp, temp lower than this will be ignored + /**< @h2xmle_description {Minimum reasonable measured temperature. A + temperature lower than this value is ignored. (in + degree C)} + @h2xmle_range {-1920..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {-1920} */ + int32_t temp_max_q6; // max reasonable meas'd temp, temp higher than this will be ignored + /**< @h2xmle_description {Maximum reasonable measured temperature. A + temperature higher than this value is ignored.(in + degree C)} + @h2xmle_range {-1920..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {12800} */ + int32_t temp_max_chg_sec_q6; // max temp change (deg C) per sec, new temp will be ignored if outside this range, 0 = disable this feature + /**< @h2xmle_description {Maximum temperature change per second. A new + temperature is ignored if it falls outside this + range.(Set 0 to disables this feature)} + @h2xmle_range {0..32767} + @h2xmle_dataFormat {Q6} + @h2xmle_default {4096} */ + int32_t temp_smoothing_factor_q31; // smoothing of temperature to compute gain + /**< @h2xmle_description {Smoothing of the temperature to compute the gain.} + @h2xmle_dataFormat {Q31} + @h2xmle_default {6735944} */ + int32_t max_attenuation_db_q7; // minimum temp control gain (dB) + /**< @h2xmle_description {Minimum temperature control gain.} + @h2xmle_range {-7680..0} + @h2xmle_dataFormat {Q7} + @h2xmle_default {-1536} */ + int32_t attack_gain_smoothing_factor; // smoothing factor for adjusting gain during attack phase (current gain < previous gain) + /**< @h2xmle_description {Smoothing factor for adjusting gain during the + attack phase (current gain less than previous + gain).} + @h2xmle_range {328..32767} + @h2xmle_default {32767} */ + int32_t release_gain_smoothing_factor; // smoothing factor for adjusting gain during release phase (current gain > previous gain) + /**< @h2xmle_description {Smoothing factor for adjusting gain during the + release phase (current gain greater than previous + gain).} + @h2xmle_range {328..32767} + @h2xmle_default {32767} */ + int32_t temp_dead_zone_q6; // deadZone for reduced P term, (deg C) + /**< @h2xmle_description {Dead zone (region near the target temperature) for a + reduced proportional term.(in degree C)} + @h2xmle_range {2..2048} + @h2xmle_dataFormat {Q6} + @h2xmle_default {64} */ + int32_t dead_zone_scaling_q15; // scaling factor to modify P term + /**< @h2xmle_description {Scaling factor to modify the proportional term.} + @h2xmle_range {328..32767} + @h2xmle_dataFormat {Q15} + @h2xmle_default {32767} */ + int32_t clip_time_out_ms; // > 0 means enable clip intr support feature with this time out + /**< @h2xmle_description {Timeout in milli seconds used for processing a clip + interrupt.(value greater than 0 enables the clip + interrupt timeout)} + @h2xmle_range {0..4000} + @h2xmle_default {0} */ + int32_t vbat_time_out_ms; // > 0 means enable vbat support feature with this time out + /**< @h2xmle_description {Timeout in milli seconds used to process a VBAT + interrupt. (value greater than 0 enables the VBAT + interrupt timeout)} + @h2xmle_range {0..1000000} + @h2xmle_default {300000} */ + + // EX_RX common params + int32_t link_all_channels_ex_gain; + /**< @h2xmle_description {Apply common gain to both channels} + @h2xmle_rangeList {"Unlinked"=0; "Linked"=1} + @h2xmle_default {0} */ + int32_t max_release_time_ms; // 1000ms + /**< @h2xmle_description {Maximum release time in msec} + @h2xmle_range {1000..4000} + @h2xmle_default {1000} */ + + int32_t dyn_proc_type; // 0 disable, 1 shelving, 2 notch and 3 reserved + /**< @h2xmle_description {Dynamic processing feature indicator} + @h2xmle_rangeList {"Disable"=0; "Notch filter"=1; "Bass boost"=2; "Notch filter with resonance tracking"=3} + @h2xmle_default {0} + @h2xmle_group {Dyn_Notch}*/ + int32_t dyn_proc_fc_q20; + /**< @h2xmle_description {Dynamic processing -- Parametric EQ filter frequency in Hz} + @h2xmle_range {104857600..2097152000} + @h2xmle_dataFormat {Q20} + @h2xmle_default {262144000} + @h2xmle_group {Dyn_Notch} */ + int32_t dyn_proc_Q_q24; + /**< @h2xmle_description {Dynamic processing -- Parametric EQ filter Q} + @h2xmle_range {1677721..1677721600} + @h2xmle_dataFormat {Q24} + @h2xmle_default {50331648} + @h2xmle_group {Dyn_Notch}*/ + int32_t dyn_proc_threshold_dBq23; + /**< @h2xmle_description {Dynamic processing -- compression threshold in dB} + @h2xmle_range {-754974720..0} + @h2xmle_dataFormat {Q23} + @h2xmle_default {0} + @h2xmle_group {Dyn_Notch}*/ + int32_t dyn_proc_ratio_q24; + /**< @h2xmle_description {Dynamic processing -- compression ratio} + @h2xmle_range {16777216 .. 1677721600} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} + @h2xmle_group {Dyn_Notch}*/ + int32_t dyn_proc_makeup_gain_q27; + /**< @h2xmle_description {Dynamic processing -- makeup gain in linear scale} + @h2xmle_range {8468566..2127207634} + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728} */ + int32_t dyn_proc_attack_time_ms; + /**< @h2xmle_description {dynamic processing -- attach time in msec} + @h2xmle_range {0..1000} + @h2xmle_default {10} + @h2xmle_group {Dyn_Notch}*/ + int32_t dyn_proc_release_time_ms; + /**< @h2xmle_description {dynamic processing -- release time in msec} + @h2xmle_range {0..1000} + @h2xmle_default {100} + @h2xmle_group {Dyn_Notch}*/ + int32_t dyn_proc_auto_release_flag; + /**< @h2xmle_description {flag for automatic release time in dynamic processing} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {1} */ + + int32_t lfsn_type; // 0 disable, 1 shelving and 2 notch + /**< @h2xmle_description {optional excursion control using low frequency shelving or notch filter} + @h2xmle_rangeList {"Disable"=0; "Low frequency shelving"=1; "notch filter at resonance frequency"=2} + @h2xmle_default {0} + @h2xmle_group {Low_Freq_Shelf}*/ + int32_t lfsn_fc_q20; + /**< @h2xmle_description {frequency setting for low frequency shelving} + @h2xmle_range {104857600..1048576000} + @h2xmle_dataFormat {Q20} + @h2xmle_default {314572800} + @h2xmle_group {Low_Freq_Shelf}*/ + int32_t lfsn_Q_q24; + /**< @h2xmle_description {Q setting for time varying notch filter at resonance frequency} + @h2xmle_range {1677721..1677721600} + @h2xmle_dataFormat {Q24} + @h2xmle_default {50331648} + @h2xmle_group {Low_Freq_Shelf}*/ + int32_t lfsn_min_gain_q27; + /**< @h2xmle_description {minimum gain of low frequency shelving or notch filter} + @h2xmle_range {8468566..134217728} + @h2xmle_dataFormat {Q27} + @h2xmle_default {67268211} + @h2xmle_group {Low_Freq_Shelf}*/ + int32_t lfsn_attack_time_ms; + /**< @h2xmle_description {attack time in msec for time varying gain of shelving or notch filter} + @h2xmle_range {0..1000} + @h2xmle_default {10} */ + int32_t lfsn_release_time_ms; + /**< @h2xmle_description {release time in msec for time varying gain of shelving or notch filter} + @h2xmle_range {0..1000} + @h2xmle_default {100} */ + int32_t lfsn_auto_release_flag; + /**< @h2xmle_description {flag for automatic release time in low frequency shelving or notch filter} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {1} */ + int32_t exc_ctrl_attack_time_ms; + /**< @h2xmle_description {attack time in msec for excursion limiter} + @h2xmle_range {0..1000} + @h2xmle_default {0} + @h2xmle_group {Exc_Control}*/ + int32_t exc_ctrl_release_time_ms; + /**< @h2xmle_description {release time in msec for excursion limiter} + @h2xmle_range {0..1000} + @h2xmle_default {100} + @h2xmle_group {Exc_Control}*/ + int32_t exc_ctrl_auto_release_flag; + /**< @h2xmle_description {flag for automatic release time in excursion limiter} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {1} */ + int32_t exc_ctrl_min_gain_q27; + /**< @h2xmle_description {minimum gain for excursion limiter} + @h2xmle_range {8468566..134217728} + @h2xmle_dataFormat {Q27} + @h2xmle_default {33713968} */ + int32_t pow_lim_enable_flag; + /**< @h2xmle_description {power limiter operating mode} + @h2xmle_rangeList {"Disable"=0; "Enable Power Limiter in mode 1"=1; "Temp-based power-limiting"=2, "Power-limiter-during-charging"=3} + @h2xmle_default {0} + @h2xmle_group {Power_Limiter}*/ + int32_t limiter_attack_time_ms; + /**< @h2xmle_description {amplitude and power limiter attack time in msec} + @h2xmle_range {0..1000} + @h2xmle_default {0} */ + int32_t limiter_release_time_ms; + /**< @h2xmle_description {amplitude and power limiter release time in msec} + @h2xmle_range {0..1000} + @h2xmle_default {100} */ + int32_t limiter_auto_release_flag; // limiter gain release constant + /**< @h2xmle_description {flag for automatic release time in limiter} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + int32_t filterbank_type; // 0 IIR and 1 FIR + @h2xmle_default {1} */ + + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + #ifdef __H2XML__ + /* Speaker-specific parameters */ + sp_th_ctrl_param_t fbsp_th_ctrl_param[0]; + /**< @h2xmle_description {structure containing speaker params for RX thermal control block.} + @h2xmle_variableArraySize {num_ch} */ + sp_ex_ctrl_param_t fbsp_ex_ctrl_param[0]; + /**< @h2xmle_description {structure containing speaker params for RX excursion control block.} + @h2xmle_variableArraySize {num_ch} */ + #endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Structure definition for Parameter */ +#define PARAM_ID_SP_TH_DEMO_CFG 0x08001B44 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_demo_cfg_t param_id_sp_th_demo_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_DEMO_CFG", + PARAM_ID_SP_TH_DEMO_CFG} + @h2xmlp_description {parameter used for setting the algorithm internal + variables related to demo configuration of thermal processing.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_demo_cfg_t +{ + uint16_t dsr; + /**< @h2xmle_description {downsample ratio from internal values to output.} + @h2xmle_default {10} */ + + uint16_t lpass_alph_q16; + /**< @h2xmle_description {lowpass smoothing factor. Q16 format.} + @h2xmle_default {512U} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Structure definition for Parameter */ +#define PARAM_ID_SP_EX_DEMO_CFG 0x08001B45 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_demo_cfg_t param_id_sp_ex_demo_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_DEMO_CFG", + PARAM_ID_SP_EX_DEMO_CFG} + @h2xmlp_description {parameter used for setting the algorithm internal + variables related to demo configuration of excursion.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_demo_cfg_t +{ + uint16_t dsr; + /**< @h2xmle_description {downsample ratio from internal values to output.} + @h2xmle_default {10} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Structure definition for Parameter */ +#define PARAM_ID_SP_TH_STATS 0x08001B46 //todo:MS13: Update in CCB as well + +/*============================================================================== + Type definitions +==============================================================================*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ + +typedef struct sp_th_rx_param_t sp_th_rx_param_t; + +struct sp_th_rx_param_t +{ + int32_t vc_resis_q24[SP_TH_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {voice coil resistance (in ohm)} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t vc_temp_q22[SP_TH_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {voice coil temperature.(in degrees C)} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q22} + @h2xmle_default {0} */ + int32_t th_gain_lnk_db_q23[SP_TH_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {thermal gain (in dB)} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q23} + @h2xmle_default {0} */ + int32_t target_temp_q22; + /**< @h2xmle_description {target temperature.(in degrees C)} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q22} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_stats_t param_id_sp_th_stats_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_STATS", + PARAM_ID_SP_TH_STATS} + @h2xmlp_description {parameter used for RTM of the algorithm internal + variables related to thermal processing.} + @h2xmlp_toolPolicy {RTM} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_stats_t +{ + //uint16_t spkr_id; + uint32_t frame_duration_in_ms; + /**< @h2xmle_description {Frame duration in milliseconds for thermal Rx + statistics.} */ + uint32_t frame_num; + /**< @h2xmle_description {Frame number of the Excursion Rx statistics.} */ + + int32_t demo_out_valid; + /**< @h2xmle_description {flag to indicate signals output contains meaningful data} + @h2xmle_rangeList {"Invalid"=0; "Valid"=1} + @h2xmle_default {0} */ + uint32_t demo_out_pkt_cnt; + /**< @h2xmle_description {output counter, keep track of repeated or lost output} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ + int32_t demo_out_samp_dist_ms; + /**< @h2xmle_description {distance in time between samples (msec)} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ +#ifdef __H2XML__ + sp_th_rx_param_t th_rx_demo_param[0]; + /**< @h2xmle_description {structure containing speaker params for RX thermal control block.} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_STATS 0x08001B47 + +/*============================================================================== + Type definitions +==============================================================================*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +typedef struct sp_ex_rx_param_t sp_ex_rx_param_t; + +struct sp_ex_rx_param_t +{ + int32_t Re_rt_q24[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Resistance of the speaker in ohm} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ + int32_t Bl_rt_q24[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {force factor (Bl product)} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ + int32_t Rms_rt_q24[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Mechanical damping or resistance of loudspeaker} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ + int32_t Kms_rt_q24[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Mechanical stiffness of driver suspension} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ + int32_t Fres_rt_q20[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Resonance frequency in Hz} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q20} */ + int32_t Qms_rt_q24[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Mechanical Q-factor} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q24} */ + int32_t dc_rt_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {estimated DC from VI} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t dp_in_rms_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {rms_in in ohm} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t dp_out_rms_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {rms_out in ohm} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t dp_notch_gain_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {notch filter gain} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t dp_tgt_rms_q27; + /**< @h2xmle_description {target rms in ohm} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t lfsn_in_peak_pred_exc_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {lfsn peak predicted excursion} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t lfsn_out_peak_pred_exc_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {lfsn peak predicted excursion} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t lfsn_filter_gain_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {lfsn filter gain} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t exc_ctrl_in_peak_pred_exc_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {peak predicted excursion in mm} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t exc_ctrl_out_peak_pred_exc_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Peak predicted excursion in mm} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t exc_ctrl_tot_out_peak_pred_exc_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Total Peak excursion} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t exc_ctrl_gain_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Excursion gain} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t exc_ctrl_tgt_excursion_q27; + /**< @h2xmle_description {target excursion in mm} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t amp_lim_in_peak_pred_amp_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {limiter output amplitude} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t amp_lim_out_peak_pred_amp_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {limiter input amplitude} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t pow_lim_in_peak_pred_pow_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {limiter input peak power} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t pow_lim_out_peak_pred_pow_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {limiter output peak power} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t amp_lim_tgt_amplitude_q27; + /**< @h2xmle_description {limiter target amplitude} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t pow_lim_tgt_power_q27; + /**< @h2xmle_description {limiter target power} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + int32_t tot_lim_gain_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {limiter gain} + @h2xmle_range {0..2147483647} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_stats_t param_id_sp_ex_stats_t; +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_STATS", + PARAM_ID_SP_EX_STATS} + @h2xmlp_description {parameter used for RTM of the algorithm internal + variables related to exertion processing.} + @h2xmlp_toolPolicy {RTM} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_stats_t +{ + uint32_t frame_duration_in_ms; + /**< @h2xmle_description {Frame duration in milliseconds for Excursion Rx + statistics.} */ + + uint32_t frame_num; + /**< @h2xmle_description {Frame number of the Excursion Rx statistics.} */ + + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + //uint16_t spkr_id; + + int32_t demo_out_valid; + /**< @h2xmle_description {flag to indicate signals output contains meaningful data} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {0} */ + uint32_t demo_out_pkt_cnt; + /**< @h2xmle_description {output counter, keep track of repeated or lost output} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ + int32_t demo_out_samp_dist_ms; + /**< @h2xmle_description {distance in time between samples (msec)} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ + +#ifdef __H2XML__ + sp_ex_rx_param_t ex_rx_demo_param[0]; +/**< @h2xmle_description {structure containing speaker params for RX excursion control block.} +@h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_STATS 0x08001B48 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_stats_t param_id_sp_stats_t; +/** @h2xmlp_parameter {"PARAM_ID_SP_STATS", + PARAM_ID_SP_STATS} + @h2xmlp_description {parameter used for RTM of the algorithm internal + variables.} + @h2xmlp_toolPolicy {RTM} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_stats_t +{ + uint32_t frame_duration_in_ms; + /**< @h2xmle_description {Frame duration in milliseconds for Rx statistics.}*/ + + uint32_t frame_num; + /**< @h2xmle_description {Frame number of the Rx statistics.} */ + + uint32_t num_speakers; + /**< @h2xmle_description {Number of speakers.} */ + + uint32_t features; + /**< @h2xmle_description {Features enabled in the speaker protection + algorithm.} + + @h2xmle_bitField {0x00000001} + @h2xmle_bitName {"Notch high-pass filter"} + @h2xmle_description {Notch high-pass filter} + @h2xmle_rangeList {"disabled"=0;"enabled"=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000002} + @h2xmle_bitName {"Thermal protection"} + @h2xmle_description {Thermal protection} + @h2xmle_rangeList {"disabled"=0;"enabled"=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x00000004} + @h2xmle_bitName {"Feedback excursion control"} + @h2xmle_description {Feedback excursion control} + @h2xmle_rangeList {"disabled"=0;"enabled"=1} + @h2xmle_bitFieldEnd */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TMAX_XMAX_LOGGING 0x08001B49 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* TMAX XMAX Logging channel dependent params sub structure */ +typedef struct sp_tmax_xmax_params_t sp_tmax_xmax_params_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_tmax_xmax_params_t +{ + int32_t max_excursion; + /**< @h2xmle_description {maximum excursion since the lastest grasp of xmax in mm} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q27} + @h2xmle_default {0} */ + uint32_t count_exceeded_excursion; + /**< @h2xmle_description {number of periods when the monitored excursion exceeds to and stays at Xmax during logging_count_period} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ + int32_t max_temperature; + /**< @h2xmle_description {maximum temperature since the lastest grasp of tmax in C} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q22} + @h2xmle_default {0} */ + uint32_t count_exceeded_temperature; + /**< @h2xmle_description {number of periods when the monitored temperature exceeds to and stays at Tmax during logging_count_period} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Structure definition for Parameter */ +typedef struct param_id_sp_tmax_xmax_logging_t param_id_sp_tmax_xmax_logging_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TMAX_XMAX_LOGGING", + PARAM_ID_SP_TMAX_XMAX_LOGGING} + @h2xmlp_description {parameter used to log max temp and max excursion logging.} + @h2xmlp_toolPolicy {RTM} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_tmax_xmax_logging_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {1} */ + + sp_tmax_xmax_params_t tmax_xmax_params[0]; + /**< @h2xmle_description {TMAX XMAX logging params sub structure.} + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPv5_SP_TMAX_XMAX_LOGGING_EXTN 0x08001B4A + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_tmax_xmax_logging_extn_params_t param_id_sp_tmax_xmax_logging_extn_params_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPv5_SP_TMAX_XMAX_LOGGING_EXTN", + PARAM_ID_SPv5_SP_TMAX_XMAX_LOGGING_EXTN} + @h2xmlp_description {parameter used to log max temp and max excursion logging.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_tmax_xmax_logging_extn_params_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + uint32_t Mode; // determines the big data logging behavior + // 0: for version 0 (reports max temperature/excursion values since previous call to bigdata) + // 1: for version 1 (reports max temperature/excursion values over entire playback) + // one param to control big data logging behavior on both speakers. + /**< @h2xmle_description {Mode of bigdata logging} + @h2xmle_rangeList {"Version_0"=0; "Version_1"=1} + @h2xmle_default {1} */ +#ifdef __H2XML__ + int32_t Tmax[0]; // rated speaker maximum temperature acts as threshold for over temperature check + /**< @h2xmle_description {Rated speaker max temperature Tmax (in degrees C)} + @h2xmle_variableArraySize {num_ch} + @h2xmle_range {-1920..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {5120} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TH_PI_DERV_CTRL_CFG 0x08001B4B + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_pi_derv_ctrl_cfg_t param_id_sp_th_pi_derv_ctrl_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_PI_DERV_CTRL_CFG", + PARAM_ID_SP_TH_PI_DERV_CTRL_CFG} + @h2xmlp_description {Proportional Integral derivative control. + To detect the rate of change of temperature and bring the gain + down more quickly to prevent temperature from overshooting.} + @h2xmlp_toolPolicy {Calibration;RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_pi_derv_ctrl_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ +#ifdef __H2XML__ + int32_t pi_ctrl_derv_value_q12[0]; // value of the D term in the PI controller + /**< @h2xmle_description {value of the derivative term in the PI controller.} + @h2xmle_variableArraySize {num_ch} + @h2xmle_range {0..32767} + @h2xmle_dataFormat {Q12} + @h2xmle_default {700} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_RX_CPS_FINE_PARAM 0x08001B4C + +/*============================================================================== + Type definitions +==============================================================================*/ +/* Structure definition for Parameter */ +typedef struct param_id_sp_rx_cps_fine_param_t param_id_sp_rx_cps_fine_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_RX_CPS_FINE_PARAM", + PARAM_ID_RX_CPS_FINE_PARAM} + @h2xmlp_description {This parameter is used for getting finer resolution of gain to be applied at Vbatt/DieTemps. + We have extended CPS tables that can be read from using this parameter } + @h2xmlp_toolPolicy {Calibration;RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_rx_cps_fine_param_t +{ + uint16_t cps_fine_tbl_en_flag; + /**< @h2xmle_description {Flag to enable/disable fine-VBAT resolution CPS gain tables} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {0} */ + + uint16_t reserved; + /**< @h2xmle_description {Reserved} + @h2xmle_visibility {hide} + @h2xmle_default {0} */ + + int32_t FourOhmTable_fine_GaindB_q24[SP_NDTEMP_DISCRETE * SP_NVBATT_DISCRETE_FINE]; + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp. + Range: -9dB to 21dB} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmlx_expandArray {true} + @h2xmle_defaultFile {cps_fourOhmGain_fine.bin} + @h2xmle_policy {Advanced} */ + + int32_t SixOhmTable_fine_GaindB_q24[SP_NDTEMP_DISCRETE * SP_NVBATT_DISCRETE_FINE]; + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp. + Range: -9dB to 21dB} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmlx_expandArray {true} + @h2xmle_defaultFile {cps_sixOhmGain_fine.bin} + @h2xmle_policy {Advanced} */ + + int32_t EightOhmTable_fine_GaindB_q24[SP_NDTEMP_DISCRETE * SP_NVBATT_DISCRETE_FINE]; + /**< @h2xmle_description {dB limiter gain based on Vbatt/DieTemp. + Range: -9dB to 21dB} + @h2xmle_range {-150994944..352321536} + @h2xmle_dataFormat {Q24} + @h2xmlx_expandArray {true} + @h2xmle_defaultFile {cps_eightOhmGain_fine.bin} + @h2xmle_policy {Advanced} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_RX_POWLIM_MODE2_CFG_PARAM 0x08001B4D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_rx_power_limiter_mode2_param_t param_id_sp_ex_rx_power_limiter_mode2_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_RX_POWLIM_MODE2_CFG_PARAM", + PARAM_ID_SP_EX_RX_POWLIM_MODE2_CFG_PARAM} + @h2xmlp_description {Temperature based power limiting is applied using this parameter} + @h2xmlp_toolPolicy {Calibration;RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +// power limiter in mode 2, required additional parameters for operation. +struct param_id_sp_ex_rx_power_limiter_mode2_param_t +{ + + int32_t mode2power_limiter_attack_time_ms; + /**< @h2xmle_description {power limiter in mode 2 attack time in msec} + @h2xmle_range {0..20000} + @h2xmle_default {0} */ + int32_t mode2power_limiter_release_time_ms; + /**< @h2xmle_description {power limiter in mode 2 release time in msec} + @h2xmle_range {0..20000} + @h2xmle_default {100} */ + int32_t temp_nominal_q22; + /**< @h2xmle_description {nominal temperature.(in degrees C)} + @h2xmle_range {-125829120..838860800} + @h2xmle_dataFormat {Q22} + @h2xmle_default {104857600} */ + int32_t temp_tgt_q22; + /**< @h2xmle_description {target temperature.(in degrees C)} + @h2xmle_range {-125829120..838860800} + @h2xmle_dataFormat {Q22} + @h2xmle_default {377487360} */ + int32_t temp_delta_q22; + /**< @h2xmle_description {target temperature.(in degrees C)} + @h2xmle_range {0..1048576000} + @h2xmle_dataFormat {Q22} + @h2xmle_default {125829120} */ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ +#ifdef __H2XML__ + uint32_t PowerW_RolloffEnd_q27[0]; // Power threshold in W that the power limiter will use if the temperature exceeds Ttgt. + /**< @h2xmle_description {value of the power limiter threshold in mode 2. range 0W to 16W} + @h2xmle_variableArraySize {num_ch} + @h2xmle_range {0..2147483648} + @h2xmle_dataFormat {Q27} + @h2xmle_default {536870912} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_VERSION 0x08001B4E + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_version_t param_id_sp_version_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_VERSION", + PARAM_ID_SP_VERSION} + @h2xmlp_description {parameter used to get the version of the SP Library.} + @h2xmlp_toolPolicy {RTC} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_version_t +{ + uint32_t lib_version_low; + /**< @h2xmle_description {Lower 32 bits of the 64-bit + library version number.} */ + + uint32_t lib_version_high; + /**< @h2xmle_description {Higher 32 bits of the 64-bit + library version number.} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/*============================================================================== + Constants +==============================================================================*/ +#define PARAM_ID_CPS_LPASS_HW_INTF_CFG 0x08001259 // we get hardware register addresses + +/*============================================================================== + Type definitions +==============================================================================*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct cps_reg_wr_values_t +{ + uint32_t value_normal_threshold[CPS_NUM_VBATT_THRESHOLD_VALUES]; + /**< @h2xmle_description {Values to be written to LPASS WR CMD register when vbatt value returns back to + normal threshold. vbatt greater than or equal to vbatt_lower_threshold_1} */ + + uint32_t value_lower_threshold_1[CPS_NUM_VBATT_THRESHOLD_VALUES]; + /**< @h2xmle_description {Values to be written to LPASS WR CMD register, if vbatt is greater than + or equal to vbatt_lower_threshold_2 and if vbatt is less than vbatt_lower_threshold_1} */ + + uint32_t value_lower_threshold_2[CPS_NUM_VBATT_THRESHOLD_VALUES]; + /**< @h2xmle_description {Values to be written to LPASS WR CMD register, if vbatt is less than + * vbatt_lower_threshold_2} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_CPS_LPASS_SWR_THRESHOLDS_CFG 0x08001254 // we get hardware register addresses + +typedef struct cps_reg_wr_values_t cps_reg_wr_values_t; +typedef struct param_id_cps_lpass_swr_thresholds_cfg_t param_id_cps_lpass_swr_thresholds_cfg_t; +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_cps_lpass_swr_thresholds_cfg_t +{ + uint32_t num_spkr; + /**< @h2xmle_description {Number of Rx speakers.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + uint32_t vbatt_lower_threshold_1; + /**< @h2xmle_description {vbatt lower threshold 1 value. Size = 8bits. + if vbatt is greater than or equal to value_lower_threshold_2 and vbatt is less than + vbatt_lower_threshold_1, write configured values to LPASS WR CMD register} + @h2xmle_range {0..255} */ + + uint32_t vbatt_lower_threshold_2; + /**< @h2xmle_description {vbatt lower threshold 2 value. Size = 8bits. + If vbatt is less than vbatt_lower_threshold_2, write configured values to LPASS WR CMD + register} + @h2xmle_range {0..255} */ + + cps_reg_wr_values_t cps_reg_wr_values[0]; + /**< @h2xmle_description {Structures for Vbat values} + @h2xmle_variableArraySize {num_spkr}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* LPASS SWR HW register speaker dependent sub structure payload */ + +typedef struct pkd_reg_addr_t pkd_reg_addr_t; +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct pkd_reg_addr_t +{ + uint32_t vbatt_pkd_reg_addr; + /**< @h2xmle_description {Per speaker packed register address written to LPASS RD CMD register. + To read Voltage value} */ + + uint32_t temp_pkd_reg_addr; + /**< @h2xmle_description {Per speaker packed register address written to LPASS RD CMD register. + To read Temp value} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* LPASS SWR HW register structure payload */ +typedef struct lpass_swr_hw_reg_cfg_t lpass_swr_hw_reg_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct lpass_swr_hw_reg_cfg_t +{ + uint32_t num_spkr; + /**< @h2xmle_description {Number of Rx speakers.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4;"5"=5;"6"=6;"7"=7;"8"=8} + @h2xmle_default {2} */ + + uint32_t lpass_wr_cmd_reg_phy_addr; + /**< @h2xmle_description {LPASS HW register physical address. Threshold values to be written based on vbatt value + read. Write only at transitions from either of the following values: lower threshold 1, lower threshold 2 and + normal} */ + + uint32_t lpass_rd_cmd_reg_phy_addr; + /**< @h2xmle_description {LPASS HW register physical address to write packed soundwire register address + values of temp and vbatt} */ + + uint32_t lpass_rd_fifo_reg_phy_addr; + /**< @h2xmle_description {LPASS HW register physical address to read temp and vbatt soundwire register values.} */ + + pkd_reg_addr_t pkd_reg_addr[0]; + /**< @h2xmle_description {Per speaker packed register address written to LPASS RD CMD register. + To read Voltage/Temp value} + @h2xmle_variableArraySize {num_spkr} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_cps_lpass_hw_intf_cfg_t param_id_cps_lpass_hw_intf_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_CPS_LPASS_HW_INTF_CFG", + PARAM_ID_CPS_LPASS_HW_INTF_CFG} + @h2xmlp_description {Parameter used for querying the hardware register details from HLOS. Temp and Voltage} + @h2xmlp_toolPolicy {NO_SUPPORT} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_cps_lpass_hw_intf_cfg_t +{ + uint32_t lpass_hw_intf_cfg_mode; + /**< @h2xmle_description {LPASS HW interface configuration mode. + 1 - SOUNDWIRE MODE + 2 - DMA MODE} + @h2xmle_rangeList {"SOUNDWIRE"=1; "DMA MODE"=2} + @h2xmle_default {2} */ + + /* Variable payload depending on lpass_hw_intf_cfg_mode will follow here */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_RX_EX_CPS2_BATTCONFIG_LFATTEN_PARAM 0x08001B4F + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_rx_ex_cps2_battconfig_lfatten_param_t param_id_sp_rx_ex_cps2_battconfig_lfatten_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_RX_EX_CPS2_BATTCONFIG_LFATTEN_PARAM", + PARAM_ID_SP_RX_EX_CPS2_BATTCONFIG_LFATTEN_PARAM} + @h2xmlp_description {1S/2S/3S battery configs induce different levels of attenuation + in the low-frequency. Using this param we configure the attenuation expected} + @h2xmlp_toolPolicy {CALIBRATION, RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_rx_ex_cps2_battconfig_lfatten_param_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + +#ifdef __H2XML__ + int32_t battery_config_low_frequency_attenuation_q27[0]; // LF SN attenuation in the low frequency, dependent on the battery config + /**< @h2xmle_description {low-frequency attenuation observed when using 88xx with different battery configurations, + input is in linear format, default for 1S : idb(-2dB), 3S : idb(0dB) in Q27} + @h2xmle_variableArraySize {num_ch} + @h2xmle_range {0,..134217728} + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_RX_CPS2_PARAM 0x08001B50 + +/*============================================================================== + Type definitions +==============================================================================*/ +typedef struct param_id_sp_cps2_param_t param_id_sp_cps2_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct param_id_sp_cps2_param_t +{ + int32_t battery_configuration; // battery configuration. + /**< @h2xmle_description {battery configuration : 0/1:1S, 2:2S, 3:3S} + @h2xmle_range {0..3} + @h2xmle_default {0} */ + + int32_t Vph_WSA_min_q24; // VPh min varies for each vendor. For 2S/3S; insert Vph_2S/2; Vph_3S/3 for simplicity. Range from 2.5 to 5V for 1S. + /**< @h2xmle_description {VPh min varies for each vendor. For 2S/3S; insert Vph_2S/2; Vph_3S/3 for simplicity. Range from 2.5 to 5V for 1S} + @h2xmle_range {41943040..83886080} + @h2xmle_dataFormat {Q24} + @h2xmle_default {50331648} */ + + int32_t Ibatt_max_per_channel_q24; // peak battery current per channel, range : 1-7A; default: 4.5A. + /**< @h2xmle_description {peak battery current per channel.} + @h2xmle_range {16777216..117440512} + @h2xmle_dataFormat {Q24} + @h2xmle_default {50331648} */ + + int32_t Iboost_throttled_perchannel_q24; // peak boost current per channel, range : 1-7A; default: 3A. + /**< @h2xmle_description {peak battery current per channel.} + @h2xmle_range {16777216..117440512} + @h2xmle_dataFormat {Q24} + @h2xmle_default {50331648} */ + + int32_t Rph_series_q24; // approx. series resistance between the battery and the Vph tap point on the amp. + /**< @h2xmle_description {approx. series resistance between the battery and the Vph tap point on the amp.} + @h2xmle_range {0..16777216} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1677722} */ + + int32_t PA_eta_q24; // overall PA efficiency that varies as a function of output power and Vbatt; range : 60-99%. + /**< @h2xmle_description {overall PA efficiency that varies as a function of output power and Vbatt; vary this at a later stage} + @h2xmle_range {10066329..16609443} + @h2xmle_dataFormat {Q24} + @h2xmle_default {15099494} */ + + sp_tdf2_cfg_t pbxo_band_splitting_even_filter_cfg; // pbxo band splitting even config + /**< @h2xmle_description {pbxo band splitting even config} + */ + sp_tdf2_cfg_t pbxo_band_splitting_odd_filter_cfg; // pbxo band splitting odd config + /**< @h2xmle_description {pbxo band splitting odd config} + */ + + int32_t clip_detect_hold_time_ms; // clip-release happens after this hold/sustain time-period, in ms. + /**< @h2xmle_description {clip-release happens after this hold/sustain time-period, in ms..} + @h2xmle_range {0..10000} + @h2xmle_default {6000} */ + + int32_t clip_detect_attenuation_perframe_q27; // max attenuation applied in each frame in q27 + /**< @h2xmle_description {max attenuation applied in each frame in linear format, + default is idb(-0.5) in q27.} + @h2xmle_range {0..134217728} + @h2xmle_dataFormat {Q27} + @h2xmle_default {126709705}*/ + + int32_t clip_detect_max_attenuation_thr_q27; // total max clip detect threshold attenuation available. + /**< @h2xmle_description {total max clip detect threshold attenuation available in linear format, + default is idb(-2) in q27 } + @h2xmle_range {0..134217728} + @h2xmle_dataFormat {Q27} + @h2xmle_default {106612930}*/ + + int32_t battery_config_low_frequency_attenuation_q27; // low freq attenuation applied as a func of battery stacks. range : -6dB to 0dB + /**< @h2xmle_description { low freq attenuation in linear format applied as a func of battery stacks. + default is idb(-2) in q27} + @h2xmle_range {67268211..134217728} + @h2xmle_dataFormat {Q27} + @h2xmle_default {106612930}*/ + + int32_t Vph_WSA_throttlelvl_q24; // q24 throttling threshold to reduce the battery current; applies additional gain regulation + /**< @h2xmle_description { throttling voltage threshold. apply nominal values for 1/2/3S as is.} + @h2xmle_range {50331648..234881024} + @h2xmle_dataFormat {Q24} + @h2xmle_default {58720256}*/ + + int32_t Vph_WSA_max_q24; // q24 approx threshold corresponding to 100% Vph, varies for each vendor + /**< @h2xmle_description { Vph-max corresponding to a full battery. apply nominal values as is for 1/2/3S.} + @h2xmle_range {50331648..301989888} + @h2xmle_dataFormat {Q24} + @h2xmle_default {70464307}*/ + + int32_t CPS2_max_inst_power_limit_W_q24; // maximum power limit permissible as a function of stacked battery; q24 + /**< @h2xmle_description { low freq attenuation applied as a func of battery stacks. 4 to 15W} + @h2xmle_range {67108864..251658240} + @h2xmle_dataFormat {Q24} + @h2xmle_default {184549376}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_rx_cps2_param_t param_id_sp_ex_rx_cps2_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_RX_CPS2_PARAM", + PARAM_ID_SP_EX_RX_CPS2_PARAM} + @h2xmlp_description {Parameter used for setting parameters related to CPS2} + @h2xmlp_toolPolicy {CALIBRATION, RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +// CPS version 2 param: construction without look-up tables. +struct param_id_sp_ex_rx_cps2_param_t +{ + int32_t clipdetect_limiter_attack_time_ms; + /**< @h2xmle_description {clip detect limiter threshold attack time in msec} + @h2xmle_range {0..1000} + @h2xmle_default {0} */ + int32_t clipdetect_limiter_release_time_ms; + /**< @h2xmle_description {clip detect limiter threshold release time in msec} + @h2xmle_range {0..10000} + @h2xmle_default {1000} */ + int32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ +#ifdef __H2XML__ + param_id_sp_cps2_param_t cps2_param[0]; + /**< @h2xmle_description {structure containing speaker params for CPS2 in Rx Excursion Control block} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_EX_RX_CPS_BOOSTOPERATION_PARAM 0x08001B51 + +/*============================================================================== + Type definitions +==============================================================================*/ + +typedef struct param_id_sp_cps_batttemp_param_t param_id_sp_cps_batttemp_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct param_id_sp_cps_batttemp_param_t +{ + int16_t attenuateSmallerLoads; //apply a small attenuation if the resistance drops from say 8 to 4. + /**< @h2xmle_description { //apply a small attenuation if the resistance drops from say 8 to 4.} + @h2xmle_range {0..1} + @h2xmle_default {0}*/ + + uint16_t reserved; + /**< @h2xmle_description {Reserved Field.} + @h2xmle_visibility {hide} + @h2xmle_default {0} */ + + int32_t RphDelta_LowTemp; // R_series_Delta with low temperature variation. + /**< @h2xmle_description {R_series_Delta with low temperature variation.} + @h2xmle_range {0..16777216 } // 1 Ohm max + @h2xmle_dataFormat {Q24} + @h2xmle_default {1006632} : 0.060 Ohms */ + + int32_t BattTempRange[2]; // Battery temperature range where the Series resistance needs to be varied. + /**< @h2xmle_description {Battery temperature range where the Series resistance needs to be varied.} + @h2xmle_range {-335544320..335544320} // -20 to 20 C + @h2xmle_dataFormat {Q24} + @h2xmle_defaultList {-335544320,335544320} */ // BattTempRange[0] > BattTempRange[1] + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_sp_cps_boostoperation_param_t param_id_sp_cps_boostoperation_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct param_id_sp_cps_boostoperation_param_t +{ + int32_t boost_headroom_voltage; + /**< @h2xmle_description {Boost headroom} + @h2xmle_range {0..50331648} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ // 1V + + int32_t UVLO_voltage; + /**< @h2xmle_description {undervoltage-lockout voltage} + @h2xmle_range {0..50331648} // auto multiplied by 2 for 2S + @h2xmle_dataFormat {Q24} + @h2xmle_default {33554432} */ // 2V + + int32_t switching_freq; + /**< @h2xmle_description {in MHz.} + @h2xmle_range {20132659..80530636} + @h2xmle_dataFormat {Q24} + @h2xmle_default {40265318} */ // 2.4MHz + + int32_t boost_max_voltage; + /**< @h2xmle_description {clip detect limiter threshold release time in msec} + @h2xmle_range {167772160..335544320} // 8-20V + @h2xmle_dataFormat {Q24} + @h2xmle_default {192937984} */ //11.5V + + int32_t boost_inductor_muH; + /**< @h2xmle_description {clip detect limiter threshold release time in msec} + @h2xmle_range {1677721..167772160} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ //1muH + + int32_t efficiency_classD; + /**< @h2xmle_description {ClassD efficiency} + @h2xmle_range {0..16777216} + @h2xmle_dataFormat {Q24} + @h2xmle_default {15770583} */ //0.94 + + int32_t peak_power_per_channel; + /**< @h2xmle_description {max amp power limit} + @h2xmle_range {16777216..251658240} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ //8W + + int32_t peak_power_per_pair; + /**< @h2xmle_description {max amp power limit for two shared channels} + @h2xmle_range {16777216..251658240} + @h2xmle_dataFormat {Q24} + @h2xmle_default {201326592} */ //12W + + int32_t inductor_current_limit[SP_NILIM_DISCRETE]; + /**< @h2xmle_description {current limit for a specific Vph-range (x num stacks), + Vph_vec[] = { 2, 2.2, 2.5, 2.7, 3, 3.3, 3.7, 4, 4.2, 4.5, 5.0 };} + @h2xmle_range {0..117440512} + @h2xmle_dataFormat {Q24} + @h2xmle_defaultList {16777,167772,1677722,21810381,33554432,41943040,53687091,60397978,67108864,67108864,67108864} */ //4A + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_spkr_prot_ex_rx_cps_boostoperation_param_t param_id_spkr_prot_ex_rx_cps_boostoperation_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPKR_PROT_EX_RX_CPS_BOOSTOPERATION_PARAM", + PARAM_ID_SPKR_PROT_EX_RX_CPS_BOOSTOPERATION_PARAM} + @h2xmlp_description {Parameter used for setting parameters related to CPS3} + @h2xmlp_toolPolicy {CALIBRATION; RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +// CPS version 3 param: construction without look-up tables. +struct param_id_spkr_prot_ex_rx_cps_boostoperation_param_t +{ + int32_t boost_limiter_attack_time_ms; + /**< @h2xmle_description {clip detect limiter threshold attack time in msec} + @h2xmle_range {0..10} + @h2xmle_default {0} */ + + int32_t boost_limiter_release_time_ms; + /**< @h2xmle_description {clip detect limiter threshold release time in msec} + @h2xmle_range {0..20} + @h2xmle_default {1} */ + + param_id_sp_cps_batttemp_param_t cps_batttemp_param; + /**< @h2xmle_description {specifics to address low batt temp behavior}*/ + + int32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4;"5"=5;"6"=6;"7"=7;"8"=8} + @h2xmle_default {2} */ + +#ifdef __H2XML__ + param_id_sp_cps_boostoperation_param_t cps3_param[0]; + /**< @h2xmle_description {structure containing speaker params for CPS3 in Rx-CPS block} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_SPEAKERS_LINK_MODE_PARAM 0x08001B52 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_speakers_link_mode_param_t param_id_sp_speakers_link_mode_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_SPEAKERS_LINK_MODE_PARAM", + PARAM_ID_SP_SPEAKERS_LINK_MODE_PARAM} + @h2xmlp_description {parameter used to set the mode informing which speakers' gain to be linked.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_speakers_link_mode_param_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + + uint32_t speakers_link_mode[0]; + /**< @h2xmle_description {mode indicating which channels to be gain linked} + @h2xmle_rangeList {"Unlink"=0;"Link_1"=1;"Link_2"=2;"Link_3"=3;"Link_4"=4} + @h2xmle_defaultList {1,1,1,1,1,1,1,1} + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_EX_RX_CPS3_DEMO_PKT_PARAM 0x08001B53 + +/*============================================================================== + Type definitions +==============================================================================*/ +typedef struct sp_ex_rx_cps3_param_t sp_ex_rx_cps3_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_ex_rx_cps3_param_t +{ + // demo packet for CPS3: boost operation included. + uint32_t BoostLimiterThr_rt_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Boost limiter threshold in linear format, -\inftydB to 0dB; limit to -12dB or something similar + default is idb(0) in Q27 } + @h2xmle_range {0..134217728} + @h2xmle_default {134217728} + @h2xmle_dataFormat {Q27} */ + + uint32_t DutyCycle_rt_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Duty cycle} + @h2xmle_range {0..134217728} + @h2xmle_default {67108864} + @h2xmle_dataFormat {Q27} */ + + // demo packet for CPS3: boost operation included. + uint32_t inductorcurrent_rt_q27[MAX_CPS_BOOST_INDUCTOR_CURRENT_SAMPLES_IN_PACKET_48K]; + /**< @h2xmle_description {Boost inductor current }// + @h2xmle_range {0..2147483648} + @h2xmle_default {0} + @h2xmle_dataFormat {Q27} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_spkr_prot_ex_rx_cps3_demo_pkt_param_t param_id_spkr_prot_ex_rx_cps3_demo_pkt_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPKR_PROT_EX_RX_CPS3_DEMO_PKT_PARAM", + PARAM_ID_SPKR_PROT_EX_RX_CPS3_DEMO_PKT_PARAM} + @h2xmlp_description {Parameter used for getting plots for cps2} + @h2xmlp_toolPolicy {RTM} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +// CPS version 3 param: construction without look-up tables. +struct param_id_spkr_prot_ex_rx_cps3_demo_pkt_param_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4;"5"=5;"6"=6;"7"=7;"8"=8} + @h2xmle_default {2} */ + int32_t demo_out_valid; + /**< @h2xmle_description {flag to indicate signals output contains meaningful data} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {0} */ +#ifdef __H2XML__ + // demo packet for CPS3 + sp_ex_rx_cps3_param_t ex_rx_cps3_demo_param[0]; + /**< @h2xmle_description {structure containing speaker params for CPS3 in Rx Excursion Control block} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_T0_CALI_PARAM 0x08001B54 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_spkr_prot_t0_cali_param_t param_id_spkr_prot_t0_cali_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPKR_PROT_T0_CALI_PARAM", + PARAM_ID_SPKR_PROT_T0_CALI_PARAM} + @h2xmlp_description {parameter used to hold intial speaker temperature T0 (in degrees C).} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_spkr_prot_t0_cali_param_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4;"5"=5;"6"=6;"7"=7;"8"=8} + @h2xmle_default {2} */ + +#ifdef __H2XML__ + int32_t t0_cali_q6[0]; + /**< @h2xmle_description {Rated speaker max temperature Tmax (in degrees C)} + @h2xmle_range {-1920..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {-1920} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_EX_RX_BATTTEMP_DATA_PARAM 0x08001B55 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_spkr_prot_ex_rx_batttemp_data_param_t param_id_spkr_prot_ex_rx_batttemp_data_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPKR_PROT_EX_RX_BATTTEMP_DATA_PARAM", + PARAM_ID_SPKR_PROT_EX_RX_BATTTEMP_DATA_PARAM} + @h2xmlp_description {parameter used to set CPS batt temp data in mC that needs to be fed into cps.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_spkr_prot_ex_rx_batttemp_data_param_t +{ + int32_t batttemp_data; // battery tem + /**< @h2xmle_description {CPS batt temp data in mC that needs to be fed into cps} + @h2xmle_range {-20000..70000} //-20 to 70C. + @h2xmle_default {20} */ //20C +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_EX_RX_CPS3_DEMO_PARAM 0x08001B56 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_spkr_prot_ex_rx_cps3_demo_param_t param_id_spkr_prot_ex_rx_cps3_demo_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPKR_PROT_EX_RX_CPS3_DEMO_PARAM", + PARAM_ID_SPKR_PROT_EX_RX_CPS3_DEMO_PARAM} + @h2xmlp_description {parameter used to set downsample ratio from internal values to output.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_spkr_prot_ex_rx_cps3_demo_param_t +{ + uint16_t dsr; // downsample ratio from internal values to output + /**< @h2xmle_description {down sampling ratio for cps demo params} + @h2xmle_default {10} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_EX_RX_CPS2_DEMO_PKT_PARAM 0x08001B57 + +/*============================================================================== + Type definitions +==============================================================================*/ +typedef struct sp_ex_rx_cps2_param_t sp_ex_rx_cps2_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_ex_rx_cps2_param_t +{ + // demo packet for CPS2 + int32_t ClipSmthThr_rt_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {Clip detect threshold in linear format, -\inftydB to 0dB; limit to -12dB or something similar + default is idb(0) in Q27 } + @h2xmle_range {0..134217728} + @h2xmle_default {134217728} + @h2xmle_dataFormat {Q27} */ + int32_t GainLow_rt_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {limiter threshold in linear format applied to the LF band of the crossover + -\inftydB to 0dB; limit to -12dB or something similar, default is idb(0) in Q27} + @h2xmle_range {0..134217728} + @h2xmle_default {134217728} + @h2xmle_dataFormat {Q27} */ + int32_t GainHigh_rt_q27[SP_EX_RX_DEMO_SMPL_PER_PKT]; + /**< @h2xmle_description {limiter threshold linear applied to the HF band of the crossover + -\inftydB to 0dB; limit to -12dB or something similar, default is idb(0) in Q27 } + @h2xmle_range {0..134217728} + @h2xmle_default {134217728} + @h2xmle_dataFormat {Q27} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_rx_cps2_demo_pkt_param_t param_id_sp_ex_rx_cps2_demo_pkt_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_RX_CPS2_DEMO_PKT_PARAM", + PARAM_ID_SP_EX_RX_CPS2_DEMO_PKT_PARAM} + @h2xmlp_description {Parameter used for getting plots for cps2} + @h2xmlp_toolPolicy {RTM} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +// CPS version 2 param: construction without look-up tables. +struct param_id_sp_ex_rx_cps2_demo_pkt_param_t +{ + uint32_t frame_duration_in_ms; + /**< @h2xmle_description {Frame duration in milliseconds for Excursion cps Rx + statistics.} */ + + uint32_t frame_num; + /**< @h2xmle_description {Frame number of the Excursion Rx statistics.} */ + + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + int32_t demo_out_valid; + /**< @h2xmle_description {flag to indicate signals output contains meaningful data} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {0} */ +#ifdef __H2XML__ + // demo packet for CPS2 + sp_ex_rx_cps2_param_t ex_rx_cps2_demo_param[0]; + /**< @h2xmle_description {structure containing speaker params for CPS2 in Rx Excursion Control block} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_RX_CPS2_DEMO_PARAM 0x08001B58 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_rx_cps2_demo_param_t param_id_sp_ex_rx_cps2_demo_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_RX_CPS2_DEMO_PARAM", + PARAM_ID_SP_EX_RX_CPS2_DEMO_PARAM} + @h2xmlp_description {parameter used to set downsample ratio from internal values to output.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_rx_cps2_demo_param_t +{ + uint16_t dsr; // downsample ratio from internal values to output + /**< @h2xmle_description {down sampling ratio for cps demo params} + @h2xmle_default {10} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_DYNAMIC_NOTCH_PARAM 0x08001B59 + +/*============================================================================== + Type definitions +==============================================================================*/ + +typedef struct sp_dynamic_notch_param_t sp_dynamic_notch_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_dynamic_notch_param_t +{ + int32_t dyn_proc_type; // 0 disable, 1 shelving, 2 notch and 3 reserved + /**< @h2xmle_description {Dynamic processing feature indicator} + @h2xmle_rangeList {"Disable"=0; "Notch filter"=1; "Bass boost"=2; "Notch filter with resonance tracking"=3} + @h2xmle_default {0} */ + int32_t dyn_proc_fc_q20; + /**< @h2xmle_description {Dynamic processing -- Parametric EQ filter frequency in Hz} + @h2xmle_range {104857600..2097152000} + @h2xmle_dataFormat {Q20} + @h2xmle_default {262144000} */ + int32_t dyn_proc_Q_q24; + /**< @h2xmle_description {Dynamic processing -- Parametric EQ filter Q} + @h2xmle_range {1677721..1677721600} + @h2xmle_dataFormat {Q24} + @h2xmle_default {50331648} */ + int32_t dyn_proc_threshold_dBq23; + /**< @h2xmle_description {Dynamic processing -- compression threshold in dB} + @h2xmle_range {-754974720..0} + @h2xmle_dataFormat {Q23} + @h2xmle_default {0} */ + int32_t dyn_proc_ratio_q24; + /**< @h2xmle_description {Dynamic processing -- compression ratio} + @h2xmle_range {16777216 .. 1677721600} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t dyn_proc_makeup_gain_q27; + /**< @h2xmle_description {Dynamic processing -- makeup gain in linear scale} + @h2xmle_range {8468566..2127207634} + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728} */ + int32_t dyn_proc_attack_time_ms; + /**< @h2xmle_description {dynamic processing -- attach time in msec} + @h2xmle_range {0..1000} + @h2xmle_default {10} */ + int32_t dyn_proc_release_time_ms; + /**< @h2xmle_description {dynamic processing -- release time in msec} + @h2xmle_range {0..1000} + @h2xmle_default {100} */ + int32_t dyn_proc_auto_release_flag; + /**< @h2xmle_description {flag for automatic release time in dynamic processing} + @h2xmle_rangeList {"Disable"=0; "Enable"=1} + @h2xmle_default {1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_spkr_prot_dynamic_notch_param_t param_id_spkr_prot_dynamic_notch_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPKR_PROT_DYNAMIC_NOTCH_PARAM", + PARAM_ID_SPKR_PROT_DYNAMIC_NOTCH_PARAM} + @h2xmlp_description {parameter used to configure per channel dynamic notch.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_spkr_prot_dynamic_notch_param_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4;"5"=5;"6"=6;"7"=7;"8"=8} + @h2xmle_default {2} */ +#ifdef __H2XML__ + sp_dynamic_notch_param_t dynamic_notch_param[0]; + /**< @h2xmle_description {Structure containing dynamic notch params} + @h2xmle_variableArraySize {num_ch}*/ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_LIN_RX_DYNAMIC_CFG 0x08001B5A + +/*============================================================================== + Type definitions +==============================================================================*/ + +typedef struct sp_lin_ex_common_ctrl_param_t sp_lin_ex_common_ctrl_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_lin_ex_common_ctrl_param_t +{ + // Ex Rx Ch 0 params + int32_t amp_gain_q24; // Amplifier gain that will be used in scaling Tx vsense signal to rx signal + /**< @h2xmle_description {speaker peak voltage for a digitally full-scale signal} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t trace_resistance_rx_q24; + /**< @h2xmle_description {trace resistance from amp output to speakers in Ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Re_ohm_q24; + /**< @h2xmle_description {DC resistance of voice coil at room temperature or small signal level in Ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {111394816} */ + int32_t Bl_q24; + /**< @h2xmle_description {Force factor (Bl product)} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {19316736} */ + int32_t Mms_gram_q24; + /**< @h2xmle_description {Ch 0: Mechanical mass of loudspeaker diaphragm in gram} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2260992} */ + int32_t Rms_KgSec_q24; + /**< @h2xmle_description {Mechanical damping or resistance of loudspeaker in Kg/sec} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1843200} */ + int32_t Kms_Nmm_q24; + /**< @h2xmle_description {Mechanical stiffness of driver suspension in N/mm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {42573824} */ + int32_t Kms1_Nmm2_q24; + /**< @h2xmle_description {Para-Suspension Stiffness} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Kms2_Nmm3_q24; + /**< @h2xmle_description {Para-Suspension Stiffness} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Kms3_Nmm4_q24; + /**< @h2xmle_description {Para-Suspension Stiffness} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Kms4_Nmm5_q24; + /**< @h2xmle_description {Para-Suspension Stiffness} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Rms1_Kgm_q24; + /**< @h2xmle_description {Para-Mechanical damping} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Rms2_Kgsm2_q24; + /**< @h2xmle_description {Para-Mechanical damping} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Bl1_NAmm_q24; + /**< @h2xmle_description {Force factor (Bl1)} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Bl2_NAmm2_q24; + /**< @h2xmle_description {Force factor (Bl2)} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Bl3_NAmm3_q24; + /**< @h2xmle_description {Force factor (Bl3)} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Bl4_NAmm4_q24; + /**< @h2xmle_description {Force factor (Bl4)} + @h2xmle_range {-2147483648..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sp_lin_ctrl_param_t sp_lin_ctrl_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_lin_ctrl_param_t +{ + /* Rx lin/Ex common parameters*/ + sp_lin_ex_common_ctrl_param_t lin_ex_common_ctrl_param; + + int32_t input_gain_q24; + /**< @h2xmle_description {linearization input gain to allow processing head room} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t max_amplitude_q24; + /**< @h2xmle_description {amplitude limiter threshold in linear scale} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_spkr_prot_lin_rx_dynamic_cfg_t param_id_spkr_prot_lin_rx_dynamic_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPKR_PROT_LIN_RX_DYNAMIC_CFG", + PARAM_ID_SPKR_PROT_LIN_RX_DYNAMIC_CFG} + @h2xmlp_description {Linearization} + @h2xmlp_toolPolicy {Calibration;RTC} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_spkr_prot_lin_rx_dynamic_cfg_t +{ + // LIN_RX common params + int32_t link_all_channels_gain; + /**< @h2xmle_description {Apply common gain to both channels} + @h2xmle_rangeList {"Unlinked"=0; "Linked"=1} + @h2xmle_default {0} */ + int32_t limiter_release_time_ms; + /**< @h2xmle_description {limiter release time in msec} + @h2xmle_range {0..32767} + @h2xmle_default {100} */ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4;"5"=5;"6"=6;"7"=7;"8"=8} + @h2xmle_default {2} */ +#ifdef __H2XML__ + /* Speaker-specific parameters */ + sp_lin_ctrl_param_t fbsp_lin_ctrl_param[0]; + /**< @h2xmle_description {structure containing speaker params for RX linearization block.} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/*============================================================================== + Constants + ==============================================================================*/ + + /* Unique Paramter id */ +#define PARAM_ID_SPKR_PROT_CPSBASIC_CFG 0x08001B5B + +/*============================================================================== + Type definitions +==============================================================================*/ + +typedef struct sp_cps_basic_param_t sp_cps_basic_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_cps_basic_param_t +{ + int32_t power_W_perchannel[N_VPH_RANGE]; + /**< @h2xmle_description {Power in W per channel in q24, we will use the same variable if SoC is chosen. use the first 20-21 entries here for SoC } + @h2xmle_range {0...2147483647} //0-14W + @h2xmle_dataFormat {Q24} + //in W assuming 8 ohm loads: 0.0007176, 0.07176, 0.18025, 0.7176, 2.8568, 4.5277, 5.7001, 5.8328, 5.9687, 6.1077, 6.25, 6.3956, 6.5446, 6.6203, 6.697, 6.697, 6.7745, 6.9323, 7.0126, 7.176, 7.176, 7.176, 7.176, 7.176, 7.176} + @h2xmle_defaultList {12039,1203933,3024093,12039330,47929151,75962201,95631809,97858145,100138169,102470202,104857600,107300363,109800168,111070203,112357016,112357016,113657250,116304694,117651905,120393302,120393302,120393302,120393302,120393302,120393302}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sp_cpsbasic_ctrl_param_t sp_cpsbasic_ctrl_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_cpsbasic_ctrl_param_t { + int32_t useSoC; + /**< @h2xmle_description {enable/disable SoC as sense input to control CPS-basic.} + @h2xmle_range {0...1} + @h2xmle_default {0} */ + + int32_t SoC_CV_mode; + /**< @h2xmle_description {SoC that determines cconst voltage charging mode.} + @h2xmle_range {0...1677721600} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1342177280} */ + + int32_t PowerW_CV_mode; + /**< @h2xmle_description {PowerW for the CV mode; during tuning } + @h2xmle_range {0..134217728} //0 to 8W + @h2xmle_dataFormat {Q24} + @h2xmle_default {117440512} 7W */ + + int32_t low_batt_temperature_threshold; + /**< @h2xmle_description {batt low temp threshold below which attenuation is applied due to increased series losses.} + @h2xmle_range {-671088640..335544320} //-40C to 20C + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ //0C + + int32_t min_low_batt_temperature; + /**< @h2xmle_description {batt minimum low temp threshold; below which no increases in attenuation are applied.} + @h2xmle_range {-671088640..0} //-40C to 0C + @h2xmle_dataFormat {Q24} + @h2xmle_default {-671088640} */ //40C + + int32_t lowbatttemp_limthr_dB_slope; + /**< @h2xmle_description {Attenuation applied as a function of low batt temp in dB/degrees C.} + @h2xmle_range {-671088640..0} //-40C to 0C + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ //0dB/degrees C + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sp_cps_basic_stereopower_param_t sp_cps_basic_stereopower_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_cps_basic_stereopower_param_t { + int32_t power_W_perpair[N_VPH_RANGE]; + /**< @h2xmle_description {Power in W per channel in q24, we will use the same variable if SoC is chosen. use the first 20-21 entries here for SoC } + @h2xmle_range {0...2147483647} //0-14W + @h2xmle_dataFormat {Q24} + //in W assuming 8 ohm loads: 0.0007 0.0718 0.1802 4.7176 6.8568 8.5277 9.7001 9.8328 9.9687 10.1077 10.2500 10.3956 10.5446 10.6203 10.6970 10.6970 10.7745 10.9323 11.0126 11.1760 11.1760 11.1760 11.1760 11.1760 11.1760} + @h2xmle_defaultList {12039, 1203933, 3024093, 79148194, 115038015, 143071065, 162740673, 164967009, 167247033, 169579066, 171966464, 174409227, 176909032, 178179067, 179465880, 179465880, 180766114, 183413558, 184760769, 187502166, 187502166, 187502166, 187502166, 187502166, 187502166}*/ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/* Structure definition for Parameter */ +typedef struct param_id_spkr_prot_cpsbasic_param_t param_id_spkr_prot_cpsbasic_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPKR_PROT_CPSBASIC_CFG", + PARAM_ID_SPKR_PROT_CPSBASIC_CFG} + @h2xmlp_description {CPS} + @h2xmlp_toolPolicy {Calibration;RTC} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_spkr_prot_cpsbasic_param_t { + sp_cpsbasic_ctrl_param_t fbsp_rx_cps_cpsbasic_ctrl_params; + /**< @h2xmle_description {specifics to address low batt temp behavior and cps-basic operation}*/ + + sp_cps_basic_stereopower_param_t fbsp_rx_cps_stereopower_params; + /**< @h2xmle_description {specifics to address stereo power in connected channels.}*/ + + int32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4;"5"=5;"6"=6;"7"=7;"8"=8} + @h2xmle_default {2} */ + +#ifdef __H2XML__ + sp_cps_basic_param_t cpsbasic_param[0]; + /**< @h2xmle_description {structure containing speaker params for CPS-basic in Rx-CPS block} + @h2xmle_variableArraySize {num_ch} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/** @} <-- End of the Module --> */ +#endif /* __SP_RX_H__ */ diff --git a/spf/api/modules/sp_vi.h b/spf/api/modules/sp_vi.h new file mode 100644 index 0000000..5876cb0 --- /dev/null +++ b/spf/api/modules/sp_vi.h @@ -0,0 +1,1663 @@ +#ifndef __SP_VI_H__ +#define __SP_VI_H__ + +/*============================================================================== + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + + @file sp_vi.h + @brief This file contains APIs for Speaker Protection Module +==============================================================================*/ + +/** @h2xml_title1 {Speaker Protection} + @h2xml_title_date {January 7, 2020} */ +#include "module_cmn_api.h" +#include "ar_defs.h" +#include "imcl_spm_intent_api.h" +#include "rtm_logging_api.h" + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ +#define VI_MAX_INPUT_PORTS 1 +#define VI_MAX_OUTPUT_PORTS 1 +#define VI_STACK_SIZE 4096 + +/* Maximum number of stages in the IIR filter. */ +#define SP_IIR_TDF2_STAGES_MAX 5 + +/* Maximum number of samples per packet. */ +#define MAX_SAMPLES_IN_PACKET_48k 480 +#define MAX_SAMPLES_IN_PACKET 480 +#define MAX_SAMPLES_IN_PACKET_8k 80 +/* Number of numerators per stage in the IIR filter. */ +#define SP_IIR_TDF2_NUM_NUM_PER_STAGE 3 + +/* Number of denominators per stage in the IIR filter. */ +#define SP_IIR_TDF2_NUM_DEN_PER_STAGE 2 + +/* Unique Module ID */ +#define MODULE_ID_SPEAKER_PROTECTION_V7_VI 0x0702C003 + +/** @h2xmlm_module {"MODULE_ID_SPEAKER_PROTECTION_V5_VI", + MODULE_ID_SPEAKER_PROTECTION_V5_VI} + @h2xmlm_displayName {"Speaker Protection v5 - VI"} + @h2xmlm_toolPolicy {Calibration;CALIBRATION} + @h2xmlm_description {ID of the VI module.\n + + This module supports the following parameter IDs:\n + - #PARAM_ID_SP_VI_OP_MODE_CFG\n + - #PARAM_ID_SP_TH_VI_R0T0_CFG\n + - #PARAM_ID_SP_VI_STATIC_CFG\n + - #PARAM_ID_SPv5_TH_VI_DYNAMIC_CFG\n + - #PARAM_ID_SP_TH_VI_CALIB_RES_CFG\n + - #PARAM_ID_SP_TH_VI_FTM_CFG\n + - #PARAM_ID_SP_TH_VI_FTM_PARAMS\n + - #PARAM_ID_SP_TH_VI_V_VALI_CFG\n + - #PARAM_ID_SP_TH_VI_V_VALI_PARAMS\n + - #PARAM_ID_SPv5_EX_VI_DYNAMIC_CFG\n + - #PARAM_ID_SP_EX_VI_STATS\n + - #PARAM_ID_SP_EX_VI_MODE_CFG\n + - #PARAM_ID_SP_EX_VI_FTM_CFG\n + - #PARAM_ID_SP_EX_VI_FTM_PARAMS\n + - #PARAM_ID_SP_VI_CHANNEL_MAP_CFG\n + - #PARAM_ID_VI_OUTPUT_SPLIT_ENABLE\n + - #PARAM_ID_RTM_LOGGING_ENABLE\n + - #PARAM_ID_SP_VI_CFSMOOTHING_CFG_PARAM\n + + +It also supports the following events: + - #EVENT_ID_SPv5_SPEAKER_DIAGNOSTICS + The payload of this event includes num channels followed by status of DC presence on each channel + + - #EVENT_ID_VI_CALIBRATION + It populates and returns the payload corresponding to 'PARAM_ID_SP_TH_VI_CALIB_RES_CFG' param + + - #EVENT_ID_TH_VI_V_VALI_PARAMS + It populates and returns the payload corresponding to 'PARAM_ID_SP_TH_VI_V_VALI_PARAMS' param + + All parameter IDs are device independent.\n + + Supported Input Media Format:\n +* - Data Format : FIXED_POINT\n +* - fmt_id : Don't care\n +* - Sample Rates : 48000, 8000\n +* - Number of channels : 1 to 8\n +* - Channel type : 1 to 63\n +* - Bits per sample : 16 , 32 \n +* - Q format : 15 for bps = 16 and 27 for bps = 32\n +* - Interleaving : de-interleaved unpacked\n +* - Signed/unsigned : Signed } + + @h2xmlm_toolPolicy {Calibration} + + @h2xmlm_dataMaxInputPorts {VI_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {VI_MAX_OUTPUT_PORTS} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {VI_STACK_SIZE} + @h2xmlm_ctrlDynamicPortIntent { "SP VI intent id for communicating Vsens and Isens data" = INTENT_ID_SP, +maxPorts= 1 } + @h2xmlm_ToolPolicy {Calibration} + + @{ <-- Start of the Module --> + + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + + @h2xml_Select {"rtm_logging_enable_payload_t"} + @h2xmlm_InsertParameter + */ + +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ + +/*============================================================================== + Constants +==============================================================================*/ +/* Vsens from the left speaker. */ +#define SP_VI_VSENS_CHAN1 1 + +/* Isens from the left speaker. */ +#define SP_VI_ISENS_CHAN1 2 + +/* Vsens from the right speaker. */ +#define SP_VI_VSENS_CHAN2 3 + +/* Isens from the right speaker. */ +#define SP_VI_ISENS_CHAN2 4 + +/* Vsens from the left speaker. */ +#define SP_VI_VSENS_CHAN3 5 + +/* Isens from the left speaker. */ +#define SP_VI_ISENS_CHAN3 6 + +/* Vsens from the right speaker. */ +#define SP_VI_VSENS_CHAN4 7 + +/* Isens from the right speaker. */ +#define SP_VI_ISENS_CHAN4 8 + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_VI_OP_MODE_CFG 0x080011F4 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_vi_op_mode_cfg_t param_id_sp_vi_op_mode_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_VI_OP_MODE_CFG", + PARAM_ID_SP_VI_OP_MODE_CFG} + @h2xmlp_description {parameter used process Vsens and Isens data for + extracting the speaker temperature and excursion.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_vi_op_mode_cfg_t +{ + uint32_t num_speakers; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2}*/ + + uint32_t th_operation_mode; // normal running or calibration + /**< @h2xmle_description {Operation mode of thermal VI module.} + @h2xmle_rangeList {"Normal Running mode"=0; + "Calibration mode"=1; + "Factory Test Mode"=2; + "V-Validation Mode"=3} */ + + uint32_t th_quick_calib_flag; // indicates whether calibration was done in quick mode or not + /**< @h2xmle_description {Indicates whether calibration is to be done in quick + mode or not. This field is valid only in + Calibration mode (operation_mode = 1).} + @h2xmle_rangeList {disabled=0;enabled=1} */ +#ifdef __H2XML__ + uint32_t th_r0t0_selection_flag[0]; // this flag determines which set of R0, T0 values the algorithm will use + // (0: use calibrated R0, T0 value, 1: use safe R0, T0 value) + /**< @h2xmle_description {Specifies which set of R0, T0 values the algorithm will use. This field is valid only in + Normal mode (operation_mode = 0).} + @h2xmle_variableArraySize {num_speakers} + @h2xmle_rangeList {"Use calibrated R0, T0 value"=0;"Use safe R0, T0 value"=1} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TH_VI_R0T0_CFG 0x080011F5 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* R0T0 channel dependent cfg sub structure */ +typedef struct vi_r0t0_cfg_t vi_r0t0_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct vi_r0t0_cfg_t +{ + int32_t r0_cali_q24; // calibration point resistance (in ohm), per device + /**< @h2xmle_description {Calibration point resistance per device (in Ohms). This field is valid only in Normal mode (operation_mode = 0).} + + @h2xmle_range {33554432..1073741824} + @h2xmle_default {33554432} + @h2xmle_dataFormat {Q24} */ + int16_t t0_cali_q6; // caliberation point Temp (deg C), per device + /**< @h2xmle_description {Calibration point temperature per device (in degrees C). This field is valid in both Normal mode and Calibration mode.} + + @h2xmle_range {-1920..5120 } + @h2xmle_dataFormat {Q6} */ + + int16_t reserved; + /**< @h2xmle_description {Reserved Field.} + @h2xmle_visibility {hide} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_vi_r0t0_cfg_t param_id_sp_th_vi_r0t0_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_VI_R0T0_CFG", + PARAM_ID_SP_TH_VI_R0T0_CFG} + @h2xmlp_description {parameter used to configure static R0T0 parameters of + thermal VI processing..} + @h2xmlp_toolPolicy {NO_SUPPORT} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_vi_r0t0_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + vi_r0t0_cfg_t r0t0_cfg[0]; + /**< @h2xmle_description {Structure containing r0 and t0 variables for calibration} + @h2xmle_variableArraySize {num_ch}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_VI_STATIC_CFG 0x080011F6 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_vi_static_cfg_t param_id_sp_vi_static_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_VI_STATIC_CFG", + PARAM_ID_SP_VI_STATIC_CFG} + @h2xmlp_description {parameter used to configure static parameters of + thermal VI processing.} + @h2xmlp_toolPolicy {CALIBRATION; RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_vi_static_cfg_t +{ + uint32_t num_speakers; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + uint32_t sampling_rate; + /**< @h2xmle_description {Sampling rate of VI signal.} + @h2xmle_rangeList {"8kHz"=8000;"48kHz"=48000} + @h2xmle_default {8000} */ + uint32_t fpilot; + /**< @h2xmle_description {Pilot tone frequencies. Pilot tone frequency values MUST be the same for the RX/TH/EX modules} + @h2xmle_rangeList {"16"=16; "40"=40} + @h2xmle_default {40} */ + + uint32_t th_ctrl_rate; // thermal control rate (Hz) + /**< @h2xmle_description {Thermal control rate.} + @h2xmle_rangeList {"1000hz"=1000} + @h2xmle_default {1000} */ + uint32_t th_frame_size_ms; // processing frame size in ms + /**< @h2xmle_description {Frame size for TH_VI processing.} + @h2xmle_rangeList {"1ms"=1} + @h2xmle_default {1} */ + int32_t th_pow_supply_freq; // power supply freq, 50Hz or 60Hz (in Hz, 0 = disable) + /**< @h2xmle_description {Specifies the power supply frequency.} + @h2xmle_rangeList {"disabled"=0; "50Hz"=50; "60Hz"=60} + @h2xmle_default {0} */ + uint32_t th_temp_est_selection_flag; // temperature estimation selection flag (0: old method, 1 new method) + /**< @h2xmle_description {Temperature estimation selection flag. + Method2 also requires setting of spk_delta_t_delta_r_ratio_u16q9 param.} + @h2xmle_rangeList {Method1=0;Method2=1} + @h2xmle_default {0} */ + + uint32_t ex_frame_size; + /**< @h2xmle_description {frame size for EX_VI parameter tracking.} + @h2xmle_rangeList {"8ms"=8; "32ms"=32} + @h2xmle_default {8} */ + uint32_t ex_tuning_mode_enable_flag; + /**< @h2xmle_description {flag for dumping predicted excursion using Vsens at 48kHz. It's only for laser display. + should be disabled at normal mode on devices.} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {0} */ + uint32_t ex_DC_detection_enable_flag; + /**< @h2xmle_description {flag for DC detection from VIsens. HAL will set a periodic query on the DC presense flag. + If DC is present, HAL will shut down WSA to protect spkrs.} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_group {DC} + @h2xmle_default {0} */ + uint32_t ex_warmup_time_ms; + /**< @h2xmle_description {EXVI parameter tracking will start after this much of warmup time in msec + due to inaccurate Rvc estimation at the beginning of playback} + @h2xmle_range {100..500} + @h2xmle_default {200} */ + + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPv5_TH_VI_DYNAMIC_CFG 0x08001B5C + +/*============================================================================== + Type definitions +==============================================================================*/ +typedef struct sp_vi_th_spkr_param_t sp_vi_th_spkr_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_vi_th_spkr_param_t +{ + int32_t r0_safe_q24; // backup caliberation point resistance (ohm), when per device calibration is not available + /**< @h2xmle_description {backup calibration point resistance + when per-device calibration is not available (in + Ohms.)} + @h2xmle_range {33554432..1073741824} + @h2xmle_dataFormat {Q24} + @h2xmle_default {104857600} */ + uint32_t pilot_tone_scale_u16q18; // scale of pi tone, relative to 0dBFs + /**< @h2xmle_description {scale of the pilot tone relative to + 0 dBFS (for example, -40 dB from the full scale).} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q18} + @h2xmle_default {5230} */ + int32_t trace_resistance_tx_q24; + /**< @h2xmle_description {trace resistance from speaker to Vsens tap points in Ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int16_t r_spk_coil_typ_q8; // typical resistnace of speaker in ohm + /**< @h2xmle_description {nominal AC impedance at 2kHz and rated power of spkr (in Ohms ).} + @h2xmle_range {512..32767} + @h2xmle_default {2048} + @h2xmle_dataFormat {Q8} */ + int16_t r_spk_coil_factor_q10; // speaker coil resistance this many times of typical will be considered open circult + /**< @h2xmle_description {factor used to determine the threshold + for speaker coil resistance (threshold for speaker + coil resistance = factor * speaker coil resistance). + If (Rvc > factor*(AC impedance)), the speaker is considered + open.} + @h2xmle_range {-32768..32767} + @h2xmle_dataFormat {Q10} + @h2xmle_default {2048} */ + int16_t v_full_sc_q10; // Speaker peak voltage for digitially full scale signal + /**< @h2xmle_description {voltage for digitally full scale + signal.} + @h2xmle_range {0..32767} + @h2xmle_dataFormat {Q10} + @h2xmle_default {8192} */ + uint16_t spk_resistivity_coeff_u16q7; // resistivity coeff (1/deg C) + /**< @h2xmle_description {one over temperature coeffcient alpha} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q7} + @h2xmle_default {32570} */ + uint16_t spk_delta_t_delta_r_ratio_u16q9; // speaker deltaT/deltaR = 1/(change in resistance per unit change in temperature) + /**< @h2xmle_description {speaker deltaT/deltaR = 1/(change in resistance + per unit change in temperature)} + @h2xmle_range {0x0..0xffff} + @h2xmle_dataFormat {Q6} + @h2xmle_default {0x4286} */ + int16_t t0_safe_q6; // backup caliberation point Temp (deg C), when per device calibration is not available + /**< @h2xmle_description {backup calibration point temperature + when per-device calibration is not available (in + degrees C).} + @h2xmle_range {-1920..5120} + @h2xmle_dataFormat {Q6} + @h2xmle_default {1600} */ + uint16_t vsen_2_v_u16q11; // conversion factor from Vsen digital to Volt + /**< @h2xmle_description {conversion factor from Vsens digital + to volts.} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q11} + @h2xmle_default {21466} */ + uint16_t isen_2_a_u16q11; // conversion factor from Isen digital to Amp + /**< @h2xmle_description {conversion factor from Isens digital + to amps.} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q11} + @h2xmle_default {14143} */ + uint16_t v_pilot_thsd_u16q16; // fraction of expected pilot tone, below this, resistance update is deem un-reliable + /**< @h2xmle_description {fraction of the expected pilot tone. + Below this value, the resistance update is + unreliable.} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q16} + @h2xmle_default {26214} */ + int16_t reserved; + /**< @h2xmle_description {Reserved} + @h2xmle_visibility {hide} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sp_vi_r0t0_cali_param_t sp_vi_r0t0_cali_param_t; +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_vi_r0t0_cali_param_t +{ + int32_t wait_time_ms; // wait time for initial settling before collecting statistic (ms) + /**< @h2xmle_description {wait time for initial settling before + collecting statistics (in milli seconds).} + @h2xmle_range {100..5000} + @h2xmle_default {200} */ + int32_t cali_time_ms; // calibration time (ms) + /**< @h2xmle_description {calibration time (in milli seconds).} + @h2xmle_range {500..30000} + @h2xmle_default {2000} */ + int32_t vi_wait_time_ms; // wait time to check if VI are above threshold levels + /**< @h2xmle_description {wait time for vi (in milli seconds).} + @h2xmle_range {100..30000} + @h2xmle_default {2000} */ + uint16_t r0_und_est_fac_q16; // under estimate R0 if it is quick calibration + /**< @h2xmle_description {underestimate R0 if it is quick + calibration.} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q16} + @h2xmle_default {0} */ + int16_t r0_rng_fac_q10; // calibrated r0 this many times of typical will call calibration failed; + /**< @h2xmle_description {factor used to determine the threshold + for calculated calibrated resistance (threshold for + calibrated resistance = factor * calibrated + resistance). After this threshold, calibrated + resistance is considered as failed.} + @h2xmle_range {-32768..32767} + @h2xmle_dataFormat {Q10} + @h2xmle_default {1536} */ + int16_t t0_min_q6; // min expected temperature from calibration (deg C) + /**< @h2xmle_description {minimum expected temperature from + calibration (in degrees C).} + @h2xmle_range {-1920..5120} + @h2xmle_dataFormat {Q6} + @h2xmle_default {0} */ + int16_t t0_max_q6; // max expected temperature from calibration (deg C) + // 12 int 16 params so far, so no holes in struct + /**< @h2xmle_description {maximum expected temperature from + calibration (in degrees C).} + @h2xmle_range {-1920..5120} + @h2xmle_dataFormat {Q6} + @h2xmle_default {3200} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_vi_dynamic_cfg_t param_id_sp_th_vi_dynamic_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPv5_TH_VI_DYNAMIC_CFG", + PARAM_ID_SPv5_TH_VI_DYNAMIC_CFG} + @h2xmlp_description {parameter used to configure dynamic thermal parameters + for feedback speaker protection VI processing.} + @h2xmlp_toolPolicy {CALIBRATION; RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_vi_dynamic_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ +#ifdef __H2XML__ + + sp_vi_th_spkr_param_t fbsp_spkr_param[0]; + /**< @h2xmle_description {structure containing speaker params for VI thermal control block.} + @h2xmle_variableArraySize {num_ch} */ + sp_vi_r0t0_cali_param_t fbsp_r0t0_cali_param[0]; + /**< @h2xmle_description {structure containing speaker params for R0T0 calibration. } + @h2xmle_variableArraySize {num_ch} */ + +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TH_VI_CALIB_RES_CFG 0x080011F8 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_vi_calib_res_cfg_t param_id_sp_th_vi_calib_res_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_VI_CALIB_RES_CFG", + PARAM_ID_SP_TH_VI_CALIB_RES_CFG} + @h2xmlp_description {Parameter used to get the calibrated resistance value + from the feedback speaker VI processing module.} + @h2xmlp_toolPolicy {NO_SUPPORT; RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_vi_calib_res_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {2} */ + uint32_t state; // calibration state + /**< @h2xmle_description {Represents the calibration state for both speakers. + The state of each speaker is tied together.} + @h2xmle_rangeList {"Incorrect operation mode (isn't normal mode)" = 0; + "Inactive mode (port is not started)" = 1; + "Warm Up" = 2; + "Calibration in progress state" = 3; + "Calibration Success" = 4; + "Calibration Failed" = 5; + "CALI_STATE_WAIT_FOR_VI" = 6; + "CALI_STATE_VI_WAIT_TIMED_OUT" = 7; + "CALI_STATE_LOW_VI" = 8; + "CALI_STATE_MAX_VAL" = 8} */ + int32_t r0_cali_q24[0]; // calibration point resistance (in ohm), per device + /**< @h2xmle_description {Calibration point resistance per device (in Ohms). This field is valid only in Normal mode (operation_mode = 0).} + @h2xmle_variableArraySize {num_ch} + @h2xmle_range {33554432..1073741824} + @h2xmle_default {33554432} + @h2xmle_dataFormat {Q24} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TH_VI_FTM_CFG 0x080011F9 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* TH FTM channel dependent cfg sub structure */ +typedef struct vi_th_ftm_cfg_t vi_th_ftm_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct vi_th_ftm_cfg_t +{ + int32_t wait_time_ms; + /**< @h2xmle_description {wait time before collecting statistics for ftm mode (ms)} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {100} */ + int32_t ftm_time_ms; + /**< @h2xmle_description {duration that ftm packets will be averaged} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {100} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_vi_ftm_cfg_t param_id_sp_th_vi_ftm_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_VI_FTM_CFG", + PARAM_ID_SP_TH_VI_FTM_CFG} + @h2xmlp_description {parameter used to set the FTM configuration in the + feedback speaker thermal VI processing module.} + @h2xmlp_toolPolicy {CALIBRATION} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_vi_ftm_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + vi_th_ftm_cfg_t th_vi_ftm_set_param[0]; + /**< @h2xmle_description {structure containing speaker params for FTM } + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TH_VI_FTM_PARAMS 0x080011FA + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* TH FTM channel dependent get params sub structure */ +typedef struct vi_th_ftm_params_t vi_th_ftm_params_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct vi_th_ftm_params_t +{ + int32_t ftm_rDC_q24; + /**< @h2xmle_description {resistance in ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_temp_q22; + /**< @h2xmle_description {temperature in degree C} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q22} + @h2xmle_default {0} */ + uint32_t status; + /**< @h2xmle_description {ftm packet status: wait, in progress or success} + @h2xmle_rangeList {"Incorrect operation mode"=0; + "Inactive mode (port is not started)"=1; + "Wait state"=2; + "In progress state"=3; + "Success"=4; + "Failed"=5} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_vi_ftm_params_t param_id_sp_th_vi_ftm_params_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_VI_FTM_PARAMS", + PARAM_ID_SP_TH_VI_FTM_PARAMS} + @h2xmlp_description {parameter used to get the FTM statistics from the + Thermal VI processing module.} + @h2xmlp_toolPolicy {RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_vi_ftm_params_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {1} */ + vi_th_ftm_params_t vi_th_ftm_params[0]; + /**< @h2xmle_description {TH FTM channel dependent get params sub structure.} + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TH_VI_V_VALI_CFG 0x080011FB + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* TH V Vali channel dependent set cfg sub structure */ +typedef struct vi_th_v_vali_cfg_t vi_th_v_vali_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct vi_th_v_vali_cfg_t +{ + int32_t wait_time_ms; + /**< @h2xmle_description {wait time before collecting statistics for V-validation mode} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {100} */ + int32_t vali_time_ms; + /**< @h2xmle_description {validation time where validation packets will be averaged} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {100} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_vi_v_vali_cfg_t param_id_sp_th_vi_v_vali_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_VI_V_VALI_CFG", + PARAM_ID_SP_TH_VI_V_VALI_CFG} + @h2xmlp_description {parameter used to set the V VALIDATION configuration in the + feedback speaker thermal VI processing module.} + @h2xmlp_toolPolicy {CALIBRATION} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_vi_v_vali_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + vi_th_v_vali_cfg_t fbsp_th_vi_v_vali_set_param[0]; + /**< @h2xmle_description {structure containing speaker params for v-validation } + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_TH_VI_V_VALI_PARAMS 0x080011FC + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* TH V Vali channel dependent get params sub structure */ +typedef struct vi_th_v_vali_params_t vi_th_v_vali_params_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct vi_th_v_vali_params_t +{ + uint32_t vrms_q24; + /**< @h2xmle_description {RMS voltage value} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + + uint32_t status; + /**< @h2xmle_description {V Validation status.} + @h2xmle_rangeList {"Incorrect operation mode"=2; + "Inactive mode"=3; + "Wait state"=4; + "In progress state"=5; + "Success"=1; + "Failed"=0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Structure definition for Parameter */ +typedef struct param_id_sp_th_vi_v_vali_params_t param_id_sp_th_vi_v_vali_params_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_TH_VI_V_VALI_PARAMS", + PARAM_ID_SP_TH_VI_V_VALI_PARAMS} + @h2xmlp_description {parameter used to get the V VALIDATION statistics from the + Thermal VI processing module.} + @h2xmlp_toolPolicy {RTC} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_vi_v_vali_params_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + vi_th_v_vali_params_t vi_th_v_vali_params[0]; + /**< @h2xmle_description {TH V Vali channel dependent get params sub structure.} + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SPv5_EX_VI_DYNAMIC_CFG 0x08001B5D + +/*============================================================================== + Type definitions +==============================================================================*/ +/* tdf2 configuration structure for RX_EX Dynamic config. */ +typedef struct fbsp_tdf_2_cfg_t fbsp_tdf_2_cfg_t; +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct fbsp_tdf_2_cfg_t +{ + int16_t numCh; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + int16_t stages; + /**< @h2xmle_description {Number of stages.} + @h2xmle_range {1..5} + @h2xmle_default {1} */ + int32_t num[SP_IIR_TDF2_STAGES_MAX*SP_IIR_TDF2_NUM_NUM_PER_STAGE]; // numerator coefficients + /**< @h2xmle_description {Numerator coefficients.} + @h2xmle_defaultList {1073741824,0,0, + 0,0,0, + 0,0,0, + 0,0,0, + 0,0,0} */ + int32_t den[SP_IIR_TDF2_STAGES_MAX*SP_IIR_TDF2_NUM_DEN_PER_STAGE]; // denominator coefficients + /**< @h2xmle_description {Denominator coefficients.} + @h2xmle_defaultList {0,0, + 0,0, + 0,0, + 0,0, + 0,0} */ + int16_t numQ[SP_IIR_TDF2_STAGES_MAX]; // numerator coefficients' Q-Factor + /**< @h2xmle_description {Q factor of numerator coefficients} + @h2xmle_defaultList {1,0,0,0,0} */ + int16_t denQ[SP_IIR_TDF2_STAGES_MAX]; // denominator coefficients' Q-Factor + /**< @h2xmle_description {Q factor of denominator coefficients.} + @h2xmle_defaultList {1,0,0,0,0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct sp_vi_ex_spkr_param_t sp_vi_ex_spkr_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct sp_vi_ex_spkr_param_t +{ + int32_t Re_ohm_q24; // typical resistnace of speaker in ohm + /**< @h2xmle_description {DC resistance of voice coil at room temperature or small signal level in Ohm} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Le_mH_q24; + /**< @h2xmle_description {Voice coil inductance in mH} + @h2xmle_range {-2147483647..2147483647.} + @h2xmle_dataFormat {Q24} + @h2xmle_default {671088} */ + int32_t L2_mH_q24; + /**< @h2xmle_description {Para-inductance of voice coil in LR2 inductor model in mH} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {33554} */ + int32_t R2_ohm_q24; + /**< @h2xmle_description {Electrical resistance in LR2 inductor model in Ohm} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Bl_q24; + /**< @h2xmle_description {Force factor (Bl product)} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Mms_gram_q24; + /**< @h2xmle_description {Mechanical mass of loudspeaker diaphragm in gram} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2722896} */ + int32_t Rms_KgSec_q24; + /**< @h2xmle_description {Mechanical damping or resistance of loudspeaker in Kg/sec} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {5056765} */ + int32_t Kms_Nmm_q24; + /**< @h2xmle_description {Mechanical stiffness of driver suspension in N/mm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {68155531} */ + int32_t Fres_Hz_q20; + /**< @h2xmle_description {Resonance frequency in Hz} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q20} + @h2xmle_default {838860800} */ + int32_t Qms_q24; + /**< @h2xmle_description {Mechanical Q-factor} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {50331648} */ + int32_t Le1_mH_mm_q24; + /**< @h2xmle_description {Para-inductance of voice coil} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Le2_mH_mm2_q24; + /**< @h2xmle_description {Para-inductance of voice coil} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Le3_mH_mm3_q24; + /**< @h2xmle_description {Para-inductance of voice coil} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Le4_mH_mm4_q24; + /**< @h2xmle_description {Para-inductance of voice coil} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Kms1_Nmm2_q24; + /**< @h2xmle_description {Para-Suspension Stiffness} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Kms2_Nmm3_q24; + /**< @h2xmle_description {Para-Suspension Stiffness} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Kms3_Nmm4_q24; + /**< @h2xmle_description {Para-Suspension Stiffness} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Kms4_Nmm5_q24; + /**< @h2xmle_description {Para-Suspension Stiffness} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Rms1_Kgm_q24; + /**< @h2xmle_description {Para-Mechanical damping} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Rms2_Kgsm2_q24; + /**< @h2xmle_description {Para-Mechanical damping} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Bl_peak_NA_q24; + /**< @h2xmle_description {Force factor (Bl peak)} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Bl_rest_m_q24; + /**< @h2xmle_description {Force factor (Bl rest)} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t Bl_var_q24; + /**< @h2xmle_description {Force factor (Bl var)} + @h2xmle_range {-2147483647..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2000} */ + int32_t dc_excursion_max_m_q24; + /**< @h2xmle_description {DC Excursion max val} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1678} */ + int32_t dc_track_step_size_k_q24; + /**< @h2xmle_description {DC step size} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2} */ + int32_t Bl_peak_track_step_size_q24; + /**< @h2xmle_description {Force Factor step size} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t dc_threshold_m_q24; + /**< @h2xmle_description {DC threshold for estimated DC offset} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1678} */ + int32_t dc_attack_time_ms; + /**< @h2xmle_description {attack time for DC Smoothing} + @h2xmle_range {0..1000} + @h2xmle_default {1} */ + int32_t dc_release_time_ms; + /**< @h2xmle_description {release time for DC Smoothing} + @h2xmle_range {0..1000} + @h2xmle_default {10} */ + int32_t Kms_track_step_size_q24; + /**< @h2xmle_description {kms tracking step size} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {335544320} */ + int32_t Kms_max_abs_dev_q24; + /**< @h2xmle_description {kms_est maximum absolute deviation from Kms } + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {5033164} */ + int32_t amp_gain_q24; + /**< @h2xmle_description {speaker peak voltage for a digitally + full-scale signal} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t vsens_scale_q24; // Vsense scaling constant + /**< @h2xmle_description {conversion factor from Vsens digital to volts} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t isens_scale_q24; // Isense scaling constant + /**< @h2xmle_description {conversion factor from Isens digital to ampere} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {33554432} */ + int32_t trace_resistance_tx_q24; + /**< @h2xmle_description {trace resistance from speaker to Vsens tap points in Ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t trace_resistance_rx_q24; + /**< @h2xmle_description {trace resistance from amp output to speakers in Ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t DC_pow_thr_mW; + /**< @h2xmle_description {DC power threshold for DC detection in mW} + @h2xmle_range {0..4000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {500} */ + int32_t DC_hold_time_mSec; + /**< @h2xmle_description {If DC power is higher than the threshold for this much of time in msec, DC is present} + @h2xmle_range {0..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {500} */ + int32_t safety_mode; + /**< @h2xmle_description {flag for conservative adaptation only for DC resistance} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {1} */ + int32_t negative_DC_comp_en; + fbsp_tdf_2_cfg_t bandpss_LPfilter_cfg; + /**< @h2xmle_description {LPF config} */ + fbsp_tdf_2_cfg_t bandpss_HPfilter_cfg; + /**< @h2xmle_description {HPF config} */ + fbsp_tdf_2_cfg_t inductor_filter_cfg; + /**< @h2xmle_description {Inductor filter config} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_vi_dynamic_cfg_t param_id_sp_ex_vi_dynamic_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPv5_EX_VI_DYNAMIC_CFG", + PARAM_ID_SPv5_EX_VI_DYNAMIC_CFG} + @h2xmlp_description {parameter used to configure the dynamic parameters of + excursion VI processing.} + @h2xmlp_toolPolicy {CALIBRATION; RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_vi_dynamic_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + sp_vi_ex_spkr_param_t fbsp_ex_spkr_param[0]; + /**< @h2xmle_description {structure containing speaker params for VI excursion block } + @h2xmle_variableArraySize {num_ch} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_VI_STATS 0x080011FE + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_vi_stats_t param_id_sp_ex_vi_stats_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_VI_STATS", + PARAM_ID_SP_EX_VI_STATS} + @h2xmlp_description {Parameter used to log excursion VI algorithm internal + variables.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_vi_stats_t +{ + uint32_t frame_duration_in_ms; + /**< @h2xmle_description {Frame duration in milliseconds for Excursion VI + statistics.} */ + + uint32_t frame_num; + /**< @h2xmle_description {Frame number of the Excursion VI statistics. This + field is reset to zero after crossing the maximum + limit for uint32 variables.} */ + + uint32_t num_ch; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {1} */ + + int32_t xpred_from_vsens[0][MAX_SAMPLES_IN_PACKET]; + /**< @h2xmle_description {xpred from vsens.} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_VI_MODE_CFG 0x080011FF + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_vi_mode_cfg_t param_id_sp_ex_vi_mode_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_VI_MODE_CFG", + PARAM_ID_SP_EX_VI_MODE_CFG} + @h2xmlp_description {parameter used to configure the mode of Feedback + Speaker Protection Excursion VI processing.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_vi_mode_cfg_t +{ + uint32_t ex_FTM_mode_enable_flag; + /**< @h2xmle_description {Factory Test Mode enablement flag. When enabled, the estimated spkr parameters are averaged + and pushed out to HAL for parameter display and saving into audio.cal} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_VI_FTM_CFG 0x08001200 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* EX FTM channel dependent set cfg sub structure */ +typedef struct vi_ex_ftm_cfg_t vi_ex_ftm_cfg_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct vi_ex_ftm_cfg_t +{ + int32_t wait_time_ms; + /**< @h2xmle_description {wait time before collecting statistics for ftm mode} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {100} */ + int32_t ftm_time_ms; + /**< @h2xmle_description {duration that ftm packets will be averaged} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {100} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_vi_ftm_cfg_t param_id_sp_ex_vi_ftm_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_VI_FTM_CFG", + PARAM_ID_SP_EX_VI_FTM_CFG} + @h2xmlp_description {parameter used to set the FTM configuration in the + Excursion VI processing module.} + @h2xmlp_toolPolicy {CALIBRATION, RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_vi_ftm_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + vi_ex_ftm_cfg_t fbsp_ex_vi_ftm_set_param[0]; + /**< @h2xmle_description {structure containing speaker params for FTM } + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_EX_VI_FTM_PARAMS 0x08001201 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* EX FTM channel dependent get params sub structure */ +typedef struct vi_ex_ftm_params_t vi_ex_ftm_params_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ +struct vi_ex_ftm_params_t +{ + int32_t ftm_Re_q24; + /**< @h2xmle_description {ftm resitance in ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_Bl_q24; + /**< @h2xmle_description {force factor (Bl_product)} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_Rms_q24; + /**< @h2xmle_description {resitance due to mechanical damping} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_Kms_q24; + /**< @h2xmle_description {suspension stiffness} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_Fres_q20; + /**< @h2xmle_description {resonant frequency} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q20} + @h2xmle_default {0} */ + int32_t ftm_Qms_q24; + /**< @h2xmle_description {Quality factor} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + uint32_t status; // FTM packet status + /**< @h2xmle_description {FTM packet status} + @h2xmle_rangeList {"Incorrect operation mode"=0; + "Inactive mode (port is not started)"=1; + "Wait state"=2; + "In progress state"=3; + "Success"=4; + "Failed"=5} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_vi_ftm_params_t param_id_sp_ex_vi_ftm_params_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_EX_VI_FTM_PARAMS", + PARAM_ID_SP_EX_VI_FTM_PARAMS} + @h2xmlp_description {parameter used to get the FTM statistics from the + Excursion VI module.} + @h2xmlp_toolPolicy {RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_ex_vi_ftm_params_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + + vi_ex_ftm_params_t fbsp_ex_vi_ftm_get_param[0]; + /**< @h2xmle_description {structure containing speaker params for FTM } + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_VI_CHANNEL_MAP_CFG 0x08001203 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_vi_channel_map_cfg_t param_id_sp_vi_channel_map_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_VI_CHANNEL_MAP_CFG", + PARAM_ID_SP_VI_CHANNEL_MAP_CFG} + @h2xmlp_description {parameter used to set the input channel mapping for Vsens and Isens + for the VI module.} + @h2xmlp_toolPolicy {CALIBRATION, RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_vi_channel_map_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of channels for Tx signal.} + @h2xmle_rangeList {"Two" = 2; "Four" = 4; "Six" = 6; "Eight"=8} + @h2xmle_default {2} */ + + int32_t chan_info[0]; + /**< @h2xmle_description {Channel mapping array that provides information + on the order in which the Vsens and Isens of + different speakers come into a Tx port. + - SP_VI_VSENS_CHAN1(1) + - SP_VI_ISENS_CHAN1(2) + - SP_VI_VSENS_CHAN2(3) + - SP_VI_ISENS_CHAN2(4) + - SP_VI_VSENS_CHAN3(5) + - SP_VI_ISENS_CHAN3(6) + - SP_VI_VSENS_CHAN4(7) + - SP_VI_ISENS_CHAN4(8) + Some possible configurations are (1,2,3,4,5,6,7,8), (2,1,4,3,6,5,8,7), + (1,2,0,0),(4,3,0,0), and (2,1,0,0). + All channels must be unique. The order does not matter + as long as the channels are valid. + If only two channels are sent (V and I), they must be + first two channels: Eg: (4,3), (1,2), etc.} + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_SP_VI_CFSMOOTHING_CFG_PARAM 0x08001364 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_ex_vi_CFSmoothing_param_t param_id_sp_ex_vi_CFSmoothing_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SP_VI_CFSMOOTHING_CFG_PARAM", + PARAM_ID_SP_VI_CFSMOOTHING_CFG_PARAM} + @h2xmlp_description { Used for applying CF smoothing to estimated ExVI parameters} + @h2xmlp_toolPolicy {CALIBRATION;RTC} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_sp_ex_vi_CFSmoothing_param_t +{ + uint16_t ex_CF_Smoothing_flag; // Smoothing flag, 0-disabled, 1-enabled. + /**< @h2xmle_description {ExVI Estimated parameters are further smoothed using the crest-factor.} + @h2xmle_rangeList {"disable"= 0; "enable"=1} + @h2xmle_default {0} */ + uint16_t reserved; + /**< @h2xmle_description {Reserved} + @h2xmle_default {0} */ + uint32_t ex_CF_scaling_factor; // scaling factor applied to the crest factor, 1 to 10 (linear) + /**< @h2xmle_description {Scaling factor applied to the crest factor to compute the time-constant} + @h2xmle_range {134217728..1342177280 } + @h2xmle_dataFormat {Q27} + @h2xmle_default {134217728}*/ + uint32_t ex_CF_subtraction_param; // CF param subtracted from estimated CFdB, typically this value varies between 3dB to 10dB + /**< @h2xmle_description {CF param subtracted from estimated CFdB , per channel.} + @h2xmle_range {402653184..1342177280 } + @h2xmle_dataFormat {Q27} + @h2xmle_default {402653184}*/ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ +// This param is introduced to allow client to choose whether he wants the output of +// VI module with bits per sample as 32 (Vsense and Isense data merged into single +// channel for each corresponding channel on RX path) or as 16. Valid only if input has bps = 32 + +#define PARAM_ID_VI_OUTPUT_SPLIT_ENABLE 0x080011C2 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_vi_output_bps_split_enable_t param_id_vi_output_bps_split_enable_t; + +/** @h2xmlp_parameter {"PARAM_ID_VI_OUTPUT_SPLIT_ENABLE", + PARAM_ID_VI_OUTPUT_SPLIT_ENABLE} + @h2xmlp_description {Parameter used to indicate if the 32bit(per channel) output of VI + module should be split into two channels of 16 bits output. This is valid only if the + input to VI module has bps =32.} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_vi_output_bps_split_enable_t +{ + uint32_t bps_split_enable; + /**< @h2xmle_description {Bits per sample of the vi module output. If the input + has bits per sample as 32 and this is enabled, it splits the output into + two channels with bits per sample as 16 for each corresponding input channel.} + @h2xmle_rangeList {"ENABLE" = 1; "DISABLE" = 0} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +#define PARAM_ID_SPv5_VI_SPKR_DIAG_GETPKT_PARAM 0x08001B5E + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_sp_vi_spkr_diag_getpkt_param_t param_id_sp_vi_spkr_diag_getpkt_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_SPv5_VI_SPKR_DIAG_GETPKT_PARAM", + PARAM_ID_SPv5_VI_SPKR_DIAG_GETPKT_PARAM} + @h2xmlp_description {Parameter used to indicate the speaker condition + 0 = OK, 1 = DC, 2 = OPEN, 3 = CLOSE} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_vi_spkr_diag_getpkt_param_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Num channels in use case} + @h2xmle_rangeList {"mono" = 1; "stereo" = 2; "three"= 3; "quad" = 4} + @h2xmle_dataFormat {Q0} + @h2xmle_default {2} */ + int32_t spkr_cond[0]; + /**< @h2xmle_description {reflects speaker general diagnostics - OK, DC, Open, Close} + @h2xmle_rangeList {"OK" = 0; "SHORT" = 1; "OPEN" = 2; "DC" = 3; "OVERTEMP" = 4} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} + @h2xmle_variableArraySize {num_ch}*/ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +//NEW_VI _PARAMS +/*============================================================================== + Constants +==============================================================================*/ + +#define PARAM_ID_SP_TH_VI_CALIB_RES_PER_SPKR_CFG 0x0800150F + +/*============================================================================== + Type definitions +==============================================================================*/ +typedef struct sp_vi_cali_param_t sp_vi_cali_param_t; +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct sp_vi_cali_param_t +{ + int32_t state; + /**< @h2xmle_description {Calibration state of speaker} + @h2xmle_rangeList {"Incorrect operation mode (isn't normal mode)" = 0; + "Inactive mode (port is not started)" = 1; + "Warm Up" = 2; + "Calibration in progress state" = 3; + "Calibration Success" = 4; + "Calibration Failed" = 5; + "CALI_STATE_WAIT_FOR_VI" = 6; + "CALI_STATE_VI_WAIT_TIMED_OUT" = 7; + "CALI_STATE_LOW_VI" = 8; + "CALI_STATE_MAX_VAL" = 8} */ + int32_t r0_cali_q24; + /**< @h2xmle_description {calibrated resistance of speaker} + @h2xmle_range {33554432..1073741824} + @h2xmle_default {33554432} + @h2xmle_dataFormat {Q24}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_sp_th_vi_calib_res_per_spkr_cfg_param_t param_id_sp_th_vi_calib_res_per_spkr_cfg_param_t; +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_sp_th_vi_calib_res_per_spkr_cfg_param_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Num channels in use case} + @h2xmle_rangeList {"mono" = 1; "stereo" = 2; "three" = 3; "quad" = 4} + @h2xmle_default {2} */ + sp_vi_cali_param_t cali_param[0]; + /**< @h2xmle_description {Gives us the combined calibration state and resistance of a speaker} + @h2xmle_variableArraySize {num_ch}*/ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ +#define PARAM_ID_MAX_RATED_TEMP 0x08001510 +/*============================================================================== + Type definitions +==============================================================================*/ +/** @h2xmlp_parameter {"PARAM_ID_MAX_RATED_TEMP", + PARAM_ID_MAX_RATED_TEMP} + @h2xmlp_description {Parameter used to indicate max rated temp for each spkr per the datasheet/vendor} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY} */ +typedef struct param_id_max_rated_temp_param_t param_id_max_rated_temp_param_t; +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_max_rated_temp_param_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of speaker channels} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4} + @h2xmle_default {2} */ + int32_t temp_rated_q6[0];// max rated temp for each spkr per the datasheet/vendor + /**< @h2xmle_description {max rated temp for each spkr per the datasheet/vendor.} + @h2xmle_variableArraySize {num_ch} + @h2xmle_range {4480..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {6400} */ + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== +EVENTS +==============================================================================*/ + +#define EVENT_ID_SPv5_SPEAKER_DIAGNOSTICS 0x08001538 +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_SPv5_SPEAKER_DIAGNOSTICS", + EVENT_ID_SPv5_SPEAKER_DIAGNOSTICS} + @h2xmlp_description { Direct Current Detection event raised by the Speaker Protection Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + //Payload for this event is: PARAM_ID_SPv5_VI_SPKR_DIAGNOSTICS_GETPKT_PARAM + +#define EVENT_ID_VI_CALIBRATION 0x0800119F +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_VI_CALIBRATION", + EVENT_ID_VI_CALIBRATION} + @h2xmlp_description { VI calibration event raised by the Speaker Protection Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + //Payload for this event is: PARAM_ID_SP_TH_VI_CALIB_RES_CFG + +#define EVENT_ID_TH_VI_V_VALI_PARAMS 0x08001129 +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_TH_VI_V_VALI_PARAMS", + EVENT_ID_TH_VI_V_VALI_PARAMS} + @h2xmlp_description { V Validation event raised by the Speaker Protection Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + //Payload for this event is: PARAM_ID_SP_TH_VI_V_VALI_PARAMS + +#define EVENT_ID_VI_PER_SPKR_CALIBRATION 0x08001511 +/*============================================================================== + Type definitions +==============================================================================*/ +/** @h2xmlp_parameter {"EVENT_ID_VI_PER_SPKR_CALIBRATION", + EVENT_ID_VI_PER_SPKR_CALIBRATION} + @h2xmlp_description { Per speaker calibration status is sent using this event.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + //Payload for this event is: PARAM_ID_SP_TH_VI_CALIB_RES_PER_SPKR_CFG + +/** @} <-- End of the Module --> */ + +#endif /* __SP_VI_H__ */ diff --git a/spf/api/modules/splitter_api.h b/spf/api/modules/splitter_api.h new file mode 100644 index 0000000..65f919b --- /dev/null +++ b/spf/api/modules/splitter_api.h @@ -0,0 +1,131 @@ +#ifndef SPLITTER_API_H +#define SPLITTER_API_H +/** + * \file splitter_api.h + * \brief + * splitter_api.h: This file contains the Module Id, Param IDs and configuration + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "module_cmn_api.h" +#include "metadata_api.h" + + +/** + @h2xml_title1 {Simple Splitter API} + @h2xml_title_agile_rev {Simple Splitter API} + @h2xml_title_date {July 9, 2018} + */ + +/*============================================================================== + Constants +==============================================================================*/ + +#define CAPI_SPLITTER_STACK_SIZE 512 + +#define SPLITTER_MAX_INPUT_PORTS 1 + +/** ID of the SPLITTER module, which is used for splitting the data on the input port + on all the output ports. + + @gpr_hdr_fields + Opcode -- MODULE_ID_SPLITTER + */ +#define MODULE_ID_SPLITTER 0x07001011 +/** + @h2xmlm_module {"MODULE_ID_SPLITTER", + MODULE_ID_SPLITTER} + @h2xmlm_displayName {"Splitter"} + @h2xmlm_description {ID of the SPLITTER module. This module is used to split the + streams on the input to all the output ports. \n + + * \n + * Supported Input Media Format: \n + * - Data Format : FIXED_POINT \n + * - fmt_id : Don't care \n + * - Sample Rates : Any (>0) \n + * - Number of channels : 1 to 32 \n + * - Channel type : 1 to 63 \n + * - Bits per sample : 16, 24, 32 \n + * - Q format : 15, 27, 31 \n + * - Interleaving : Any \n + * - Signed/unsigned : Any \n + *} + @h2xmlm_dataMaxInputPorts {SPLITTER_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {INFINITE} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC, APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {CAPI_SPLITTER_STACK_SIZE} + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + /** @h2xmlp_subStruct */ +struct per_port_md_cfg_t +{ + uint32_t port_id; + /**< @h2xmle_description {output port_id on which metadata propagation + will be configured.} */ + uint32_t num_white_listed_md; + /**< @h2xmle_description {number of metadata IDs that should be propagated on the splitter's + output that maps to this port_id} */ +#if defined(__H2XML__) + uint32_t md_whitelist[0]; + /**< @h2xmle_description {array of Metadata IDs corresponding to the metadata that need to be propagated. + By default - Splitter will NOT propagate any.} + @h2xmle_variableArraySize {num_white_listed_md}*/ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Sub-Structure for per_port_md_cfg_t parameter. */ +typedef struct per_port_md_cfg_t per_port_md_cfg_t; + +/** + ID of the Port EoS parameter, used by the Splitter Module + Used to disable the EoS metadata propagation on + certain output ports. + */ +#define PARAM_ID_SPLITTER_METADATA_PROP_CFG 0x0800103C +/** @h2xmlp_parameter {"PARAM_ID_SPLITTER_METADATA_PROP_CFG", PARAM_ID_SPLITTER_METADATA_PROP_CFG} + @h2xmlp_description {Structure for PARAM_ID_SPLITTER_METADATA_PROP_CFG parameter for Multiport modules. + Module should have received CAPI_PORT_NUM_INFO before this. + If this parameter is not issued to the module - The default behavior is to propagate the + metadata on the output ports. BUT, if this parameter is issued, only the whitelisted + metadata will be propagated.} + @h2xmlp_toolPolicy {Calibration} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** Payload of the PARAM_ID_SPLITTER_METADATA_PROP_CFG parameter. + */ +struct param_id_splitter_metadata_prop_cfg_t +{ + uint32_t num_ports; + /**< @h2xmle_description {Specifies the number of ports for which the metadata propagation is configured.} + @h2xmle_default {0} + @h2xmle_range {0..32767}*/ +#if defined(__H2XML__) + per_port_md_cfg_t port_md_prop_cfg_arr[0]; + /**< @h2xmle_description {port_id_arr payload is of variable length and depends on the number + of port_ids. This payload has port ids on which eos metadata propagation + will be disabled.} + @h2xmle_variableArraySize {num_ports}*/ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +/* Structure for PARAM_ID_SPLITTER_METADATA_PROP_CFG parameter. */ +typedef struct param_id_splitter_metadata_prop_cfg_t param_id_splitter_metadata_prop_cfg_t; + +/** @} <-- End of the Module -->*/ + +#endif /* SPLITTER_API_H */ diff --git a/spf/api/modules/spr_api.h b/spf/api/modules/spr_api.h new file mode 100644 index 0000000..fbdb15f --- /dev/null +++ b/spf/api/modules/spr_api.h @@ -0,0 +1,978 @@ +#ifndef _SPR_BUFFER_API_H_ +#define _SPR_BUFFER_API_H_ +/** + * \file spr_api.h + * \brief + * This file contains Public APIs for Splitter-Renderer module. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/*# @h2xml_title1 {Splitter Renderer Module} + @h2xml_title_agile_rev {Splitter Renderer Module} + @h2xml_title_date {March 19, 2019} */ + + +/*# @h2xmlp_subStruct */ + +/** @ingroup ar_spf_mod_spr_mod + Defines the timestamp value. + */ +struct time_us_t +{ + uint32_t value_lsw; + /**< Lower 32 bits of 64-bit time value in microseconds. */ + + /*#< @h2xmle_description {Lower 32 bits of 64-bit time value in + microseconds.} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t value_msw; + /**< Upper 32 bits of 64-bit time value in microseconds. */ + + /*#< @h2xmle_description {Upper 32 bits of 64-bit time value in + microseconds.} + @h2xmle_range {0..0xFFFFFFFF} */ +}; +typedef struct time_us_t time_us_t; + + +/** @ingroup ar_spf_mod_spr_macros + Indicates that the render start time is immediate. Data is rendered as soon + as it is available after the render decision. */ +#define SPR_RENDER_MODE_IMMEDIATE 1 + +/** @ingroup ar_spf_mod_spr_macros + Indicates that the render start time is at given value of absolute time. + This value is the 64-bit absolute wall clock time (in microseconds). */ +#define SPR_RENDER_MODE_ABSOLUTE_TIME 2 + +/** @ingroup ar_spf_mod_spr_macros + Indicates that the render start time is at a specified offset from the + current absolute time wall clock time. This value is a 64-bit time for + render delay (in microseconds). */ +#define SPR_RENDER_MODE_DELAYED 3 + + +/*# @h2xmlp_subStruct */ + +/** @ingroup ar_spf_mod_spr_mod + Contains configuration information for the Render mode. + */ +struct config_spr_render_mode_t +{ + uint32_t render_mode; + /**< Mode that indicates when to start rendering data. + + @valuesbul + - #SPR_RENDER_MODE_IMMEDIATE (Default) + - #SPR_RENDER_MODE_ABSOLUTE_TIME + - #SPR_RENDER_MODE_DELAYED @tablebulletend */ + + /*#< @h2xmle_description {Mode that indicates when to start rendering data.} + @h2xmle_rangeList {"SPR_RENDER_MODE_IMMEDIATE"=1; + "SPR_RENDER_MODE_ABSOLUTE_TIME"=2; + "SPR_RENDER_MODE_DELAYED"=3} + @h2xmle_default {1} */ + + time_us_t render_start_time; + /**< Render start time in microseconds. This value is based on the value of + render_mode field. */ + + /*#< @h2xmle_description {Render start time in microseconds. This value is + based on the value of the render_mode field.} */ +}; +typedef struct config_spr_render_mode_t config_spr_render_mode_t; + + +/** @ingroup ar_spf_mod_spr_macros + MSW of the sign-extended default time (-infinity) for the render window + start time. */ +#define DEFAULT_RENDER_WINDOW_START_MSW AR_NON_GUID(0x80000000) + +/** @ingroup ar_spf_mod_spr_macros + LSW of the sign-extended default time (-infinity) for the render window + start time. */ +#define DEFAULT_RENDER_WINDOW_START_LSW AR_NON_GUID(0x00000000) + +/** @ingroup ar_spf_mod_spr_macros + MSW of the sign-extended default time (-infinity) for the render window end + time. */ +#define DEFAULT_RENDER_WINDOW_END_MSW AR_NON_GUID(0x7FFFFFFF) + +/** @ingroup ar_spf_mod_spr_macros + LSW of the sign extended default time (-infinity) for the render window end + time. */ +#define DEFAULT_RENDER_WINDOW_END_LSW AR_NON_GUID(0xFFFFFFFF) + + +/*# @h2xmlp_subStruct */ + +/** @ingroup ar_spf_mod_spr_mod + Contains configuration information for the render window. + */ +struct config_spr_render_window_t +{ + time_us_t render_window_start; + /**< Start of the tolerance window for incoming timestamps used to make + rendering decisions. Timestamps behind the current window start are + held. + + This value is supported only in resolutions of microseconds. + + The 64-bit render window value is treated as a signed value. The client + who is sending this configuration to the module is responsible for the + sign extension. */ + + /*#< @h2xmle_description {Start of the tolerance window for incoming + timestamps used to make rendering decisions. + Timestamps behind the current window start are + held. \n + This value is supported only in resolutions of + microseconds. The 64-bit render window value is + treated as signed value. The client who is sending + this configuration to the module is responsible + for the sign extension.} */ + + time_us_t render_window_end; + /**< End of the tolerance window for incoming timestamps used to make + rendering decisions. Timestamps ahead of current window end are + dropped. + + This value is supported only in resolutions of microseconds. + + The 64-bit render window value is treated as a signed value. The client + who is sending this configuration to the module is responsible for the + sign extension. */ + + /*#< @h2xmle_description {End of the tolerance window for incoming + timestamps used to make rendering decisions. + Timestamps ahead of current window end are + dropped. \n + This value is supported only in resolutions of + microseconds. The 64-bit render window value is + treated as signed value. The client who is sending + this configuration to the module is responsible + for the sign extension.} */ +}; +typedef struct config_spr_render_window_t config_spr_render_window_t; + + +/** @ingroup ar_spf_mod_spr_macros + Indicates that the render decision is based on the rendering rate of the + primary device (or the session clock mode) served by the SPF module. */ +#define SPR_RENDER_REFERENCE_DEFAULT 1 + +/** @ingroup ar_spf_mod_spr_macros + Indicates that the render decision is based on the local wall clock + reference. */ +#define SPR_RENDER_REFERENCE_WALL_CLOCK 2 + + +/*# @h2xmlp_subStruct */ + +/** @ingroup ar_spf_mod_spr_mod + Contains configuration information for the render decision reference. + */ +struct config_spr_render_reference_t +{ + uint32_t render_reference; + /**< Indicates the choice of render decision reference for incoming data. + + @valuesbul + - #SPR_RENDER_REFERENCE_DEFAULT + - #SPR_RENDER_REFERENCE_WALL_CLOCK + + For loopback use cases, we recommend the wall clock value. */ + + /*#< @h2xmle_description {Indicates the choice of render decision reference + for incoming data. In default mode, the decision + is based on the rendering rate of the primary + device served by the SPR. + In local wall clock mode, the decision is based on + the local wall clock. We recommend this mode for + loopback usecases.} + @h2xmle_rangeList {"SPR_RENDER_REFERENCE_DEFAULT"=1; + "SPR_RENDER_REFERENCE_WALL_CLOCK"=2} + @h2xmle_default {1} */ +}; +typedef struct config_spr_render_reference_t config_spr_render_reference_t; + + +/*# @h2xmlp_subStruct */ + +/** @ingroup ar_spf_mod_spr_mod + Defines the duration of the hold buffer when a render decision is to hold + data in the buffer. + */ +struct config_spr_render_hold_duration_t +{ + time_us_t max_hold_buffer_duration; + /**< Maximum size (in microseconds) of the hold buffer. + + If the client does not set the max_hold_buffer_duration, the module + assumes a default size of 150 ms. */ + + /*#< @h2xmle_description {Maximum size (in microseconds) of the hold buffer + when a render decision is to hold data in the + buffer. If the client does not set the + max_hold_buffer_duration, the module assumes a + default size of 150 ms.} + @h2xmle_default {0} */ +}; +typedef struct config_spr_render_hold_duration_t config_spr_render_hold_duration_t; + + +/** @ingroup ar_spf_mod_spr_macros + Definition of the Render mode bitmask. */ +#define SPR_RENDER_BIT_MASK_RENDER_MODE AR_NON_GUID(0x00000001) + +/** @ingroup ar_spf_mod_spr_macros + Definition of the Render mode shift value. */ +#define SPR_RENDER_SHIFT_RENDER_MODE 0 + +/** @ingroup ar_spf_mod_spr_macros + Definition of the render reference bitmask. */ +#define SPR_RENDER_BIT_MASK_RENDER_REFERENCE AR_NON_GUID(0x00000002) + +/** @ingroup ar_spf_mod_spr_macros + Definition of the render reference shift value. */ +#define SPR_RENDER_SHIFT_RENDER_REFERENCE 1 + +/** @ingroup ar_spf_mod_spr_macros + Definition of the render window bitmask. */ +#define SPR_RENDER_BIT_MASK_RENDER_WINDOW AR_NON_GUID(0x00000004) + +/** @ingroup ar_spf_mod_spr_macros + Definition of the render window shift value. */ +#define SPR_RENDER_SHIFT_RENDER_WINDOW 2 + +/** @ingroup ar_spf_mod_spr_macros + Definition of the render hold duration. */ +#define SPR_RENDER_BIT_MASK_HOLD_DURATION AR_NON_GUID(0x00000008) + +/** @ingroup ar_spf_mod_spr_macros + Definition of the render hold duration shift value. */ +#define SPR_RENDER_SHIFT_HOLD_DURATION 3 + +/** Indicates Non-time stamp honor mode can be enabled or not. */ +#define SPR_RENDER_BIT_MASK_ALLOW_NON_TIMESTAMP_HONOR_MODE AR_NON_GUID(0x00000010) + +/** Definition of Non-time stamp honor mode shift value. */ +#define SPR_RENDER_SHIFT_ALLOW_NONTIMESTAMP_HONOR_MODE 4 + +/** @ingroup ar_spf_mod_spr_mod + ID of the parameter that defines end of the delay path. + + The SPR module requires a path delay to perform accurate AV synchronization + or return the session time to the client. A path is defined as a series of + connections from one module to another through which data flows. Path delay + is the sum of the various delays suffered by the data as it flows through + the path. Contributors to path delay are algorithmic delays, buffering + delays, and so on. + + For the SPR module, the required path delay is the aggregation of delay + from the SPR to the endpoint module. The SPR must be told about the + endpoint through this API. + + For the delay to be accurate, it must be automatically calculated, which is + possible with this API. + - The SPR might have multiple output ports. + - The SPF searches for and finds the appropriate output port that leads to + the given endpoint. + - If there are multiple paths that lead to the same endpoint (due to splits + and merges), the first path is chosen (which can be arbitrary). + + For multiple endpoints that are fed from the SPR module, the same parameter + is sent multiple times. The SPR will store delay per output port by + auto-detecting the output port that corresponds to the endpoint. If two + different endpoints are fed from same output port (due to a splitter that + is downstream of the SPR), the SPR uses the latest endpoint. + + @msgpayload + param_id_spr_delay_path_end_t @newpage + */ +#define PARAM_ID_SPR_DELAY_PATH_END 0x080010C4 + +/*# @h2xmlp_parameter {"PARAM_ID_SPR_DELAY_PATH_END", + PARAM_ID_SPR_DELAY_PATH_END} + @h2xmlp_description {ID for the parameter that defines end of the delay + path. For more details, see AudioReach Signal Processing + Framework (SPF) API Reference.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_spr_mod + Payload of the #PARAM_ID_SPR_DELAY_PATH_END parameter. + */ +#include "spf_begin_pack.h" +struct param_id_spr_delay_path_end_t +{ + uint32_t module_instance_id; + /**< Identifier for the module instance ID at the end of the path used for + delay calculations. */ + + /*#< @h2xmle_description {ID for the module instance at the end of the path + used for delay calculations.} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_spr_delay_path_end_t param_id_spr_delay_path_end_t; + +/*============================================================================== + Constants +==============================================================================*/ + +/** @ingroup ar_spf_mod_spr_macros + Bitmask for the Timestamp Valid flag in param_id_session_time_t. */ +#define PARAM_ID_SESSION_TIME_BIT_MASK_IS_TIMESTAMP_VALID AR_NON_GUID(0x80000000UL) + +/** @ingroup ar_spf_mod_spr_macros + Shift value for the Timestamp Valid flag in param_id_session_time_t. */ +#define PARAM_ID_SESSION_TIME_SHIFT_IS_TIMESTAMP_VALID 31 + +/*============================================================================== + API definitions +==============================================================================*/ + +/** @ingroup ar_spf_mod_spr_mod + Identifier for the Get parameter used to query the session time. This + parameter provides information related to the current session time. + + The session time value must be interpreted by clients as a signed 64-bit + value. A negative session time can be returned when the client is to start + running a session in the future, but first queries for the session + clock. The timestamp field is populated using the last processed timestamp. + + This field follows certain rules: + - For an uninitialized or invalid timestamp, the value reads 0, and the + flag that follows this timestamp field is set to 0 to indicate + Uninitialized/Invalid. + - During steady state rendering, the session time reflects the last + processed timestamp. + - Clients must interpret the timestamp value in the command response as an + unsigned 64-bit value. The absolute time can be in the past or future. + - If the client does not enable the AV synchronization feature via + #PARAM_ID_SPR_AVSYNC_CONFIG, these values are returned as 0. + + @msgpayload + param_id_spr_session_time_t @newpage +*/ +#define PARAM_ID_SPR_SESSION_TIME 0x0800113D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/*# @h2xmlp_parameter {"PARAM_ID_SPR_SESSION_TIME", + PARAM_ID_SPR_SESSION_TIME} + @h2xmlp_description {Identifier for the Get parameter used to query the + session time. This parameter provides information + related to the current session time. For more + details, see AudioReach Signal Processing Framework + SPF) API Reference.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_spr_mod + Payload of the #PARAM_ID_SPR_SESSION_TIME parameter. + */ +#include "spf_begin_pack.h" +struct param_id_spr_session_time_t +{ + time_us_t session_time; + /**< Value of the current session time in microseconds. */ + + /*#< @h2xmle_description {Value of the current session time in + microseconds.} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0} */ + + time_us_t absolute_time; + /**< Value of the absolute time in microseconds when the sample that + corresponds to the session time is rendered at the hardware. + + This time can be slightly in the future or past depending on when this + parameter is queried. */ + + /*#< @h2xmle_description {Value of the absolute time in microseconds when + the sample that corresponds to the session time is + rendered at the hardware. This time can be + slightly in the future or past depending on when + this parameter is queried.} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0} */ + + time_us_t timestamp; + /**< Value of the last processed timestamp in microseconds. The 64-bit + number is treated as signed. */ + + /*#< @h2xmle_description {Value of the last processed timestamp in + microseconds. The 64-bit number is treated as + signed.} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_default {0} */ + + uint32_t flags; + /**< Configures additional properties associated with this payload. + + @valuesbul{for bit 31} + - 0 -- Value of last processed timestamp is invalid/uninitialized + - 1 -- Value of last processed timestamp is valid/initialized + + All other bits are reserved and are set to 0. */ + + /*#< @h2xmle_description {Configures additional properties associated with + this payload. Bit 31 indicates whether the + timestamp is valid (1) or not (0). All other bits + are reserved and are set to 0.} + @h2xmle_rangeList {"TS_INVALID"=0x00000000; + "TS_VALID"=0x80000000} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_spr_session_time_t param_id_spr_session_time_t; + +/** @ingroup ar_spf_mod_spr_macros + Indicates that the SPR operates in the Default Mode where session_time is + reset when + 1) Flush command is issued + 2) Gapless stream switch occurs */ +#define SPR_SESSION_TIME_RESET_MODE_DEFAULT 0 + +/** @ingroup ar_spf_mod_spr_macros + Indicates that the SPR operates in the mode where session_time reset is + skipped when Gapless stream switch occurs */ +#define SPR_SESSION_TIME_SKIP_RESET_GAPLESS_SWITCH 1 + +/** @ingroup ar_spf_mod_spr_mod + Identifier for the parameter used to configure the SPR module behavior + with respect to resetting session time. + + Guidelines for using this param are as below :- + + - This parameter has to be sent by the client explicitly when there + is a need to change the default behavior of the SPR module. + + - Until the subgraph hosting the SPR is started, the client can set + this parameter multiple times. The last configured value is taken + into consideration. + + If a subgraph hosting SPR is stopped and started, the functionality + proceeds with the previous configuration (if any). The client can + configure this parameter before restarting the session to ensure the + desired behavior behavior. + + - If no AVSync functionality is enabled via PARAM_ID_SPR_AVSYNC_CONFIG, + then this configuration does not take effect. + + - If client is interested in obtaining the value of session time before reset, + refer to #EVENT_ID_SPR_SESSION_TIME_RESET + + The mode field in this payload supports 2 values currently :- + + #SPR_SESSION_TIME_RESET_MODE_DEFAULT + - This indicates that session time will be reset whenever there is + a flush command or gapless stream switch. + - The SPR will choose to operate in this default mode. + + #SPR_SESSION_TIME_SKIP_RESET_GAPLESS_SWITCH + - This indicates that the session time will not be reset when + gapless stream switch occurs. + + @msgpayload + param_id_spr_session_time_t @newpage +*/ +#define PARAM_ID_SPR_SESSION_TIME_RESET_INFO 0x08001B07 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/*# @h2xmlp_parameter {"PARAM_ID_SPR_SESSION_TIME_RESET_INFO", + PARAM_ID_SPR_SESSION_TIME_RESET_INFO} + @h2xmlp_description {Identifier for the parameter used to configure the + SPR module behavior with respect to resetting session + time.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/** @ingroup ar_spf_mod_spr_mod + Payload of the #PARAM_ID_SPR_SESSION_TIME_RESET_INFO parameter. + */ +#include "spf_begin_pack.h" +struct param_id_spr_session_time_reset_info_t +{ + uint32_t mode; + /**< Indicates the configuration for handling session time reset. + + @valuesbul + - #SPR_SESSION_TIME_RESET_MODE_DEFAULT + - #SPR_SESSION_TIME_SKIP_RESET_GAPLESS_SWITCH */ + + + /*#< @h2xmle_description {Mode of operation for session time reset} + @h2xmle_rangeList {"SPR_SESSION_TIME_RESET_MODE_DEFAULT"=0; + "SPR_SESSION_TIME_SKIP_RESET_GAPLESS_SWITCH"=1} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_spr_session_time_reset_info_t param_id_spr_session_time_reset_info_t; + +/** @ingroup ar_spf_mod_spr_mod + Identifier for the parameter that configures information required for + AV synchronization functionalities in the SPR module, including a data + render decision. + + The SPR module makes render decisions on incoming data. A render decision + involves rendering (allowing data to output), and holding or dropping the + incoming data. + + SPR module must know if the AVSync feature is to be enabled. If so, the + following additional information is required: + - When to render + - What to gate or compare against + - Render tolerance window + + Because the SPR performs gating of input to output, a Graph Start on the + subgraph hosting the SPR module does not guarantee immediate data flow in + the subgraph if the render decision parameter is not configured to render + immediately. + + This parameter is expected to be set before the SPR module is moved to the + Start state. If the parameter is not set by then, no AVSync functionality + is enabled for the current run. + + If this parameter is set with enable=1 AND the client is to use the + default values for all the other render parameters for this run, the + expected payload values are enable=1 AND render_mask=0. The individual + parameter descriptions contain the default values. + + If the client is to configure fields specifically, it can set enable=1 and + set up the render_mask to reflect the values that are to be updated by the + SPR. For the fields that are not configured, the SPR chooses the default + values. + + Once the subgraph hosting the SPR is moved to the Start state, changes in + this configuration are not allowed except in the following case: If the + client enabled AVSync before the Start state transition, only the render + window is allowed to be updated at run time. Any other changes are rejected + and result in a failure for the Set parameter command. + + Until the subgraph hosting the SPR is started, the client can set this + parameter multiple times. The last configured value is taken into + consideration. + + If a subgraph hosting SPR is stopped and started or paused and resumed, the + AVSync functionality proceeds with the previous configuration (if any) and + uses the first buffer to perform the first sample rendering. The client can + configure this parameter before restarting the session to ensure the + specified behavior. + + @note1hang This parameter supports only setting of the configuration, not + getting the configuration. + + @msgpayload + param_id_spr_avsync_config_t @newpage +*/ +#define PARAM_ID_SPR_AVSYNC_CONFIG 0x0800115B + +/*# @h2xmlp_parameter {"PARAM_ID_SPR_AVSYNC_CONFIG", + PARAM_ID_SPR_AVSYNC_CONFIG} + @h2xmlp_description {ID for the parameter that configures information + required for the AVSync functionalities for the SPR + module, including a data render decision. For more + details, see AudioReach Signal Processing Framework + SPF) API Reference.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_spr_mod + Payload of the #PARAM_ID_SPR_AVSYNC_CONFIG parameter. + */ +#include "spf_begin_pack.h" +struct param_id_spr_avsync_config_t +{ + uint16_t enable; + /**< Indicates if the AVSync functionality is to be enabled. + + @valuesbul + - 0 -- Disable + - 1 -- Enable + + This parameter can be enabled or disabled until the subgraph hosting + the SPR container is started. The value of the variable most recently + configured is used to decide whether the AVSync feature is to be + enabled. + + If this field is set to 0, the rest of the values are ignored by the + SPR and any configured fields are reset. */ + + /*#< @h2xmle_description {Indicates if the AVSync functionality is to be + enabled (1) or not (0). \n + This parameter can be enabled or disabled until + the subgraph hosting the SPR container is started. + The value of the variable most recently configured + is used to decide whether the AVSync feature is to + be enabled. \n + If this field is set to 0, the rest of the values + are ignored by the SPR and any configured fields + are reset.} + @h2xmle_rangeList {"DISABLE"=0, + "ENABLE"=1} + @h2xmle_default {0} */ + + uint16_t render_mask; + /**< Render mask with bitfields to selectively configure fields. + + @tblsubhd{Bit 0} + Configures the render mode for the SPR. This value is effective only + if enable=1. @vertspace{-3} + - 0 -- IGNORE + - 1 -- CONFIGURE + + @tblsubhd{Bit 1} + Configures the render reference for the SPR. This value is effective + only if enable=1. @vertspace{-3} + - 0 -- IGNORE + - 1 -- CONFIGURE + + @tblsubhd{Bit 2} + Configures the render window for the SPR. This value is effective only + if enable=1. @vertspace{-3} + - 0 -- IGNORE + - 1 -- CONFIGURE + + @tblsubhd{Bit 3} + Configures the maximum hold duration that is expected for the SPR. This + value is effective only if enable=1. @vertspace{-3} + - 0 -- IGNORE + - 1 -- CONFIGURE + + @tblsubhd{Bits 15 to 4} + Reserved bits that are set to 0. + + All other bits are reserved; clients must set them to 0. If any of + these bits are set to IGNORE, the last configured value or the default + value is used as long as AVSync enable=1. */ + + /*#< @h2xmle_description {Render mask with bitfields to selectively + configure fields. All other bits are reserved; + clients must set them to 0. \n + If any of these bits are set to ignore, the last + configured value or the default value is used as + long as AVSync enable=1.} + @h2xmle_range {0x0000..0xFFFF} + + @h2xmle_bitField {0x0001} + @h2xmle_bitName {Bit_0_Render_Mode_Config} + @h2xmle_description {Configures the render mode for the SPR. This + value is effective only if enable=1.} + @h2xmle_rangeList {"IGNORE"=0, + "CONFIGURE"=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x0002} + @h2xmle_bitName {Bit_1_Render_Reference_Config} + @h2xmle_description {Configures the render reference for the SPR. This + value is effective only if enable=1. } + @h2xmle_rangeList {"IGNORE"=0, + "CONFIGURE"=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x0004} + @h2xmle_bitName {Bit_2_Render_Window_Config} + @h2xmle_description {Configures the render window for the SPR. This + value is effective only if enable=1.} + @h2xmle_rangeList {"IGNORE"=0, + "CONFIGURE"=1} + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x0008} + @h2xmle_bitName {Bit_3_Hold_Duration_Config} + @h2xmle_description {Configures the maximum hold duration that is + expected for the SPR. This value is effective only + if enable=1.} + @h2xmle_rangeList {"IGNORE"=0, + "CONFIGURE"=1} + @h2xmle_bitFieldEnd + @h2xmle_bitFieldEnd + + @h2xmle_bitField {0x0010} + @h2xmle_bitName {Bit_4_Allow_Non_TimeStamp_Honor_Mode} + @h2xmle_description {Configures the non-timestamp honor mode} + @h2xmle_rangeList {"DISABLE"= 0, + "ENABLE" = 1} + @h2xmle_bitFieldEnd + + @h2xmle_bitfield {0xFFF0} + @h2xmle_bitName {Bit_15_to_4_RESERVED} + @h2xmle_description {Reserved bits [15:4].} + @h2xmle_rangeList {"RESERVED"=0} + @h2xmle_visibility {hide} + @h2xmle_bitfieldEnd */ + + config_spr_render_mode_t render_mode_config; + /**< Configuration parameter for the Render mode and start time. */ + + /*#< @h2xmle_description {Configuration parameter for the Render mode and + start time.} */ + + config_spr_render_reference_t render_reference_config; + /**< Configuration parameter for the render reference. */ + + /*#< @h2xmle_description {Configuration parameter for the render + reference.} */ + + config_spr_render_window_t render_window; + /**< Configuration parameter for the render window. */ + + /*#< @h2xmle_description {Configuration parameter for the render window.} */ + + config_spr_render_hold_duration_t render_hold_buffer_size; + /**< Configuration parameter for the size of the render hold buffer. */ + + /*#< @h2xmle_description {Configuration parameter for the size of the render + hold buffer.} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_spr_avsync_config_t param_id_spr_avsync_config_t; + + +/*# @h2xmlp_subStruct + @h2xmlp_description {Defines a control port-to-output data port mapping. + Each output port ID must be linked to only one control + port ID.} */ + +/** @ingroup ar_spf_mod_spr_mod + Defines a control port-to-output data port mapping. Each output port ID + must be linked to only one control port ID. +*/ +#include "spf_begin_pack.h" +struct spr_port_binding_t +{ + uint32_t control_port_id; + /**< Identifier for the control port of the module. */ + + /*#< @h2xmle_description {Control port ID of the module.} + @h2xmle_default {0} */ + + uint32_t output_port_id; + /**< Identifier for the output port to which a control port is linked. */ + + /*#< @h2xmle_description {Output port ID to which a control port is linked.} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct spr_port_binding_t spr_port_binding_t; + + +/** @ingroup ar_spf_mod_spr_mod + Identifier for the parameter that defines the control port-to-data port + mapping. + + SPR control ports that are connected to the endpoint must be coupled to + output port IDs. Each control port can be coupled to only one output port + ID; thus, the number of bindings is same as the number of output ports. + + @msgpayload + param_id_spr_ctrl_to_data_port_map_t +*/ +#define PARAM_ID_SPR_CTRL_TO_DATA_PORT_MAP 0x0800113A + +/*# @h2xmlp_parameter {"PARAM_ID_SPR_CTRL_TO_DATA_PORT_MAP", + PARAM_ID_SPR_CTRL_TO_DATA_PORT_MAP} + @h2xmlp_description {ID for the parameter that defines the control + port-to-data port mapping. \n + SPR control ports that are connected to the endpoint + must be coupled to output port IDs. Each control port + can be coupled to only one output port ID; thus, the + number of bindings is same as the number of output + ports.} + @h2xmlp_toolPolicy {Calibration} */ + +/** @ingroup ar_spf_mod_spr_mod + Payload of the #PARAM_ID_SPR_CTRL_TO_DATA_PORT_MAP parameter. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_spr_ctrl_to_data_port_map_t +{ + uint32_t num_ctrl_ports; + /**< Number of control port IDs attached to the module. */ + + /*#< @h2xmle_description {Number of control port IDs attached to the + module.} + @h2xmle_default {0} */ + +#if defined(__H2XML__) + spr_port_binding_t ctrl_to_outport_map[0]; + /**< Array of control port-to-data port mappings of size num_ctrl_ports. */ + + /*#< @h2xmle_description {Array of control port-to-data port mappings + of size num_ctrl_ports.} + @h2xmle_variableArraySize {num_ctrl_ports} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct param_id_spr_ctrl_to_data_port_map_t param_id_spr_ctrl_to_data_port_map_t; + + +/** @ingroup ar_spf_mod_spr_macros + Indicates an underrun occurred because input is not available. */ +#define UNDERRUN_STATUS_INPUT_NOT_AVAILABLE 0x1 + +/** @ingroup ar_spf_mod_spr_macros + Indicates an underrun occurred because the input is held after the render + decision (AVSync). +*/ +#define UNDERRUN_STATUS_INPUT_HOLD 0x2 + +/** @ingroup ar_spf_mod_spr_macros + Indicates an underrun occurred because input is dropped after the render + decision (AVSync). +*/ +#define UNDERRUN_STATUS_INPUT_DROP 0x3 + + +/** @ingroup ar_spf_mod_spr_mod + Identifier for the underrun event raised by the SPR module. A client can + register to listen to this event. + + @msgpayload + event_id_spr_underrun_t +*/ +#define EVENT_ID_SPR_UNDERRUN 0x080011E6 + +/*# @h2xmlp_parameter {"EVENT_ID_SPR_UNDERRUN", EVENT_ID_SPR_UNDERRUN} + @h2xmlp_description {ID for the underrun event raised by the SPR module. + A client can register to listen to this event.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/** @ingroup ar_spf_mod_spr_mod + Payload of the #EVENT_ID_SPR_UNDERRUN event. + */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct event_id_spr_underrun_t +{ + uint32_t status; + /**< Status of the underrun event being raised by the SPR module. + + @valuesbul + - #UNDERRUN_STATUS_INPUT_NOT_AVAILABLE + - #UNDERRUN_STATUS_INPUT_HOLD + - #UNDERRUN_STATUS_INPUT_DROP @tablebulletend */ + + /*#< @h2xmle_description {Status of the underrun event being raised by the + SPR module.} + @h2xmle_range {1..3} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; +typedef struct event_id_spr_underrun_t event_id_spr_underrun_t; + +/** @ingroup ar_spf_mod_spr_mod + Identifier for the session time reset event raised by SPR module. + The event provides the current session time at SPR before resetting the + session time to 0. Upto 1 client can register for this event with the + SPR module. + + If the client does not enable the AV synchronization feature via + #PARAM_ID_SPR_AVSYNC_CONFIG, these values are returned as 0. + + @msgpayload + param_id_session_time_t +*/ + +#define EVENT_ID_SPR_SESSION_TIME_RESET 0x08001B60 + +/*# @h2xmlp_parameter {"EVENT_ID_SPR_SESSION_TIME_RESET", EVENT_ID_SPR_SESSION_TIME_RESET} + @h2xmlp_description {ID for the session time reset event raised by SPR module.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/** @ingroup ar_spf_mod_spr_mod + Identifier for the Splitter Renderer module, which is used to split an + audio stream into multiple devices. + + This module is used for AV Synchronization as well as decision rendering. + The module is only to be used in an audio playback use case. It is + supported only in a container whose position is APM_CONT_GRAPH_POS_STREAM. + (For information about APM_CONT_GRAPH_POS_STREAM, see AudioReach Signal + Processing Framework (SPF) API Reference. + + @subhead4{Supported input media format ID} + - Data format : #DATA_FORMAT_FIXED_POINT @lstsp1 + - fmt_id : #MEDIA_FMT_ID_PCM @lstsp1 + - Sample rates : Any @lstsp1 + - Number of channels: Any @lstsp1 + - Bit width : Any @lstsp1 + - Interleaving : De-interleaved unpacked @lstsp1 + - Endianness : little + + @par Output media format + Until the input media format is available, the output media format is + arbitrarily decided. @newpage + */ +#define MODULE_ID_SPR 0x07001032 + +/*# @h2xmlm_module {"MODULE_ID_SPR", MODULE_ID_SPR} + @h2xmlm_displayName {"Splitter Renderer"} + @h2xmlm_modSearchKeys {Audio} + @h2xmlm_description {ID for the Splitter Renderer module, which + is used to split an audio stream into + multiple devices. For more details about + this module, see AudioReach Signal Processing + Framework (SPF) API Reference.} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {-1} + @h2xmlm_toolPolicy {Calibration} + @h2xmlm_ctrlDynamicPortIntent {"Drift Info IMCL"=INTENT_ID_TIMER_DRIFT_INFO, + maxPorts= -1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {1024} + + @{ <-- Start of the Module --> + @h2xml_Select {param_id_spr_delay_path_end_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_spr_session_time_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_spr_avsync_config_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_spr_avsync_config_t::render_window::render_window_start} + @h2xmle_defaultList {0x00000000,0x80000000} + + @h2xml_Select {param_id_spr_avsync_config_t::render_window::render_window_end} + @h2xmle_defaultList {0xFFFFFFFF,0x7FFFFFFF} + + @h2xml_Select {param_id_spr_ctrl_to_data_port_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {time_us_t} + @h2xmlm_InsertStructure + @h2xml_Select {config_spr_render_mode_t} + @h2xmlm_InsertStructure + @h2xml_Select {config_spr_render_window_t} + @h2xmlm_InsertStructure + @h2xml_Select {config_spr_render_reference_t} + @h2xmlm_InsertStructure + @h2xml_Select {config_spr_render_hold_duration_t} + @h2xmlm_InsertStructure + @h2xml_Select {spr_port_binding_t} + @h2xmlm_InsertStructure + @} <-- End of the Module --> */ + + +#endif /* _SPR_BUFFER_API_H_ */ diff --git a/spf/api/modules/sync_api.h b/spf/api/modules/sync_api.h new file mode 100644 index 0000000..3d83d46 --- /dev/null +++ b/spf/api/modules/sync_api.h @@ -0,0 +1,80 @@ +#ifndef _SYNC_API_H_ +#define _SYNC_API_H_ +/** + * \file sync_api.h + * \brief + * This file contains the Sync module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "apm_graph_properties.h" + +/** + @h2xml_title1 {Sync Module API} + @h2xml_title_agile_rev {Sync Module API} + @h2xml_title_date {July 12, 2018} */ + +/*============================================================================== + Defines +==============================================================================*/ + +/*============================================================================== + API definitions +==============================================================================*/ + +#define SYNC_STACK_SIZE 4096 +#define SYNC_MAX_IN_PORTS 32 +#define SYNC_MAX_OUT_PORTS 32 + +#define MODULE_ID_SYNC 0x07001038 +/** @h2xmlm_module {"MODULE_ID_SYNC", MODULE_ID_SYNC} + @h2xmlm_displayName {"Sync Module"} + @h2xmlm_description {- Generic Synchronziation Module\n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT, \n + - fmt_id : MEDIA_FMT_ID_PCM \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1 to 8 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q31 \n + - Interleaving : Deinterleaved unpacked, deinterleaved packed. \n + - Endianess : little, big \n + - Ports are allowed to have different media formats. The only \n + - restriction is that if one port runs at a fractional rate, the other ports must also \n + - run at a fractional rate (use cases where ports have variable input frame sizes are \n + - not supported).} + + @h2xmlm_dataMaxInputPorts {SYNC_MAX_IN_PORTS} + @h2xmlm_dataInputPorts {IN0 = 6; + IN1 = 8; + IN2 = 10; + IN3 = 12; + IN4 = 14; + IN5 = 16; + IN6 = 18; + IN7 = 20} + @h2xmlm_dataMaxOutputPorts {SYNC_MAX_OUT_PORTS} + @h2xmlm_dataOutputPorts {OUT0 = 5; + OUT1 = 7; + OUT2 = 9; + OUT3 = 11; + OUT4 = 13; + OUT5 = 15; + OUT6 = 17; + OUT7 = 19} + + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_SC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { SYNC_STACK_SIZE } + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + +#endif //_SYNC_API_H_ diff --git a/spf/api/modules/test_module_api.h b/spf/api/modules/test_module_api.h new file mode 100644 index 0000000..858449a --- /dev/null +++ b/spf/api/modules/test_module_api.h @@ -0,0 +1,290 @@ +#ifndef _TEST_MODULE_API_H_ +#define _TEST_MODULE_API_H_ +/** + * \file test_module_api.h + * \brief + * This file contains test module APIs. The test module is implemented + * to be used in CSIM tests for nonstandard capi behavior like threshold, + * partial processing, duration change, etc. For production this module will + * be stubbed + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" +#include "module_cmn_api.h" +/*============================================================================== + Defines +==============================================================================*/ +/** Module IDs for testing custom stub modules in AMDB tests */ +#define MODULE_ID_GAIN_CUSTOM 0x07001025 +#define MODULE_ID_AAC_DEC_CUSTOM 0x07001026 +#define MODULE_ID_AAC_ENC_CUSTOM 0x07001027 + +/*============================================================================== + API definitions +==============================================================================*/ +/* ID of the parameter used to configure as a threshold module */ +#define PARAM_ID_TEST_THRESHOLD_CFG 0x0800100D + +/** Configures whether to act as a threshold module. The threshold can be configured + to be hard or soft. A hard threshold means that the module will raise a port threshold + event, and will error out from the process() call if there is not enough data in the input + or space in the output to process the entire threshold. A soft threshold means that the module + will not raise a port threshold event. During process(), the module will process at MOST the + threshold amount of data. If less data than the threshold is provided, all data will be processed. */ + +#include "spf_begin_pack.h" +/* Payload for parameter param_id_test_threshold_cfg_t */ +struct param_id_test_threshold_cfg_t +{ + uint32_t threshold_us; + /**< Threshold duration. 0 means disabled. + range 0..1000000 + default 0 */ + + uint16_t is_input; + /**< description Whether the threshold applies to the input port or output port. + rangeList "Output Port" = 0; + "Input Port" = 1 + default 0 */ + + uint16_t is_hard_thresh; + /**< description Whether the threshold is a hard threshold or soft threshold. + rangeList "Hard Threshold" = 0; + "Soft Threshold" = 1 + default 0 */ +} +#include "spf_end_pack.h" +; + +typedef struct param_id_test_threshold_cfg_t param_id_test_threshold_cfg_t; + +/* ID of the parameter used to configure busy-waiting during process. */ +#define PARAM_ID_TEST_BUSY_WAIT_CFG 0x0800106D + +/** Configures the threshold module to busy-wait at the end of process. The module will not busy wait + if this is not configured. Even when busy waiting is enabled, the test module will still do all + normal processing before busy waiting. Busy waiting is implemented as an assembly loop full of nops. */ + +#include "spf_begin_pack.h" +/* Payload for parameter param_id_busy_wait_cfg_t */ +struct param_id_busy_wait_cfg_t +{ + uint32_t enable; + /**< description {Enable/disable busy waiting.} + rangeList {"Disable" = 0; + "Enable" = 1} + default {0} */ + uint32_t busy_wait_cycles; + /**< description {How many cycles the module should busy wait. + TODO(claguna) Estimates of cycle-to-duration: + MSM8998: 1ms = X cycles, 5ms = X cycles, 10ms = X cycles} + range {0..0xFFFFFFFF} + default {0} */ + + uint16_t period; + /**< description {The module will only busy-wait every process calls.} + range {0..65535} + default {0} */ + + uint16_t duty_cycle; + /**< description {How many consecutive process calls the module should busy-wait for. + If larger than the period, then the module will busy wait every + process cycle.} + range {0..65535} + default {0} */ + +} +#include "spf_end_pack.h" +; + +typedef struct param_id_busy_wait_cfg_t param_id_busy_wait_cfg_t; + +/* ID of the parameter used to configure algorithmic delay. Currently the actual delay is 0; + * this only configures the reported delay. */ +#define PARAM_ID_TEST_ALGO_DELAY_CFG 0x080010F7 + +/** Configures the threshold module to busy-wait at the end of process. The module will not busy wait + if this is not configured. Even when busy waiting is enabled, the test module will still do all + normal processing before busy waiting. Busy waiting is implemented as an assembly loop full of nops. */ + +#include "spf_begin_pack.h" +/* Payload for parameter param_id_algo_delay_cfg_t */ +struct param_id_algo_delay_cfg_t +{ + uint32_t delay_in_us; + /**< description {Reported delay in microseconds.} + range {0..0xFFFFFFFF} + default {0} */ + +} +#include "spf_end_pack.h" +; + +typedef struct param_id_algo_delay_cfg_t param_id_algo_delay_cfg_t; + +/* ID of the parameter used to configure hw accelerator delay. */ +#define PARAM_ID_TEST_HW_ACCL_PROC_DELAY 0x0800130F + +#include "spf_begin_pack.h" +/* Payload for parameter PARAM_ID_TEST_HW_ACCL_PROC_DELAY */ +struct param_id_hw_acc_proc_delay_cfg_t +{ + uint32_t delay_in_us; + /**< description {Reported delay in microseconds.} + range {0..0xFFFFFFFF} + default {0} */ + +} +#include "spf_end_pack.h" +; + +typedef struct param_id_hw_acc_proc_delay_cfg_t param_id_hw_acc_proc_delay_cfg_t; + + +/* ID used to configure DTMF and send metadata for DTMF configuration */ +#define PARAM_ID_TEST_DTMF_GEN_MD_CFG 0x08001147 +/** Sends configuration as DTMF Gen metadata. */ + + +/* ID used to add TTR delay to TTR metadata attached to buffers */ +#define PARAM_ID_TEST_SET_TTR_DELAY 0x0800101D +/** Creates ttr metadata with delay */ + +#include "spf_begin_pack.h" +struct param_id_set_ttr_delay_t +{ + uint32_t ttr_delay_in_us; + /**< description {delay in microseconds.} + range {0..0xFFFFFFFF} + default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_set_ttr_delay_t param_id_set_ttr_delay_t; +/* ID of the parameter used to configure timestamp offset. All timestamps are offset by this amount - this is + used to simulate timestamp discontinuities. */ +#define PARAM_ID_TEST_TIMESTAMP_OFFSET 0x080010F8 + +/** Configures the timestamp offset - all timestamps are adjust by algo delay + this amount. */ + +#include "spf_begin_pack.h" +/* Payload for parameter param_id_timestamp_offset_t */ +struct param_id_timestamp_offset_t +{ + int32_t offset_us; + /**< description {Timestamp offset in microseconds.} + range {0..0xFFFFFFFF} + default {0} */ + + int32_t delay_num_proc_calls; + /** description {Don't apply the offset until this many process calls have happened.} + range {0..0xFFFFFFFF} + default {0} */ +} +#include "spf_end_pack.h" +; + +typedef struct param_id_timestamp_offset_t param_id_timestamp_offset_t; + +#define PARAM_ID_TEST_PERIODIC_MD_GEN_CFG 0x0800125C + +typedef enum periodicity_mode_t +{ + FRAME_PERIODIC, + /*MD gets generated every n frames (process calls)*/ +}periodicity_mode_t; + +typedef struct test_module_periodicity_t +{ + periodicity_mode_t mode; + /**< description {mode of periodicity - default - frame periodic} + range {0..0xFFFFFFFF} + default {0} */ + uint32_t period; + /**< description {period} + range {0..0xFFFFFFFF} + default {10} */ +}test_module_periodicity_t; + + +#include "spf_begin_pack.h" +/* Payload for parameter param_id_test_periodic_md_gen_cfg_t */ +struct param_id_test_periodic_md_gen_cfg_t +{ + uint32_t gen_enable; + /**< description {enable generation} + range {0..0xFFFFFFFF} + default {0} */ + + uint32_t md_id; + /** description {metadata_to_generate. relevant cfg needs to have been received - if reqd} + range {0..0xFFFFFFFF} + default {0} */ + + test_module_periodicity_t periodicity; + /** description {by default, periodic md is generated once every 10 frames} + range {0..0xFFFFFFFF} + default {0} */ +} +#include "spf_end_pack.h" +; + +typedef struct param_id_test_periodic_md_gen_cfg_t param_id_test_periodic_md_gen_cfg_t; + +#define PARAM_ID_TEST_MD_TRACKING_CFG 0x080012EA + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/* Payload for parameter param_id_test_md_tracking_cfg_t */ +struct param_id_test_md_tracking_cfg_t +{ + uint32_t tracking_enable; + /**< description {enable tracking md} + range {0..0xFFFFFFFF} + default {0} */ + + uint32_t md_id; + /** description {MD ID for which to enable tracking - module expects separate md cfg as necessary} */ + + uint8_t tracking_info[0]; + /** description {tracking info. Module will parse the size of module_cmn_md_tracking_t} + range {0..0xFFFFFFFF} + default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_test_md_tracking_cfg_t param_id_test_md_tracking_cfg_t; + + +/* ID of the parameter used to configure algorithmic delay. Currently the actual delay is 0; + * this only configures the reported delay. */ +#define PARAM_ID_TEST_FORCE_OUTPUT_SAMPLES_CFG 0x08001318 + +/** Configures the test module to force it to output a certain number of samples per channel for a single process call. */ + +#include "spf_begin_pack.h" +/* Payload for parameter param_id_test_force_output_samples_cfg_t */ +struct param_id_test_force_output_samples_cfg_t +{ + uint32_t samples_per_channel; + /**< description {Samples per channel to output for a single process call. If larger than current frame, + size is cropped to actual frame size.} + range {0..0xFFFFFFFF} + default {0} */ + +} +#include "spf_end_pack.h" +; + +typedef struct param_id_test_force_output_samples_cfg_t param_id_test_force_output_samples_cfg_t; + +/** Module ID for test module */ +#define MODULE_ID_TEST_MODULE 0x07001021 + +#endif //_TEST_MODULE_API_H_ diff --git a/spf/api/modules/trm_api.h b/spf/api/modules/trm_api.h new file mode 100644 index 0000000..24c261f --- /dev/null +++ b/spf/api/modules/trm_api.h @@ -0,0 +1,72 @@ +#ifndef _TRM_API_H_ +#define _TRM_API_H_ +/** + * \file trm_api.h + * \brief + * API file for Timed Renderer Module + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "apm_graph_properties.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of TRM */ +#define TRM_DATA_INPUT_PORT 0x2 + +/* Output port ID of TRM */ +#define TRM_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of TRM */ +#define TRM_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of TRM */ +#define TRM_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of TRM */ +#define TRM_STACK_SIZE 1024 + + +/*============================================================================== + Param ID +==============================================================================*/ + +/*============================================================================== + Module +==============================================================================*/ + +/** @h2xml_title1 {TRM API} + @h2xml_title_agile_rev {TRM API} + @h2xml_title_date {July 7, 2019} */ + +/** + * Module ID for Timed Renderer Module + */ +#define MODULE_ID_TRM 0x07001087 + +/** + @h2xmlm_module {"Timed Renderer", MODULE_ID_TRM} + @h2xmlm_displayName {"Timed Renderer"} + @h2xmlm_description { + This module holds or releases buffers, based on the time + to render. This module's main purpose is for time stamp + based voice packet rendering on downlink path\n + } + @h2xmlm_dataMaxInputPorts {TRM_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {TRM_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=TRM_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=TRM_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {TRM_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + +#endif //_TRM_API_H_ diff --git a/spf/api/modules/tsm_module_api.h b/spf/api/modules/tsm_module_api.h new file mode 100644 index 0000000..486318c --- /dev/null +++ b/spf/api/modules/tsm_module_api.h @@ -0,0 +1,208 @@ +/*============================================================================== + @file tsm_api.h + @brief This file contains TSM module apis +==============================================================================*/ +/*----------------------------------------------------------------------- +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +-----------------------------------------------------------------------*/ +/** @h2xml_title1 {TSM Module} + @h2xml_title_agile_rev {TSM Module} + @h2xml_title_date {March, 2023} */ + +/*============================================================================== + Constants +==============================================================================*/ + +#ifndef TSM_MODULE_API_H +#define TSM_MODULE_API_H + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "module_cmn_api.h" +#include "apm_graph_properties.h" + + +/*============================================================================== + Constants +==============================================================================*/ +/*Stack size of TSM module*/ +#define TSM_STACK_SIZE 100 * 1024 + +/* Max number of input/output ports of TSM module */ +#define TSM_MAX_PORTS 1 + +/*Min TSM Channels supported*/ +#define TSM_MIN_CHANNELS 1 + +/*Max TSM Channels supported*/ +#define TSM_MAX_CHANNELS 2 + +#define CAPI_TSM_DEFAULT_PORT 0 +/*============================================================================== + Param ID +==============================================================================*/ + +#define PARAM_ID_TSM_MAX_MIN_SPEED 0x08001A62 +/** @h2xmlp_parameter {"PARAM_ID_TSM_MAX_MIN_SPEED", PARAM_ID_TSM_MAX_MIN_SPEED} + @h2xmlp_description {Parameter to change the speed and this should be in the range (max,min) provided in static config} + @h2xmlp_toolPolicy {Calibration} */ + +typedef struct param_id_tsm_max_min_speed_t param_id_tsm_max_min_speed_t; + +#include "spf_begin_pack.h" + +struct param_id_tsm_max_min_speed_t { + uint32_t min_speed_factor; + /**< @h2xmle_description {Speed factor in Q24 format} + @h2xmle_default {4194304} + @h2xmle_range {1677721..67108864} */ + uint32_t max_speed_factor; + /**< @h2xmle_description {Speed factor in Q24 format} + @h2xmle_default {33554432} + @h2xmle_range {1677721..67108864} */ +} +#include "spf_end_pack.h" +; + +#define PARAM_ID_TSM_SPEED_FACTOR 0x08001A63 +/** @h2xmlp_parameter {"PARAM_ID_TSM_SPEED_FACTOR", PARAM_ID_TSM_SPEED_FACTOR} + @h2xmlp_description {Parameter for configuring/viewing TSM module Speed Factor} + @h2xmlp_toolPolicy {Calibration} */ + +typedef struct param_id_tsm_speed_t param_id_tsm_speed_t; + +#include "spf_begin_pack.h" +struct param_id_tsm_speed_t { + uint32_t speed_factor; + /**< @h2xmle_description {Speed factor in Q24 format} + @h2xmle_default {16777216} + @h2xmle_range {1677721..67108864} + @h2xmle_readOnly {true} */ + + uint32_t reserved; + /**< @h2xmle_description {reserved} + @h2xmle_default {0} + @h2xmle_range {0..0} + @h2xmle_visibility {hide} + @h2xmle_readOnly {true} */ +} +#include "spf_end_pack.h" +; + + +#define PARAM_ID_TSM_VERSION 0x08001A65 +/** @h2xmlp_parameter {"PARAM_ID_TSM_VERSION", PARAM_ID_TSM_VERSION} + @h2xmlp_description {Parameter for viewing TSM module version} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +typedef struct param_id_tsm_ver_t param_id_tsm_ver_t; + +#include "spf_begin_pack.h" +struct param_id_tsm_ver_t { + + uint32_t ver_high; + /**< @h2xmle_description {Higher 32 bits of 64 bit version number} + @h2xmle_default {0x02000100} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t ver_low; + /**< @h2xmle_description {Lower 32 bits of 64 bit version number} + @h2xmle_default {0x00000000} + @h2xmle_range {0..0xFFFFFFFF} */ + + uint32_t reserved1; + /**< @h2xmle_description {reserved} + @h2xmle_default {0} + @h2xmle_range {0..0} + @h2xmle_visibility {hide} + @h2xmle_readOnly {true} */ + + uint32_t reserved2; + /**< @h2xmle_description {reserved} + @h2xmle_default {0} + @h2xmle_range {0..0} + @h2xmle_visibility {hide} + @h2xmle_readOnly {true} */ +} +#include "spf_end_pack.h" +; + +#define PARAM_ID_TSM_SESSION_TIME_SCALING 0x08001A58 +/** @h2xmlp_parameter {"PARAM_ID_TSM_SESSION_TIME_SCALING", PARAM_ID_TSM_SESSION_TIME_SCALING} + @h2xmlp_description {Param to indicate SPR from TSM through metadata if to propagate Session time.} + @h2xmlp_toolPolicy {Calibration} */ + +typedef struct param_id_tsm_session_time_scaling_t param_id_tsm_session_time_scaling_t; + +#include "spf_begin_pack.h" +struct param_id_tsm_session_time_scaling_t +{ + uint32_t is_session_time_scaling_enabled; + /**< @h2xmle_description {To specify if the TSM module needs to send the metadata for SPR to scale the + session time based on the current speed factor.} + @h2xmle_rangeList {"Disable"=0; + "Enable"=1} + @h2xmle_default {1} + @h2xmle_policy {Basic} */ + + uint32_t reserved; + /**< @h2xmle_description {reserved} + @h2xmle_default {0} + @h2xmle_range {0..0} + @h2xmle_visibility {hide} + @h2xmle_readOnly {true} */ +} +#include "spf_end_pack.h" +; + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +#define MODULE_ID_TSM 0x07001172 +/** + @h2xmlm_module {"MODULE_ID_TSM", MODULE_ID_TSM} + @h2xmlm_displayName {"Time Scale Modification"} + @h2xmlm_description { Time scaling with varying speed factors\n + - This module supports the following parameter IDs:\n + - #PARAM_ID_MAX_MIN_SPEED\n + - #PARAM_ID_TSM_SPEED_FACTOR\n + - #PARAM_ID_TSM_VERSION\n + - #PARAM_ID_TSM_SESSION_TIME_SCALING\n + - Supported Input Media Format: \n + - Data Format : FIXED \n + - fmt_id : Don't care \n + - Sample Rates : 8000,11025, 12000, 16000, 22500, 24000, 32000, 44100, 48000\n + - Number of channels : 1, 2 \n + - Channel type : Don't care \n + - Bits per sample : 16 \n + - Q format : Q15 \n + - Interleaving : de-interleaved unpacked \n + - Signed/unsigned : Signed \n + \n} + @h2xmlm_dataMaxInputPorts {TSM_MAX_PORTS} + @h2xmlm_dataMaxOutputPorts {TSM_MAX_PORTS} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {8192} + @h2xmlm_toolPolicy {Calibration} + + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_tsm_max_min_speed_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_tsm_speed_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_tsm_ver_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_tsm_session_time_scaling_t} + @h2xmlm_InsertParameter + + @} <-- End of the Module -->*/ +#endif diff --git a/spf/api/modules/tts_module_calibration_api.h b/spf/api/modules/tts_module_calibration_api.h new file mode 100644 index 0000000..30a354c --- /dev/null +++ b/spf/api/modules/tts_module_calibration_api.h @@ -0,0 +1,306 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TTS_MODULE_CALIBRATION_API_H +#define TTS_MODULE_CALIBRATION_API_H + +/** @h2xml_title1 {Text To Speech (TTS)} + @h2xml_title_agile_rev {Text To Speech (TTS)} + @h2xml_title_date {Feb 26, 2024} */ + +#include "module_cmn_api.h" +#include "imcl_fwk_intent_api.h" + +/* Global unique Module ID definition + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_TTS 0x0702C001 + +/** + @h2xmlm_module {"MODULE_ID_TTS", + MODULE_ID_TTS} + @h2xmlm_displayName {"Text To Speech"} + @h2xmlm_description {ID of the TTS module.\n + + . This module supports the following parameter IDs:\n + . #PARAM_ID_TTS_CONFIG\n + . #PARAM_ID_TTS_SPEECH_CONFIG\n + . #PARAM_ID_TTS_GAIN_CONFIG\n + . #PARAM_ID_TTS_VERSION\n + . #PARAM_ID_TTS_MODEL\n + . #PARAM_ID_TTS_FORCE_STOP\n + \n + . Supported Input Media Format: \n + . Data Format : RAW_COMPRESSED \n + . fmt_id : MEDIA_FMT_ID_ASR \n + . payload : payload_media_fmt_asr_t \n + \n + } + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataOutputPorts {IN=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {4096} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + +*/ + +#define TTS_RELEASE_VERSION_MAJOR 0x00000001 +#define TTS_RELEASE_VERSION_MINOR 0x00000000 + +#define PARAM_ID_TTS_VERSION 0x08001B28 +/** @h2xmlp_parameter {"PARAM_ID_TTS_VERSION", PARAM_ID_TTS_VERSION} + @h2xmlp_description {Structure to get the current library version.} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +typedef struct tts_version_t tts_version_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct tts_version_t +{ + uint32_t lib_version_low; + /**< @h2xmle_description {Lower 32 bits of the 64-bit library version number} + @h2xmle_default {TTS_RELEASE_VERSION_MAJOR} */ + uint32_t lib_version_high; + /**< @h2xmle_description {Higher 32 bits of the 64-bit library version number} + @h2xmle_default {TTS_RELEASE_VERSION_MINOR} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {tts_version_t} + @h2xmlm_InsertParameter */ + +/* +Supported language codes +*/ +namespace TTS { + typedef enum TTS_LANGUAGE_CODE_t{ + en_US=0, + zh_CN, + hi_IN, + es_US, + ko_KR, + ja_JP, + language_code_end_1 + }TTS_LANGUAGE_CODE_t; +} + +/* +Supported language codes +*/ +typedef enum TTS_SPEECH_FORMAT_t{ + SPEECH_FORMAT_PCM=0, + SPEECH_FORMAT_END +}TTS_SPEECH_FORMAT_t; + + +/* ID of the TTS configuration parameter used by MODULE_ID_TTS.*/ +#define PARAM_ID_TTS_CONFIG 0x08001B25 + +/* Structure for the configuration parameters of TTS module. */ +typedef struct param_id_tts_config_t param_id_tts_config_t; +/** @h2xmlp_parameter {"PARAM_ID_TTS_CONFIG", PARAM_ID_TTS_CONFIG} + @h2xmlp_description {Configures the TTS module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_TTS_CONFIG parameter used by the + TTS module. + */ +struct param_id_tts_config_t +{ + uint32_t language_code; // language code, refer enum TTS_LANGUAGE_CODE_t + /**< @h2xmle_description {Code to specify TTS input-output language.} + @h2xmle_rangeList {"en_US"=en_US;"zh_CN"=zh_CN;"hi_IN"=hi_IN;"es_US"=es_US;"ko_KR"=ko_KR;"ja_JP"=ja_JP;"language_code_end"=language_code_end_1} + @h2xmle_default {en_US} */ + uint32_t speech_format; // output speech format, refer enum TTS_SPEECH_FORMAT_t + /**< @h2xmle_description {Code to specify TTS output speech format.} + @h2xmle_rangeList {"PCM"=SPEECH_FORMAT_PCM;"SPEECH_FORMAT_END"=SPEECH_FORMAT_END} + @h2xmle_default {SPEECH_FORMAT_PCM} */ + uint32_t reserved; // Reserved field + /**< @h2xmle_description {Reserved field} + @h2xmle_visibility {hide} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/* @h2xml_Select {param_id_tts_config_t} + @h2xmlm_InsertParameter */ + +/* ID of the TTS speech configuration parameter used by MODULE_ID_TTS.*/ +#define PARAM_ID_TTS_SPEECH_CONFIG 0x08001B26 + +/* Structure for the speech specific configuration TTS module. */ +typedef struct param_id_tts_speech_config_t param_id_tts_speech_config_t; +/** @h2xmlp_parameter {"PARAM_ID_TTS_SPEECH_CONFIG", PARAM_ID_TTS_SPEECH_CONFIG} + @h2xmlp_description {Speech specific configuration of the TTS module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_TTS_SPEECH_CONFIG parameter used by the + TTS module. + */ +struct param_id_tts_speech_config_t +{ + uint32_t speaker_rate_q4; // speaker rate of output speech + /**< @h2xmle_description {Rate of speech output to control slow or faster rate of output speech.} + @h2xmle_rangeList {"0.25x"=4, + "0.50x"=8, + "0.75x"=12, + "1.00x"=16, + "1.25x"=20, + "1.50x"=24, + "1.75x"=28, + "2.00x"=32, + "4.00x"=64} + @h2xmle_default {16} + @h2xmle_range {4..64} */ + int32_t pitch; // speaker pitch + /**< @h2xmle_description {Pitch of the speech output} + @h2xmle_visibility {hide} + @h2xmle_default {0} + @h2xmle_range {-20..20} */ + uint32_t reserved; // Reserved field + /**< @h2xmle_description {Reserved field} + @h2xmle_visibility {hide} + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_tts_speech_config_t} + @h2xmlm_InsertParameter */ + + +/* ID of the TTS force stop parameter used by MODULE_ID_TTS.*/ +#define PARAM_ID_TTS_FORCE_STOP 0x08001B2A + +/* Structure for the force stop parameter of TTS module. */ +typedef struct param_id_tts_force_stop_t param_id_tts_force_stop_t; +/** @h2xmlp_parameter {"PARAM_ID_TTS_FORCE_STOP", PARAM_ID_TTS_FORCE_STOP} + @h2xmlp_description {Forces the TTS module to stop data processing irrespective of buffered input or output} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_TTS_FORCE_STOP parameter used by the + TTS module. + */ +struct param_id_tts_force_stop_t +{ + uint32_t force_stop; // forces TTS to stop data process + /**< @h2xmle_description {forces TTS module to stop processing irrespective of presence of buffered input and\or output data } + @h2xmle_default {0} + @h2xmle_rangeList {"CONTINUE"=0;"STOP"=1}*/ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_tts_force_stop_t} + @h2xmlm_InsertParameter */ + +/* ID of the TTS gain configuration parameter used by MODULE_ID_TTS.*/ +#define PARAM_ID_TTS_GAIN_CONFIG 0x08001B27 + +/* Structure for the output configuration parameter of TTS module. */ +typedef struct param_id_tts_gain_config_t param_id_tts_gain_config_t; +/** @h2xmlp_parameter {"PARAM_ID_TTS_GAIN_CONFIG", PARAM_ID_TTS_GAIN_CONFIG} + @h2xmlp_description {Param to configure required gain parameters of speech output } + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/* Payload of the PARAM_ID_TTS_GAIN_CONFIG parameter used by the + TTS module. + */ + +struct param_id_tts_gain_config_t +{ + int32_t gain; // TTS output speech gain + /**< @h2xmle_description {Gain of the speech output in dB} + @h2xmle_default {0} + @h2xmle_range {-96..16} */ + uint32_t reserved; // Reserved field + /**< @h2xmle_description {Reserved field} + @h2xmle_visibility {hide} + @h2xmle_default {0} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* @h2xml_Select {param_id_tts_gain_config_t} + @h2xmlm_InsertParameter */ + +/* ID of the TTS model parameter used by MODULE_ID_TTS.*/ +#define PARAM_ID_TTS_MODEL 0x08001B29 + +typedef struct tts_model_param_t tts_model_param_t; +/** @h2xmlp_parameter {"PARAM_ID_TTS_MODEL", PARAM_ID_TTS_MODEL} + @h2xmlp_description {NN Model related parameters} + @h2xmlp_ToolPolicy {CALIBRATION} + @h2xmlp_isHwAccel {FALSE} + @h2xmlp_isNeuralNetParam {TRUE} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType { Shared } +*/ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct tts_model_param_t +{ + uint32_t model_align; + /**< @h2xmle_description {Data Alignment required for the model_data} + @h2xmle_default {256} + @h2xmle_range {0..8192} + @h2xmle_group {SPF} + @h2xmle_subgroup {NNVAD} + @h2xmle_policy {Advanced} */ + + uint32_t model_offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of model by model_align} + @h2xmle_default {0} + @h2xmle_range {0..8191} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint32_t model_size; + /**< @h2xmle_description {Size of the model in bytes} + @h2xmle_default {0} + @h2xmle_range {0x00000000..0xFFFFFFFF} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint8_t model[0]; + /**< @h2xmle_description {Model data: The path to the model file on the platform} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/** @} <-- End of the Module -->*/ +#endif /* TTS_MODULE_CALIBRATION_API_H */ diff --git a/spf/api/modules/tty_cmn_api.h b/spf/api/modules/tty_cmn_api.h new file mode 100644 index 0000000..2e1c5a3 --- /dev/null +++ b/spf/api/modules/tty_cmn_api.h @@ -0,0 +1,75 @@ +/** + * \file tty_cmn_api.h + * \brief + * This file contains api exposed to voice service in modem for tty modules. + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TTY_CMN_API_H +#define TTY_CMN_API_H + +#include "ar_defs.h" +#include "apm_graph_properties.h" + +/*============================================================================== + Param ID +==============================================================================*/ + +#define PARAM_ID_LTETTY_CHAR 0x080011A8 +/** @h2xmlp_parameter {"PARAM_ID_LTETTY_CHAR", PARAM_ID_LTETTY_CHAR} + @h2xmlp_description {Parameter for sending the TTY character to Module. Voice Service should send this parameter.} + @h2xmlp_toolPolicy {Calibration} */ + + +typedef struct param_id_ltetty_char_t param_id_ltetty_char_t; + +#include "spf_begin_pack.h" +struct param_id_ltetty_char_t +{ + uint32_t tty_char; + /**< @h2xmle_description {TTY character. In UTF-8 format.} + @h2xmle_default {0} + @h2xmle_range {0x0..0xFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + + +/*============================================================================== + Event ID +==============================================================================*/ + +#define EVENT_ID_LTETTY_CHAR 0x080011A9 +/** @h2xmlp_parameter {"EVENT_ID_LTETTY_CHAR", EVENT_ID_LTETTY_CHAR} + @h2xmlp_description {Event for sending the detected TTY character to Voice Service. Voice Service must register this event with LTETTY-Tx Module.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + + +typedef struct event_id_ltetty_char_t event_id_ltetty_char_t; + +#include "spf_begin_pack.h" +struct event_id_ltetty_char_t +{ + uint32_t tty_char; + /**< @h2xmle_description {TTY character. In UTF-8 format.} + @h2xmle_default {0} + @h2xmle_range {0x0..0xFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/*------------------------------------------------------------------------------ + Param ID +------------------------------------------------------------------------------*/ +#define PARAM_ID_CTM_RESYNC 0x08001190 +/** @h2xmlp_emptyParameter {"PARAM_ID_CTM_RESYNC", PARAM_ID_CTM_RESYNC} + @h2xmlp_description {Parameter to re-synchronize the CTM blocks.} + @h2xmlp_toolPolicy {Calibration} */ + + +#endif // TTY_CMN_API_H diff --git a/spf/api/modules/us_detect_api.h b/spf/api/modules/us_detect_api.h new file mode 100644 index 0000000..17f75fd --- /dev/null +++ b/spf/api/modules/us_detect_api.h @@ -0,0 +1,303 @@ +#ifndef _US_DETECT_API_H +#define _US_DETECT_API_H +/*============================================================================== + @file us_detect_api.h + @brief This file contains US_DETECT module APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off + +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "module_cmn_api.h" +#include "ar_defs.h" +#include "apm_graph_properties.h" +#include "imcl_spm_intent_api.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of MIC INPUT OF US DETECTOR module */ +#define US_DETECTOR_PRIMARY_DATA_INPUT_PORT 0x2 + +/* Input port ID of REFERENCE INPUT OF US DETECTOR module */ +#define US_DETECTOR_REFERENCE_DATA_INPUT_PORT 0x4 + +/* Output port ID of US DETECTOR module */ +#define US_DETECTOR_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of US DETECTOR module */ +#define US_DETECTOR_DATA_MAX_INPUT_PORTS 0x2 + +/* Max number of output ports of US DETECTOR module */ +#define US_DETECTOR_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of US DETECTOR module */ +#define US_DETECTOR_MODULE_STACK_SIZE 4096 + +#define US_MAX_DETECTION_EVENT_CLIENTS 4 + +/*============================================================================== + Param ID +==============================================================================*/ + +/** Parameter ID for US generation */ +#define PARAM_ID_EXAMPLE_US_DETECT_TONE_FREQUENCY 0x08001352 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_DETECT_TONE_FREQUENCY", PARAM_ID_EXAMPLE_US_DETECT_TONE_FREQUENCY} + @h2xmlp_description {Parameter for tuning US Detection Module } */ + +#include "spf_begin_pack.h" +struct param_id_us_detect_tone_frequency_t +{ + uint32_t frequency; + /**< @h2xmle_description {US Tone frequency in Hz} + @h2xmle_default {100} + @h2xmle_range {0..4294967295} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_detect_tone_frequency_t param_id_us_detect_tone_frequency_t; + +/** Parameter ID for Detection event raised by the US Detector Module */ +#define EVENT_ID_GENERIC_US_DETECTION 0x08001358 + +/** @h2xmlp_parameter {"EVENT_ID_EXAMPLE_US_DETECTION",EVENT_ID_EXAMPLE_US_DETECTION} + @h2xmlp_description { Detection event raised by the US Detector Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + +/* Payload returned by us module in response to the EVENT_ID_EXAMPLE_US_DETECTION + * registered by the client*/ +typedef enum +{ + US_DETECT_INVALID = 0, /** Invalid detection event type */ + US_DETECT_NEAR = 1, /** Near proximity event */ + US_DETECT_FAR = 2 /** Far proximity event */ +}us_detect_event_type; + +#include "spf_begin_pack.h" +struct event_id_upd_detection_event_t +{ + uint32_t detection_timestamp_lsw; + /**< @h2xmle_description {This denotes the buffer timestamp (lsw) in micro-seconds when the proximity is detected} + @h2xmle_default {0} + @h2xmle_range {0..4294967295} + @h2xmle_policy {Basic} */ + + uint32_t detection_timestamp_msw; + /**< @h2xmle_description {This denotes the buffer timestamp (msw) in micro-seconds when the proximity is detected} + @h2xmle_default {0} + @h2xmle_range {0..4294967295} + @h2xmle_policy {Basic} */ + + uint32_t proximity_event_type; + /**< @h2xmle_description { proximity_event_type sent by the Detection module to the client} + @h2xmle_default {0} + @h2xmle_rangeList {"US_DETECT_INVALID"=0;"US_DETECT_NEAR"=1;"US_DETECT_FAR"=2} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct event_id_upd_detection_event_t event_id_upd_detection_event_t ; + +/** Parameter ID for enabling/disabling duty cycling */ +#define PARAM_ID_EXAMPLE_US_DETECT_DUTY_CYCLING 0x08001353 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_DETECT_DUTY_CYCLING",PARAM_ID_EXAMPLE_US_DETECT_DUTY_CYCLING} + @h2xmlp_description { Parameter ID for enabling/disabling duty cycling.} + @h2xmlp_toolPolicy {RTC}*/ + +#include "spf_begin_pack.h" +struct param_id_us_detect_duty_cycling_t +{ + uint32_t enable; + /**< @h2xmle_description {Specifies whether to enable or disable duty cycling} + @h2xmle_default {1} + @h2xmle_rangeList {"Disable"=0;"Enable"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_detect_duty_cycling_t param_id_us_detect_duty_cycling_t; + +/** Parameter ID for enabling/disabling codec duty cycling */ +#define PARAM_ID_EXAMPLE_US_DETECT_CODEC_DUTY_CYCLING 0x08001354 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_DETECT_CODEC_DUTY_CYCLING",PARAM_ID_EXAMPLE_US_DETECT_CODEC_DUTY_CYCLING} + @h2xmlp_description { Parameter ID for enabling/disabling codec duty cycling.} + @h2xmlp_toolPolicy {RTC}*/ + +#include "spf_begin_pack.h" +struct param_id_us_detect_codec_duty_cycling_t +{ + uint32_t enable; + /**< @h2xmle_description {Specifies whether to enable or disable codec duty cycling} + @h2xmle_default {0} + @h2xmle_rangeList {"Disable"=0;"Enable"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_detect_codec_duty_cycling_t param_id_us_detect_codec_duty_cycling_t; + +/** Parameter ID for enabling/disabling access to sensor APIs */ +#define PARAM_ID_EXAMPLE_US_DETECT_SENSOR_ACCESS 0x08001355 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_DETECT_SENSOR_ACCESS",PARAM_ID_EXAMPLE_US_DETECT_SENSOR_ACCESS} + @h2xmlp_description { Parameter ID for enabling/disabling access to sensor APIs} + @h2xmlp_toolPolicy {RTC}*/ + +#include "spf_begin_pack.h" +struct param_id_us_detect_sensor_access_t +{ + uint32_t enable; + /**< @h2xmle_description {Specifies whether to enable/disable access to sensor APIs} + @h2xmle_default {0} + @h2xmle_rangeList {"Disable"=0;"Enable"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_detect_sensor_access_t param_id_us_detect_sensor_access_t; + +/** Parameter ID reserved for future use */ +#define PARAM_ID_EXAMPLE_US_DETECT_PARAM_1 0x08001356 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_DETECT_PARAM_1", PARAM_ID_EXAMPLE_US_DETECT_PARAM_1} + @h2xmlp_description {Parameter reserved for future use } + @h2xmlp_toolPolicy {RTC} */ + +#include "spf_begin_pack.h" +struct param_id_us_detect_param_1_t +{ + uint32_t param_1_data; + /**< @h2xmle_description {param_1_data reserved for future use} + @h2xmle_default {0} + @h2xmle_range {0..4294967295} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_detect_param_1_t param_id_us_detect_param_1_t; + +/** Parameter ID reserved for future use */ +#define PARAM_ID_EXAMPLE_US_DETECT_PARAM_2 0x08001357 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_DETECT_PARAM_2", PARAM_ID_EXAMPLE_US_DETECT_PARAM_2} + @h2xmlp_description {Parameter reserved for future use } + @h2xmlp_toolPolicy {RTC} */ + +#include "spf_begin_pack.h" +struct param_id_us_detect_param_2_t +{ + uint32_t param_2_data; + /**< @h2xmle_description {param_2_data reserved for future use} + @h2xmle_default {0} + @h2xmle_range {0..4294967295} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_detect_param_2_t param_id_us_detect_param_2_t; + +/*============================================================================== + Module +==============================================================================*/ + +/** @h2xml_title1 {US DETECTOR Module API} + @h2xml_title_agile_rev {US DETECTOR Module API} + @h2xml_title_date {Feb 13, 2020} */ + +/** + * Module ID for US detector. + */ +#define MODULE_ID_EXAMPLE_US_DETECT0x070010D7 + +/** + @h2xmlm_module {"MODULE_ID_EXAMPLE_US_DETECT", MODULE_ID_EXAMPLE_US_DETECT} + + @h2xmlm_displayName {"US Detector"} + @h2xmlm_description {ID of the US DETECTOR module. This module is used to detect the US tones. \n + . MFC needs to be configured before US detector module so that it receives the signal with the below supported input media format. \n + . The module can be used as a single input single output module or as a sink module \n + + - Supports the following param:\n + -- PARAM_ID_MODULE_ENABLE\n + -- PARAM_ID_EXAMPLE_US_DETECT_TONE_FREQUENCY\n + -- EVENT_ID_EXAMPLE_US_DETECTION\n + -- PARAM_ID_EXAMPLE_US_DETECT_DUTY_CYCLING\n + -- PARAM_ID_EXAMPLE_US_DETECT_CODEC_DUTY_CYCLING\n + -- PARAM_ID_EXAMPLE_US_DETECT_SENSOR_ACCESS\n + -- PARAM_ID_EXAMPLE_US_DETECT_PARAM_1\n + -- PARAM_ID_EXAMPLE_US_DETECT_PARAM_2\n + - Supported Input Media Format:\n + Data Format : FIXED_POINT \n + . fmt_id : MEDIA_FMT_ID_PCM \n + . Sample Rates : 96000 \n + . Number of channels : 1 \n + . Channel type : 1 to 63 \n + . Bits per sample : 16 \n + . Q format : 15 \n + . Interleaving : Deinterleaved Unpacked \n + . Signed/unsigned : Signed \n + } + @h2xmlm_dataMaxInputPorts {US_DETECTOR_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {US_DETECTOR_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {MIC_INPUT = US_DETECTOR_PRIMARY_DATA_INPUT_PORT;REF_INPUT = US_DETECTOR_REFERENCE_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=US_DETECTOR_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC, APM_CONTAINER_TYPE_SC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {US_DETECTOR_MODULE_STACK_SIZE} +@h2xmlm_ctrlDynamicPortIntent {"US detect to us gen for sending param data" = INTENT_ID_EXAMPLE_US_DETECT_PARAM_DATA, maxPorts = 1} + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_us_detect_tone_frequency_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter} +@h2xml_Select {"event_id_upd_detection_event_t "} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {NO_SUPPORT} + @h2xml_Select {"param_id_us_detect_duty_cycling_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_detect_codec_duty_cycling_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_detect_sensor_access_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_detect_param_1_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_detect_param_2_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @} <-- End of the Module --> +*/ + +#endif //US_DETECT_API_H diff --git a/spf/api/modules/us_gen_api.h b/spf/api/modules/us_gen_api.h new file mode 100644 index 0000000..ae43e31 --- /dev/null +++ b/spf/api/modules/us_gen_api.h @@ -0,0 +1,214 @@ +#ifndef _US_GEN_API_H_ +#define _US_GEN_API_H_ +/*============================================================================== + @file us_gen_api.h + @brief This file contains US_GEN module APIs + +================================================================================ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause +==============================================================================*/ +// clang-format off +/*============================================================================== + Include Files +==============================================================================*/ + +#include "media_fmt_api.h" +#include "module_cmn_api.h" +#include "ar_defs.h" +// Commented imcl api, not needed for HLOS +//#include "imcl_upd_api.h" +/*============================================================================== + Constants +==============================================================================*/ + +/* Input port ID of US_GEN module */ +//#define US_GEN_DATA_INPUT_PORT 0x2 + +/* Output port ID of US_GEN module */ +#define US_GEN_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of US_GEN module */ +#define US_GEN_DATA_MAX_INPUT_PORTS 0x0 + +/* Max number of output ports of US_GEN module */ +#define US_GEN_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of US_GEN module */ +#define US_GEN_MODULE_STACK_SIZE 4096 + + +/*============================================================================== + Param ID +==============================================================================*/ + +/** Parameter ID for US generation */ +#define PARAM_ID_EXAMPLE_US_GEN_TONE_FREQUENCY 0x08001347 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_GEN_TONE_FREQUENCY", PARAM_ID_EXAMPLE_US_GEN_TONE_FREQUENCY} + @h2xmlp_description {Parameter for generating US tone } + @h2xmlp_toolPolicy {RTC} */ + +#include "spf_begin_pack.h" +struct param_id_us_gen_struct_frequency_t +{ + uint32_t frequency; + /**< @h2xmle_description {US Tone frequency in Hz} + @h2xmle_default {192000} + @h2xmle_range {0..4294967295} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_gen_struct_frequency_t param_id_us_gen_struct_frequency_t; + + +/** Parameter ID for enabling/disabling duty cycling */ +#define PARAM_ID_EXAMPLE_US_GEN_DUTY_CYCLING 0x08001348 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_GEN_DUTY_CYCLING", PARAM_ID_EXAMPLE_US_GEN_DUTY_CYCLING} + @h2xmlp_description {Parameter for enabling/disabling duty cycling } + @h2xmlp_toolPolicy {RTC} */ + +#include "spf_begin_pack.h" +struct param_id_us_gen_duty_cycling_t +{ + uint32_t enable; + /**< @h2xmle_description {Specifies whether to enable or disable duty cycling} + @h2xmle_default {1} + @h2xmle_rangeList {"Disable"=0;"Enable"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_gen_duty_cycling_t param_id_us_gen_duty_cycling_t; + +/** Parameter ID for enabling/disabling codec duty cycling */ +#define PARAM_ID_EXAMPLE_US_GEN_CODEC_DUTY_CYCLING 0x08001349 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_GEN_CODEC_DUTY_CYCLING", PARAM_ID_EXAMPLE_US_GEN_CODEC_DUTY_CYCLING} + @h2xmlp_description {Parameter for enabling/disabling codec duty cycling } + @h2xmlp_toolPolicy {RTC} */ + +#include "spf_begin_pack.h" +struct param_id_us_gen_codec_duty_cycling_t +{ + uint32_t enable; + /**< @h2xmle_description {Specifies whether to enable or disable codec duty cycling} + @h2xmle_default {0} + @h2xmle_rangeList {"Disable"=0;"Enable"=1} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_gen_codec_duty_cycling_t param_id_us_gen_codec_duty_cycling_t; + +/** Parameter ID reserved for future use */ +#define PARAM_ID_EXAMPLE_US_GEN_PARAM_1 0x08001350 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_GEN_PARAM_1", PARAM_ID_EXAMPLE_US_GEN_PARAM_1} + @h2xmlp_description {Parameter reserved for future use } + @h2xmlp_toolPolicy {RTC} */ + +#include "spf_begin_pack.h" +struct param_id_us_gen_param_1_t +{ + uint32_t param_1_data; + /**< @h2xmle_description {param_1_data reserved for future use} + @h2xmle_default {0} + @h2xmle_range {0..4294967295} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_gen_param_1_t param_id_us_gen_param_1_t; + +/** Parameter ID reserved for future use */ +#define PARAM_ID_EXAMPLE_US_GEN_PARAM_2 0x08001351 + +/** @h2xmlp_parameter {"PARAM_ID_EXAMPLE_US_GEN_PARAM_2", PARAM_ID_EXAMPLE_US_GEN_PARAM_2} + @h2xmlp_description {Parameter reserved for future use } + @h2xmlp_toolPolicy {RTC} */ + +#include "spf_begin_pack.h" +struct param_id_us_gen_param_2_t +{ + uint32_t param_2_data; + /**< @h2xmle_description {param_2_data reserved for future use} + @h2xmle_default {0} + @h2xmle_range {0..4294967295} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; + +/* Type definition for the above structure */ +typedef struct param_id_us_gen_param_2_t param_id_us_gen_param_2_t; + +/*============================================================================== + Module +==============================================================================*/ + +/** @h2xml_title1 {US Gen Module API} + @h2xml_title_agile_rev {US Gen Module API} + @h2xml_title_date {Feb 13, 2020} */ + +/** + * Module ID for US generator. + */ +#define MODULE_ID_EXAMPLE_US_GEN 0x070010D6 + +/** + @h2xmlm_module {"MODULE_ID_EXAMPLE_US_GEN", MODULE_ID_EXAMPLE_US_GEN} + @h2xmlm_displayName {"Ultrasound Generator"} + @h2xmlm_description {This module is used for Example Ultrasound frequency generation.\n + - Supports the following param:\n + -- PARAM_ID_MODULE_ENABLE\n + -- PARAM_ID_EXAMPLE_US_GEN_TONE_FREQUENCY\n + -- PARAM_ID_EXAMPLE_US_GEN_DUTY_CYCLING\n + -- PARAM_ID_EXAMPLE_US_GEN_CODEC_DUTY_CYCLING\n + -- PARAM_ID_EXAMPLE_US_GEN_PARAM_1\n + -- PARAM_ID_EXAMPLE_US_GEN_PARAM_2\n + - Supported Input Media Format:\n + -- Any\n + - Output media format:\n + -- 16 bit, Mono, 96KHz, Fixed, MEDIA_FMT_ID_PCM\n} + @h2xmlm_dataMaxInputPorts {US_GEN_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {US_GEN_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataOutputPorts {OUT=US_GEN_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC, APM_CONTAINER_TYPE_SC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {US_GEN_MODULE_STACK_SIZE} + @h2xmlm_ctrlDynamicPortIntent { "US Detect to us gen for sampling frequency control" = INTENT_ID_EXAMPLE_US_DETECT_PARAM_DATA, maxPorts= 1 } + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_gen_struct_frequency_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_gen_duty_cycling_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_gen_codec_duty_cycling_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_gen_param_1_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @h2xml_Select {"param_id_us_gen_param_2_t"} + @h2xmlm_InsertParameter + @h2xmlp_toolPolicy {Calibration} + @} <-- End of the Module --> +*/ + +#endif //_US_GEN_API_H_ diff --git a/spf/api/modules/us_tone_renderer_api.h b/spf/api/modules/us_tone_renderer_api.h new file mode 100644 index 0000000..fc427bb --- /dev/null +++ b/spf/api/modules/us_tone_renderer_api.h @@ -0,0 +1,349 @@ +/** + * \file us_tone_renderer_api.h + * \brief + * This file contains CAPI us tone renderer params + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +// clang-format off +/* +$Header: +*/ +// clang-format on + +#ifndef _US_TONE_RENDERER_API_H_ +#define _US_TONE_RENDERER_API_H_ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "module_cmn_api.h" + +/** + @h2xml_title1 {US Tone Renderer module} + @h2xml_title_agile_rev {US Tone Renderer module} + @h2xml_title_date {July 19, 2021} + */ + +#define US_TONE_RENDERER_STACK_SIZE 1024 + +#define US_TONE_RENDERER_MAX_INPUT_PORTS 0 +#define US_TONE_RENDERER_MAX_OUTPUT_PORTS 1 + +/*============================================================================== + Param IDs +==============================================================================*/ +/* ID of the parameter used to media format configuration of the module. */ +#define PARAM_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CFG 0x08001A79 +/** @h2xmlp_parameter {"PARAM_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CFG", PARAM_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CFG} + @h2xmlp_description {- This contains the media format information that changed during the session. \n + - Any change in media format be notified to client through the event id \n + DATA_EVENT_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CHANGE } + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlx_expandStructs {false} +*/ + +enum us_tone_renderer_ep_media_format_status_t +{ + US_TONE_RENDERER_EP_MEDIA_FORMAT_INFO_INVALID = 0, + /* Invalid Status*/ + + US_TONE_RENDERER_EP_MEDIA_FORMAT_INFO_CHANGE_START = 1, + /* Change to given media format will be initiated */ + + US_TONE_RENDERER_EP_MEDIA_FORMAT_INFO_CHANGE_DONE = 2, + /* Change to media format recieved during the change + * start is now complete. */ +}; + +/* Payload of the PARAM_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CFG command. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_us_tone_renderer_ep_media_format_cfg_t +{ + uint32_t status; + /**< @h2xmle_description {Media format change is to be initiated or complete. + Rest of the fields are not applicable if status is either + US_TONE_RENDERER_EP_MEDIA_FORMAT_INFO_INVALID or + US_TONE_RENDERER_EP_MEDIA_FORMAT_INFO_CHANGE_DONE. } + @h2xmle_default {US_TONE_RENDERER_EP_MEDIA_FORMAT_INFO_INVALID} + @h2xmle_rangeEnum {us_tone_renderer_ep_media_format_status_t} */ + + uint32_t sampling_rate; + /**< @h2xmle_description { Sampling rate of the PCM data.} + @h2xmle_default {0xBB80} + @h2xmle_range {0..96000} */ + + uint32_t bit_width; + /**< @h2xmle_description { Bitwidth of the PCM data} + @h2xmle_default {16} + @h2xmle_range {0..32} */ + + uint32_t num_channels; + /**< @h2xmle_description { Number of channels at end point .} + @h2xmle_range {0..32} + @h2xmle_default {2} */ + +#if defined(__H2XML__) + uint8_t channel_type[0]; + /**< @h2xmle_description { Defines channel IDs for each of the channel index. + Range is defined between 1 to 63. Value '0' is considered + invalid and must not be set. } + @h2xmle_range { 0..63} + @h2xmle_variableArraySize { "num_channels" } */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_us_tone_renderer_ep_media_format_cfg_t param_id_us_tone_renderer_ep_media_format_cfg_t; + +#define PARAM_ID_US_TONE_RENDERER_OUTPUT_MEDIA_FORMAT 0x08001A82 +/** @h2xmlp_parameter {"PARAM_ID_US_TONE_RENDERER_OUTPUT_MEDIA_FORMAT", PARAM_ID_US_TONE_RENDERER_OUTPUT_MEDIA_FORMAT} + @h2xmlp_description {- This is a mandatory parameter for this module to work. This specifies the media format of the + the module. The output media format can only be set through this parameter. } + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlx_expandStructs {false} +*/ + +/* Payload of the PARAM_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CFG command. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_us_tone_renderer_output_media_format_t +{ + uint32_t sampling_rate; + /**< @h2xmle_description { Sampling rate of the PCM data.} + @h2xmle_default {0xBB80} + @h2xmle_range {0..96000} */ + + uint32_t bit_width; + /**< @h2xmle_description { Bitwidth of the PCM data - currently only 16 bit is supported} + @h2xmle_default {16} + @h2xmle_range {00..32} */ + + uint32_t num_channels; + /**< @h2xmle_description { Number of channels at end point .} + @h2xmle_range {0..32} + @h2xmle_default {2} */ + +#if defined(__H2XML__) + uint8_t channel_type[0]; + /**< @h2xmle_description { Defines channel IDs for each of the channel index. + Range is defined between 1 to 63. Value '0' is considered + invalid and must not be set. } + @h2xmle_range { 0..63} + @h2xmle_variableArraySize { "num_channels" } */ +#endif + +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_us_tone_renderer_output_media_format_t param_id_us_tone_renderer_output_media_format_t; + +#define PARAM_ID_US_TONE_RENDERER_TONE_CFG 0x08001A7A +/** @h2xmlp_parameter {"PARAM_ID_US_TONE_RENDERER_TONE_CFG", PARAM_ID_US_TONE_RENDERER_TONE_CFG} + @h2xmlp_description {- This is a mandatory param for US Tone Renderer module to work.\n + - Contains the audio sample which will be rendered at the given \n + periodicity at the media format received via PARAM_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CFG\n + - If not configured there will be no tone generated } + @h2xmlp_toolPolicy {NO_SUPPORT} + @h2xmlx_expandStructs {false} +*/ + +enum us_tone_cfg_buffer_interleaving_t +{ + US_TONE_CFG_BUFFER_INTERLEAVING_INVALID = 0, + US_TONE_CFG_BUFFER_INTERLEAVING_INTERLEAVED = 1, + US_TONE_CFG_BUFFER_INTERLEAVING_DEINTERLEAVED = 2 + +}; +/* Payload of the PARAM_ID_US_TONE_RENDERER_TONE_CFG command. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_us_tone_renderer_tone_cfg_t +{ + uint32_t period_us; + /**< @h2xmle_description { Periodicity at which the sample will be repeated } + @h2xmle_range {0..100000} + @h2xmle_default {0} */ + + uint32_t num_repetitions; + /**< @h2xmle_description { Number of times the tone will be repeated in the + given period } + @h2xmle_default {1} */ + + uint32_t phase_offset_us; + /**< @h2xmle_description { Phase offset for every extra channel \n + If phase offset is 10us then second channel + tone will be at an offset of 10us third + will be 20us so on. If 0us then all will be + played with zero offset. } + @h2xmle_default {0} */ + + uint32_t gain; + /**< @h2xmle_description { Gain in Q13 format applied to the tone. } + @h2xmle_default {0x2000} */ + + + uint32_t buffer_data_interleaving; + /**< @h2xmle_description {Interleaving of the data in the payload } + @h2xmle_default {US_TONE_CFG_BUFFER_INTERLEAVING_INVALID} + @h2xmle_rangeEnum {us_tone_cfg_buffer_interleaving_t} */ + + uint32_t tone_num_channels; + /**< @h2xmle_description {Number of channels pertaining to the tone buffer } + @h2xmle_range {0..32} + @h2xmle_default {1} */ + + uint32_t payload_len; + /**< @h2xmle_description { Total length in bytes of the audio samples } + @h2xmle_range {0..1024} + @h2xmle_default {0} */ + +#ifdef __H2XML__ + uint8_t payload[payload_len]; + /**< @h2xmle_description { Sample content which will be rendered } */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_us_tone_renderer_tone_cfg_t param_id_us_tone_renderer_tone_cfg_t; + +#define PARAM_ID_US_TONE_RENDERER_ENABLE 0x08001A7B +/** @h2xmlp_parameter {"PARAM_ID_US_TONE_RENDERER_ENABLE", PARAM_ID_US_TONE_RENDERER_ENABLE} + @h2xmlp_description {- This is used to start / stop rendering the tone. \n + - By default audio renderer will start generating the tone.} + @h2xmlp_toolPolicy {NO_SUPPORT} + @h2xmlx_expandStructs {false} +*/ + +/* Payload of the PARAM_ID_US_TONE_RENDERER_ENABLE command. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_us_tone_renderer_enable_t +{ + uint32_t enable; + /**< @h2xmle_description { 1: Play Audio Sample 0: Halt playing } + @h2xmle_default {1} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_us_tone_renderer_enable_t param_id_us_tone_renderer_enable_t; + +#define PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_ENABLE 0x08001A7C +/** @h2xmlp_parameter {"PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_ENABLE", PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_ENABLE} + @h2xmlp_description {If enabled, then whenever us tone renderer is disabled -> PA_Off } + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlx_expandStructs {false} +*/ + +/* Payload of the PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_ENABLE command. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_us_tone_renderer_duty_cycle_enable_t +{ + uint32_t duty_cycle_enable; + /**< @h2xmle_description { 1: Enable Duty Cycling 0: Disable Duty Cycling } + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_us_tone_renderer_duty_cycle_enable_t param_id_us_tone_renderer_duty_cycle_enable_t; + +#define PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_THRESHOLD 0x08001A7D +/** @h2xmlp_parameter {"PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_THRESHOLD", PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_THRESHOLD} + @h2xmlp_description {Denotes the minimum duration below which duty-cycling cannot be done.} + @h2xmlx_expandStructs {false} +*/ + +/* Payload of the PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_THRESHOLD command. */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_us_tone_renderer_duty_cycle_threshold_t +{ + uint32_t duty_cycle_threshold_us; + /**< @h2xmle_description { minimum duration below which duty-cycling cannot be done } + @h2xmle_default {0} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +typedef struct param_id_us_tone_renderer_duty_cycle_threshold_t param_id_us_tone_renderer_duty_cycle_threshold_t; + + +/*============================================================================== + Event IDs +==============================================================================*/ + +#define DATA_EVENT_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CHANGE 0x06001002 +/** @h2xmlp_parameter {"DATA_EVENT_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CHANGE", DATA_EVENT_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CHANGE} + @h2xmlp_description {- This is used to notify client of any change in media format - num_channels/channel_type/bit width/SR } + @h2xmlx_expandStructs {false} +*/ + +/* Payload of the DATA_EVENT_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CHANGE command. */ +typedef struct param_id_us_tone_renderer_ep_media_format_cfg_t data_event_id_us_tone_renderer_media_format_change_t; + +/*============================================================================== + Constants +==============================================================================*/ +/* Global unique Module ID definition + Module library is independent of this number, it defined here for static + loading purpose only */ + +#define MODULE_ID_US_TONE_RENDERER 0x07001175 + +/*============================================================================== + Constants +==============================================================================*/ +/** + @h2xml_title1 {US Tone Renderer Module API} + @h2xml_title_agile_rev {USToneRenderer Module API} + @h2xml_title_date {July 13, 2023} */ + +/** + @h2xmlm_module { "MODULE_ID_US_TONE_RENDERER", MODULE_ID_US_TONE_RENDERER} + @h2xmlm_displayName { "US Tone Renderer" } + @h2xmlm_description { - Repeates given audio sample with configured periodicity and position \n + - This is a source module and supports the following params: \n + - PARAM_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CFG\n + - PARAM_ID_US_TONE_RENDERER_ENABLE\n + - PARAM_ID_US_TONE_RENDERER_TONE_CFG\n + - PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_ENABLE \n + - PARAM_ID_US_TONE_RENDERER_DUTY_CYCLE_THRESHOLD \n + - This module also supports the following event:\n + - DATA_EVENT_ID_US_TONE_RENDERER_EP_MEDIA_FORMAT_CHANGE \n} + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { US_TONE_RENDERER_STACK_SIZE } + @h2xmlm_toolPolicy { Calibration } + @h2xmlm_dataMaxInputPorts { US_TONE_RENDERER_MAX_INPUT_PORTS } + @h2xmlm_dataMaxOutputPorts { US_TONE_RENDERER_MAX_OUTPUT_PORTS } + @{ <-- Start of the Module --> + @h2xml_Select {param_id_us_tone_renderer_ep_media_format_cfg_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_us_tone_renderer_enable_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_us_tone_renderer_duty_cycle_enable_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_us_tone_renderer_duty_cycle_threshold_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + + + +#endif /*_US_TONE_RENDERER_API_H_*/ diff --git a/spf/api/modules/usb_api.h b/spf/api/modules/usb_api.h new file mode 100644 index 0000000..6a029e9 --- /dev/null +++ b/spf/api/modules/usb_api.h @@ -0,0 +1,174 @@ +#ifndef _USB_API_H_ +#define _USB_API_H_ + +/** + * \file usb_api.h + * \brief + * This file contains USB module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** @h2xml_title1 {USB Module API} + @h2xml_title_agile_rev {USB Module API} + @h2xml_title_date {April 24, 2019} */ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "hw_intf_cmn_api.h" + +/*============================================================================== + Constants +==============================================================================*/ + +/* Stack size for USB Module*/ +#define USB_STACK_SIZE 4096 +/* Input port ID of USB module */ +#define PORT_ID_USB_INPUT 0x2 + +/* Output port ID of USB module */ +#define PORT_ID_USB_OUTPUT 0x1 +/*============================================================================== + Type definition +==============================================================================*/ + +/** Parameter used to configure the USB interface */ +#define PARAM_ID_USB_AUDIO_INTF_CFG 0x080010D6 +/** @h2xmlp_parameter {"PARAM_ID_USB_AUDIO_INTF_CFG", + PARAM_ID_USB_AUDIO_INTF_CFG} + @h2xmlp_description {Configures the USB interface.} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +/** Payload for parameter PARAM_ID_USB_AUDIO_INTF_CFG */ +struct param_id_usb_audio_intf_cfg_t +{ + uint32_t usb_token; + /**< @h2xmle_description {Valid token for the USB audio device} */ + uint32_t svc_interval; + /**< @h2xmle_description {USB device service interval in microseconds. Though the acceptable + values are between 125- 3276800, the actual supported values are + determined by the equation specified in USB 3.0 documentation.} + @h2xmle_range {125..3276800} + @h2xmle_default {125} + */ +} +#include "spf_end_pack.h" +; + +/* Structure type def for above payload. */ +typedef struct param_id_usb_audio_intf_cfg_t param_id_usb_audio_intf_cfg_t; +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ + +/** Module ID for USB sink module */ +#define MODULE_ID_USB_AUDIO_SINK 0x0700104F +/** @h2xmlm_module {"MODULE_ID_USB_AUDIO_SINK", + MODULE_ID_USB_AUDIO_SINK} + @h2xmlm_displayName {"USB Sink"} + @h2xmlm_description {- USB Sink Module\n + - Supports following params: \n + - PARAM_ID_USB_AUDIO_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - Supported Input Media Format: \n + - Data Format : FIXED_POINT \n + - fmt_id : Don't care \n + - Sample Rates : 8, 11.025, 12, 16, 22.05, 24, 32, 44.1, 48, \n + - 88.2, 96, 176.4, 192, 352.8, 384 kHz \n + - Number of channels : 1, 2, 3, 4, 5, 6, 7, 8 \n + - Channel type : Don't care \n + - Bit Width : 16 (bits per sample 16 and Q15), \n + - : 24 (bits per sample 24 and Q27), \n + - : 32 (bits per sample 32 and Q31) \n + - Q format : Q15, Q27, Q31 \n + - Interleaving : USB sink module needs de-interleaved unpacked } + @h2xmlm_dataInputPorts {IN = PORT_ID_USB_INPUT} + @h2xmlm_dataMaxInputPorts {1} + @h2xmlm_dataMaxOutputPorts {0} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HW-EP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { USB_STACK_SIZE } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_rangeList {"ONE"=1; + "TWO"=2; + "THREE"=3; + "FOUR"=4; + "FIVE"=5; + "SIX"=6; + "SEVEN"=7; + "EIGHT"=8} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"FIXED_POINT"=1} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_usb_audio_intf_cfg_t} + @h2xmlm_InsertParameter + @} <-- End of the Module -->*/ + +/** Module ID for USB source module */ +#define MODULE_ID_USB_AUDIO_SOURCE 0x07001050 +/** @h2xmlm_module {"MODULE_ID_USB_AUDIO_SOURCE", + MODULE_ID_USB_AUDIO_SOURCE} + @h2xmlm_displayName {"USB Source"} + @h2xmlm_description {- USB Source Module\n + - Supports following params: \n + - PARAM_ID_USB_AUDIO_INTF_CFG \n + - PARAM_ID_HW_EP_MF_CFG \n + - PARAM_ID_HW_EP_FRAME_SIZE_FACTOR \n + - PARAM_ID_HW_EP_SRC_CHANNEL_MAP\n + - Supported Input Media Format: \n + - USB source module doesn't take any inputs } + @h2xmlm_dataOutputPorts {OUT = PORT_ID_USB_OUTPUT} + @h2xmlm_dataMaxInputPorts {0} + @h2xmlm_dataMaxOutputPorts {1} + @h2xmlm_ctrlDynamicPortIntent { "Qtimer HWEP drift info"=INTENT_ID_TIMER_DRIFT_INFO, maxPorts= -1 } + @h2xmlm_ctrlDynamicPortIntent { "HW EP Module Instance info"=INTENT_ID_MODULE_INSTANCE_INFO, maxPorts= -1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_stackSize { USB_STACK_SIZE } + @h2xmlm_toolPolicy { Calibration } + @{ <-- Start of the Module --> + + @h2xml_Select {param_id_hw_ep_mf_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_mf_t::num_channels} + @h2xmle_rangeList {"ONE"=1; + "TWO"=2; + "THREE"=3; + "FOUR"=4; + "FIVE"=5; + "SIX"=6; + "SEVEN"=7; + "EIGHT"=8} + @h2xmle_default {1} + @h2xml_Select {param_id_hw_ep_mf_t::data_format} + @h2xmle_rangeList {"FIXED_POINT"=1} + @h2xmle_default {1} + + @h2xml_Select {param_id_frame_size_factor_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_usb_audio_intf_cfg_t} + @h2xmlm_InsertParameter + + @h2xml_Select {param_id_hw_ep_src_channel_map_t} + @h2xmlm_InsertParameter + @h2xml_Select {param_id_hw_ep_src_channel_map_t::num_channels} + @h2xmle_range { 0..8 } + @} <-- End of the Module -->*/ + +#endif //_USB_API_H_ diff --git a/spf/api/modules/vad_api.h b/spf/api/modules/vad_api.h new file mode 100644 index 0000000..e744524 --- /dev/null +++ b/spf/api/modules/vad_api.h @@ -0,0 +1,348 @@ +/** + * \file vad_api.h + * \brief + * This file contains CAPI VAD module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ +// clang-format off +/* +$Header: //components/rel/avs.fwk/1.0/api/modules/sh_mem_pull_push_mode_api.h#11 $ +*/ +// clang-format on + +#ifndef __VAD_API_H__ +#define __VAD_API_H__ + +/*============================================================================ +EDIT HISTORY FOR MODULE + +when who what, where, why +-------- ------ ------------------------------------------------- + sboliset Created File. +============================================================================*/ +#include "imcl_fwk_intent_api.h" +#include "contexts_api.h" + +/** + @h2xml_title1 {Module VAD API} + @h2xml_title_agile_rev {Module VAD API} + @h2xml_title_date {March 23, 2026} +*/ +#define VAD_RELEASE_VERSION_MSB AR_NON_GUID(0x01000100) +#define VAD_RELEASE_VERSION_LSB AR_NON_GUID(0x00000000) + +/*============================================================================== + Constants +==============================================================================*/ +#define CAPI_VAD_MAX_INPUT_PORTS 1 +#define CAPI_VAD_MAX_OUTPUT_PORTS 0 +#define CAPI_VAD_STACK_SIZE_REQUIREMENT 8192 // TODO: profile and update + + +/* Global unique Module ID definition. + Module library is independent of this number, it defined here for static + loading purpose only */ +#define MODULE_ID_VAD 0x07001188 + +/*============================================================================== + Module definition +==============================================================================*/ +/** + @h2xml_title1 {Voice Activity Detector Module API} + @h2xml_title_agile_rev {Voice Activity Detector Module API} + @h2xml_title_date {March 23, 2026} */ + +/** @h2xmlm_module {"MODULE_ID_VAD",MODULE_ID_VAD} + @h2xmlm_displayName {"Voice Activity Detector (VAD)"} + @h2xmlm_description {Supports the wakeup detection feature. \n + * - #PARAM_ID_VAD_STATIC_CFG \n + * - #PARAM_ID_VAD_CONTEXT_ML_MODEL_CONFIG \n + * - #PARAM_ID_VAD_CONTEXT_THRESHOLD \n + * - #PARAM_ID_VAD_SPEECH_DYNAMIC_CONFIG \n + * - #PARAM_ID_VAD_ENABLE_SPEECH_RESET \n + * - #PARAM_ID_VAD_SPEECH_RESET_PERIOD \n + * - #PARAM_ID_VAD_PRE_ROLL_DURATION \n + * + * Supported Input Media Format: \n + * - Data Format : FIXED_POINT \n + * - fmt_id : Don't care \n + * - Sample Rates : 16Khz \n + * - Number of channels : 1 to 2 \n + * - Channel type : 1 to 63 \n + * - Bits per sample : 16 \n + * - Q format : 15 \n + * - Interleaving : Deinterleaved Unpacked \n + * - Signed/unsigned : Any } + @h2xmlm_dataMaxInputPorts {CAPI_VAD_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {CAPI_VAD_MAX_OUTPUT_PORTS} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {CAPI_VAD_STACK_SIZE_REQUIREMENT} + @h2xmlm_ctrlDynamicPortIntent { "VAD-DAM Control" = INTENT_ID_AUDIO_DAM_DETECTION_ENGINE_CTRL, + maxPorts= 1 } + + @h2xmlm_ToolPolicy {Calibration} + @{ <-- Start of the Module --> +*/ + +#define PARAM_ID_VAD_STATIC_CFG 0x08001BE2 + +/** @h2xmlp_parameter {"PARAM_ID_VAD_STATIC_CFG", PARAM_ID_VAD_STATIC_CFG} + @h2xmlp_description {Parameter for static configuration for VAD module.} + @h2xmlp_toolPolicy {RTC_READONLY} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_vad_static_cfg_t +{ + + int32_t num_channel_processing; + /**< @h2xmle_description {Number of channel processing} + @h2xmle_default {1} + @h2xmle_range {1..2} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} + @h2xmle_readOnly {true} */ + int32_t conf_change; + /**< @h2xmle_description {Change in confidence level for sending detection update} + @h2xmle_default {1} + @h2xmle_range {0..100} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} + @h2xmle_visibility {hide} */ + int16_t mic_gain; + /**< @h2xmle_description {Microphone gain to be applied in Q4.11 format} + @h2xmle_default {0x0800} + @h2xmle_range {0..0x7FFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} + @h2xmle_readOnly {true} */ + + int16_t reserved; + /**< @h2xmle_description {Added for alignment} + @h2xmle_default {0} + @h2xmle_range {0x0000..0x0000} + @h2xmle_visibility {hide} + @h2xmle_readOnly {true} */ + +} param_id_vad_static_cfg_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_VAD_CONTEXT_ML_MODEL_CONFIG 0x08001BEA + +/** @h2xmlp_parameter {"PARAM_ID_VAD_CONTEXT_ML_MODEL_CONFIG", PARAM_ID_VAD_CONTEXT_ML_MODEL_CONFIG} + @h2xmlp_description {VAD stage1 ML MODEL} + @h2xmlp_ToolPolicy {Calibration} + @h2xmlp_isNeuralNetParam {TRUE} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_isHwAccel {TRUE} + @h2xmlp_persistType {SHARED} +*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +typedef struct param_id_vad_context_ml_model_config_t +{ + uint32_t model_align; + /**< @h2xmle_description {Data Alignment required for the model_data} + @h2xmle_default {256} + @h2xmle_range {0..8192} + @h2xmle_group {MODEL} + @h2xmle_visibility {hide} + @h2xmle_policy {Advanced} */ + + uint32_t model_offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of model by model_align} + @h2xmle_default {0} + @h2xmle_range {0..8191} + @h2xmle_group {MODEL} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint32_t model_size; + /**< @h2xmle_description {Size of the model in bytes} + @h2xmle_default {0} + @h2xmle_range {0x00000000..0xFFFFFFFF} + @h2xmle_group {MODEL} + @h2xmle_visibility {hide} + @h2xmle_policy {Basic} */ + + uint8_t model[0]; + /**< @h2xmle_description {Model data: The path to the model file on the platform} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} + @h2xmle_group {MODEL} + @h2xmle_policy {Basic} */ + +} param_id_vad_context_ml_model_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/** @h2xmlp_subStruct */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct capi_vad_context_threshold_struct_t +{ + uint32_t context_id; + /**< @h2xmle_description {context ID for which threshold being set. Context_id is indepedent of mode_bit and usecase designer has to tune this based on model which is being set from application} + @h2xmle_default {MODULE_CMN_CONTEXT_ID_AMBIENCE_SPEECH} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} + @h2xmle_visibility {hide} */ + + uint32_t threshold; + /**< @h2xmle_description {Threshold confidence score value} + @h2xmle_default {50} + @h2xmle_range {0..100} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + +} capi_vad_context_threshold_struct_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_VAD_CONTEXT_THRESHOLD 0x08001BE3 + +/** @h2xmlp_parameter {"PARAM_ID_VAD_CONTEXT_THRESHOLD", PARAM_ID_VAD_CONTEXT_THRESHOLD} + @h2xmlp_description {Parameter to set context thresholds for VAD module. + Threshold payload uses capi_vad_context_threshold_struct_t} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +typedef struct param_id_vad_context_threshold_t +{ + + uint32_t num_contexts; + /**< @h2xmle_description {Number of contexts being set} + @h2xmle_default {1} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} + @h2xmle_visibility {hide} */ + +#if defined(__H2XML__) + capi_vad_context_threshold_struct_t threshold_array[0]; + /**< @h2xmle_description {pointer to context wise threshold structure} + @h2xmle_variableArraySize {num_contexts} + */ +#endif +} param_id_vad_context_threshold_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_VAD_SPEECH_DYNAMIC_CONFIG 0x08001BE4 + +/** @h2xmlp_parameter {"PARAM_ID_VAD_SPEECH_DYNAMIC_CONFIG", PARAM_ID_VAD_SPEECH_DYNAMIC_CONFIG} + @h2xmlp_description {Parameter to set dynamic config for speech/NVD. Applicable if speech_or_nvd bit is set and don't care for other modes} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_vad_speech_dynamic_config_t +{ + uint32_t len_hangover_speech; + /**< @h2xmle_description {Number of blocks of no detected speech before vad classification goes to 0} + @h2xmle_default {10} + @h2xmle_range {0..0xFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + uint32_t max_conf_frames_speech; + /**< @h2xmle_description {Number of blocks for capping speech confidence frames} + @h2xmle_default {300} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + + uint32_t min_conf_frames_speech; + /**< @h2xmle_description {Minimum confidence frames for speech detection} + @h2xmle_default {30} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_group {GLOBAL} + @h2xmle_policy {Advanced} */ + +} param_id_vad_speech_dynamic_config_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_VAD_ENABLE_SPEECH_RESET 0x08001BE5 + +/** @h2xmlp_parameter {"PARAM_ID_VAD_ENABLE_SPEECH_RESET", PARAM_ID_VAD_ENABLE_SPEECH_RESET} + @h2xmlp_description {flag to enable speech reset} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_vad_enable_speech_reset_t +{ + + int32_t enable_reset; + /**< @h2xmle_description {flag to enable speech reset} + @h2xmle_default {1} + @h2xmle_range {0..1} + @h2xmle_policy {Advanced} */ + +} param_id_vad_enable_speech_reset_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define PARAM_ID_VAD_SPEECH_RESET_PERIOD 0x08001BE6 + +/** @h2xmlp_parameter {"PARAM_ID_VAD_SPEECH_RESET_PERIOD", PARAM_ID_VAD_SPEECH_RESET_PERIOD} + @h2xmlp_description {reset period in ms } + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_vad_speech_reset_period_t +{ + + int32_t speech_reset_period_in_ms; + /**< @h2xmle_description {reset period in milliseconds} + @h2xmle_default {3000} + @h2xmle_range {0..9000} + @h2xmle_policy {Advanced} */ + +} param_id_vad_speech_reset_period_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +#define PARAM_ID_VAD_PRE_ROLL_DURATION 0x08001BE7 + +/** @h2xmlp_parameter {"PARAM_ID_VAD_PRE_ROLL_DURATION", PARAM_ID_VAD_PRE_ROLL_DURATION} + @h2xmlp_description {Desired duration of pre roll history buffer in milliseconds.} + @h2xmlp_toolPolicy {Calibration}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +typedef struct param_id_vad_pre_roll_duration_t +{ + + uint32_t pre_roll_history_buffer_size_in_ms; + /**< @h2xmle_description {Desired duration of pre roll history buffer in milliseconds} + @h2xmle_default {500} + @h2xmle_range {0..0x7D0}*/ + +} param_id_vad_pre_roll_duration_t +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/** @} <-- End of the Module -->*/ + +#endif // #ifndef __VAD_API_H__ diff --git a/spf/api/modules/vocoder_cmn_api.h b/spf/api/modules/vocoder_cmn_api.h new file mode 100644 index 0000000..fa0854b --- /dev/null +++ b/spf/api/modules/vocoder_cmn_api.h @@ -0,0 +1,210 @@ +#ifndef _VOCODER_CMN_API_H_ +#define _VOCODER_CMN_API_H_ + +/** + * \file vocoder_cmn_api.h + * \brief + * This file contains vocoder modules' commmon APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** @h2xml_title1 {Vocoder Common API} + @h2xml_title_agile_rev {Vocoder Common API} + @h2xml_title_date {April, 2019} */ + +#include "module_cmn_api.h" + +/*============================================================================== + Constants +==============================================================================*/ +#define VOICE_TTY_MODE_OFF 0 /* TTY OFF or disabled */ +#define VOICE_TTY_MODE_HCO 1 /* Hearing carry over mode. */ +#define VOICE_TTY_MODE_VCO 2 /* Voice carry over mode. */ +#define VOICE_TTY_MODE_FULL 3 /* FULL mode. */ + +#define VOCODER_OPERATING_MODE_NB 0 /* Vocoder bandwidth mode is 8 kHz. */ +#define VOCODER_OPERATING_MODE_WB 1 /* Vocoder bandwidth mode is 16 kHz. */ +#define VOCODER_OPERATING_MODE_SWB 2 /* Vocoder bandwidth mode is 32 kHz. */ +#define VOCODER_OPERATING_MODE_FB 3 /* Vocoder bandwidth mode is 48 kHz. */ +#define VOCODER_OPERATING_MODE_NONE 0xffffffff + +typedef enum vocoder_client_id_t +{ + AUDIO_CLIENT = 0x0, + VOICE_CLIENT = 0x1, +} vocoder_client_id_t; + + +typedef enum tty_cdma_vocoder_type_t { + TTY_CDMA_V13K = 0, + TTY_CDMA_EVRC, + TTY_CDMA_FOURGV +}tty_cdma_vocoder_type_t; + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_VOCODER_ENABLE_DTX_MODE 0x08001123 + +/* Structure definition for Parameter */ + +/** @h2xmlp_parameter {"PARAM_ID_VOCODER_ENABLE_DTX_MODE", + PARAM_ID_VOCODER_ENABLE_DTX_MODE} + @h2xmlp_description {Enables/Disables the Discontinous Transmission Mode} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_vocoder_enable_dtx_mode_t +{ + uint32_t enable; + /**< @h2xmle_description {Enables the DTX transmission mode} + @h2xmle_rangeList {Disabled=0;Enabled=1} + @h2xmle_default {0} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_vocoder_enable_dtx_mode_t param_id_vocoder_enable_dtx_mode_t; + + +/** ID of the parameter used to configure the encoder minimum and maximum rates */ +#define PARAM_ID_VOCODER_MINMAX_RATE 0x08001124 + + +/** @h2xmlp_parameter {"PARAM_ID_VOCODER_MINMAX_RATE", PARAM_ID_VOCODER_MINMAX_RATE} + @h2xmlp_description {Parameter for setting the min and max rates on the encoder module} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_vocoder_minmax_rate_param_t +{ + uint32_t min_rate; + /**< @h2xmle_description {Minimum supported encoding rate} + @h2xmle_rangeList {"SILENCE_RATE"=0,"QUARTER_RATE"=1,"HALF_RATE"=3,"FULL_RATE"=4 } + @h2xmle_policy {Basic} */ + + uint32_t max_rate; + /**< @h2xmle_description {Maximum supported encoding rate} + @h2xmle_rangeList {"SILENCE_RATE"=0,"QUARTER_RATE"=1,"HALF_RATE"=3,"FULL_RATE"=4 } + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_vocoder_minmax_rate_param_t param_id_vocoder_minmax_rate_param_t; + + +/** ID of the parameter used to configure the encoding rate */ +#define PARAM_ID_VOCODER_ENC_RATE 0x080011B1 + +/** @h2xmlp_parameter {"PARAM_ID_VOCODER_ENC_RATE", PARAM_ID_VOCODER_ENC_RATE} + @h2xmlp_description {Parameter for setting encoder rate} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_vocoder_enc_rate_param_t +{ + uint32_t rate; + /**< + @h2xmle_description {Encoding rate to be set. The exact interpretation + of the value and valid range depends on the type of encoder} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct param_id_vocoder_enc_rate_param_t param_id_vocoder_enc_rate_param_t; + + +/** ID of the parameter used to configure the encoding rate for modulation */ +#define PARAM_ID_VOCODER_RATE_MODULATION 0x08001125 + + +/** @h2xmlp_parameter {"PARAM_ID_VOCODER_RATE_MODULATION", PARAM_ID_VOCODER_RATE_MODULATION} + @h2xmlp_description {Parameter for setting the encoding rate for modulation + The exact interpretation of the value and valid range depends on the + type of encoder} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_vocoder_rate_modulation_param_t +{ + uint32_t rate_modulation_param; + /**< @h2xmle_description {Encoder rate modulation command} + @h2xmle_policy {Basic} */ + +} +#include "spf_end_pack.h" +; +typedef struct param_id_vocoder_rate_modulation_param_t param_id_vocoder_rate_modulation_param_t; + +/** ID of the parameter used to set the TTY mode */ +#define PARAM_ID_TTY_MODE 0x08001127 + +/** @h2xmlp_parameter {"PARAM_ID_TTY_MODE", PARAM_ID_TTY_MODE} + @h2xmlp_description {Parameter for setting the TTY mode of operation} + @h2xmlp_toolPolicy {Calibration} */ + +#include "spf_begin_pack.h" +struct param_id_tty_mode_t +{ + uint32_t mode; + /**< @h2xmle_description {TTY mode to be set} + @h2xmle_rangeList {"VOICE_TTY_MODE_OFF"=0, + "VOICE_TTY_MODE_HCO"=1, + "VOICE_TTY_MODE_VCO"=2, + "VOICE_TTY_MODE_FULL"=3} + @h2xmle_policy {Basic} */ // TODO : Check the policy + +} +#include "spf_end_pack.h" +; +typedef struct param_id_tty_mode_t param_id_tty_mode_t; + +/* Unique Paramter id */ +/** + * Parameter to reset voice encoder/decoder. + This param id can be used reset vocoder whenever client sends homing sequence to network. + Since these homing sequence reset far end decoder, client can use this param id to reset + near end encoder so that both encoder and decoder are in sync. + This param doesn't have any payload associated with it. Once module receives this param, it is expected to + RESET itself + */ +#define PARAM_ID_VOCODER_RESET 0x08001128 + +/** + * Event ID that is raised by the vocoder when client registers for operating mode updates + * with the vocoder. Payload of the event contains the operating mode details. + * We have 4 operating modes - one for each of 8k/16k/32k/48k bandwidths + */ + +#define EVENT_ID_VOCODER_OPERATING_MODE 0x08001197 + + +/** @h2xmlp_parameter {"EVENT_ID_VOCODER_OPERATING_MODE", + EVENT_ID_VOCODER_OPERATING_MODE} + @h2xmlp_description { Operating mode that is returned by the vocoder.} + @h2xmlp_toolPolicy { Calibration}*/ + +#include "spf_begin_pack.h" +struct event_id_vocoder_operating_mode_t +{ + uint32_t operating_mode; + /**< @h2xmle_description {Operating mode returned by the vocoder} + @h2xmle_rangeList {"VOCODER_OPERATING_MODE_NB"=0, + "VOCODER_OPERATING_MODE_WB"=1, + "VOCODER_OPERATING_MODE_SWB"=2, + "VOCODER_OPERATING_MODE_FB"=3} + @h2xmle_policy {Basic} */ // TODO : Check the policy + uint32_t client_data; + /**< @h2xmle_description {Client data to be used by the modem} + @h2xmle_policy {Basic} */ // TODO : Check the policy + +} +#include "spf_end_pack.h" +; +typedef struct event_id_vocoder_operating_mode_t event_id_vocoder_operating_mode_t; + +#endif /* _VOCODER_CMN_API_H_ */ diff --git a/spf/api/modules/vorbis_decoder_api.h b/spf/api/modules/vorbis_decoder_api.h new file mode 100644 index 0000000..3005540 --- /dev/null +++ b/spf/api/modules/vorbis_decoder_api.h @@ -0,0 +1,85 @@ +#ifndef _VORBIS_DECODER_API_H_ +#define _VORBIS_DECODER_API_H_ +/*============================================================================== + @file vorbis_decoder_api.h + @brief This file contains VORBIS decoder APIs + + Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + SPDX-License-Identifier: BSD-3-Clause + ==============================================================================*/ +// clang-format off + +/*============================================================================== + * Include files + ==============================================================================*/ + +#include "media_fmt_api.h" +#include "common_enc_dec_api.h" + +/** @h2xml_title1 {VORBIS Decoder Module API} + @h2xml_title_agile_rev {VORBIS Decoder Module API} + @h2xml_title_date {April 15, 2019} */ + +/*============================================================================== + Constants +==============================================================================*/ +/* Input port ID of VORBIS module */ +#define VORBIS_DEC_DATA_INPUT_PORT 0x2 + +/* Output port ID of VORBIS module */ +#define VORBIS_DEC_DATA_OUTPUT_PORT 0x1 + +/* Max number of input ports of VORBIS module */ +#define VORBIS_DEC_DATA_MAX_INPUT_PORTS 0x1 + +/* Max number of output ports of VORBIS module */ +#define VORBIS_DEC_DATA_MAX_OUTPUT_PORTS 0x1 + +/* Stack size of VORBIS module */ +#define VORBIS_DEC_MODULE_STACK_SIZE 8192 + + +/*============================================================================== + Module +==============================================================================*/ + +/** + * Module ID for VORBIS decoder. + * Decodes data of format-id = MEDIA_FMT_ID_VORBIS + */ +#define MODULE_ID_VORBIS_DEC 0x07001030 + /** + @h2xmlm_module {"MODULE_ID_VORBIS_DEC", MODULE_ID_VORBIS_DEC} + @h2xmlm_displayName {"VORBIS Decoder"} + @h2xmlm_description {This module is used as the decoder for VORBIS use cases.\n + - This module has only one input and one output port.\n + - Payload for media_format_t: payload_media_fmt_vorbis_t\n + - Media format is not directly set on the decoder, it's set on the EP module which + propagates it in the data path.\n + - Decodes data of format-id = MEDIA_FMT_ID_VORBIS\n + - Supports following params:\n + -- PARAM_ID_PCM_OUTPUT_FORMAT_CFG\n + -- PARAM_ID_REMOVE_INITIAL_SILENCE\n + -- PARAM_ID_REMOVE_TRAILING_SILENCE\n + - Supported Input Media Format\n + -- Data format : RAW_COMPRESSED\n + -- fmt_id : MEDIA_FMT_ID_VORBIS\n + -- payload : payload_media_fmt_vorbis_t\n + } + @h2xmlm_dataMaxInputPorts {VORBIS_DEC_DATA_MAX_INPUT_PORTS} + @h2xmlm_dataMaxOutputPorts {VORBIS_DEC_DATA_MAX_OUTPUT_PORTS} + @h2xmlm_dataInputPorts {IN=VORBIS_DEC_DATA_INPUT_PORT} + @h2xmlm_dataOutputPorts {OUT=VORBIS_DEC_DATA_OUTPUT_PORT} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {true} + @h2xmlm_stackSize {VORBIS_DEC_MODULE_STACK_SIZE} + @h2xmlm_toolPolicy {Calibration} + @{ <-- Start of the Module --> + @h2xml_Select {"param_id_pcm_output_format_cfg_t"} + @h2xmlm_InsertParameter + @h2xml_Select {"payload_pcm_output_format_cfg_t"} + @h2xmlm_InsertStructure + @} <-- End of the Module --> + */ + #endif // _VORBIS_DECODER_API_H + diff --git a/spf/api/modules/wr_sh_mem_client_api.h b/spf/api/modules/wr_sh_mem_client_api.h new file mode 100644 index 0000000..82e69f0 --- /dev/null +++ b/spf/api/modules/wr_sh_mem_client_api.h @@ -0,0 +1,68 @@ +/** + * \file wr_sh_mem_client_api.h + * \brief + * This file contains Shared mem Client module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef WR_SH_MEM_CLEINT_API_H_ +#define WR_SH_MEM_CLEINT_API_H_ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "apm_graph_properties.h" +/** + @h2xml_title1 {Write Shared Memory Client Module API} + @h2xml_title_agile_rev {Write Shared Memory Client Module API} + @h2xml_title_date {May 23, 2019} +*/ + +/** + * Output port ID of the Write Shared Memory Client module + */ +#define PORT_ID_WR_SHARED_MEM_CLIENT_OUTPUT 0x1 + +/** + * Input port ID of the Write Shared Memory Client module + */ +#define PORT_ID_WR_SHARED_MEM_CLIENT_INPUT 0x2 + +/** + * ID of the Write Shared Memory Client Module + * + * This module has one static input port with ID 2 and output port with ID 1 + * + * This module is supported only in Offload container. The modules functions as the + * Client to the MODULE_ID_WR_SHARED_MEM_EP module. The module send the data from the + * Master process domain to the Write End-point module in the satellite SPF. + * + * Supported Input Media Format: + * - Any + */ +#define MODULE_ID_WR_SHARED_MEM_CLIENT 0x0700105C +/** + @h2xmlm_module {"MODULE_ID_WR_SHARED_MEM_CLIENT", MODULE_ID_WR_SHARED_MEM_CLIENT} + @h2xmlm_displayName {"Write Shared Memory Client"} + @h2xmlm_description { + This module is used to send data from spf in Master process domain to + the spf in satellite process domain using the GPR packet exchange mechanism. + This module has one static input port with ID 0 and output port with ID 1 + } + @h2xmlm_offloadInsert { WR_CLIENT } + @h2xmlm_dataInputPorts { IN = PORT_ID_WR_SHARED_MEM_CLIENT_INPUT} + @h2xmlm_dataMaxInputPorts { 1 } + @h2xmlm_dataOutputPorts { OUT = PORT_ID_WR_SHARED_MEM_CLIENT_OUTPUT} + @h2xmlm_dataMaxOutputPorts { 1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_OLC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { 4096 } + @{ <-- Start of the Module --> + @} <-- End of the Module --> +*/ + +#endif // WR_SH_MEM_CLIENT_API_H_ diff --git a/spf/api/modules/wr_sh_mem_ep_api.h b/spf/api/modules/wr_sh_mem_ep_api.h new file mode 100644 index 0000000..41b44a7 --- /dev/null +++ b/spf/api/modules/wr_sh_mem_ep_api.h @@ -0,0 +1,552 @@ +/** + * \file wr_sh_mem_ep_api.h + * \brief + * This file contains Shared mem module APIs + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef WR_SH_MEM_EP_API_H_ +#define WR_SH_MEM_EP_API_H_ + +/*------------------------------------------------------------------------ + * Include files + * -----------------------------------------------------------------------*/ +#include "ar_defs.h" +#include "common_enc_dec_api.h" +#include "ar_guids.h" + +/** + @h2xml_title1 {Write Shared Memory End Point Module API} + @h2xml_title_agile_rev {Write Shared Memory End Point Module API} + @h2xml_title_date {August 13, 2018} +*/ + +/** + @h2xmlx_xmlNumberFormat {int} +*/ +/** + * Data command to write a buffer to the shared memory end point module. + * The client writes to this buffer and WR_SHARED_MEM_EP reads. + * + * The command can be used for PCM, raw compressed raw bit streams as well as packetized streams. + * Before issuing this command the graph must be opened and a media format issued (command or data). + * + * for PCM, the buffer must contain same number of samples on all channels. + * + * Once the buffer is consumed, DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE event is raised by the module. + * + */ +#define DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER 0x04001000 + +/** Definition of a timestamp valid flag bitmask. */ +#define WR_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG AR_NON_GUID(0x80000000) + +/** Definition of a timestamp valid flag shift value. */ +#define WR_SH_MEM_EP_SHIFT_TIMESTAMP_VALID_FLAG 31 + +/** Definition of the last buffer flag bitmask. +*/ +#define WR_SH_MEM_EP_BIT_MASK_LAST_BUFFER_FLAG AR_NON_GUID(0x40000000) + +/** Definition of the last buffer flag shift value. +*/ +#define WR_SH_MEM_EP_SHIFT_LAST_BUFFER_FLAG 30 + +/** Definition of the shift value for the timestamp continue flag. +*/ +#define WR_SH_MEM_EP_BIT_MASK_TS_CONTINUE_FLAG AR_NON_GUID(0x20000000) + +/** Definition of the shift value for the timestamp continue flag. +*/ +#define WR_SH_MEM_EP_SHIFT_TS_CONTINUE_FLAG 29 + +/** Definition of an End of Frame (EOF) flag bitmask. */ +#define WR_SH_MEM_EP_BIT_MASK_EOF_FLAG AR_NON_GUID(0x00000010) + +/** Definition of an EOF flag shift value. */ +#define WR_SH_MEM_EP_SHIFT_EOF_FLAG 4 + +#include "spf_begin_pack.h" +struct data_cmd_wr_sh_mem_ep_data_buffer_t +{ + uint32_t buf_addr_lsw; + /**< Lower 32 bits of the address of the buffer containing the data */ + + uint32_t buf_addr_msw; + /**< Upper 32 bits of the address of the buffer containing the data. + + The 64 bit buffer address must be a valid address + that was mapped via #APM_CMD_SHARED_MEM_MAP_REGIONS. + The 64-bit number formed by buf_addr_lsw and buf_addr_msw must be + aligned to the cache-line of the processor where spf runs (64-byte alignment for Hexagon). + + @tblsubhd{For a 32-bit shared memory address} This buf_addr_msw field + must be set to 0. + + @tblsubhd{For a 36-bit address} Bits 31 to 4 of this + buf_addr_msw field must be set to 0. */ + + uint32_t mem_map_handle; + /**< Unique identifier for the shared memory address. + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t buf_size; + /**< Number of valid bytes available in the buffer for processing. The + first byte starts at the buffer address. */ + + uint32_t timestamp_lsw; + /**< Lower 32 bits of the 64-bit timestamp in microseconds of the + first buffer sample. */ + + uint32_t timestamp_msw; + /**< Upper 32 bits of the 64-bit timestamp in microseconds of the + first buffer sample. + + The 64-bit number of interpreted as signed number. */ + + uint32_t flags; + /**< Bitfield of flags. + + @values{for bit 31} + - 1 -- Valid timestamp + - 0 -- Invalid timestamp + - To set this bit, use #WR_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG and + #WR_SH_MEM_EP_SHIFT_TIMESTAMP_VALID_FLAG + + @values{for bit 30} + - 1 -- Last buffer + - 0 -- Not the last buffer + - To set this bit, use #WR_SH_MEM_EP_BIT_MASK_LAST_BUFFER_FLAG and + #WR_SH_MEM_EP_SHIFT_LAST_BUFFER_FLAG + + @values{for bit 29} + - 1 -- Continue the timestamp from the previous buffer + - 0 -- Timestamp of the current buffer is not related to the timestamp + of the previous buffer + - To set this bit, use #WR_SH_MEM_EP_BIT_MASK_TS_CONTINUE_FLAG and + #WR_SH_MEM_EP_SHIFT_TS_CONTINUE_FLAG + + @values{for bit 4 (end-of-frame flag)} + - 1 -- End of the frame + - 0 -- Not the end of frame, or this information is not known + - To set this bit, use #WR_SH_MEM_EP_BIT_MASK_EOF_FLAG as the bitmask and + #WR_SH_MEM_EP_SHIFT_EOF_FLAG + + All other bits are reserved; clients must set them to 0. + + @tblsubhd{If bit 31=0 and bit 29=1} + The timestamp of the first sample in this buffer continues from the + timestamp of the last sample in the previous buffer. + + The samples in the current buffer do not have a valid timestamp in + the following situations: + - If there is no previous buffer (this buffer is the first + buffer sent after opening & starting the graph or after a flush operation) + - If the previous buffer does not have a valid timestamp + + In these cases, the samples in the current buffer are played out as + soon as possible. + + @tblsubhd{If bit 31=0 and bit 29=0} + No timestamp is associated with the first sample in this buffer. The + samples are played out as soon as possible. + + @tblsubhd{If bit 31=1 and bit 29 is ignored} + The timestamp specified in this payload is honored. + + @tblsubhd{If bit 30=0} + This buffer is not the last buffer. This case is useful + in removing trailing samples in gapless use cases. + + @contcell + @tblsubhd{For bit 4} + The client can set this end-of-frame flag for every buffer sent in + which the last byte is the end of a frame. If this flag is set, the + buffer can contain data from multiple frames, but it must always end + at a frame boundary. Restrictions allow the spf to detect an end of + frame without requiring additional processing. */ +} +#include "spf_end_pack.h" +; + +/** Structure for DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER */ +typedef struct data_cmd_wr_sh_mem_ep_data_buffer_t data_cmd_wr_sh_mem_ep_data_buffer_t; + +/** + * Indicates that the referenced buffer has been fully consumed and + * is again available to the client. + */ +#define DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE 0x05001000 + +#include "spf_begin_pack.h" +struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_t +{ + uint32_t buf_addr_lsw; + /**< Lower 32 bits of the address of the buffer being returned. */ + + uint32_t buf_addr_msw; + /**< Upper 32 bits of the address of the buffer being returned. + + The valid, mapped, 64-bit address is the same address that + the client provides in #DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER. */ + + uint32_t mem_map_handle; + /**< Unique identifier for the shared memory address. + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t status; + /**< Status message (error code) that indicates whether the referenced + buffer has been successfully consumed. + + @values Refer to @xrefcond{Q5,80-NF774-4,80-NA610-4} */ +} +#include "spf_end_pack.h" +; + +/* Structure DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE */ +typedef struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_t data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_t; + + +/** + * Data command to write a buffer and associated metadata to the shared memory end point module. + * The client writes data and metadata to this buffer and WR_SHARED_MEM_EP reads. + * + * The command can be used for PCM, raw compressed raw bit streams as well as packetized streams. + * Before issuing this command the graph must be opened and a media format issued (command or data). + * + * for PCM, the buffer must contain same number of samples on all channels. + * + * The Metadata should be filled in the specified format at the corresponding address + * + * Once the buffer is consumed, DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE event is raised by the module. + * + */ +#define DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2 0x0400100A + +#include "spf_begin_pack.h" +struct data_cmd_wr_sh_mem_ep_data_buffer_v2_t +{ + uint32_t data_buf_addr_lsw; + /**< Lower 32 bits of the address of the buffer containing the data */ + + uint32_t data_buf_addr_msw; + /**< Upper 32 bits of the address of the buffer containing the data. + + The 64 bit buffer address must be a valid address + that was mapped via #APM_CMD_SHARED_MEM_MAP_REGIONS. + The 64-bit number formed by data_buf_addr_lsw and data_buf_addr_msw must be + aligned to the cache-line of the processor where spf runs (64-byte alignment for Hexagon). + + @tblsubhd{For a 32-bit shared memory address} This data_buf_addr_msw field + must be set to 0. + + @tblsubhd{For a 36-bit address} Bits 31 to 4 of this + data_buf_addr_msw field must be set to 0. */ + + uint32_t data_mem_map_handle; + /**< Unique identifier for the shared memory corresponding to data buffer address + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t data_buf_size; + /**< Number of valid bytes available in the buffer for processing. The + first byte starts at the data buffer address. */ + + uint32_t timestamp_lsw; + /**< Lower 32 bits of the 64-bit timestamp in microseconds of the + first data buffer sample. */ + + uint32_t timestamp_msw; + /**< Upper 32 bits of the 64-bit timestamp in microseconds of the + first data buffer sample. + + The 64-bit number of interpreted as signed number. */ + + uint32_t flags; + /**< Bitfield of flags. + + @values{for bit 31} + - 1 -- Valid timestamp + - 0 -- Invalid timestamp + - To set this bit, use #WR_SH_MEM_EP_BIT_MASK_TIMESTAMP_VALID_FLAG and + #WR_SH_MEM_EP_SHIFT_TIMESTAMP_VALID_FLAG + + @values{for bit 30} + - 1 -- Last data buffer + - 0 -- Not the last data buffer + - To set this bit, use #WR_SH_MEM_EP_BIT_MASK_LAST_BUFFER_FLAG and + #WR_SH_MEM_EP_SHIFT_LAST_BUFFER_FLAG + + @values{for bit 29} + - 1 -- Continue the timestamp from the previous data buffer + - 0 -- Timestamp of the current buffer is not related to the timestamp + of the previous data buffer + - To set this bit, use #WR_SH_MEM_EP_BIT_MASK_TS_CONTINUE_FLAG and + #WR_SH_MEM_EP_SHIFT_TS_CONTINUE_FLAG + + @values{for bit 4 (end-of-frame flag)} + - 1 -- End of the frame + - 0 -- Not the end of frame, or this information is not known + - To set this bit, use #WR_SH_MEM_EP_BIT_MASK_EOF_FLAG as the bitmask and + #WR_SH_MEM_EP_SHIFT_EOF_FLAG + + All other bits are reserved; clients must set them to 0. + + @tblsubhd{If bit 31=0 and bit 29=1} + The timestamp of the first sample in this data buffer continues from the + timestamp of the last sample in the previous data buffer. + + The samples in the current data buffer do not have a valid timestamp in + the following situations: + - If there is no previous data buffer (this buffer is the first + data buffer sent after opening & starting the graph or after a flush operation) + - If the previous data buffer does not have a valid timestamp + + In these cases, the samples in the current data buffer are played out as + soon as possible. + + @tblsubhd{If bit 31=0 and bit 29=0} + No timestamp is associated with the first sample in this data buffer. The + samples are played out as soon as possible. + + @tblsubhd{If bit 31=1 and bit 29 is ignored} + The timestamp specified in this payload is honored. + + @tblsubhd{If bit 30=0} + This buffer is not the last data buffer. This case is useful + in removing trailing samples in gapless use cases. + + @contcell + @tblsubhd{For bit 4} + The client can set this end-of-frame flag for every data buffer sent in + which the last byte is the end of a frame. If this flag is set, the + data buffer can contain data from multiple frames, but it must always end + at a frame boundary. Restrictions allow the spf to detect an end of + frame without requiring additional processing. */ + + uint32_t md_buf_addr_lsw; + /**< Lower 32 bits of the address of the buffer containing the metadata */ + + uint32_t md_buf_addr_msw; + /**< Upper 32 bits of the address of the buffer containing the metadata. + + The 64 bit buffer address must be a valid address + that was mapped via #APM_CMD_SHARED_MEM_MAP_REGIONS. + The 64-bit number formed by md_buf_addr_lsw and md_buf_addr_msw must be + aligned to the cache-line of the processor where spf runs (64-byte alignment for Hexagon). + + @tblsubhd{For a 32-bit shared memory address} This md_buf_addr_msw field + must be set to 0. + + @tblsubhd{For a 36-bit address} Bits 31 to 4 of this + md_buf_addr_msw field must be set to 0. */ + + uint32_t md_mem_map_handle; + /**< Unique identifier for the shared memory corresponding to metadata buffer address. + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS.*/ + + uint32_t md_buf_size; + /**< Number of valid bytes available in the metadata buffer for processing. + * The first byte starts at the metadata buffer address. + * */ +} +#include "spf_end_pack.h" +; + +/** Structure for DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2 */ +typedef struct data_cmd_wr_sh_mem_ep_data_buffer_v2_t data_cmd_wr_sh_mem_ep_data_buffer_v2_t; + +/** + * Indicates that the referenced write buffer has been fully consumed and + * is again available to the client. + */ +#define DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2 0x05001004 + +#include "spf_begin_pack.h" +struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2_t +{ + uint32_t data_buf_addr_lsw; + /**< Lower 32 bits of the address of the data buffer being returned. */ + + uint32_t data_buf_addr_msw; + /**< Upper 32 bits of the address of the data buffer being returned. + + The valid, mapped, 64-bit data buffer address is the same address that + the client provides in #DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2. */ + + uint32_t data_mem_map_handle; + /**< Unique identifier for the shared memory corresponding to data buffer address. + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t data_status; + /**< Status message (error code) that indicates whether the referenced + data buffer has been successfully consumed. + + @values Refer to @xrefcond{Q5,80-NF774-4,80-NA610-4} */ + + uint32_t md_buf_addr_lsw; + /**< Lower 32 bits of the address of the metadata buffer being returned. */ + + uint32_t md_buf_addr_msw; + /**< Upper 32 bits of the address of the metadata buffer being returned. + + The valid, mapped, 64-bit metadata buffer address is the same address that + the client provides in #DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2. */ + + uint32_t md_mem_map_handle; + /**< Unique identifier for the shared memory corresponding to metadata buffer address + + The spf returns this handle through #APM_CMD_RSP_SHARED_MEM_MAP_REGIONS. */ + + uint32_t md_status; + /**< Status message (error code) that indicates whether the referenced + metadata buffer has been successfully consumed. + + @values Refer to @xrefcond{Q5,80-NF774-4,80-NA610-4} */ +} +#include "spf_end_pack.h" +; + +/* Structure DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2 */ +typedef struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2_t data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2_t; + +/** + * Indicates an update to the media format, which applies to future buffers + written to this stream. + + This command is accepted only when subgraph is in START state. + + Some decoders may not work without receiving either + PARAM_ID_MEDIA_FORMAT or DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT + + Payload is of type media_format_t + */ +#define DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT 0x04001001 + +/** + * Communicates an EoS marker, which indicates that the last buffer in a stream was delivered. + * + * Once the stream is received by another end point (E.g. hardware end point), + * it raises DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED event. + * + * The token in the GPR payload is used as token in DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED for correlation. + */ +#define DATA_CMD_WR_SH_MEM_EP_EOS 0x04001002 + +/** + * EoS policy according to which last of the final end point raises the DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED + * OR the last container which drops/renders the EoS raises the DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED event. + * + */ +#define WR_SH_MEM_EP_EOS_POLICY_LAST 1 + + +/** + * EoS policy according to which each of the final EP raises the DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED + * OR the each container which drop the EoS raises the DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED event. + */ +#define WR_SH_MEM_EP_EOS_POLICY_EACH 2 + +#include "spf_begin_pack.h" +struct data_cmd_wr_sh_mem_ep_eos_t +{ + uint32_t policy; + /**< Policy used to raise DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED + * WR_SH_MEM_EP_EOS_POLICY_LAST + * WR_SH_MEM_EP_EOS_POLICY_EACH */ +} +#include "spf_end_pack.h" +; + +/** + * Structure for DATA_CMD_WR_SH_MEM_EP_EOS + */ +typedef struct data_cmd_wr_sh_mem_ep_eos_t data_cmd_wr_sh_mem_ep_eos_t; + +/** + * Indicates that DATA_CMD_WR_SH_MEM_EP_EOS has been received by the final end-point. + * No more data is left to be rendered. + * + * Uses the same token as was sent in DATA_CMD_WR_SH_MEM_EP_EOS. + * + * the source port in the GPR packet will contain the SH MEM EP that received DATA_CMD_WR_SH_MEM_EP_EOS + */ +#define DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED 0x05001001 + +/** + * Render status of EoS, where EoS message is rendered on final end device. + */ +#define WR_SH_MEM_EP_EOS_RENDER_STATUS_RENDERED 1 +/** + * Render status of EoS, where EoS message is dropped before it reached the final end device. + */ +#define WR_SH_MEM_EP_EOS_RENDER_STATUS_DROPPED 2 + +#include "spf_begin_pack.h" +struct data_cmd_rsp_wr_sh_mem_ep_eos_rendered_t +{ + uint32_t module_instance_id; + /**< module instance id from which the DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED is being raised + * Invalid (0) when dropped. */ + + uint32_t render_status; + /**< Render status - 1 - Rendered. 2 - Dropped */ +} +#include "spf_end_pack.h" +; + + +/** Structure for DATA_CMD_RSP_WR_SH_MEM_EP_EOS_RENDERED */ +typedef struct data_cmd_rsp_wr_sh_mem_ep_eos_rendered_t data_cmd_rsp_wr_sh_mem_ep_eos_rendered_t; + +/** + * Output port ID of the Write Shared Memory EP + */ +#define PORT_ID_WR_SHARED_MEM_EP_OUTPUT 0x1 + +/** + * Input port ID of the Write Shared Memory EP + * This Port is connected only in OFFLOAD(MDF) use-cases + */ +#define PORT_ID_WR_SHARED_MEM_EP_INPUT 0x2 + +/** + * ID of the Write Shared Memory End-Point Module + * + * This module has only one static output port with ID 1 + * + * Supported Input Media Format: + * - Any + */ +#define MODULE_ID_WR_SHARED_MEM_EP 0x07001000 +/** + @h2xmlm_module {"MODULE_ID_WR_SHARED_MEM_EP", MODULE_ID_WR_SHARED_MEM_EP} + @h2xmlm_displayName {"Write Shared Memory EndPoint"} + @h2xmlm_description { + This module is used to write data to spf from the host through packet exchange mechanism. + For regular use-case, this module support only one static output port with ID 1 + For MDF use-cases where the module is automatically inserted by the ARCT, + this module support one static output port with ID 1 and one static input port with ID 2. + } + @h2xmlm_offloadInsert { WR_EP } + @h2xmlm_dataInputPorts { IN = PORT_ID_WR_SHARED_MEM_EP_INPUT} + @h2xmlm_dataOutputPorts { OUT = PORT_ID_WR_SHARED_MEM_EP_OUTPUT} + @h2xmlm_dataMaxInputPorts { 1 } + @h2xmlm_dataMaxOutputPorts { 1 } + @h2xmlm_supportedContTypes { APM_CONTAINER_TYPE_GC } + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize { 1024 } + @{ <-- Start of the Module --> + @h2xml_Select {"media_format_t"} + @h2xmlm_InsertParameter + @} <-- End of the Module --> +*/ + +#endif // WR_SH_MEM_EP_API_H_ diff --git a/spf/api/modules/wsa_haptics_vi_api.h b/spf/api/modules/wsa_haptics_vi_api.h new file mode 100644 index 0000000..adea457 --- /dev/null +++ b/spf/api/modules/wsa_haptics_vi_api.h @@ -0,0 +1,1730 @@ +#ifndef __WSA_HAPTICS_VI_API_H__ +#define __WSA_HAPTICS_VI_API_H__ + +/*============================================================================== + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + + @file wsa_haptics_vi_api.h + @brief This file contains APIs for Haptics Module +==============================================================================*/ + +/** @h2xml_title1 {Haptics} + @h2xml_title_date {June 21, 2022} */ +#include "module_cmn_api.h" +#include "ar_defs.h" +#include "imcl_spm_intent_api.h" +#include "rtm_logging_api.h" + + +/*------------------------------------------------------------------------------ + Module +------------------------------------------------------------------------------*/ +/*============================================================================== + Constants +==============================================================================*/ +#define HAPTICS_VI_MAX_INPUT_PORTS 1 +#define HAPTICS_VI_MAX_OUTPUT_PORTS 1 +#define HAPTICS_VI_STACK_SIZE 4096 + +/* Unique Module ID */ +#define MODULE_ID_HAPTICS_VI 0x070010E5 + +/** @h2xmlm_module {"MODULE_ID_HAPTICS_VI", + MODULE_ID_HAPTICS_VI} + @h2xmlm_displayName {"HAPTICS - VI"} + @h2xmlm_toolPolicy {Calibration;CALIBRATION} + @h2xmlm_description {ID of the HAPTICS VI module.\n + this module includes VI Sens feedback data processing, + Thermal tracking, LRA state tracking. + + This module supports the following parameter IDs:\n + - #PARAM_ID_HAPTICS_VI_STATIC_CONFIG\n + - #PARAM_ID_HAPTICS_VI_OP_MODE_PARAM\n + - #PARAM_ID_HAPTICS_VI_EX_FTM_MODE_PARAM\n + - #PARAM_ID_HAPTICS_TH_VI_R0T0_SET_PARAM\n + - #PARAM_ID_HAPTICS_TH_VI_R0_GET_PARAM\n + - #PARAM_ID_HAPTICS_TH_VI_DYNAMIC_PARAM\n + - #PARAM_ID_HAPTICS_TH_VI_FTM_SET_CFG\n + - #PARAM_ID_HAPTICS_TH_VI_FTM_GET_PARAM\n + - #PARAM_ID_HAPTICS_EX_VI_DYNAMIC_PARAM\n + - #PARAM_ID_HAPTICS_EX_VI_PERSISTENT\n + - #PARAM_ID_HAPTICS_EX_VI_FTM_SET_CFG\n + - #PARAM_ID_HAPTICS_EX_VI_FTM_GET\n + - #PARAM_ID_HAPTICS_LRA_DIAG_GETPKT_PARAM\n + - #PARAM_ID_HAPTICS_EX_VI_DEMO_PKT_PARAM\n + - #PARAM_ID_HAPTICS_VI_CHANNEL_MAP_CFG\n + - #PARAM_ID_HAPTICS_VI_FTM_DATA_PARAM\n + - #PARAM_ID_HAPTICS_VI_CALIB_DATA_PARAM\n + - #PARAM_ID_HAPTICS_VI_CALIB_PARAM\n + - #PARAM_ID_HAPTICS_VI_CALIB_PARAM_V2\n + - #PARAM_ID_HAPTICS_VI_FTM_CFG\n + - #PARAM_ID_HAPTICS_VI_TUNING_DATA_0_PARAM\n + - #PARAM_ID_HAPTICS_VI_TUNING_DATA_1_PARAM\n + - #PARAM_ID_HAPTICS_VI_TUNING_DATA_2_PARAM\n + - #PARAM_ID_HAPTICS_VI_TUNING_DATA_3_PARAM\n + - #PARAM_ID_HAPTICS_VI_TUNING_DATA_4_PARAM\n + - #PARAM_ID_HAPTICS_LRA_SELECTION_PARAM\n + + All parameter IDs are device independent.\n + + Supported Input Media Format:\n +* - Data Format : FIXED_POINT\n +* - fmt_id : Don't care\n +* - Sample Rates : 48000\n +* - Number of channels : 2, 4\n +* - Channel type : 1 to 63\n +* - Bits per sample : 16 , 32 \n +* - Q format : 15 for bps = 16 and 27 for bps = 32\n +* - Interleaving : de-interleaved unpacked\n +* - Signed/unsigned : Signed } + + @h2xmlm_toolPolicy {Calibration} + + @h2xmlm_dataMaxInputPorts {HAPTICS_VI_MAX_INPUT_PORTS} + @h2xmlm_dataInputPorts {IN=2} + @h2xmlm_dataMaxOutputPorts {HAPTICS_VI_MAX_OUTPUT_PORTS} + @h2xmlm_dataOutputPorts {OUT=1} + @h2xmlm_supportedContTypes {APM_CONTAINER_TYPE_GC} + @h2xmlm_isOffloadable {false} + @h2xmlm_stackSize {HAPTICS_VI_STACK_SIZE} + @h2xmlm_ctrlDynamicPortIntent { "HAPTICS VI intent id for communicating Vsens and Isens data" = 0x0800136E, maxPorts= +1 } + @h2xmlm_ToolPolicy {Calibration} + + @{ <-- Start of the Module --> + + @h2xml_Select {"param_id_module_enable_t"} + @h2xmlm_InsertParameter + + @h2xml_Select {"rtm_logging_enable_payload_t"} + @h2xmlm_InsertParameter + */ + +/*------------------------------------------------------------------------------ + Parameters +------------------------------------------------------------------------------*/ + +/*============================================================================== + Constants +==============================================================================*/ +/* Vsens from the left speaker. */ +#define HAPTICS_VI_VSENS_LEFT_CHAN 1 + +/* Isens from the left speaker. */ +#define HAPTICS_VI_ISENS_LEFT_CHAN 2 + +/* Vsens from the right speaker. */ +#define HAPTICS_VI_VSENS_RIGHT_CHAN 3 + +/* Isens from the right speaker. */ +#define HAPTICS_VI_ISENS_RIGHT_CHAN 4 + +/*============================================================================== + Constants +==============================================================================*/ + +// Maximum output channels +#define HAPTICS_MAX_OUT_CHAN (2) + +// Maximum number of output channels +//#define HAPTICS_MAX_OUT_CHAN (HAPTICS_MAX_OUT_CHAN) + +#define MAX_SAMPLES_IN_PACKET 480 + +/*typedef enum haptics_vi_calib_state_t +{ + HAPTICS_VI_CALIB_STATE_INCORRECT_OP_MODE = 0, // returned if "operation_mode" is not "Thermal Calibration" + HAPTICS_VI_CALIB_STATE_INACTIVE = 1, // init value + HAPTICS_VI_CALIB_STATE_WARMUP = 2, // wait state for warmup + HAPTICS_VI_CALIB_STATE_INPROGRESS = 3, // in calibration state + HAPTICS_VI_CALIB_STATE_SUCCESS = 4, // calibration successful + HAPTICS_VI_CALIB_STATE_FAILED = 5, // calibration failed + HAPTICS_VI_CALIB_STATE_WAIT_FOR_VI = 6, // wait state for vi threshold + HAPTICS_VI_CALIB_STATE_VI_WAIT_TIMED_OUT = 7, // calibration could not start due to vi signals below threshold + HAPTICS_VI_CALIB_STATE_LOW_VI = 8, // calibration failed due to vi signals below threshold + HAPTICS_VI_CALIB_STATE_MAX_VAL = 0xFFFFFFFF // // max 32-bit unsigned value. tells the compiler to use 32-bit data type +} haptics_vi_calib_state_t; + +// FTM support +typedef enum haptics_th_vi_ftm_state_t +{ + HAPTICS_TH_VI_FTM_STATE_INCORRECT_OP_MODE = 0, // returned if "operation_mode" is not "Thermal FTM" + HAPTICS_TH_VI_FTM_STATE_INACTIVE = 1, // init value + HAPTICS_TH_VI_FTM_STATE_WARMUP = 2, // wait state + HAPTICS_TH_VI_FTM_STATE_INPROGRESS = 3, // in FTM state + HAPTICS_TH_VI_FTM_STATE_SUCCESS = 4, // FTM successful + HAPTICS_TH_VI_FTM_STATE_FAILED = 5, // FTM failed + HAPTICS_TH_VI_FTM_STATE_MAX_VAL = 0xFFFFFFFF // // max 32-bit unsigned value. tells the compiler to use 32-bit data type +} haptics_th_vi_ftm_state_t; + +// FTM support +typedef enum haptics_ex_vi_ftm_state_t +{ + HAPTICS_EX_VI_FTM_STATE_INCORRECT_OP_MODE = 0, // returned if "operation_mode" is not "FTM" + HAPTICS_EX_VI_FTM_STATE_INACTIVE = 1, // init value + HAPTICS_EX_VI_FTM_STATE_WARMUP = 2, // wait state + HAPTICS_EX_VI_FTM_STATE_INPROGRESS = 3, // in FTM state + HAPTICS_EX_VI_FTM_STATE_SUCCESS = 4, // FTM successful + HAPTICS_EX_VI_FTM_STATE_FAILED = 5, // FTM failed + HAPTICS_EX_VI_FTM_STATE_MAX_VAL = 0xFFFFFFFF // // max 32-bit unsigned value. tells the compiler to use 32-bit data type +} haptics_ex_vi_ftm_state_t; + +// LRA diagnostics states in normal operation mode +typedef enum haptics_th_vi_lra_cond_t +{ + HAPTICS_TH_VI_LRA_COND_OK = 0, + HAPTICS_TH_VI_LRA_COND_SHORT = 1, + HAPTICS_TH_VI_LRA_COND_OPEN = 2, + HAPTICS_TH_VI_LRA_COND_DC = 3, + HAPTICS_TH_VI_LRA_COND_MAX_VAL = 0xFFFFFFFF // // max 32-bit unsigned value. tells the compiler to use 32-bit data type +} haptics_th_vi_lra_cond_t; + +// LRA temperature status in normal operation mode +typedef enum haptics_th_vi_lra_temperature_t +{ + HAPTICS_TEMPERATURE_OK = 0, + HAPTICS_TEMPERATURE_ABOVE_MAX_LIMIT = 1, + HAPTICS_TEMPERATURE_BELOW_MIN_LIMIT = 2, + HAPTICS_TEMPERATURE_MAX_VAL = 0xFFFFFFFF // // max 32-bit unsigned value. tells the compiler to use 32-bit data type +} haptics_th_vi_lra_temperature_t;*/ + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_STATIC_CONFIG 0x080013A4 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_static_config_t param_id_haptics_vi_static_config_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_STATIC_CONFIG", + PARAM_ID_HAPTICS_VI_STATIC_CONFIG} + @h2xmlp_description {Parameter used to configure static parameters of VI processing.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_static_config_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + uint32_t sampling_rate; + /**< @h2xmle_description {Sampling rate of VI signal.} + @h2xmle_rangeList {"8kHz"=8000;"16kHz"=16000;"48kHz"=48000} + @h2xmle_default {48000} */ + uint32_t fpilot_Hz; + /**< @h2xmle_description {Pilot tone frequency, in Hz. Pilot tone frequency values MUST be the same for the RX/TH/EX modules} + @h2xmle_rangeList {"40"=40} + @h2xmle_default {40} */ + int32_t fpilot_amplitude_db; // Pilot tone amplitude [-37] -37dB. + // Note: Pilot tone amplitude values MUST be the same for the RX/TH/EX modules. + /**< @h2xmle_description {Pilot tone amplitude relative to 0 dbFS (for example, -37 dB from the full scale), in dB. Pilot tone amplitude values MUST be the same for the RX/TH/EX modules} + @h2xmle_range {-40..-30} dB + @h2xmle_default {-37} */ + int32_t smoothing_time_const_q24; + /**< @h2xmle_description {Smoothing time constant for f0 tracking parameter update. Default = 1.3, Range: 0 to 9.5} + @h2xmle_range {0..159383553} + @h2xmle_dataFormat {Q24} + @h2xmle_default {21810380} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_OP_MODE_PARAM 0x080013A5 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_op_mode_param_t param_id_haptics_vi_op_mode_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_OP_MODE_PARAM", + PARAM_ID_HAPTICS_VI_OP_MODE_PARAM} + @h2xmlp_description {Parameter used to select the operation mode of WSA smart haptics VI processing.} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_op_mode_param_t { + uint32_t th_operation_mode; // normal running or calibration + /**< @h2xmle_description {Operation mode of thermal VI module.} + @h2xmle_rangeList {"Normal Running mode"=0; + "Calibration mode"=1; + "Factory Test Mode"=2} */ + + uint32_t th_r0t0_selection_flag[HAPTICS_MAX_OUT_CHAN]; // this flag determines which set of R0, T0 values the algorithm will use + // (0: use calibrated R0, T0 value, 1: use safe R0, T0 value) + /**< @h2xmle_description {Specifies which set of R0, T0 values the algorithm will use. This field is valid only in + Normal mode (operation_mode = 0).} + @h2xmle_rangeList {"Use calibrated R0, T0 value"=0;"Use safe R0, T0 value"=1} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_EX_FTM_MODE_PARAM 0x080013A6 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_ex_FTM_mode_param_t param_id_haptics_vi_ex_FTM_mode_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_EX_FTM_MODE_PARAM", + PARAM_ID_HAPTICS_VI_EX_FTM_MODE_PARAM} + */ + +struct param_id_haptics_vi_ex_FTM_mode_param_t { + uint32_t ex_FTM_mode_enable_flag; + /**< @h2xmle_description {Factory Test Mode enablement flag. When enabled, the estimated lra parameters are averaged + and pushed out to HAL for parameter display and saving into audio.cal} + @h2xmle_rangeList {"disabled"=0; "enabled"=1} + @h2xmle_default {0} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_TH_VI_R0T0_SET_PARAM 0x080013A7 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_th_vi_r0t0_set_param_t param_id_haptics_th_vi_r0t0_set_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_TH_VI_R0T0_SET_PARAM", + PARAM_ID_HAPTICS_TH_VI_R0T0_SET_PARAM} + @h2xmlp_description {Parameter used to configure static R0T0 parameters of thermal VI processing} + @h2xmlp_toolPolicy {NO_SUPPORT}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_th_vi_r0t0_set_param_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of channels for Rx signal.} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + int32_t r0_cali_q24[HAPTICS_MAX_OUT_CHAN]; // calibration point resistance (in ohm), per device + /**< @h2xmle_description {Calibration point resistance per device (in Ohms). This field is valid only in Normal mode (operation_mode = 0). Default = 8Ohms, Range: 2 to 64Ohms} + @h2xmle_range {33554432..1073741824} + @h2xmle_default {134217728} + @h2xmle_dataFormat {Q24} */ + int32_t t0_cali_q6[HAPTICS_MAX_OUT_CHAN]; // caliberation point Temp (deg C), per device + /**< @h2xmle_description {Calibration point temperature per device (in degrees C). This field is valid in both Normal mode and Calibration mode. Default = 25 deg C, Range: -30 to 80 deg C.} + @h2xmle_range {-1920..5120} + @h2xmle_dataFormat {Q6} + @h2xmle_default {1600} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +/* TBD: + * This param is associated with EVENT_ID_HAPTICS_VI_CALIBRATION + * If there is no need of GET and SET support for this param from HLOS + * Then, there is no need to allocate param ID for this structure. + * Just having structure definition is enough */ +#define PARAM_ID_HAPTICS_VI_CALIB_PARAM 0x08001ADD + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_calib_param_t param_id_haptics_vi_calib_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_CALIB_PARAM", + PARAM_ID_HAPTICS_VI_CALIB_PARAM} + */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_calib_param_t { + uint32_t state; // Calibration/FTM state     + /**< @h2xmle_description {Calibration/FTM state} + @h2xmle_range {0...8} + @h2xmle_default {0} */ + uint32_t operation_mode; // Calibration or FTM + /**< @h2xmle_description {Operation mode in which parameters were estimated.} + @h2xmle_rangeList {"Normal mode"=0; + "Calibration mode"=1; + "Factory Test Mode"=2} */ + int32_t Re_ohm_q24[HAPTICS_MAX_OUT_CHAN]; // LRA resistance from Calibration/FTM + /**< @h2xmle_description {DC resistance of LRA coil estimated during calibration/FTM mode, in Ohms. Default = 8Ohm, Range: 2 to 128Ohms} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Fres_Hz_q20[HAPTICS_MAX_OUT_CHAN]; // Resonance frequency from Calibration/FTM + /**< @h2xmle_description {Resonance frequency of LRA estimated during calibration/FTM mode, in Hz. Default = 160Hz, Range = 50 to 400Hz} + @h2xmle_range {52428800..419430400} + @h2xmle_dataFormat {Q20} + @h2xmle_default {167772160} */ + int32_t Bl_q24[HAPTICS_MAX_OUT_CHAN]; // Force factor (Bl) from Calibration/FTM + /**< @h2xmle_description {Force factor (Bl product) estimated during calibration/FTM mode. Default = 1, Range: 0.01 to 128} + @h2xmle_range {167772..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Rms_KgSec_q24[HAPTICS_MAX_OUT_CHAN]; // Mechanical damping from Calibration/FTM + /**< @h2xmle_description {Mechanical damping of LRA, estimated during calibration/FTM mode, in kg/s. Default = 0.0945kg/s, Range = 0.0001 to 20kg/s} + @h2xmle_range {16777..335544320} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1585446} */ + int32_t Blq_ftm_q24[HAPTICS_MAX_OUT_CHAN]; // Non-linearity estimate for Bl (normalized value) from FTM + /**< @h2xmle_description {Non-linearity estimate for Bl (normalized value) estimated during FTM mode. Default = 0, Range: 0 to 1} + @h2xmle_range {0..16777216} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Le_mH_ftm_q24[HAPTICS_MAX_OUT_CHAN]; // LRA inductance from FTM + /**< @h2xmle_description {Inductance of LRA coil at room temperature estimated during FTM mode, in mH. Default = 0.04mH, Range: 0.001mH to 128mH} + @h2xmle_range {16777..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {671088} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +/* TBD: + * This param is associated with EVENT_ID_HAPTICS_VI_CALIBRATION + * If there is no need of GET and SET support for this param from HLOS + * Then, there is no need to allocate param ID for this structure. + * Just having structure definition is enough */ +#define PARAM_ID_HAPTICS_VI_CALIB_PARAM_V2 0x08001B24 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_calib_param_v2_t param_id_haptics_vi_calib_param_v2_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_CALIB_PARAM_V2", + PARAM_ID_HAPTICS_VI_CALIB_PARAM_V2} + */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_calib_param_v2_t { + uint32_t state; // Calibration/FTM state     + /**< @h2xmle_description {Calibration/FTM state} + @h2xmle_range {0...8} + @h2xmle_default {0} */ + uint32_t operation_mode; // Calibration or FTM + /**< @h2xmle_description {Operation mode in which parameters were estimated.} + @h2xmle_rangeList {"Normal mode"=0; + "Calibration mode"=1; + "Factory Test Mode"=2} */ + int32_t Re_ohm_q24[HAPTICS_MAX_OUT_CHAN]; // LRA resistance from Calibration/FTM + /**< @h2xmle_description {DC resistance of LRA coil estimated during calibration/FTM mode, in Ohms. Default = 8Ohm, Range: 2 to 128Ohms} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Fres_Hz_q20[HAPTICS_MAX_OUT_CHAN]; // Resonance frequency from Calibration/FTM + /**< @h2xmle_description {Resonance frequency of LRA estimated during calibration/FTM mode, in Hz. Default = 160Hz, Range = 50 to 400Hz} + @h2xmle_range {52428800..419430400} + @h2xmle_dataFormat {Q20} + @h2xmle_default {167772160} */ + int32_t Bl_q24[HAPTICS_MAX_OUT_CHAN]; // Force factor (Bl) from Calibration/FTM + /**< @h2xmle_description {Force factor (Bl product) estimated during calibration/FTM mode. Default = 1, Range: 0.01 to 128} + @h2xmle_range {167772..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Rms_KgSec_q24[HAPTICS_MAX_OUT_CHAN]; // Mechanical damping from Calibration/FTM + /**< @h2xmle_description {Mechanical damping of LRA, estimated during calibration/FTM mode, in kg/s. Default = 0.0945kg/s, Range = 0.0001 to 20kg/s} + @h2xmle_range {16777..335544320} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1585446} */ + int32_t Blq_ftm_q24[HAPTICS_MAX_OUT_CHAN]; // Non-linearity estimate for Bl (normalized value) from FTM + /**< @h2xmle_description {Non-linearity estimate for Bl (normalized value) estimated during FTM mode. Default = 0, Range: 0 to 1} + @h2xmle_range {0..16777216} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Le_mH_ftm_q24[HAPTICS_MAX_OUT_CHAN]; // LRA inductance from FTM + /**< @h2xmle_description {Inductance of LRA coil at room temperature estimated during FTM mode, in mH. Default = 0.04mH, Range: 0.001mH to 128mH} + @h2xmle_range {16777..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {671088} */ + int32_t Fres_offset_Hz_q20[HAPTICS_MAX_OUT_CHAN]; // F0 offset from duffing non linerity + /**< @h2xmle_description {F0 offset from duffing non linerity (in Hz). Default = 0, Range: 0 to 100} + @h2xmle_range {0..0x64} + @h2xmle_dataFormat {Q20} + @h2xmle_default {0} */ + int32_t Tuned_LRA_ID[HAPTICS_MAX_OUT_CHAN]; // ID of LRA selected during FTM + /**< @h2xmle_description {ID of LRA selected during FTM. Default = 0, Range: 0 to 4} + @h2xmle_range {0..4} + @h2xmle_default {0} */ + uint32_t payload_size; // Custom payload size in bytes, returned from FTM. + /**< @h2xmle_description {Custom payload size in bytes, returned from FTM.} + @h2xmle_range {0...10240} + @h2xmle_default {0} */ +#ifdef __H2XML__ + uint8_t payload_data[0]; + /**< @h2xmle_description {Custom payload data, returned from FTM.} + @h2xmle_variableArraySize {payload_size} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants + ==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_FTM_CFG 0x08001B1D + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_ftm_cfg_t param_id_haptics_vi_ftm_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_FTM_CFG", + PARAM_ID_HAPTICS_VI_FTM_CFG} + @h2xmlp_description {Parameter to set FTM configuration} + @h2xmlp_toolPolicy {CALIBRATION} */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_vi_ftm_cfg_t { + uint32_t non_linearity_compensation; // Enable/Disable duffing non linearity compensation + /**< @h2xmle_description {Enable/Disable duffing non linearity compensation} + @h2xmle_rangeList {"Disabled"=0; + "Enabled"=1}*/ + int32_t ftm_amplitude_q24[HAPTICS_MAX_OUT_CHAN]; // FTM playback amplitude level in Volts + /**< @h2xmle_description {FTM playback amplitude level in Volts} + @h2xmle_range {0..0x7FFFFFFF} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t f0_tracking_duration_ms[HAPTICS_MAX_OUT_CHAN]; // f0 tracking duration in ms + /**< @h2xmle_description {FTM f0 tracking duration in ms} + @h2xmle_range {0..1000} + @h2xmle_default {250} */ + int32_t f0_duffing_duration_ms[HAPTICS_MAX_OUT_CHAN]; // FTM f0 tracking non linearity compensation max duration in ms + /**< @h2xmle_description {FTM f0 tracking non linearity compensation max duration in ms} + @h2xmle_range {0..8000} + @h2xmle_default {6000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_TH_VI_R0_GET_PARAM 0x080013A8 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_th_vi_r0_get_param_t param_id_haptics_th_vi_r0_get_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_TH_VI_R0_GET_PARAM", + PARAM_ID_HAPTICS_TH_VI_R0_GET_PARAM} + */ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_th_vi_r0_get_param_t { + uint32_t state; // calibration state + /**< @h2xmle_description {Calibration state} + @h2xmle_range {0...8} */ + int32_t r0_cali_q24[HAPTICS_MAX_OUT_CHAN]; // calibration point resistance (in ohm), per device + /**< @h2xmle_description {Calibration point resistance per device (in Ohms). Default = 8Ohms, Range: 2 to 64Ohms} + @h2xmle_range {33554432..1073741824} + @h2xmle_default {134217728} + @h2xmle_dataFormat {Q24} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_TH_VI_DYNAMIC_PARAM 0x080013A9 + +/*============================================================================== + Type definitions +==============================================================================*/ + +// Structure encapsulating LRA parameters for Thermal VI module +typedef struct wsa_haptics_th_lra_param_t wsa_haptics_th_lra_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ + +struct wsa_haptics_th_lra_param_t +{ + int32_t r0_safe_q24; // backup calibration point resistance (ohm), when per device calibration is not available + /**< @h2xmle_description {backup calibration point resistance when per-device calibration is not available (in + Ohms.) Default = 8Ohms, Range: 2 to 64Ohms} + @h2xmle_range {33554432..1073741824} + @h2xmle_default {134217728} + @h2xmle_dataFormat {Q24} */ + int32_t t0_safe_q6; // backup caliberation point Temp (deg C), when per device calibration is not available + /**< @h2xmle_description {backup calibration point temperature when per-device calibration is not available (in + degrees C). Default = 25 deg C, Range: -30 to 80 deg C.} + @h2xmle_range {-1920..5120} + @h2xmle_dataFormat {Q6} + @h2xmle_default {1600} */ + int16_t amp_gain_q10; // LRA peak voltage for digitially full scale signal + /**< @h2xmle_description {voltage for digitally full scale signal. Default = 10, Range: 0 to 32} + @h2xmle_range {0..32767} + @h2xmle_dataFormat {Q10} + @h2xmle_default {10240} */ + uint16_t lra_resistivity_coeff_u16q7; // resistivity coeff (1/deg C) + /**< @h2xmle_description {one over temperature coeffcient alpha in 1/deg C. Default = 254.45, Range: 0 to 511.99} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q7} + @h2xmle_default {32570} */ + uint16_t vsen_2_v_u16q11; // conversion factor from Vsen digital to Volt + /**< @h2xmle_description {conversion factor from Vsens digital to Volts. Default = 10.48, Range: 0 to 31.99} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q11} + @h2xmle_default {21466} */ + uint16_t isen_2_a_u16q11; // conversion factor from Isen digital to Amp + /**< @h2xmle_description {conversion factor from Isens digital to Amps. Default = 6.90, Range: 0 to 31.99} + @h2xmle_range {0..65535} + @h2xmle_dataFormat {Q11} + @h2xmle_default {14143} */ + int32_t trace_resistance_tx_q24; + /**< @h2xmle_description {trace resistance from LRA to Vsens tap points in Ohm. Default = 0, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Re_ohm_q24; + /**< @h2xmle_description {DC resistance of LRA coil at room temperature, in Ohms. Default = 8Ohms, Range: 2 to 128Ohms} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t r_lra_coil_factor_q10; + /**< @h2xmle_description {factor used to determine the threshold + for LRA coil resistance (max threshold for LRA + coil resistance = factor * LRA coil resistance and min threshold = LRA coil resistance/ factor). Default = 2, Range: 1 to 8} + @h2xmle_range {1024..8192} + @h2xmle_dataFormat {Q10} + @h2xmle_default {2048} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure encapsulating LRA parameters for R0T0 calibration*/ +typedef struct wsa_haptics_r0t0_cali_param_t wsa_haptics_r0t0_cali_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ + +struct wsa_haptics_r0t0_cali_param_t +{ + int32_t wait_time_ms; // wait time for initial settling before collecting statistic (ms) + /**< @h2xmle_description {wait time for initial settling before + collecting statistics (in milli seconds).} + @h2xmle_range {100..5000} + @h2xmle_default {200} */ + int32_t cali_time_ms; // calibration time (ms) + /**< @h2xmle_description {calibration time (in milli seconds).} + @h2xmle_range {500..30000} + @h2xmle_default {2000} */ + int32_t vi_wait_time_ms; // wait time to check if VI are above threshold levels + /**< @h2xmle_description {wait time for vi (in milli seconds).} + @h2xmle_range {100..30000} + @h2xmle_default {2000} */ + int16_t r0_rng_fac_q10; + /**< @h2xmle_description {If the calibrated R0 is greater than range factor times the typical value, or less than the typical value divided by the range factor, calibration failed will be called. Default = 1.5, Range: 1 to 8} + @h2xmle_range {1024..8192} + @h2xmle_dataFormat {Q10} + @h2xmle_default {1536} */ + int16_t t0_min_q6; // min expected temperature from calibration (deg C) + /**< @h2xmle_description {minimum expected temperature from + calibration (in degrees C). Default = 0 deg C, Range: -30 to 80 deg C} + @h2xmle_range {-1920..5120} + @h2xmle_dataFormat {Q6} + @h2xmle_default {0} */ + int16_t t0_max_q6; // max expected temperature from calibration (deg C) + /**< @h2xmle_description {maximum expected temperature from + calibration (in degrees C). Default = 50 deg C, Range: -30 to 80 deg C} + @h2xmle_range {-1920..5120} + @h2xmle_dataFormat {Q6} + @h2xmle_default {3200} */ + uint16_t reserved; +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_th_vi_dynamic_param_t param_id_haptics_th_vi_dynamic_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_TH_VI_DYNAMIC_PARAM", + PARAM_ID_HAPTICS_TH_VI_DYNAMIC_PARAM} + @h2xmlp_description {Parameter used to configure dynamic thermal parameters for WSA smart haptics VI processing.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_th_vi_dynamic_param_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + int32_t temp_min_q6; + /**< @h2xmle_description {Minimum reasonable measured temperature (in degree C). Default = -30 deg C, Range: -30 to 200 deg C} + @h2xmle_range {-1920..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {-1920} */ + int32_t temp_max_q6; + /**< @h2xmle_description {Maximum reasonable measured temperature (in degree C). Default = 200 deg C, Range: -30 to 80 deg C} + @h2xmle_range {-1920..12800} + @h2xmle_dataFormat {Q6} + @h2xmle_default {12800} */ +#ifdef __H2XML__ + wsa_haptics_th_lra_param_t wsa_haptics_th_lra_param[0]; + /**< @h2xmle_description {Structure encapsulating LRA parameters for Thermal VI module.} + @h2xmle_variableArraySize {num_channels} */ + wsa_haptics_r0t0_cali_param_t wsa_haptics_r0t0_cali_param[0]; + /**< @h2xmle_description {Structure encapsulating LRA parameters for R0T0 calibration.} + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_TH_VI_FTM_SET_CFG 0x080013AA + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_th_vi_ftm_set_cfg param_id_haptics_th_vi_ftm_set_cfg; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_TH_VI_FTM_SET_CFG", + PARAM_ID_HAPTICS_TH_VI_FTM_SET_CFG} + @h2xmlp_description {Parameter used to set the FTM configuration in the WSA smart haptics thermal VI processing module.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_th_vi_ftm_set_cfg { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + int32_t wait_time_ms[HAPTICS_MAX_OUT_CHAN]; // wait time before collecting statistics for ftm mode (ms) + /**< @h2xmle_description {wait time before collecting statistics for ftm mode (ms)} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {2000} */ + int32_t ftm_time_ms[HAPTICS_MAX_OUT_CHAN]; // duration that ftm packets will be averaged + /**< @h2xmle_description {duration that ftm packets will be averaged, in ms} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {2000} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_TH_VI_FTM_GET_PARAM 0x080013AB + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_th_vi_ftm_get_param_t param_id_haptics_th_vi_ftm_get_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_TH_VI_FTM_GET_PARAM", + PARAM_ID_HAPTICS_TH_VI_FTM_GET_PARAM} + @h2xmlp_description {Thermal VI FTM mode parameters returned from WSA Smart haptics thermal FTM mode} + @h2xmlp_toolPolicy {RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_th_vi_ftm_get_param_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + int32_t ftm_rDC_q24[HAPTICS_MAX_OUT_CHAN]; // rDC value in q24 + /**< @h2xmle_description {resistance in ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_temp_q22[HAPTICS_MAX_OUT_CHAN]; // temperature value in q22 + /**< @h2xmle_description {temperature in degree C} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q22} + @h2xmle_default {0} */ + uint32_t status[HAPTICS_MAX_OUT_CHAN]; // wait, in progress or success + /**< @h2xmle_description {wait, in progress or success} + @h2xmle_range {0..5} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_VI_DYNAMIC_PARAM 0x080013AC + +/*============================================================================== + Type definitions +==============================================================================*/ + +// Structure encapsulating LRA parameters for VI excursion module +typedef struct wsa_haptics_ex_lra_param_t wsa_haptics_ex_lra_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ + +struct wsa_haptics_ex_lra_param_t +{ + int32_t Re_ohm_q24; + /**< @h2xmle_description {DC resistance of LRA coil at room temperature, in Ohms. Default = 8Ohm, Range: 2 to 128Ohms} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Le_mH_q24; + /**< @h2xmle_description {Inductance of LRA coil at room temperature, in mH. Default = 0.04mH, Range: 0.001mH to 128mH} + @h2xmle_range {16777..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {671088} */ + int32_t Bl_q24; + /**< @h2xmle_description {Force factor (Bl product). Default = 1, Range: 0.01 to 128} + @h2xmle_range {167772..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Mms_gram_q24; + /**< @h2xmle_description {Mass of LRA moving mass, in grams. Default = 1g, Range: 0.05 to 128g} + @h2xmle_range {838860..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Rms_KgSec_q24; + /**< @h2xmle_description {Mechanical damping or resistance of LRA, in kg/s. Default = 0.0945kg/s, Range = 0.0001 to 20kg/s} + @h2xmle_range {16777..335544320} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1585446} */ + int32_t Kms_Nmm_q24; + /**< @h2xmle_description {Mechanical stiffness of driver suspension, in N/mm. Default = 1.838N/mm, Range = 0.1 to 50N/mm} + @h2xmle_range {1677721..838860800} + @h2xmle_dataFormat {Q24} + @h2xmle_default {30836523} */ + int32_t Fres_Hz_q20; + /**< @h2xmle_description {Resonance frequency, in Hz. Default = 160Hz, Range = 50 to 400Hz} + @h2xmle_range {52428800..419430400} + @h2xmle_dataFormat {Q20} + @h2xmle_default {167772160} */ + int32_t amp_gain_q24; + /**< @h2xmle_description {LRA peak voltage for a digitally full-scale signal. Default = 10, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {167772160} */ + int32_t vsens_scale_q24; // Vsense scaling constant + /**< @h2xmle_description {conversion factor from Vsens digital to Volts. Default = 10.48, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {175849472} */ + int32_t isens_scale_q24; // Isense scaling constant + /**< @h2xmle_description {conversion factor from Isens digital to Amperes. Default = 6.90, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {115859456} */ + int32_t trace_resistance_tx_q24; + /**< @h2xmle_description {trace resistance from LRA to Vsens tap points in Ohm. Default = 0Ohm, Range: 0 to 128Ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t trace_resistance_rx_q24; + /**< @h2xmle_description {trace resistance from amp output to LRA in Ohm. Default = 0Ohm, Range: 0 to 128Ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t Min_Bl_q24; + /**< @h2xmle_description {Force factor (Bl product) - Min limit. Default = 0.01, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {167772} */ + int32_t Max_Bl_q24; + /**< @h2xmle_description {Force factor (Bl product) - Max limit. Default = 10, Range: 0 to 128} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {167772160} */ + int32_t Min_Rms_KgSec_q24; + /**< @h2xmle_description {Mechanical damping or resistance of LRA in Kg/sec - Min limit. Default = 0.001Kg/sec, Range: 0 to 128Kg/sec} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777} */ + int32_t Max_Rms_KgSec_q24; + /**< @h2xmle_description {Mechanical damping or resistance of LRA in Kg/sec - Max limit. Default = 20Kg/sec, Range: 0 to 128Kg/sec} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {335544320} */ + int32_t Min_Kms_Nmm_q24; + /**< @h2xmle_description {Mechanical stiffness of driver suspension in N/mm - Min limit. Default = 0.1N/mm, Range: 0 to 128N/mm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1677721} */ + int32_t Max_Kms_Nmm_q24; + /**< @h2xmle_description {Mechanical stiffness of driver suspension in N/mm - Max limit. Default = 50N/mm, Range: 0 to 128N/mm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {838860800} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_vi_dynamic_param_t param_id_haptics_ex_vi_dynamic_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_VI_DYNAMIC_PARAM", + PARAM_ID_HAPTICS_EX_VI_DYNAMIC_PARAM} + @h2xmlp_description {Parameter used to configure the dynamic parameters of excursion VI processing.} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_vi_dynamic_param_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ +#ifdef __H2XML__ + wsa_haptics_ex_lra_param_t wsa_haptics_ex_lra_param[0]; + /**< @h2xmle_description {Structure encapsulating LRA parameters for VI excursion module} + @h2xmle_variableArraySize {num_channels} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_VI_PERSISTENT 0x080013AD + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_vi_persistent param_id_haptics_ex_vi_persistent; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_VI_PERSISTENT", + PARAM_ID_HAPTICS_EX_VI_PERSISTENT} + @h2xmlp_description {Excursion VI persistent parameters} + @h2xmlp_toolPolicy {RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_vi_persistent { + int32_t Re_ohm_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {DC resistance of LRA coil at room temperature, in Ohms. Default = 8Ohm, Range: 2 to 128Ohms} + @h2xmle_range {33554432..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {134217728} */ + int32_t Le_mH_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Inductance of LRA coil at room temperature, in mH. Default = 0.04mH, Range: 0.001mH to 128mH} + @h2xmle_range {16777..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {671088} */ + int32_t Bl_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Force factor (Bl product). Default = 1, Range: 0.01 to 128} + @h2xmle_range {167772..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {16777216} */ + int32_t Rms_KgSec_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Mechanical damping or resistance of LRA, in kg/s. Default = 0.0945kg/s, Range = 0.0001 to 20kg/s} + @h2xmle_range {16777..335544320} + @h2xmle_dataFormat {Q24} + @h2xmle_default {1585446} */ + int32_t Kms_Nmm_q24[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Mechanical stiffness of driver suspension, in N/mm. Default = 1.838N/mm, Range = 0.1 to 50N/mm} + @h2xmle_range {1677721..838860800} + @h2xmle_dataFormat {Q24} + @h2xmle_default {30836523} */ + int32_t Fres_Hz_q20[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {Resonance frequency, in Hz. Default = 160Hz, Range = 50 to 400Hz} + @h2xmle_range {52428800..419430400} + @h2xmle_dataFormat {Q20} + @h2xmle_default {167772160} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_VI_FTM_SET_CFG 0x080013AE + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_vi_ftm_set_cfg param_id_haptics_ex_vi_ftm_set_cfg; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_VI_FTM_SET_CFG", + PARAM_ID_HAPTICS_EX_VI_FTM_SET_CFG} + @h2xmlp_description {Excursion VI FTM mode parameters} + @h2xmlp_toolPolicy {CALIBRATION;RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_vi_ftm_set_cfg { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + int32_t wait_time_ms[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {wait time before collecting statistics for ftm mode, in ms} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {2000} */ + int32_t ftm_time_ms[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {duration that ftm packets will be averaged, in ms} + @h2xmle_range {100..5000} + @h2xmle_dataFormat {Q0} + @h2xmle_default {1000} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_VI_FTM_GET 0x080013AF + +/*============================================================================== + Type definitions +==============================================================================*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +/** @h2xmlp_subStruct */ + +typedef struct wsa_ex_vi_ftm_get_param_t wsa_ex_vi_ftm_get_param_t; + +struct wsa_ex_vi_ftm_get_param_t { + int32_t ftm_Re_q24; + /**< @h2xmle_description {ftm resitance in ohm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_Bl_q24; + /**< @h2xmle_description {force factor (Bl_product)} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_Rms_q24; + /**< @h2xmle_description {resitance due to mechanical damping, Kg/sec} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_Kms_q24; + /**< @h2xmle_description {suspension stiffness, in N/mm} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t ftm_Fres_q20; + /**< @h2xmle_description {resonant frequency in Hz} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q20} + @h2xmle_default {0} */ + uint32_t status; // FTM packet status + /**< @h2xmle_description {FTM packet status} + @h2xmle_range {0...5} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_vi_ftm_get param_id_haptics_ex_vi_ftm_get; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_VI_FTM_GET", + PARAM_ID_HAPTICS_EX_VI_FTM_GET} + @h2xmlp_description {Excursion VI FTM mode parameters returned from WSA Smart haptics excursion FTM mode} + @h2xmlp_toolPolicy {RTC_READONLY}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_vi_ftm_get { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ +#ifdef __H2XML__ + wsa_ex_vi_ftm_get_param_t wsa_ex_vi_ftm_get_param[0]; + /**< @h2xmle_description {structure containing LRA params for FTM } + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_LRA_DIAG_GETPKT_PARAM 0x080013B0 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_lra_diag_getpkt_param_t param_id_haptics_lra_diag_getpkt_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_LRA_DIAG_GETPKT_PARAM", + PARAM_ID_HAPTICS_LRA_DIAG_GETPKT_PARAM} + @h2xmlp_description {Parameter used to get general LRA diagnostics like whether LRA is open, or close or if DC is flowing through it.} + @h2xmlp_toolPolicy {RTC_READONLY}*/ +// General LRA Diagnostics + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_lra_diag_getpkt_param_t { + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ + uint32_t lra_cond[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {reflects LRA general diagnostics - OK, Short, Open, DC} + @h2xmle_range {0...3} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ + uint32_t temperature_status[HAPTICS_MAX_OUT_CHAN]; + /**< @h2xmle_description {reflects LRA temperature status - OK, above max limit, below min limit} + @h2xmle_range {0...2} + @h2xmle_dataFormat {Q0} + @h2xmle_default {0} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_EX_VI_DEMO_PKT_PARAM 0x080013B1 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_ex_vi_demo_pkt_param_t param_id_haptics_ex_vi_demo_pkt_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_EX_VI_DEMO_PKT_PARAM", + PARAM_ID_HAPTICS_EX_VI_DEMO_PKT_PARAM} + @h2xmlp_description {Parameter used to get general LRA diagnostics like whether LRA is open, or close or if DC is flowing through it.} + @h2xmlp_toolPolicy {RTC_READONLY}*/ +// General LRA Diagnostics + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_ex_vi_demo_pkt_param_t +{ + uint32_t num_channels; + /**< @h2xmle_description {Number of LRA channels} + @h2xmle_rangeList {"1"=1;"2"=2} + @h2xmle_default {1} */ +#ifdef __H2XML__ + int32_t xpred_from_vsens[0][MAX_SAMPLES_IN_PACKET]; + /**< @h2xmle_description {structure containing LRA params for excursion prediction } + @h2xmle_variableArraySize {num_channels} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_FTM_DATA_PARAM 0x08001ADC + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_ftm_data_param_t param_id_haptics_vi_ftm_data_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_FTM_DATA_PARAM", PARAM_ID_HAPTICS_VI_FTM_DATA_PARAM} + @h2xmlp_description {Parameter for registering haptics ftm data to lib.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_ftm_data_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for FTM data file} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of ftm data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the FTM data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00000064} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics FTM data: The path to the FTM cal file} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_CALIB_DATA_PARAM 0x08001ADB + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_calib_data_param_t param_id_haptics_vi_calib_data_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_CALIB_DATA_PARAM", PARAM_ID_HAPTICS_VI_CALIB_DATA_PARAM} + @h2xmlp_description {Parameter for registering haptics calibration data to lib.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_calib_data_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for Calibration data file} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of calibration data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the calibration data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00000064} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {Haptics calibration data: The path to the calibration cal file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_CHANNEL_MAP_CFG 0x080013BE + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_channel_map_cfg_t param_id_haptics_vi_channel_map_cfg_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_CHANNEL_MAP_CFG", + PARAM_ID_HAPTICS_VI_CHANNEL_MAP_CFG} + @h2xmlp_description {parameter used to set the input channel mapping for Vsens and Isens + for the Haptics VI module.} + @h2xmlp_toolPolicy {CALIBRATION, RTC_READONLY} */ +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +struct param_id_haptics_vi_channel_map_cfg_t +{ + uint32_t num_ch; + /**< @h2xmle_description {Number of channels for Tx signal.} + @h2xmle_rangeList {"Two" = 2; "Four" = 4} + @h2xmle_default {2} */ + + int32_t chan_info[0]; + /**< @h2xmle_description {Channel mapping array that provides information + on the order in which the Vsens and Isens of + different LRA come into a Tx port. + - HAPTICS_VI_VSENS_LEFT_CHAN(1) + - HAPTICS_VI_ISENS_LEFT_CHAN(2) + - HAPTICS_VI_VSENS_RIGHT_CHAN(3) + - HAPTICS_VI_ISENS_RIGHT_CHAN(4) + Some possible configurations are (1,2,3,4), (4,2,1,3), + (1,2,0,0),(4,3,0,0), and (2,1,0,0). + All channels must be unique. The order does not matter + as long as the channels are valid. + If only two channels are sent (V and I), they must be + first two channels: Eg: (4,3), (1,2), etc.} + @h2xmle_variableArraySize {num_ch} */ +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_TUNING_DATA_0_PARAM 0x08001B1E + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_tuning_data_0_param_t param_id_haptics_vi_tuning_data_0_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_TUNING_DATA_0_PARAM", PARAM_ID_HAPTICS_VI_TUNING_DATA_0_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 0 to VI module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_tuning_data_0_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for VI module tuning data file for LRA 0} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of VI module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the VI module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {VI module tuning data for LRA 0: path to the VI module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_TUNING_DATA_1_PARAM 0x08001B1F + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_tuning_data_1_param_t param_id_haptics_vi_tuning_data_1_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_TUNING_DATA_1_PARAM", PARAM_ID_HAPTICS_VI_TUNING_DATA_1_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 1 to VI module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_tuning_data_1_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for VI module tuning data file for LRA 1} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of VI module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the VI module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {VI module tuning data for LRA 1: path to the VI module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_TUNING_DATA_2_PARAM 0x08001B20 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_tuning_data_2_param_t param_id_haptics_vi_tuning_data_2_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_TUNING_DATA_2_PARAM", PARAM_ID_HAPTICS_VI_TUNING_DATA_2_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 2 to VI module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_tuning_data_2_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for VI module tuning data file for LRA 2} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of VI module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the VI module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {VI module tuning data for LRA 2: path to the VI module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_TUNING_DATA_3_PARAM 0x08001B21 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_tuning_data_3_param_t param_id_haptics_vi_tuning_data_3_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_TUNING_DATA_3_PARAM", PARAM_ID_HAPTICS_VI_TUNING_DATA_3_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 3 to VI module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_tuning_data_3_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for VI module tuning data file for LRA 3} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of VI module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the VI module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {VI module tuning data for LRA 3: path to the VI module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_VI_TUNING_DATA_4_PARAM 0x08001B22 + +/*============================================================================== + Type definitions +==============================================================================*/ + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_vi_tuning_data_4_param_t param_id_haptics_vi_tuning_data_4_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_VI_TUNING_DATA_4_PARAM", PARAM_ID_HAPTICS_VI_TUNING_DATA_4_PARAM} + @h2xmlp_description {Parameter for registering tuning data for LRA source 4 to VI module.} + @h2xmlp_toolPolicy {CALIBRATION} + @h2xmlp_isOffloaded {TRUE} + @h2xmlp_persistType {Shared}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_vi_tuning_data_4_param_t { + uint32_t alignment; + /**< @h2xmle_description {Data Alignment required for VI module tuning data file for LRA 4} + @h2xmle_default {4} + @h2xmle_range {0..4} */ + uint32_t offset; + /**< @h2xmle_description {Data offset (bytes) to align the start address of VI module tuning data file by alignment} + @h2xmle_default {0} + @h2xmle_range {0..3} */ + uint32_t size; + /**< @h2xmle_description {Length of the VI module tuning data file in bytes.} + @h2xmle_default {0} + @h2xmle_range {0x0..0x00002710} */ +#ifdef __H2XML__ + uint8_t data[0]; + /**< @h2xmle_description {VI module tuning data for LRA 4: path to the VI module tuning binary file.} + @h2xmle_elementType {rawData} + @h2xmle_displayType {stringField} */ +#endif +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/*============================================================================== + Constants +==============================================================================*/ + +/* Unique Paramter id */ +#define PARAM_ID_HAPTICS_LRA_SELECTION_PARAM 0x08001B23 + +/*============================================================================== + Type definitions +==============================================================================*/ + +// Structure encapsulating min and max range for LRAs from multiple sources +typedef struct haptics_lra_selection_range_param_t haptics_lra_selection_range_param_t; + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" +/** @h2xmlp_subStruct */ + +struct haptics_lra_selection_range_param_t +{ + int32_t min_value; + /**< @h2xmle_description {Min valid selection parameter value for selected source (including min_value)} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {0} */ + int32_t max_value; + /**< @h2xmle_description {Max valid selection parameter value for selected source (excluding max_value)} + @h2xmle_range {0..2147483647} + @h2xmle_dataFormat {Q24} + @h2xmle_default {2147483647} */ +} + +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +/* Structure definition for Parameter */ +typedef struct param_id_haptics_lra_selection_param_t param_id_haptics_lra_selection_param_t; + +/** @h2xmlp_parameter {"PARAM_ID_HAPTICS_LRA_SELECTION_PARAM", + PARAM_ID_HAPTICS_LRA_SELECTION_PARAM} + @h2xmlp_description {Parameter defining differentiation criteria for LRAs from multiple sources.} + @h2xmlp_toolPolicy {CALIBRATION}*/ + +#include "spf_begin_pack.h" +#include "spf_begin_pragma.h" + +struct param_id_haptics_lra_selection_param_t { + uint32_t num_lra_sources; + /**< @h2xmle_description {Number of LRA sources} + @h2xmle_rangeList {"1"=1;"2"=2;"3"=3;"4"=4;"5"=5} + @h2xmle_default {1} */ + uint32_t lra_selection_criteria; + /**< @h2xmle_description {Parameter used to differentiate the LRAs from different sources} + @h2xmle_rangeList {"LRA DC Resisistance"=0;"LRA Coil Inductance"=1} + @h2xmle_default {0} */ +#ifdef __H2XML__ + haptics_lra_selection_range_param_t lra_selection_range[0]; + /**< @h2xmle_description {Selection parameter range for selected source} + @h2xmle_variableArraySize {num_lra_sources} */ +#endif +} +#include "spf_end_pragma.h" +#include "spf_end_pack.h" +; + +#define EVENT_ID_HAPTICS_VI_CALIBRATION 0x080013B4 +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_HAPTICS_VI_CALIBRATION", + EVENT_ID_HAPTICS_VI_CALIBRATION} + @h2xmlp_description { VI calibration event raised by the Haptics Protection Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + +#define EVENT_ID_HAPTICS_LRA_DIAGNOSTICS 0x080013B3 +/*============================================================================== + Type definitions +==============================================================================*/ + +/** @h2xmlp_parameter {"EVENT_ID_HAPTICS_LRA_DIAGNOSTICS", + EVENT_ID_HAPTICS_LRA_DIAGNOSTICS} + @h2xmlp_description { if change in lra diagnostics state and temperature status, + event will be raised by the Haptics Protection Module.} + @h2xmlp_toolPolicy { NO_SUPPORT}*/ + + +/** @} <-- End of the Module --> */ + +#endif /* __WSA_HAPTICS_VI_API_H__ */ diff --git a/spf/api/vcpm/vcpm_api.h b/spf/api/vcpm/vcpm_api.h new file mode 100644 index 0000000..2954b54 --- /dev/null +++ b/spf/api/vcpm/vcpm_api.h @@ -0,0 +1,1360 @@ +#ifndef _VCPM_API_H_ +#define _VCPM_API_H_ +/** + * \file vcpm_api.h + + \brief + * This file contains Voice Call Proxy Manager Commands and Data Structures + * + * \copyright + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ar_defs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*__cplusplus*/ + +/*------------------------------------------------------------------------------ + * Module ID Definitions + *----------------------------------------------------------------------------*/ + +/** @ingroup spf_vpcm_voice_cfg + Instance identifier for the VCPM static module. */ +#define VCPM_MODULE_INSTANCE_ID ( 0x00000004 ) + +/* Instance identifier for the Voice Services static module. */ +#define VOICE_SERVICES_MODULE_INSTANCE_ID ( 0x00000005 ) + +/* TTY mode values. */ + +/** @ingroup spf_vpcm_tty + TTY is Off or disabled. */ +#define VOICE_TTY_MODE_OFF 0 + +/** @ingroup spf_vpcm_tty + Hearing Carry Over mode. */ +#define VOICE_TTY_MODE_HCO 1 + +/** @ingroup spf_vpcm_tty + Voice Carry Over mode. */ +#define VOICE_TTY_MODE_VCO 2 + +/** @ingroup spf_vpcm_tty + HCO mode plus VCO mode. */ +#define VOICE_TTY_MODE_FULL 3 + + +/** @ingroup spf_vpcm_tty + Identifier for the parameter that sets the TTY mode of operation. + + @msgpayload + vcpm_param_id_tty_mode_t + */ +#define VCPM_PARAM_ID_TTY_MODE 0x080011E4 + +/*# @h2xmlp_parameter {"VCPM_PARAM_ID_TTY_MODE", VCPM_PARAM_ID_TTY_MODE} + @h2xmlp_description {ID for the parameter that sets the TTY mode of + operation.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/** @ingroup spf_vpcm_tty + Payload for #VCPM_PARAM_ID_TTY_MODE. + */ +#include "spf_begin_pack.h" +struct vcpm_param_id_tty_mode_t +{ + uint32_t vsid; + /**< Voice System identifier for TTY mode. */ + + /*#< @h2xmle_description {Voice System ID for TTY mode.} + @h2xmle_rangeList {"VSID_SUB1"=0x11C05000, + "VSID_SUB2"=0x11DC5000, + "VSID_LB_SUB1"=0x12006000, + "VSID_LB_SUB2"=0x121C6000} */ + + uint32_t mode; + /**< TTY mode to be set. + + @valuesbul + - #VOICE_TTY_MODE_OFF + - #VOICE_TTY_MODE_HCO + - #VOICE_TTY_MODE_VCO + - #VOICE_TTY_MODE_FULL @tablebulletend @newpagetable */ + + /*#< @h2xmle_description {TTY mode to be set.} + @h2xmle_rangeList {"VOICE_TTY_MODE_OFF"=VOICE_TTY_MODE_OFF, + "VOICE_TTY_MODE_HCO"=VOICE_TTY_MODE_HCO, + "VOICE_TTY_MODE_VCO"=VOICE_TTY_MODE_VCO, + "VOICE_TTY_MODE_FULL"=VOICE_TTY_MODE_FULL} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_id_tty_mode_t vcpm_param_id_tty_mode_t; + + +/** @ingroup spf_vpcm_voice_cfg + Identifier for the parameter that contains instance IDs of specific modules + in a stream subgraph that is part of a voice call use case graph + (applications processor). + + The HLOS sets this parameter to the VCPM instance ID when the graph is + opened. + + @msgpayload + vcpm_param_voice_config_payload_t \n + @indent{12pt} vcpm_cfg_subgraph_properties_t \n + @indent{12pt} vcpm_property_config_struct_t + */ +#define VCPM_PARAM_ID_VOICE_CONFIG 0x08001162 + + +/** @ingroup spf_vpcm_tty + Payload for #VCPM_PARAM_ID_VOICE_CONFIG. + + Immediately following this structure is an array of structures of type + %vcpm_cfg_subgraph_properties_t. The length of the array is equal to + num_voice_subgraph_info_objects. +*/ +#include "spf_begin_pack.h" +struct vcpm_param_voice_config_payload_t +{ + uint32_t num_sub_graphs; + /**< Number of %vcpm_cfg_subgraph_properties_t structures and payloads that + immediately follow this structure. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_voice_config_payload_t vcpm_param_voice_config_payload_t; + + +/** @ingroup spf_vpcm_voice_cfg + Payload for #VCPM_PARAM_ID_VOICE_CONFIG. This structure contains subgraph + properties. + */ +#include "spf_begin_pack.h" +struct vcpm_cfg_subgraph_properties_t +{ + uint32_t sub_graph_id; + /**< Identifier for the subgraph for which the information is provided. */ + + uint32_t num_vcpm_properties; + /**< Number of %vcpm_property_config_struct_t structures that follow this + structure. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_cfg_subgraph_properties_t vcpm_cfg_subgraph_properties_t; + + +/** @ingroup spf_vpcm_voice_cfg + Payload for #VCPM_PARAM_ID_VOICE_CONFIG. This structure contains property + configuration objects. + */ +#include "spf_begin_pack.h" +struct vcpm_property_config_struct_t +{ + uint32_t property_id; + /**< Identifier for the VCPM property. */ + + uint32_t property_size; + /**< Size of the property payload that immediately follows this + structure. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_property_config_struct_t vcpm_property_config_struct_t; + + +/** @ingroup spf_vpcm_voice_cfg + Identifier for the property that contains instance IDs of modules in + different subgraphs that are part of a voice call use case graph + (applications processor). + + Set this property to VCPM as part of the #VCPM_PARAM_ID_VOICE_CONFIG + payload. + + @msgpayload + vcpm_property_id_tag_info_payload_t \n + @indent{12pt} vcpm_tag_miid_info_t +*/ +#define VCPM_PROPERTY_ID_TAG_INFO 0x080011B2 + + +/** @ingroup spf_vpcm_voice_cfg + Payload for #VCPM_PROPERTY_ID_TAG_INFO. + */ +#include "spf_begin_pack.h" +struct vcpm_property_id_tag_info_payload_t +{ + uint32_t num_tag_info; + /**< Number of %vcpm_tag_miid_info_t structures that immediately follow + this structure.*/ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_property_id_tag_info_payload_t vcpm_property_id_tag_info_payload_t; + + +/** @ingroup spf_vpcm_voice_cfg + Payload for #VCPM_PROPERTY_ID_TAG_INFO. This structure contains module tag + information. + */ +#include "spf_begin_pack.h" +struct vcpm_tag_miid_info_t +{ + uint32_t tag_id; + /**< Identifier for the tag that the VCPM publishes. + + @valuesbul + - #VOICE_MOD_TAG_ID_ENCODER + - #VOICE_MOD_TAG_ID_TX_MAILBOX + - #VOICE_MOD_TAG_ID_TX_STREAM_HPCM + - #VOICE_MOD_TAG_ID_DECODER + - #VOICE_MOD_TAG_ID_RX_MAILBOX + - #VOICE_MOD_TAG_ID_RX_STREAM_HPCM + - #VOICE_MOD_TAG_ID_CTMTTY_TX + - #VOICE_MOD_TAG_ID_LTETTY_TX + - #VOICE_MOD_TAG_ID_CTMTTY_RX + - #VOICE_MOD_TAG_ID_LTETTY_RX + - #VOICE_MOD_TAG_ID_1XTTY_RX + - #VOICE_MOD_TAG_ID_RX_TRM + - #VOICE_MOD_TAG_ID_TX_SMART_SYNC @tablebulletend */ + + uint32_t module_iid; + /**< Identifier for the module instance that corresponds to the tag ID. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_tag_miid_info_t vcpm_tag_miid_info_t; + + +/* Tag IDs for the voice graph modules. */ + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for the voice encoder. */ +#define VOICE_MOD_TAG_ID_ENCODER 0x08001177 + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for a mailbox in the Tx stream. */ +#define VOICE_MOD_TAG_ID_TX_MAILBOX 0x08001178 + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for Host PCM in the Tx stream. */ +#define VOICE_MOD_TAG_ID_TX_STREAM_HPCM 0x08001179 + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for the voice decoder. */ +#define VOICE_MOD_TAG_ID_DECODER 0x0800117B + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for a mailbox in the Rx stream. */ +#define VOICE_MOD_TAG_ID_RX_MAILBOX 0x0800117C + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for HPCM in the Rx stream. */ +#define VOICE_MOD_TAG_ID_RX_STREAM_HPCM 0x0800117D + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for the Timed Renderer module in the Rx stream. */ +#define VOICE_MOD_TAG_ID_RX_TRM 0x080011AC + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for smart synchronization in the Tx stream. */ +#define VOICE_MOD_TAG_ID_TX_SMART_SYNC 0x080011AD + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for LTE TTY in the Tx stream. */ +#define VOICE_MOD_TAG_ID_LTETTY_TX 0x0800117A + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for cellular text modem TTY in the Tx stream. */ +#define VOICE_MOD_TAG_ID_CTMTTY_TX 0x080011E1 + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for LTE TTY in the Rx stream. */ +#define VOICE_MOD_TAG_ID_LTETTY_RX 0x0800117E + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for cellular text modem TTY in the Rx stream. */ +#define VOICE_MOD_TAG_ID_CTMTTY_RX 0x080011E2 + +/** @ingroup spf_vpcm_voice_cfg + Tag ID for 1x TTY in the Rx stream. @newpage */ +#define VOICE_MOD_TAG_ID_1XTTY_RX 0x080011E3 + + +/** @ingroup spf_vpcm_cal_tbl + Identifier for the parameter that registers calibration tables per + subgraph (from the applications processor). + + @msgpayload + vcpm_param_cal_table_payload_t \n + @indent{12pt} vcpm_sgid_cal_table_t +*/ +#define VCPM_PARAM_ID_CAL_TABLE 0x08001163 + + +/** @ingroup spf_vpcm_cal_tbl + Payload for #VCPM_PARAM_ID_CAL_TABLE. + + Immediately following this structure is an array of structures of type + %vcpm_sgid_cal_table_t. The array length is equal to num_sub_graphs. +*/ +#include "spf_begin_pack.h" +struct vcpm_param_cal_table_payload_t +{ + uint32_t num_sub_graphs; + /**< Number of voice subgraphs for which calibration tables are + provided. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_cal_table_payload_t vcpm_param_cal_table_payload_t; + + +/** @ingroup spf_vpcm_cal_tbl + Payload for #VCPM_PARAM_ID_CAL_TABLE. This structure contains calibration + objects. + + Immediately following this structure is the calibration table of size + cal_table_size. +*/ +#include "spf_begin_pack.h" +struct vcpm_sgid_cal_table_t +{ + uint32_t sub_graph_id; + /**< Subgraph identifier for the calibration table that follows this + structure. */ + + uint32_t cal_table_size; + /**< Size of the calibration table that follows this structure.*/ + + /*uint8_t cal_table[cal_table_size] */ + /* Immediately following this structure is the calibration table of size + cal_table_size. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_sgid_cal_table_t vcpm_sgid_cal_table_t; + + +/** @ingroup spf_vpcm_cal_keys + Identifier for the calibration key that identifes the vocoder class (from + the applications processor and modem). + + This key supports the following values: + - #VCPM_CAL_KEY_VOCODER_CLASS_AMR + - #VCPM_CAL_KEY_VOCODER_CLASS_EVRC + - #VCPM_CAL_KEY_VOCODER_CLASS_EVS + */ +#define VCPM_CAL_KEY_ID_VOCODER_CLASS 0x08001164 + + +/** @ingroup spf_vpcm_cal_keys + Calibration key that identifies the sampling rate.*/ +#define VCPM_CAL_KEY_ID_SAMPLING_RATE 0x08001165 + +/** @ingroup spf_vpcm_cal_keys + Calibration key that identifies the volume level.*/ +#define VCPM_CAL_KEY_ID_VOLUME_LEVEL 0x08001166 + +/** @ingroup spf_vpcm_cal_keys + Calibration key that identifies the bandwidth extension mode. */ +#define VCPM_CAL_KEY_ID_BWE 0x08001167 + + +/** @ingroup spf_vpcm_cal_keys + Identifier for the calibration key that identifes the network. + + This key supports the following values: + - #VCPM_CAL_KEY_NETWORK_CDMA + - #VCPM_CAL_KEY_NETWORK_GSM + - #VCPM_CAL_KEY_NETWORK_WCDMA + - #VCPM_CAL_KEY_NETWORK_LTE + - #VCPM_CAL_KEY_NETWORK_TDSCDMA + */ +#define VCPM_CAL_KEY_ID_NETWORK 0x080011B5 + +/** @ingroup spf_vpcm_cal_keys + Calibration key that identifies the Volume boost mode. */ +#define VCPM_CAL_KEY_ID_VOL_BOOST 0x080011B6 + + +/* Values supported for the key ID VCPM_CAL_KEY_ID_VOCODER_CLASS */ + +/** @ingroup spf_vpcm_cal_keys + Calibration key that represents all the vocoders covered in the AMR class + for #VCPM_CAL_KEY_ID_VOCODER_CLASS. */ +#define VCPM_CAL_KEY_VOCODER_CLASS_AMR 0x08001168 + +/** @ingroup spf_vpcm_cal_keys + Calibration key that represents all the vocoders covered in the EVRC class + for #VCPM_CAL_KEY_ID_VOCODER_CLASS. */ +#define VCPM_CAL_KEY_VOCODER_CLASS_EVRC 0x08001169 + +/** @ingroup spf_vpcm_cal_keys + Calibration key that represents all the vocoders covered in the EVS class + #VCPM_CAL_KEY_ID_VOCODER_CLASS. */ +#define VCPM_CAL_KEY_VOCODER_CLASS_EVS 0x0800116A + + +/* Values supported for the key ID VCPM_CAL_KEY_ID_NETWORK */ + +/** @ingroup spf_vpcm_cal_keys + Calibration key that represents the CDMA network for + #VCPM_CAL_KEY_ID_NETWORK. */ +#define VCPM_CAL_KEY_NETWORK_CDMA 0x080011B7 + +/** @ingroup spf_vpcm_cal_keys + Calibration key that represents the GSM network for + #VCPM_CAL_KEY_ID_NETWORK. */ +#define VCPM_CAL_KEY_NETWORK_GSM 0x080011B8 + +/** @ingroup spf_vpcm_cal_keys + Calibration key that represents the WCDMA network for + #VCPM_CAL_KEY_ID_NETWORK. */ +#define VCPM_CAL_KEY_NETWORK_WCDMA 0x080011B9 + +/** @ingroup spf_vpcm_cal_keys + Calibration key that represents the LTE network for + #VCPM_CAL_KEY_ID_NETWORK. */ +#define VCPM_CAL_KEY_NETWORK_LTE 0x080011BA + +/** @ingroup spf_vpcm_cal_keys + Calibration key that represents the TD-SCDMA network for + #VCPM_CAL_KEY_ID_NETWORK. @newpage */ +#define VCPM_CAL_KEY_NETWORK_TDSCDMA 0x080011BB + + +/** @ingroup spf_vpcm_cal_keys + Identifier for the parameter that sets calibration keys from both the + applications processor and modem to the VCPM. + + @msgpayload + vcpm_param_cal_keys_payload_t \n + @indent{12pt} vcpm_ckv_pair_t + */ +#define VCPM_PARAM_ID_CAL_KEYS 0x0800116B + + +/** @ingroup spf_vpcm_cal_keys + Payload for #VCPM_PARAM_ID_CAL_KEYS. + + Immediately following this structure is an array of structures of type + %vcpm_ckv_pair_t. The array length is equal to num_sub_graphs. +*/ +#include "spf_begin_pack.h" +struct vcpm_param_cal_keys_payload_t +{ + uint32_t vsid; + /**< Voice System identifier for the calibration key. */ + + uint32_t num_ckv_pairs; + /**< Number of %vcpm_ckv_pair_t structures that immediately follow this + structure. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_cal_keys_payload_t vcpm_param_cal_keys_payload_t; + + +/** @ingroup spf_vpcm_cal_keys + Payload for #VCPM_PARAM_ID_CAL_KEYS and #VCPM_PARAM_ID_ACTIVE_CAL_KEYS. + This structure contains the calibration key and value pair objects. + */ +#include "spf_begin_pack.h" +struct vcpm_ckv_pair_t +{ + uint32_t cal_key_id; + /**< Unique identifier for the calibration key. + + @valuesbul{from modem processor} + - #VCPM_CAL_KEY_ID_VOCODER_CLASS + - #VCPM_CAL_KEY_ID_SAMPLING_RATE + - #VCPM_CAL_KEY_ID_NETWORK + + @valuesbul{from applications processor} + - #VCPM_CAL_KEY_ID_VOLUME_LEVEL + - #VCPM_CAL_KEY_ID_BWE + - #VCPM_CAL_KEY_ID_VOL_BOOST @tablebulletend */ + + uint32_t value; + /**< Values of the following calibration keys from the modem processor. + + @valuesbul{for VCPM\_CAL\_KEY\_ID\_VOCODER\_CLASS} + - #VCPM_CAL_KEY_VOCODER_CLASS_AMR + - #VCPM_CAL_KEY_VOCODER_CLASS_EVRC + - #VCPM_CAL_KEY_VOCODER_CLASS_EVS + + @valuesbul{for VCPM\_CAL\_KEY\_ID\_NETWORK} + - #VCPM_CAL_KEY_NETWORK_CDMA + - #VCPM_CAL_KEY_NETWORK_GSM + - #VCPM_CAL_KEY_NETWORK_WCDMA + - #VCPM_CAL_KEY_NETWORK_LTE + - #VCPM_CAL_KEY_NETWORK_TDSCDMA @tablebulletend @newpagetable */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_ckv_pair_t vcpm_ckv_pair_t; + + +/** @ingroup spf_vpcm_cal_keys + Identifier for the parameter the applications processor uses to query + active calibration keys for each voice call subgraph. + + This parameter supports only an #APM_CMD_GET_CFG command from the client. + It does not support an APM_CMD_SET_CFG command. + + @msgpayload + vcpm_param_active_cal_keys_payload_t \n + @indent{12pt} vcpm_ckv_pair_t +*/ +#define VCPM_PARAM_ID_ACTIVE_CAL_KEYS 0x080011C1 + + +/** @ingroup spf_vpcm_cal_keys + Payload for #VCPM_PARAM_ID_ACTIVE_CAL_KEYS. + + Immediately following this structure is an array of structures of type + %vcpm_ckv_pair_t. The array length is equal to num_ckv_pairs. +*/ +#include "spf_begin_pack.h" +struct vcpm_param_active_cal_keys_payload_t +{ + uint32_t sg_id; + /**< Unique identifier for the subgraph for which the parameter payload is + provided. */ + + uint32_t num_max_ckv_pairs; + /**< Maximum number of ckv_pairs of the given subgraph ID. + + The client fills this value when #APM_CMD_GET_CFG is called for this + parameter ID. */ + + uint32_t num_ckv_pairs; + /**< Number of %vcpm_ckv_pair_t structures that immediately follow this + structure. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_active_cal_keys_payload_t vcpm_param_active_cal_keys_payload_t; + + +/** @ingroup spf_vpcm_cal_keys + Identifier for the parameter that sets the number of volume steps from the + applications processor to the VCPM. + + @msgpayload + vcpm_param_num_vol_steps_payload_t @newpage +*/ +#define VCPM_PARAM_ID_NUM_VOL_STEPS 0x0800116C + + +/** @ingroup spf_vpcm_cal_keys + Payload for #VCPM_PARAM_ID_NUM_VOL_STEPS. + */ +#include "spf_begin_pack.h" +struct vcpm_param_num_vol_steps_payload_t +{ + uint32_t vsid; + /**< Voice System identifier for the volume step. */ + + uint32_t num_vol_steps; + /**< Total number of volume steps for the VSID session. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_num_vol_steps_payload_t vcpm_param_num_vol_steps_payload_t; + + +/** @ingroup spf_vpcm_clk_ctrl + Identifier for the parameter that sets the clock control parameters. + + @msgpayload + vcpm_param_clk_ctrl_payload_t +*/ +#define VCPM_PARAM_ID_CLK_CTRL 0x080011AE + + +/** @ingroup spf_vpcm_clk_ctrl + Payload for #VCPM_PARAM_ID_CLK_CTRL. + */ +#include "spf_begin_pack.h" +struct vcpm_param_clk_ctrl_payload_t +{ + uint32_t kpps_scale_factor; + /**< Scale factor to apply to the aggregated kpps of the subgraph. */ + + uint32_t bus_bw_scale_factor; + /**< Scale factor to apply to the aggregated bus bandwidth of the + subgraph.*/ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_clk_ctrl_payload_t vcpm_param_clk_ctrl_payload_t; + + +/** @ingroup spf_vpcm_events + ID for the event that indicates a voice call graph is opened. + + @msgpayload + vcpm_event_graph_open_payload_t \n + @indent{12pt} vcpm_vs_tag_miid_info_t +*/ +#define VCPM_EVENT_ID_GRAPH_OPEN 0x080011AF + + +/** @ingroup spf_vpcm_events + Payload for #VCPM_EVENT_ID_GRAPH_OPEN. + */ +#include "spf_begin_pack.h" +struct vcpm_event_graph_open_payload_t +{ + uint32_t vsid; + /**< Voice System identifier for the voice call graph. */ + + uint32_t num_tag_info; + /**< Number of %vcpm_vs_tag_miid_info_t structures that immediately follow + this structure. @newpagetable */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_event_graph_open_payload_t vcpm_event_graph_open_payload_t; + + +/** @ingroup spf_vpcm_events + Payload for #VCPM_EVENT_ID_GRAPH_OPEN. This structure contains tag and MIID + mapping information for each subgraph. The information is sent to the Voice + System. +*/ +#include "spf_begin_pack.h" +struct vcpm_vs_tag_miid_info_t +{ + uint32_t sg_id; + /**< ID for the sub-graph that corresponds to the module instance ID. */ + + uint32_t tag_id; + /**< Tag IDs published by the VCPM. + + @valuesbul + - #VOICE_MOD_TAG_ID_ENCODER + - #VOICE_MOD_TAG_ID_TX_MAILBOX + - #VOICE_MOD_TAG_ID_TX_STREAM_HPCM + - #VOICE_MOD_TAG_ID_DECODER + - #VOICE_MOD_TAG_ID_RX_MAILBOX + - #VOICE_MOD_TAG_ID_RX_STREAM_HPCM + - #VOICE_MOD_TAG_ID_CTMTTY_TX + - #VOICE_MOD_TAG_ID_LTETTY_TX + - #VOICE_MOD_TAG_ID_CTMTTY_RX + - #VOICE_MOD_TAG_ID_LTETTY_RX + - #VOICE_MOD_TAG_ID_1XTTY_RX + - #VOICE_MOD_TAG_ID_RX_TRM + - #VOICE_MOD_TAG_ID_TX_SMART_SYNC @tablebulletend */ + + uint32_t module_iid; + /**< ID for the module instance that corresponds to the tag ID. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_vs_tag_miid_info_t vcpm_vs_tag_miid_info_t; + + +/** @ingroup spf_vpcm_events + Identifier for the event that indicates a voice call graph is closed. + + @msgpayload + vcpm_event_graph_close_payload_t +*/ +#define VCPM_EVENT_ID_GRAPH_CLOSE 0x080011B0 + + +/** @ingroup spf_vpcm_events + Payload for #VCPM_EVENT_ID_GRAPH_CLOSE. + */ +#include "spf_begin_pack.h" +struct vcpm_event_graph_close_payload_t +{ + uint32_t vsid; + /**< Voice System identifier for the voice call graph. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_event_graph_close_payload_t vcpm_event_graph_close_payload_t; + + +/** @ingroup spf_vpcm_timing_cfg + Identifier for the parameter that sets timing parameters from the modem to + the VCPM. + + @msgpayload + vcpm_param_timing_params_t + */ +#define VCPM_PARAM_ID_TIMING_PARAMS 0x0800116E + +/*# @h2xmlp_parameter {"VCPM_PARAM_ID_TIMING_PARAMS", + VCPM_PARAM_ID_TIMING_PARAMS} + @h2xmlp_description {ID for the parameter that sets timing parameters from + the modem to the VCPM.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/** @ingroup spf_vpcm_timing_cfg + Payload for #VCPM_PARAM_ID_TIMING_PARAMS. + */ +#include "spf_begin_pack.h" +struct vcpm_param_timing_params_t +{ + uint32_t vfr_mode; + /**< Frame synchronization mode for the vocoder. */ + + /*#< @h2xmle_description {Frame synchronization mode for the vocoder.} + @h2xmle_default {0} + @h2xmle_range {0, 1} + @h2xmle_policy {Basic} */ + + uint32_t vsid; + /**< Voice System identifier for the vocoder. */ + + /*#< @h2xmle_description {Voice System ID for the vocoder.} + @h2xmle_default {0} + @h2xmle_range {0x11C05000, 0x11DC5000} + @h2xmle_policy {Basic} */ + + uint32_t tx_delivery_offset_us; + /**< Offset (in microseconds) from the VFR to deliver a Tx vocoder + packet. */ + + /*#< @h2xmle_description {Offset (in microseconds) from the VFR to deliver a + Tx vocoder packet.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t rx_start_offset_us; + /**< Offset (in microseconds) from the VFR to indicate the deadline to + receive an Rx vocoder packet. */ + + /*#< @h2xmle_description {Offset (in microseconds) from the VFR to indicate + the deadline to receive an Rx vocoder packet.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t vfr_cycle_us; + /**< VFR cycle duration for the voice call. @newpagetable */ + + /*#< @h2xmle_description {VFR cycle duration for the voice call.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_timing_params_t vcpm_param_timing_params_t; + + +/** @ingroup spf_vpcm_timing_cfg + Identifier for the parameter that sets timing references from the modem to + the VCPM. + + @msgpayload + vcpm_param_timing_references_t + */ +#define VCPM_PARAM_ID_TIMING_REFERENCES 0x080010A5 + +/*# @h2xmlp_parameter {"VCPM_PARAM_ID_TIMING_REFERENCES", + VCPM_PARAM_ID_TIMING_REFERENCES} + @h2xmlp_description {ID for the parameter that sets timing references from + the modem to the VCPM.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/** @ingroup spf_vpcm_timing_cfg + Payload for #VCPM_PARAM_ID_TIMING_REFERENCES. + */ +#include "spf_begin_pack.h" +struct vcpm_param_timing_references_t +{ + uint32_t vfr_mode; + /**< Frame synchronization mode for the vocoder. */ + + /*#< @h2xmle_description {Frame synchronization mode for the vocoder.} + @h2xmle_default {0} + @h2xmle_range {0, 1} + @h2xmle_policy {Basic} */ + + uint32_t vsid; + /**< Voice System identifier for the encoder. */ + + /*#< @h2xmle_description {Voice System ID for the encoder.} + @h2xmle_default {0} + @h2xmle_range {0x11C05000, 0x11DC5000} + @h2xmle_policy {Basic} */ + + uint64_t tx_ref_timstamp_us; + /**< Time reference (in microseconds) used to align the encoder's timeline + to the client's timeline at the beginning of the vocoder's packet + exchange operation. + + Use the QTimer as the clock source for interpreting the timestamp. */ + + /*#< @h2xmle_description {Time reference (in microseconds) used to align + the encoder's timeline to the client's timeline at + the beginning of the vocoder's packet exchange + operation. \n + Use the QTimer as the clock source for + interpreting the timestamp.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint64_t rx_ref_timstamp_us; + /**< Time reference(in microseconds) used to align the decoder's timeline to + the client's timeline at the beginning of the vocoder's packet exchange + operation. + + Use the QTimer as the clock source for interpreting the timestamp. */ + + /*#< @h2xmle_description {Time reference(in microseconds) used to align the + decoder's timeline to the client's timeline at the + beginning of the vocoder's packet exchange + operation. \n + Use the QTimer as the clock source for + interpreting the timestamp.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t vfr_cycle_us; + /**< VFR cycle duration for the voice call. */ + + /*#< @h2xmle_description {VFR cycle duration for the voice call.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_timing_references_t vcpm_param_timing_references_t; + + +/** @ingroup spf_vpcm_timing_cfg + Identifier for the parameter that sets version 2 of the timing references + from the modem to the VCPM. + + @msgpayload + vcpm_param_timing_references_v2_t + */ +#define VCPM_PARAM_ID_TIMING_REFERENCES_V2 0x08001256 + +/*# @h2xmlp_parameter {"VCPM_PARAM_ID_TIMING_REFERENCES_V2", + VCPM_PARAM_ID_TIMING_REFERENCES_V2} + @h2xmlp_description {Identifier for the parameter that sets version 2 of + the timing references from the modem to the VCPM.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + +/** @ingroup spf_vpcm_timing_cfg + Payload for #VCPM_PARAM_ID_TIMING_REFERENCES_V2. + */ +#include "spf_begin_pack.h" +struct vcpm_param_timing_references_v2_t +{ + uint32_t vfr_mode; + /**< Frame synchronization mode for the vocoder. */ + + /*#< @h2xmle_description {Frame synchronization mode for the vocoder.} + @h2xmle_default {0} + @h2xmle_range {0, 1} + @h2xmle_policy {Basic} */ + + uint32_t vsid; + /**< Voice System identifier 2 for the vocoder. */ + + /*#< @h2xmle_description {Voice System ID 2 for the vocoder.} + @h2xmle_default {0} + @h2xmle_range {0x11C05000, 0x11DC5000} + @h2xmle_policy {Basic} */ + + uint64_t tx_ref_timstamp_us; + /**< Time reference (in microseconds) used to align the encoder's timeline + to the client's timeline at the beginning of the vocoder's packet + exchange operation. + + Use the QTimer as the clock source for interpreting the timestamp. */ + + /*#< @h2xmle_description {Time reference (in microseconds) used to align the + encoder's timeline to the client's timeline at the + beginning of the vocoder's packet exchange + operation. \n + Use the QTimer as the clock source for + interpreting the timestamp.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint64_t rx_ref_timstamp_us; + /**< Time reference(in microseconds) used to align the decoder's timeline to + the client's timeline at the beginning of the vocoder's packet exchange + operation. + + Use the QTimer as the clock source for interpreting the timestamp. */ + + /*#< @h2xmle_description {Time reference(in microseconds) used to align the + decoder's timeline to the client's timeline at the + beginning of the vocoder's packet exchange + operation. \n + Use the QTimer as the clock source for + interpreting the timestamp.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t is_frame_type_event_enabled; + /**< Enables the event-driven mailbox packet exchange mode in the Tx path + for NO_DATA packets. */ + + /*#< @h2xmle_description {Enables the event-driven mailbox packet exchange + mode in the Tx path for NO_DATA packets.} + @h2xmle_default {0} + @h2xmle_range {0..1} + @h2xmle_policy {Basic} */ + + uint64_t frame_type_ref_timestamp_us; + /**< Client's time reference for receiving the frame type of an uplink + packet (absolute time in microseconds). + + An indication of a NO_DATA frame for the next CDRx cycle must be sent + before this reference. + + The clock source to use for interpreting the timestamp is + product-specific. Currently, the QTimer is used as the timing reference + for all products. + + The frame_type_ref_timestamp_us, read_ref_timestamp_us, and + enc_packet_ready_margin_us fields are used together to determine the + uplink packet delivery timeline for speech packets: + + @indent{12pt} Timestamp of speech packet delivery = minimum + @indent{12pt} ( (frame_type_ref_timestamp_us + enc_proc_time * + @indent{12pt} (vfr_cycle_duration_us/20000_us)), (read_ref_timestamp_us + @indent{12pt} - enc_packet_ready_margin_us) ) + + A value equal to 0 implies the mailbox enhancements feature is + disabled. + + Events for the NO_DATA frame type are not sent to the client. */ + + /*#< @h2xmle_description {Client's time reference for receiving the frame + type of uplink packet (absolute time in + microseconds). \n + An indication of a NO_DATA frame for the next CDRx + cycle must be sent before this reference. \n + The clock source to use for interpreting the + timestamp is product-specific (currently, the + QTimer for all products). \n + For more details, see the AudioReach SPF API + Reference (80-VN500-5).} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t enc_packet_ready_margin_us; + /**< Minimum allowed delay margin between the timestamp of the encoder + packet being ready and read_ref_timestamp_us. + + The encoder packet is ready and available in the mailbox buffer at + least enc_packet_ready_margin_us ahead of read_ref_timestamp_us. + + The value is specified in microseconds. */ + + /*#< @h2xmle_description {Minimum allowed delay margin between the timestamp + of the encoder packet being ready and + read_ref_timestamp_us. \n + The encoder packet is ready and available in the + mailbox buffer at least enc_packet_ready_margin_us + ahead of read_ref_timestamp_us. \n + The value is specified in microseconds.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ + + uint32_t vfr_cycle_us; + /**< Duration of the VFR cycle for the voice call. */ + + /*#< @h2xmle_description {Duration of the VFR cycle for the voice call.} + @h2xmle_default {0} + @h2xmle_range {0..0xFFFFFFFF} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_timing_references_v2_t vcpm_param_timing_references_v2_t; + + +/** @ingroup spf_vpcm_voice_cfg + Identifier for the parameter that sets the Voice System ID from the + applications processor to the VCPM. + + @msgpayload + vcpm_param_vsid_payload_t +*/ +#define VCPM_PARAM_ID_VSID 0x080011BC + + +/** @ingroup spf_vpcm_voice_cfg + Payload for #VCPM_PARAM_ID_VSID. + */ +#include "spf_begin_pack.h" +struct vcpm_param_vsid_payload_t +{ + uint32_t vsid; + /**< Voice System identifier for the graph. + + This ID is to be set on the graph that was previously created with a + don't care value. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_vsid_payload_t vcpm_param_vsid_payload_t; + + +/** @ingroup spf_vpcm_mailbox_mem + Parameter identifier for configuring memory on the modem that is shared + with mailbox Tx and Rx modules present on the aDSP for vocoder packet + exchange. + + @msgpayload + vcpm_param_id_mailbox_memory_config_t + */ +#define VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG 0x080011E7 + + +/** @ingroup spf_vpcm_mailbox_mem + Payload for #VCPM_PARAM_ID_MAILBOX_MEMORY_CONFIG. + */ +#include "spf_begin_pack.h" +struct vcpm_param_id_mailbox_memory_config_t +{ + uint32_t mailbox_mem_address_adsp_lsw; + /**< Lower 32 bits of the IO virtual address (understandable to the aDSP) of + the mailbox memory. + + This memory is carved out from the APQ DDR specifically for mailbox + packet exchange between the aDSP and modem. */ + + uint32_t mailbox_mem_address_adsp_msw; + /**< Upper 32 bits of the IO virtual address (understandable to aDSP) of the + mailbox memory. + + This memory is carved out from the APQ DDR specifically for mailbox + packet exchange between the aDSP and modem. */ + + uint32_t mailbox_mem_address_pcie_lsw; + /**< Lower 32 bits of the IO virtual address (understandable to the PCIe) of + the mailbox memory. + + This memory is carved out from the APQ DDR specifically for mailbox + packet exchange between the aDSP and modem. */ + + uint32_t mailbox_mem_address_pcie_msw; + /**< Upper 32 bits of the IO virtual address (understandable to the PCIe) of + the mailbox memory. + + This memory is carved out from the APQ DDR specifically for mailbox + packet exchange between the aDSP and modem. */ + + uint32_t mem_size; + /**< Size (in bytes) of the mailbox memory carved out from the APQ DDR. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_id_mailbox_memory_config_t vcpm_param_id_mailbox_memory_config_t; + + +/** @ingroup spf_vpcm_mailbox_mem + Parameter ID the VCPM exposes to the HLOS to set the Tx channel + information processed by the Tx sub-graph. This sub-graph hosts the ECNS + module for a given voice call use case. + + The Tx channel information must be set as follows: + - After the valid VSID configuration is set and before a Prepare command + is issued to the voice sub-graphs + - During voice call setup and device switch scenarios + + @msgpayload + vcpm_param_id_tx_dev_pp_channel_info_t + */ +#define VCPM_PARAM_ID_TX_DEV_PP_CHANNEL_INFO 0x08001310 + + +/** @ingroup spf_vpcm_mailbox_mem + Payload for #VCPM_PARAM_ID_TX_DEV_PP_CHANNEL_INFO. +*/ +#include "spf_begin_pack.h" +struct vcpm_param_id_tx_dev_pp_channel_info_t +{ + uint32_t vsid; + /**< Voice System identifier for the channel. */ + + uint32_t num_channels; + /**< Number of channels processed by the Tx voice processor sub-graph. */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_id_tx_dev_pp_channel_info_t vcpm_param_id_tx_dev_pp_channel_info_t; + + +/** @ingroup spf_vpcm_mailbox_mem + Identifier for the parameter that sets up the vocoder packet loopback + delay. + + @msgpayload + vcpm_param_id_voc_pkt_loopback_delay_t @newpage + */ +#define VCPM_PARAM_ID_VOC_PKT_LOOPBACK_DELAY 0x08001311 + +/*# @h2xmlp_parameter {"VCPM_PARAM_ID_VOC_PKT_LOOPBACK_DELAY", + VCPM_PARAM_ID_VOC_PKT_LOOPBACK_DELAY} + @h2xmlp_description {ID for the parameter used to set up the vocoder + packet loopback delay in milliseconds.} + @h2xmlp_toolPolicy {NO_SUPPORT} */ + + +/** @ingroup spf_vpcm_mailbox_mem + Payload structure for the #VCPM_PARAM_ID_VOC_PKT_LOOPBACK_DELAY. +*/ +#include "spf_begin_pack.h" +struct vcpm_param_id_voc_pkt_loopback_delay_t +{ + uint32_t vsid; + /**< Voice System identifier for the vocoder packet loopback. */ + + /*#< @h2xmle_description {Voice System ID for the vocoder packet loopback.} + @h2xmle_default {0} + @h2xmle_range {0x12006000, 0x121C6000} + @h2xmle_policy {Basic} */ + + uint32_t delay_ms; + /**< Vocoder packet loopback delay in milliseconds. + + Increment the delay in steps of 20 ms. It will be rounded off to the + next 20 ms multiple. */ + + /*#< @h2xmle_description {Vocoder packet loopback delay in milliseconds. + Increment the delay in steps of 20 ms. It will be + rounded off to the next 20 ms multiple.} + @h2xmle_default {0} + @h2xmle_range {0..5000} + @h2xmle_policy {Basic} */ +} +#include "spf_end_pack.h" +; +typedef struct vcpm_param_id_voc_pkt_loopback_delay_t vcpm_param_id_voc_pkt_loopback_delay_t; + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS // to end of file +/*------------------------------------------------------------------------------ + * H2XML annotations + *----------------------------------------------------------------------------*/ +enum platforms_spf +{ + PLATFORM_SPF = 0xFFFFFFFE /**< @h2xmle_name {SPF} */ +}; + +/** @h2xml_platforms{PLATFORM_SPF} */ + +enum vcpm_key_ids +{ + voice_vocoder_class = VCPM_CAL_KEY_ID_VOCODER_CLASS, + voice_sample_rate = VCPM_CAL_KEY_ID_SAMPLING_RATE, + voice_vol_level = VCPM_CAL_KEY_ID_VOLUME_LEVEL, + voice_bandwidth_extension = VCPM_CAL_KEY_ID_BWE, + voice_network = VCPM_CAL_KEY_ID_NETWORK, + voice_vol_boost = VCPM_CAL_KEY_ID_VOL_BOOST +}; + +/*# @h2xmlk_key {voice_vocoder_class} + @h2xmlk_isVoice {true} + @h2xmlk_description {Calibration key for the vocoder class.} */ + +enum vcpm_key_vocoder_class +{ + voc_cal_key_amr = VCPM_CAL_KEY_VOCODER_CLASS_AMR, + /*#< @h2xmle_description {AMR vocoder class.} */ + + voc_cal_key_evrc = VCPM_CAL_KEY_VOCODER_CLASS_EVRC, + /*#< @h2xmle_description {EVRC vocoder class.} */ + + voc_cal_key_evs = VCPM_CAL_KEY_VOCODER_CLASS_EVS + /*#< @h2xmle_description {EVS vocoder class.} */ +}; + +/*# @h2xmlk_key {voice_sample_rate} + @h2xmlk_sampleRate + @h2xmlk_isVoice {true} + @h2xmlk_description {Calibration key for the sampling rate.} */ + +enum vcpm_key_sample_rate +{ + SR_NB = 0x1F40, + /*#< @h2xmle_sampleRate {8000} + @h2xmle_description {Narrowband sampling rate.} */ + + SR_WB = 0x3E80, + /*#< @h2xmle_sampleRate {16000} + @h2xmle_description {Wideband sampling rate.} */ + + SR_SWB = 0x7D00, + /*#< @h2xmle_sampleRate {32000} + @h2xmle_description {Superwideband sampling rate.} */ + + SR_FB = 0xBB80, + /*#< @h2xmle_sampleRate {48000} + @h2xmle_description {Fullband sampling rate.} */ +}; + + +/*# @h2xmlk_key {voice_vol_level} + @h2xmlk_isVoice {true} + @h2xmlk_isDynamic {true} + @h2xmlk_description {Calibration key for the volume level.} */ + +enum vcpm_key_volume_level +{ + vol_level_0 = 0x00000000, /*#< @h2xmle_description {Volume level 0.} */ + vol_level_1 = 0x00000001, /*#< @h2xmle_description {Volume level 1.} */ + vol_level_2 = 0x00000002, /*#< @h2xmle_description {Volume level 2.} */ + vol_level_3 = 0x00000003, /*#< @h2xmle_description {Volume level 3.} */ + vol_level_4 = 0x00000004, /*#< @h2xmle_description {Volume level 4.} */ + vol_level_5 = 0x00000005, /*#< @h2xmle_description {Volume level 5.} */ +}; + + +/*# @h2xmlk_key {voice_bandwidth_extension} + @h2xmlk_isVoice {true} + @h2xmlk_description {Calibration key for BWE.} */ + +enum vcpm_key_bandwidth_extension +{ + enable = 0x00000001, /*#< @h2xmle_description {Enable BWE.} */ + disable = 0 /*#< @h2xmle_description {Disable BWE.} */ +}; + + +/*# @h2xmlk_key {voice_network} + @h2xmlk_isVoice {true} + @h2xmlk_description {Calibration key for the vocoder network.} */ + +enum vcpm_key_vocoder_network +{ + voc_cal_key_cdma = VCPM_CAL_KEY_NETWORK_CDMA, + /*#< @h2xmle_description {CDMA for the vocoder network.} */ + + voc_cal_key_gsm = VCPM_CAL_KEY_NETWORK_GSM, + /*#< @h2xmle_description {GSM for the vocoder network.} */ + + voc_cal_key_wcdma = VCPM_CAL_KEY_NETWORK_WCDMA, + /*#< @h2xmle_description {WCDMA for the vocoder network.} */ + + voc_cal_key_lte = VCPM_CAL_KEY_NETWORK_LTE, + /*#< @h2xmle_description {LTE for the vocoder network.} */ + + voc_cal_key_TDSCDMA = VCPM_CAL_KEY_NETWORK_TDSCDMA + /*#< @h2xmle_description {TDS CDMA for the vocoder network.} */ +}; + +/*# @h2xmlk_key {voice_vol_boost} + @h2xmlk_isVoice {true} + @h2xmlk_isDynamic {true} + @h2xmlk_description {Calibration key for volume boost.} */ + +enum vcpm_key_vol_boost +{ + vol_boost_enable = 0x00000001, + /*#< @h2xmle_description {Enable volume boost.} */ + + vol_boost_disable = 0 + /*#< @h2xmle_description {Disable volume boost.} */ +}; + + +/*# @h2xmlk_ckeys + @h2xmlk_isVoice {true} + @h2xmlk_description {Calibration keys for a voice call use case.} */ + +enum vcpm_cal_Keys +{ + ck_vocoder_class = voice_vocoder_class, + ck_sampling_rate = voice_sample_rate, + ck_volume_level = voice_vol_level, + ck_WV2 = voice_bandwidth_extension, + ck_voice_network = voice_network, + ck_vol_boost = voice_vol_boost +}; + +/*# @h2xmlk_modTagList + @h2xmlk_description {Module tag information.} */ + +typedef enum +{ + voice_mod_tag_id_encoder = VOICE_MOD_TAG_ID_ENCODER, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {Voice encoder.} */ + + voice_mod_tag_id_tx_mailbox = VOICE_MOD_TAG_ID_TX_MAILBOX, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {Mailbox in the Tx Stream.} */ + + voice_mod_tag_id_tx_stream_hpcm = VOICE_MOD_TAG_ID_TX_STREAM_HPCM, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {Host PCM in the Tx Stream.} */ + + voice_mod_tag_id_tx_smart_sync = VOICE_MOD_TAG_ID_TX_SMART_SYNC, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {Smart synchronization in the Tx stream.} */ + + voice_mod_tag_id_decoder = VOICE_MOD_TAG_ID_DECODER, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {Voice decoder.} */ + + voice_mod_tag_id_rx_mailbox = VOICE_MOD_TAG_ID_RX_MAILBOX, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {Mailbox in the Rx stream.} */ + + voice_mod_tag_id_rx_stream_hpcm = VOICE_MOD_TAG_ID_RX_STREAM_HPCM, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {Host PCM in the Rx stream.} */ + + voice_mod_tag_id_1x_rx_tty = VOICE_MOD_TAG_ID_1XTTY_RX, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {1x TTY in the Rx stream.} */ + + voice_mod_tag_id_ctm_rx_tty = VOICE_MOD_TAG_ID_CTMTTY_RX, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {CTM TTY in the Rx stream.} */ + + voice_mod_tag_id_ctm_tx_tty = VOICE_MOD_TAG_ID_CTMTTY_TX, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {CTM TTY in the Tx stream.} */ + + voice_mod_tag_id_lte_rx_tty = VOICE_MOD_TAG_ID_LTETTY_RX, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {LTE TTY in the Rx stream.} */ + + voice_mod_tag_id_lte_tx_tty = VOICE_MOD_TAG_ID_LTETTY_TX, + /*#< @h2xmle_isVoice {true} + @h2xmle_description {LTE TTY in the Tx stream.} */ + +}vcpm_graph_tag_Keys; + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + + +#endif /* _VCPM_API_H_ */ diff --git a/spf/spf.pc.in b/spf/spf.pc.in new file mode 100644 index 0000000..e999317 --- /dev/null +++ b/spf/spf.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: spf +Description: spf library +Version: @LT_VERSION@ +Libs: -L${libdir} -lar-spfhdrs +Cflags: -I${includedir}/spf -I${includedir}/spf/asps