diff --git a/LICENSE b/LICENSE
index f60fb811..d6d7bf23 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,26 +1,15 @@
HDF - Hardware Driver Foundation
Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
-HDF is dual licensed: you can use it either under the terms of
+The framework directory is dual licensed: you can use it either under the terms of
the GPL V2, or the BSD3 license, at your option.
-a) GNU General Public License version 2, (https://opensource.org/licenses/GPL-2.0)
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+The adapter/khdf/liteos and khdf/liteos_m subdirectories are licensed under 3-Clause BSD License.
+The adapter/khdf/linux subdirectory is licensed under the GPL V2 License.
+The adapter/platform subdirectory is is dual licensed: you can use it either under the terms of
+the GPL V2, or the 3-Clause BSD License, at your option.
+The adapter/uhdf and adapter/uhdf2 and others subdirectories are licensed under Apache License, Version 2.0.
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public
-License along with this library; if not, write to the Free
-Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
-MA 02110-1301 USA
-
-Alternatively,
-b) The BSD3 License, (https://opensource.org/licenses/BSD-3-Clause)
+a) The 3-Clause BSD License, (https://opensource.org/licenses/BSD-3-Clause)
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:
@@ -49,3 +38,197 @@ 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.
+
+b) The Apache License, Version 2.0, (https://www.apache.org/licenses/LICENSE-2.0)
+ 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
+
+c) GNU General Public License version 2, (https://opensource.org/licenses/GPL-2.0)
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+MA 02110-1301 USA
diff --git a/OAT.xml b/OAT.xml
index a3661195..6c0acde8 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -1,9 +1,14 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
@@ -85,6 +107,7 @@ Note:If the text contains special characters, please escape them according to th
+
diff --git a/README.md b/README.md
index 6280ecb5..10502b0d 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ This repository stores the core source code information of the OpenHarmony drive
## Directory Structure
```
-/drivers/framework
+/drivers/hdf_core/framework
├── core # Core code for implementing the HDF
│ ├── adapter # Kernel adaptation layer
│ ├── common # Common basic code
diff --git a/README_zh.md b/README_zh.md
index 215d3f8d..088b3332 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -21,7 +21,7 @@
## 目录
```
-/drivers/framework
+/drivers/hdf_core/framework
├── core #实现驱动框架的核心代码
│ ├── adapter #实现对内核操作接口适配,提供抽象化的接口供开发者使用
│ ├── common #驱动框架公共基础代码
diff --git a/adapter/.gitignore b/adapter/.gitignore
new file mode 100644
index 00000000..68a2bb6e
--- /dev/null
+++ b/adapter/.gitignore
@@ -0,0 +1 @@
+hdf_config_gen*
diff --git a/adapter/BUILD.gn b/adapter/BUILD.gn
new file mode 100644
index 00000000..36282106
--- /dev/null
+++ b/adapter/BUILD.gn
@@ -0,0 +1,57 @@
+# Copyright (c) 2022 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if (defined(ohos_lite)) {
+ group("uhdf_entry") {
+ deps = [
+ "//drivers/hdf_core/adapter/uhdf/manager:hdf_core",
+ "//drivers/hdf_core/adapter/uhdf/platform:hdf_platform",
+ "//drivers/hdf_core/adapter/uhdf/posix:hdf_posix_osal",
+ "//drivers/hdf_core/adapter/uhdf/posix/old:hdf_posix",
+ ]
+ }
+ group("uhdf_test_entry") {
+ deps = [
+ "//drivers/hdf_core/adapter/build/test_common:libhdf_test_common",
+ "//drivers/hdf_core/adapter/uhdf/test:hdf_test_uhdf",
+ ]
+ }
+} else {
+ group("uhdf_entry") {
+ deps = [
+ "//drivers/hdf_core/adapter/uhdf2/hcs:hdf_default.hcb",
+ "//drivers/hdf_core/adapter/uhdf2/hcs:hdf_devhost.cfg",
+ "//drivers/hdf_core/adapter/uhdf2/hdi:libhdi",
+ "//drivers/hdf_core/adapter/uhdf2/host:hdf_devhost",
+ "//drivers/hdf_core/adapter/uhdf2/host:libhdf_host",
+ "//drivers/hdf_core/adapter/uhdf2/host/test/unittest/sample_driver:libsample_driver",
+ "//drivers/hdf_core/adapter/uhdf2/ipc:libhdf_ipc_adapter",
+ "//drivers/hdf_core/adapter/uhdf2/manager:hdf_devmgr",
+ "//drivers/hdf_core/adapter/uhdf2/manager:hdf_devmgr.cfg",
+ "//drivers/hdf_core/adapter/uhdf2/platform:libhdf_platform",
+ "//drivers/hdf_core/adapter/uhdf2/utils:libhdf_utils",
+ "//drivers/hdf_core/framework/tools/hdf_dbg:hdf_dbg",
+ "//drivers/peripheral/base:hdf_peripheral.cfg",
+ ]
+ }
+ group("uhdf_test_entry") {
+ testonly = true
+ deps = [
+ "//drivers/hdf_core/adapter/build/test_common:libhdf_test_common",
+ "//drivers/hdf_core/adapter/uhdf2/hdi/test:unittest",
+ "//drivers/hdf_core/adapter/uhdf2/host/test:unittest",
+ "//drivers/hdf_core/adapter/uhdf2/osal/test:unittest",
+ "//drivers/hdf_core/adapter/uhdf2/test:hdf_test_uhdf",
+ ]
+ }
+}
diff --git a/adapter/LICENSE b/adapter/LICENSE
new file mode 100644
index 00000000..6dbf94ce
--- /dev/null
+++ b/adapter/LICENSE
@@ -0,0 +1,228 @@
+The khdf/liteos and khdf/liteos_m subdirectories are licensed under 3-Clause BSD License.
+The uhdf and uhdf2 subdirectories are licensed under Apache License, Version 2.0.
+The platform subdirectory is is dual licensed: you can use it either under the terms of
+the GPL V2, or the 3-Clause BSD Licens, at your option.
+
+a) The 3-Clause BSD License, (https://opensource.org/licenses/BSD-3-Clause)
+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 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.
+
+b) The Apache License, Version 2.0, (https://www.apache.org/licenses/LICENSE-2.0)
+ 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
+
+c) GNU General Public License version 2, (https://opensource.org/licenses/GPL-2.0)
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+MA 02110-1301 USA
diff --git a/adapter/OAT.xml b/adapter/OAT.xml
new file mode 100644
index 00000000..4a9810f6
--- /dev/null
+++ b/adapter/OAT.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/adapter/README.md b/adapter/README.md
new file mode 100644
index 00000000..bf27029a
--- /dev/null
+++ b/adapter/README.md
@@ -0,0 +1,30 @@
+# HDF Adapter
+
+- [Introduction](#section11660541593)
+- [Directory Structure](#section161941989596)
+- [Repositories Involved](#section1371113476307)
+
+## Introduction
+
+This repository stores the code and compilation scripts for the kerner or user-mode Hardware Driver Foundation \(HDF\) of the OpenHarmony driver subsystem and provides basic capabilities for the HDF.
+
+## Directory Structure
+
+```
+/drivers/hdf_core/adapter
+├── khdf/liteos # HDF dependent adapter for LiteOS-A kernel
+├── khdf/liteos_m # HDF dependent adapter for LiteOS-M kernel
+├── uhdf # HDF user mode interface dependent adapter
+└── uhdf2 # HDF user mode dependent adapter
+```
+
+## Repositories Involved
+
+[Driver subsystem](https://gitee.com/openharmony/docs/blob/master/en/readme/driver-subsystem.md)
+
+[drivers\_framework](https://gitee.com/openharmony/drivers_framework/blob/master/README.md)
+
+[drivers\_adapter](https://gitee.com/openharmony/drivers_adapter/blob/master/README.md)
+
+[drivers\_adapter\_khdf\_linux](https://gitee.com/openharmony/drivers_adapter_khdf_linux/blob/master/README.md)
+
diff --git a/adapter/README_zh.md b/adapter/README_zh.md
new file mode 100644
index 00000000..5e9799f4
--- /dev/null
+++ b/adapter/README_zh.md
@@ -0,0 +1,30 @@
+# HDF适配
+
+- [简介](#section11660541593)
+- [目录](#section161941989596)
+- [相关仓](#section1371113476307)
+
+## 简介
+
+该目录主要存放OpenHarmony驱动子系统内核或用户态驱动框架的代码和编译脚本,提供驱动框架的能力。
+
+## 目录
+
+```
+/drivers/hdf_core/adapter
+├── khdf/liteos #提供驱动框架对LiteOS-A内核依赖适配
+├── khdf/liteos_m #提供驱动框架对LiteOS-M内核依赖适配
+├── uhdf #提供用户态驱动接口对系统依赖适配
+└── uhdf2 #提供用户态驱动框架对系统依赖适配
+```
+
+## 相关仓
+
+[驱动子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E9%A9%B1%E5%8A%A8%E5%AD%90%E7%B3%BB%E7%BB%9F.md)
+
+[drivers\_framework](https://gitee.com/openharmony/drivers_framework/blob/master/README_zh.md)
+
+[drivers\_adapter](https://gitee.com/openharmony/drivers_adapter/blob/master/README_zh.md)
+
+[drivers\_adapter\_khdf\_linux](https://gitee.com/openharmony/drivers_adapter_khdf_linux/blob/master/README_zh.md)
+
diff --git a/adapter/build/test_common/BUILD.gn b/adapter/build/test_common/BUILD.gn
new file mode 100644
index 00000000..70278598
--- /dev/null
+++ b/adapter/build/test_common/BUILD.gn
@@ -0,0 +1,91 @@
+# Copyright (c) 2022 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("//build/ohos.gni")
+import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni")
+
+config("hdf_test_common_pub_config") {
+ visibility = [ ":*" ]
+
+ include_dirs = [ "//drivers/hdf_core/framework/test/unittest/include" ]
+}
+if (defined(ohos_lite)) {
+ ohos_shared_library("libhdf_test_common") {
+ output_extension = "z.so"
+ sources = [
+ "//drivers/hdf_core/framework/test/unittest/common/hdf_common_test.c",
+ ]
+
+ include_dirs = [
+ "//third_party/bounds_checking_function/include",
+ "//drivers/hdf_core/framework/include/platform",
+ "//drivers/hdf_core/framework/include/core",
+ "//drivers/hdf_core/framework/include/osal",
+ "//drivers/hdf_core/framework/include/utils",
+ "//drivers/hdf_core/adapter/uhdf/posix/include",
+ "//drivers/hdf_core/framework/test/unittest/include",
+ ]
+
+ ldflags = [
+ "-lstdc++",
+ "-lm",
+ "-pthread",
+ ]
+
+ deps = [
+ "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
+ "//drivers/hdf_core/adapter/uhdf/manager:hdf_core",
+ "//drivers/hdf_core/adapter/uhdf/posix:hdf_posix_osal",
+ ]
+ public_deps = [ "//third_party/bounds_checking_function:libsec_shared" ]
+ cflags = [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-fsigned-char",
+ "-fno-common",
+ "-fno-strict-aliasing",
+ ]
+ }
+} else {
+ ohos_shared_library("libhdf_test_common") {
+ public_configs = [ ":hdf_test_common_pub_config" ]
+ sources = [
+ "//drivers/hdf_core/framework/test/unittest/common/hdf_common_test.c",
+ ]
+
+ include_dirs = [ "//drivers/hdf_core/framework/test/unittest/include" ]
+
+ deps = [ "//drivers/hdf_core/adapter/uhdf2/utils:libhdf_utils" ]
+ defines = [ "__OHOS__USER__" ]
+ cflags = [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-fsigned-char",
+ "-fno-common",
+ "-fno-strict-aliasing",
+ ]
+ install_images = [ chipset_base_dir ]
+ subsystem_name = "hdf"
+ part_name = "hdf_core"
+ if (is_standard_system) {
+ external_deps = [
+ "hiviewdfx_hilog_native:libhilog",
+ "utils_base:utils",
+ ]
+ } else {
+ external_deps = [ "hilog:libhilog" ]
+ }
+ }
+}
diff --git a/adapter/khdf/linux/.gitignore b/adapter/khdf/linux/.gitignore
new file mode 100644
index 00000000..f741dfaa
--- /dev/null
+++ b/adapter/khdf/linux/.gitignore
@@ -0,0 +1 @@
+*.hcb
diff --git a/adapter/khdf/linux/Kconfig b/adapter/khdf/linux/Kconfig
new file mode 100644
index 00000000..ff129ec2
--- /dev/null
+++ b/adapter/khdf/linux/Kconfig
@@ -0,0 +1,32 @@
+
+menuconfig DRIVERS_HDF
+ bool "HDF driver framework support"
+ default n
+ help
+ Answer Y to enable Linux support HDF.
+
+if DRIVERS_HDF
+config HDF_SUPPORT_LEVEL
+ int "Set HDF support level"
+ default 2
+ range 0 5
+ depends on DRIVERS_HDF
+ help
+ Answer 1 on small OHOS, 2 on standard OHOS
+
+source "drivers/hdf/khdf/platform/Kconfig"
+source "drivers/hdf/khdf/test/Kconfig"
+source "drivers/hdf/khdf/model/display/Kconfig"
+source "drivers/hdf/khdf/model/input/Kconfig"
+source "drivers/hdf/khdf/model/network/wifi/Kconfig"
+source "drivers/hdf/khdf/model/network/bluetooth/Kconfig"
+source "drivers/hdf/khdf/model/sensor/Kconfig"
+source "drivers/hdf/khdf/model/storage/Kconfig"
+source "drivers/hdf/khdf/model/usb/host/Kconfig"
+source "drivers/hdf/khdf/model/usb/device/Kconfig"
+source "drivers/hdf/khdf/model/audio/Kconfig"
+source "drivers/hdf/khdf/model/misc/vibrator/Kconfig"
+source "drivers/hdf/khdf/model/misc/dsoftbus/Kconfig"
+source "drivers/hdf/khdf/model/misc/light/Kconfig"
+
+endif
diff --git a/adapter/khdf/linux/LICENSE b/adapter/khdf/linux/LICENSE
new file mode 100644
index 00000000..ff0812fd
--- /dev/null
+++ b/adapter/khdf/linux/LICENSE
@@ -0,0 +1,359 @@
+Valid-License-Identifier: GPL-2.0
+Valid-License-Identifier: GPL-2.0-only
+Valid-License-Identifier: GPL-2.0+
+Valid-License-Identifier: GPL-2.0-or-later
+SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
+Usage-Guide:
+ To use this license in source code, put one of the following SPDX
+ tag/value pairs into a comment according to the placement
+ guidelines in the licensing rules documentation.
+ For 'GNU General Public License (GPL) version 2 only' use:
+ SPDX-License-Identifier: GPL-2.0
+ or
+ SPDX-License-Identifier: GPL-2.0-only
+ For 'GNU General Public License (GPL) version 2 or any later version' use:
+ SPDX-License-Identifier: GPL-2.0+
+ or
+ SPDX-License-Identifier: GPL-2.0-or-later
+License-Text:
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/adapter/khdf/linux/Makefile b/adapter/khdf/linux/Makefile
new file mode 100644
index 00000000..03401b7f
--- /dev/null
+++ b/adapter/khdf/linux/Makefile
@@ -0,0 +1,58 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+CURRENT_DIR := $(abspath $(dir $(realpath $(lastword $(MAKEFILE_LIST)))))
+
+obj-$(CONFIG_DRIVERS_HDF) += osal/
+obj-$(CONFIG_DRIVERS_HDF) += network/
+obj-$(CONFIG_DRIVERS_HDF) += utils/
+
+$(warning PRODUCT_PATH=$(PRODUCT_PATH))
+ifeq ($(PRODUCT_PATH),)
+$(error PRODUCT_PATH is not set)
+endif
+
+HCS_DIR := ../../../../../$(PRODUCT_PATH)/hdf_config/khdf
+ifeq ($(wildcard $(CURRENT_DIR)/$(HCS_DIR)),)
+HCS_DIR := ../../../../../$(PRODUCT_PATH)/hdf_config
+endif
+
+ifeq ($(CONFIG_DRIVERS_HDF), y)
+ifeq ($(wildcard $(CURRENT_DIR)/$(HCS_DIR)),)
+HCS_ABS_DIR := $(abspath $(CURRENT_DIR)/$(HCS_DIR))
+$(error miss hcs config in $(HCS_ABS_DIR) for small system\
+ or $(HCS_ABS_DIR)/khdf for standrad system)
+endif
+
+ifeq ($(CONFIG_DRIVERS_HDF_TEST), y)
+obj-$(CONFIG_DRIVERS_HDF_TEST) += test/
+obj-$(CONFIG_DRIVERS_HDF_TEST) += $(HCS_DIR)/hdf_test/
+else
+obj-$(CONFIG_DRIVERS_HDF) += $(HCS_DIR)/
+endif
+endif
+
+obj-$(CONFIG_DRIVERS_HDF) += manager/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM) += platform/
+obj-$(CONFIG_DRIVERS_HDF_DISP) += model/display/
+obj-$(CONFIG_DRIVERS_HDF_INPUT) += model/input/
+obj-$(CONFIG_DRIVERS_HDF_WIFI) += model/network/wifi/
+obj-$(CONFIG_DRIVERS_HDF_USB_PNP_NOTIFY) += model/usb/host/
+obj-$(CONFIG_DRIVERS_HDF_USB_F_GENERIC) += model/usb/device/
+obj-$(CONFIG_DRIVERS_HDF_SENSOR) += model/sensor/
+obj-$(CONFIG_DRIVERS_HDF_STORAGE) += model/storage/
+obj-$(CONFIG_DRIVERS_HDF_BT) += model/network/bluetooth/
+obj-$(CONFIG_DRIVERS_HDF_LIGHT) += model/misc/light/
+obj-$(CONFIG_DRIVERS_HDF_VIBRATOR) += model/misc/vibrator/
+obj-$(CONFIG_DRIVERS_HDF_AUDIO) += model/audio/
+obj-$(CONFIG_DRIVERS_HDF_DSOFTBUS) += model/misc/dsoftbus/
diff --git a/adapter/khdf/linux/OAT.xml b/adapter/khdf/linux/OAT.xml
new file mode 100644
index 00000000..43e0d50d
--- /dev/null
+++ b/adapter/khdf/linux/OAT.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/adapter/khdf/linux/README.md b/adapter/khdf/linux/README.md
new file mode 100644
index 00000000..8a5024c4
--- /dev/null
+++ b/adapter/khdf/linux/README.md
@@ -0,0 +1,57 @@
+# linux\_khdf
+
+- [Introduction](#section11660541593)
+- [Directory Structure](#section161941989596)
+- [Repositories Involved](#section1371113476307)
+
+## Introduction
+
+This repository stores the code and compilation scripts for the OpenHarmony driver subsystem to adapt to the Linux kernel and to deploy the hardware driver foundation \(HDF\).
+
+## Directory Structure
+
+```
+/drivers/hdf_core/adapter/khdf/linux
+├── utils # Compilation scripts for building and configuring the parsing code
+├── manager # Code for starting and adapting to the HDF
+├── model # Code for adapting to Linux
+│ ├── audio # Audio driver model
+│ ├── display # Display driver model
+│ ├── input # Input driver model
+│ ├── misc # Misc driver model, including dsoftbus, light, vibrator
+│ ├── network # WLAN driver model
+│ ├── sensor # Sensor driver model
+│ ├── storage # Storage driver model
+│ ├── usb # USB driver model
+├── network # Code for adapting to the Linux kernel network
+├── osal # POSIX APIs for adapting to the Linux kernel
+├── platform # Code for adapting the platform APIs to the Linux kernel
+│ ├── adc # ADC APIs
+│ ├── emmc # EMMC APIs
+│ ├── gpio # GPIO APIs
+│ ├── i2c # I2C APIs
+│ ├── mipi_csi # MIPI CSI APIs
+│ ├── mipi_dsi # MIPI DSI APIs
+│ ├── mmc # MMC APIs
+│ ├── pwm # PWM APIs
+│ ├── regulator # Regulator APIs
+│ ├── rtc # RTC APIs
+│ ├── sdio # SDIO APIs
+│ ├── spi # SPI APIs
+│ ├── uart # UART APIs
+│ └── watchdog # WATCHDOG APIs
+├── test # Testcase for testing the Linux kernel driver
+```
+
+## Repositories Involved
+
+[Driver subsystem](https://gitee.com/openharmony/docs/blob/master/en/readme/driver-subsystem.md)
+
+[drivers\_framework](https://gitee.com/openharmony/drivers_framework/blob/master/README.md)
+
+[drivers\_adapter](https://gitee.com/openharmony/drivers_adapter/blob/master/README.md)
+
+[drivers\_adapter\_khdf\_linux](https://gitee.com/openharmony/drivers_adapter_khdf_linux/blob/master/README.md)
+
+[drivers\_peripheral](https://gitee.com/openharmony/drivers_peripheral/blob/master/README.md)
+
diff --git a/adapter/khdf/linux/README_zh.md b/adapter/khdf/linux/README_zh.md
new file mode 100644
index 00000000..444c9912
--- /dev/null
+++ b/adapter/khdf/linux/README_zh.md
@@ -0,0 +1,57 @@
+# linux\_khdf
+
+- [简介](#section11660541593)
+- [目录](#section161941989596)
+- [相关仓](#section1371113476307)
+
+## 简介
+
+该目录主要存放OpenHarmony驱动子系统适配linux内核的代码和编译脚本,在linux内核中部署OpenHarmony驱动框架。
+
+## 目录
+
+```
+/drivers/hdf_core/adapter/khdf/linux
+├── utils #linux内核下编译配置解析代码的编译脚本
+├── manager #linux内核下启动适配启动HDF框架代码
+├── model #驱动模型适配linux代码
+│ ├── audio #音频驱动模型
+│ ├── display #显示驱动模型
+│ ├── input #输入驱动模型
+│ ├── misc #杂项驱动模型,包括dsoftbus、light、vibrator
+│ ├── network #wifi驱动模型
+│ └── sensor #传感器驱动模型
+│ └── storage #存储驱动模型
+│ └── usb #USB驱动模型
+├── network #适配linux内核网络代码
+├── osal #适配linux内核的posix接口
+├── platform #平台设备接口适配linux内核代码
+│ ├── adc #adc接口
+│ ├── emmc #emmc操作接口
+│ ├── gpio #gpio接口
+│ ├── i2c #i2c接口
+│ ├── mipi_csi #mipi csi接口
+│ ├── mipi_dsi #mipi dsi接口
+│ ├── mmc #mmc接口
+│ ├── pwm #pwm接口
+│ ├── regulator #regulator接口
+│ ├── rtc #rtc接口
+│ ├── sdio #sdio接口
+│ ├── spi #spi接口
+│ ├── uart #uart接口
+│ └── watchdog #watchdog接口
+├── test #linux内核测试用例
+```
+
+## 相关仓
+
+[驱动子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E9%A9%B1%E5%8A%A8%E5%AD%90%E7%B3%BB%E7%BB%9F.md)
+
+[drivers\_framework](https://gitee.com/openharmony/drivers_framework/blob/master/README_zh.md)
+
+[drivers\_adapter](https://gitee.com/openharmony/drivers_adapter/blob/master/README_zh.md)
+
+[drivers\_adapter\_khdf\_linux](https://gitee.com/openharmony/drivers_adapter_khdf_linux/blob/master/README_zh.md)
+
+[drivers\_peripheral](https://gitee.com/openharmony/drivers_peripheral/blob/master/README_zh.md)
+
diff --git a/adapter/khdf/linux/include/core/hdf_driver_module.h b/adapter/khdf/linux/include/core/hdf_driver_module.h
new file mode 100644
index 00000000..c7cfd681
--- /dev/null
+++ b/adapter/khdf/linux/include/core/hdf_driver_module.h
@@ -0,0 +1,41 @@
+/*
+ * hdf_driver_module.h
+ *
+ * osal driver
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HDF_DRIVER_MODULE_H
+#define HDF_DRIVER_MODULE_H
+
+#include
+#include
+
+#include "hdf_driver.h"
+
+#define HDF_DRIVER_MODULE(module) \
+ static int __init hdf_driver_init(void) \
+ { \
+ HDF_LOGI("hdf driver " #module " register"); \
+ return HdfRegisterDriverEntry(&module); \
+ } \
+ static void __exit hdf_driver_exit(void) \
+ { \
+ HDF_LOGI("hdf driver " #module " unregister"); \
+ HdfUnregisterDriverEntry(&module); \
+ } \
+ module_init(hdf_driver_init); \
+ module_exit(hdf_driver_exit);
+
+#endif // HDF_DRIVER_MODULE_H
\ No newline at end of file
diff --git a/adapter/khdf/linux/manager/Makefile b/adapter/khdf/linux/manager/Makefile
new file mode 100644
index 00000000..af3cdc33
--- /dev/null
+++ b/adapter/khdf/linux/manager/Makefile
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+OHOS_SOURCE_ROOT := ../../../../../../
+HDF_FRAMEWORK_SRC_DIR := ../../../../
+
+SEC_LIB_SOURCES = memcpy_s.c memmove_s.c memset_s.c securecutil.c secureinput_a.c secureprintoutput_a.c snprintf_s.c \
+ sprintf_s.c strcat_s.c strcpy_s.c strncat_s.c strncpy_s.c strtok_s.c vsnprintf_s.c vsprintf_s.c
+SEC_FUNCTION_OBJECTS := $(patsubst %.c,%.o,$(SEC_LIB_SOURCES))
+SEC_FUNCTION_OBJECTS := $(addprefix $(OHOS_SOURCE_ROOT)/third_party/bounds_checking_function/src/,${SEC_FUNCTION_OBJECTS})
+
+obj-y += \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/utils/src/hdf_cstring.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/utils/src/hdf_slist.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/utils/src/hdf_sref.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/utils/src/hdf_map.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/utils/src/hdf_sbuf.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/utils/src/hdf_sbuf_impl_raw.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/utils/src/hdf_task_queue.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/devhost_service.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/devmgr_service_clnt.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/devsvc_manager_clnt.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_device.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_device_node.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_device_token.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_driver_loader.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_observer_record.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_service_subscriber.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_device_object.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_power_manager.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/hdf_service_observer.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/host/src/power_state_token.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/devhost_service_clnt.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/device_token_clnt.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/devmgr_service.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/devsvc_manager.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/devsvc_manager_ext.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/servstat_listener_holder.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/hdf_driver_installer.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/hdf_host_info.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/power_state_token_clnt.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/manager/src/driver_manager.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/shared/src/hdf_service_record.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/shared/src/hdf_device_info.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/shared/src/hdf_object_manager.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/shared/src/hdf_io_service.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/shared/src/service_status.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/common/src/devlite_object_config.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/common/src/hdf_attribute.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/common/src/devmgr_service_start.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/common/src/hdf_device_node_ext.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/common/src/buildin_config_entry.o \
+ $(HDF_FRAMEWORK_SRC_DIR)/framework/core/adapter/vnode/src/hdf_vnode_adapter.o \
+ ./src/devmgr_load.o \
+ ./src/devmgr_pm_reg.o \
+ ./src/sym_export.o \
+ ./src/hdf_kevent.o \
+ $(SEC_FUNCTION_OBJECTS)
+
+ccflags-y += \
+ -I$(srctree)/drivers/hdf/framework/include \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/include \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/host/include \
+ -I$(srctree)/drivers/hdf/framework/core/manager/include \
+ -I$(srctree)/drivers/hdf/framework/core/shared/include \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/manager \
+ -I$(srctree)/drivers/hdf/framework/core/adapter/vnode/include \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/include/uapi/linux \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/manager/src/devmgr_load.c b/adapter/khdf/linux/manager/src/devmgr_load.c
new file mode 100644
index 00000000..5119e865
--- /dev/null
+++ b/adapter/khdf/linux/manager/src/devmgr_load.c
@@ -0,0 +1,40 @@
+/*
+ * devmgr_load.c
+ *
+ * device manager loader of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include
+#include "devmgr_service_start.h"
+#include "hdf_log.h"
+
+static int __init DeviceManagerInit(void)
+{
+ int ret;
+
+ HDF_LOGD("%s enter", __func__);
+ ret = DeviceManagerStart();
+ if (ret < 0) {
+ HDF_LOGE("%s start failed %d", __func__, ret);
+ } else {
+ HDF_LOGD("%s start success", __func__);
+ }
+ return ret;
+}
+
+late_initcall(DeviceManagerInit);
+
diff --git a/adapter/khdf/linux/manager/src/devmgr_pm_reg.c b/adapter/khdf/linux/manager/src/devmgr_pm_reg.c
new file mode 100644
index 00000000..3b48afaa
--- /dev/null
+++ b/adapter/khdf/linux/manager/src/devmgr_pm_reg.c
@@ -0,0 +1,89 @@
+/*
+ * devmgr_pm.c
+ *
+ * HDF power manager of linux
+ *
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+
+#include "devmgr_service.h"
+#include "hdf_base.h"
+#include "hdf_log.h"
+
+#define HDF_LOG_TAG devmgr_pm
+
+static int DevmgrPmSuspend(void)
+{
+ HDF_LOGD("%s enter", __func__);
+ struct IDevmgrService *devmgrService = DevmgrServiceGetInstance();
+ if (devmgrService == NULL) {
+ return HDF_FAILURE;
+ }
+
+ if (devmgrService->PowerStateChange(devmgrService, POWER_STATE_SUSPEND) != HDF_SUCCESS) {
+ HDF_LOGE("%s drivers suspend failed", __func__);
+ devmgrService->PowerStateChange(devmgrService, POWER_STATE_RESUME);
+ return HDF_FAILURE;
+ }
+
+ return HDF_SUCCESS;
+}
+
+static int DevmgrPmResume(void)
+{
+ HDF_LOGD("%s enter", __func__);
+ struct IDevmgrService *devmgrService = DevmgrServiceGetInstance();
+ if (devmgrService == NULL) {
+ return HDF_FAILURE;
+ }
+
+ devmgrService->PowerStateChange(devmgrService, POWER_STATE_RESUME);
+ HDF_LOGD("%s resume done", __func__);
+ return HDF_SUCCESS;
+}
+
+static int DevmgrPmNotifier(struct notifier_block *nb, unsigned long mode, void *data)
+{
+ int ret = HDF_SUCCESS;
+ switch (mode) {
+ case PM_SUSPEND_PREPARE:
+ ret = DevmgrPmSuspend();
+ break;
+ case PM_POST_SUSPEND:
+ ret = DevmgrPmResume();
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+static struct notifier_block PmNotifier = {
+ .notifier_call = DevmgrPmNotifier,
+};
+
+int DevMgrPmRegister(void)
+{
+ int ret;
+
+ HDF_LOGD("%s enter", __func__);
+ ret = register_pm_notifier(&PmNotifier);
+ if (ret) {
+ HDF_LOGE("%s register_pm_notifier failed", __func__);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(DevMgrPmRegister);
diff --git a/adapter/khdf/linux/manager/src/hdf_kevent.c b/adapter/khdf/linux/manager/src/hdf_kevent.c
new file mode 100644
index 00000000..ee1e49c2
--- /dev/null
+++ b/adapter/khdf/linux/manager/src/hdf_kevent.c
@@ -0,0 +1,467 @@
+/*
+ *
+ * hdf_kevent.c
+ *
+ * HDF kevent implement for linux
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+#include "devmgr_service_clnt.h"
+#include "hdf_device_desc.h"
+#include "hdf_dlist.h"
+#include "hdf_log.h"
+#include "hdf_power_state.h"
+#include "hdf_sbuf.h"
+#include "osal_mem.h"
+#include "osal_mutex.h"
+#include "osal_sysevent.h"
+
+#define HDF_LOG_TAG kevent
+
+#define EVENT_TIMEOUT_JIFFIES 5
+#define EVENT_DEFAULT_SIZE 64
+#define KEVENT_COMPLETE_EVENT 1
+
+struct HdfKeventWait {
+ struct completion comp;
+ struct DListHead listNode;
+ uint32_t waitCount;
+};
+
+struct HdfKeventClient {
+ struct HdfDeviceIoClient *ioClient;
+ struct DListHead listNode;
+};
+
+struct HdfKeventModule {
+ struct HdfDeviceObject *devObj;
+ struct notifier_block keventPmNotifier;
+ struct notifier_block fbNotifier;
+ struct DListHead waitList;
+ struct OsalMutex mutex;
+ struct OsalMutex clientMutex;
+ struct DListHead clientList;
+ int32_t clientCount;
+};
+
+static struct HdfKeventModule *g_keventModule = NULL;
+
+static struct HdfKeventWait *HdfKeventWaitAlloc(void)
+{
+ struct HdfKeventWait *wait = OsalMemAlloc(sizeof(struct HdfKeventWait));
+ if (wait != NULL) {
+ init_completion(&wait->comp);
+ }
+
+ return wait;
+}
+
+static void HdfKeventWaitFree(struct HdfKeventWait *wait)
+{
+ if (wait != NULL) {
+ OsalMemFree(wait);
+ }
+}
+
+static struct HdfSBuf *PrepareEvent(
+ struct HdfKeventWait **wait, uint64_t class, int32_t eventId, const char *content, bool sync)
+{
+ struct HdfSBuf *eventBuf = NULL;
+ struct HdfSysEvent sysEvent;
+ struct HdfKeventWait *eventWait = NULL;
+
+ eventBuf = HdfSbufObtain(EVENT_DEFAULT_SIZE);
+ if (eventBuf == NULL) {
+ HDF_LOGE("%s: failed to obtain sbuf", __func__);
+ return NULL;
+ }
+
+ sysEvent.eventClass = class;
+ sysEvent.eventid = eventId;
+ sysEvent.syncToken = 0;
+
+ if (sync) {
+ eventWait = HdfKeventWaitAlloc();
+ if (eventWait == NULL) {
+ HdfSbufRecycle(eventBuf);
+ return NULL;
+ }
+ sysEvent.syncToken = (uint64_t)eventWait;
+ }
+
+ if (!HdfSbufWriteBuffer(eventBuf, &sysEvent, sizeof(sysEvent))) {
+ HdfSbufRecycle(eventBuf);
+ return NULL;
+ }
+
+ if (!HdfSbufWriteString(eventBuf, content)) {
+ HdfSbufRecycle(eventBuf);
+ return NULL;
+ }
+
+ *wait = eventWait;
+ return eventBuf;
+}
+
+static int SendKevent(
+ struct HdfKeventModule *keventModule, uint16_t class, int32_t event, const char *content, bool sync)
+{
+ struct HdfSBuf *eventBuf = NULL;
+ struct HdfKeventWait *wait = NULL;
+ struct HdfKeventClient *client = NULL;
+ int ret;
+
+ if (keventModule->clientCount <= 0) {
+ return 0;
+ }
+
+ eventBuf = PrepareEvent(&wait, class, event, content, sync);
+ if (eventBuf == NULL) {
+ return HDF_FAILURE;
+ }
+
+ OsalMutexLock(&keventModule->mutex);
+ if (sync) {
+ DListInsertTail(&wait->listNode, &keventModule->waitList);
+ }
+
+ OsalMutexLock(&keventModule->clientMutex);
+ if (sync) {
+ wait->waitCount = keventModule->clientCount;
+ }
+
+ DLIST_FOR_EACH_ENTRY(client, &keventModule->clientList, struct HdfKeventClient, listNode) {
+ ret = HdfDeviceSendEventToClient(client->ioClient, HDF_SYSEVENT, eventBuf);
+ if (ret) {
+ HDF_LOGE("%s: failed to send device event, %d", __func__, ret);
+ }
+ }
+ OsalMutexUnlock(&keventModule->clientMutex);
+
+ if (sync) {
+ OsalMutexUnlock(&keventModule->mutex);
+ if (wait_for_completion_timeout(&wait->comp, EVENT_TIMEOUT_JIFFIES * HZ) == 0) {
+ HDF_LOGE("%s:send kevent timeout, class=%d, event=%d", __func__, class, event);
+ ret = HDF_ERR_TIMEOUT;
+ }
+
+ OsalMutexLock(&keventModule->mutex);
+ DListRemove(&wait->listNode);
+ HdfKeventWaitFree(wait);
+ }
+
+ OsalMutexUnlock(&keventModule->mutex);
+ HdfSbufRecycle(eventBuf);
+ return ret;
+}
+
+int32_t HdfSysEventSend(uint64_t eventClass, uint32_t event, const char *content, bool sync)
+{
+ struct HdfKeventModule *keventmodule = g_keventModule;
+ if (keventmodule == NULL) {
+ return HDF_DEV_ERR_OP;
+ }
+
+ return SendKevent(keventmodule, eventClass, event, content, sync);
+}
+
+static int32_t KernalSpacePmNotify(int32_t powerEvent)
+{
+ uint32_t pmStatus = POWER_STATE_MAX;
+ struct DevmgrServiceClnt *devmgrClnt = NULL;
+
+ switch (powerEvent) {
+ case KEVENT_POWER_SUSPEND:
+ pmStatus = POWER_STATE_SUSPEND;
+ break;
+ case KEVENT_POWER_DISPLAY_OFF:
+ pmStatus = POWER_STATE_DOZE_SUSPEND;
+ break;
+ case KEVENT_POWER_RESUME:
+ pmStatus = POWER_STATE_RESUME;
+ break;
+ case KEVENT_POWER_DISPLAY_ON:
+ pmStatus = POWER_STATE_DOZE_RESUME;
+ break;
+ default:
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ devmgrClnt = DevmgrServiceClntGetInstance();
+ if (devmgrClnt == NULL || devmgrClnt->devMgrSvcIf == NULL) {
+ return HDF_FAILURE;
+ }
+
+ return devmgrClnt->devMgrSvcIf->PowerStateChange(devmgrClnt->devMgrSvcIf, pmStatus);
+}
+
+static int32_t KeventPmNotifierFn(struct notifier_block *nb, unsigned long action, void *dummy)
+{
+ struct HdfKeventModule *keventModule = NULL;
+ int32_t powerEvent;
+ bool sync = false;
+ int ret = 0;
+
+ keventModule = CONTAINER_OF(nb, struct HdfKeventModule, keventPmNotifier);
+ HDF_LOGI("%s:action=%d", __func__, action);
+ switch (action) {
+ case PM_SUSPEND_PREPARE:
+ HDF_LOGI("%s:receive suspend event", __func__);
+ powerEvent = KEVENT_POWER_SUSPEND;
+ sync = true;
+ break;
+ case PM_POST_SUSPEND:
+ HDF_LOGI("%s:receive resume event", __func__);
+ powerEvent = KEVENT_POWER_RESUME;
+ break;
+ default:
+ return 0;
+ }
+
+ ret = SendKevent(keventModule, HDF_SYSEVENT_CLASS_POWER, powerEvent, NULL, sync);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: failed to notify userspace pm status");
+ }
+
+ return KernalSpacePmNotify(powerEvent);
+}
+
+static int32_t KeventFbNotifierFn(struct notifier_block *nb, unsigned long event, void *data)
+{
+ int *blank = NULL;
+ struct fb_event *fbEvent = data;
+ struct HdfKeventModule *keventModule = NULL;
+ int32_t powerEvent;
+ bool sync = false;
+ int ret = 0;
+
+ if (event != FB_EVENT_BLANK) {
+ return 0;
+ }
+
+ if (fbEvent == NULL || fbEvent->data == NULL) {
+ return 0;
+ }
+
+ keventModule = CONTAINER_OF(nb, struct HdfKeventModule, fbNotifier);
+ blank = fbEvent->data;
+
+ HDF_LOGI("%s:blank=%d", __func__, *blank);
+ switch (*blank) {
+ case FB_BLANK_UNBLANK:
+ HDF_LOGI("%s:receive display on event", __func__);
+ powerEvent = KEVENT_POWER_DISPLAY_ON;
+ break;
+ default:
+ HDF_LOGI("%s:receive display off event", __func__);
+ powerEvent = KEVENT_POWER_DISPLAY_OFF;
+ sync = true;
+ break;
+ }
+
+ ret = SendKevent(keventModule, HDF_SYSEVENT_CLASS_POWER, powerEvent, NULL, sync);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: failed to notify userspace pm status");
+ }
+
+ return KernalSpacePmNotify(powerEvent);
+}
+
+void CompleteKevent(struct HdfKeventModule *keventModule, struct HdfSBuf *tokenBuffer)
+{
+ uint64_t token = 0;
+ struct HdfKeventWait *wait = NULL;
+
+ if (tokenBuffer == NULL || !HdfSbufReadUint64(tokenBuffer, &token)) {
+ return;
+ }
+
+ OsalMutexLock(&keventModule->mutex);
+ DLIST_FOR_EACH_ENTRY(wait, &keventModule->waitList, struct HdfKeventWait, listNode) {
+ if (token == (uint64_t)wait) {
+ wait->waitCount--;
+ if (wait->waitCount == 0) {
+ complete(&wait->comp);
+ }
+ }
+ }
+ OsalMutexUnlock(&keventModule->mutex);
+}
+
+static int32_t HdfKeventIoServiceDispatch(
+ struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
+{
+ struct HdfKeventModule *keventModule;
+ (void)reply;
+
+ keventModule = (struct HdfKeventModule *)client->device->priv;
+ if (keventModule == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ switch (id) {
+ case KEVENT_COMPLETE_EVENT: {
+ CompleteKevent(keventModule, data);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int32_t HdfKeventDriverOpen(struct HdfDeviceIoClient *client)
+{
+ struct HdfKeventModule *keventModule = NULL;
+ struct HdfKeventClient *kClient = NULL;
+
+ if (client == NULL || client->device == NULL || client->device->priv == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ keventModule = (struct HdfKeventModule *)client->device->priv;
+ kClient = OsalMemCalloc(sizeof(struct HdfKeventClient));
+ if (kClient == NULL) {
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ kClient->ioClient = client;
+ client->priv = kClient;
+
+ OsalMutexLock(&keventModule->clientMutex);
+ DListInsertTail(&kClient->listNode, &keventModule->clientList);
+ keventModule->clientCount++;
+ OsalMutexUnlock(&keventModule->clientMutex);
+
+ HDF_LOGI("%s:kevnet usecount=%d", __func__, keventModule->clientCount);
+ return 0;
+}
+
+static void HdfKeventDriverClose(struct HdfDeviceIoClient *client)
+{
+ struct HdfKeventClient *kClient = NULL;
+ struct HdfKeventModule *keventModule;
+
+ keventModule = (struct HdfKeventModule *)client->device->priv;
+ if (keventModule == NULL) {
+ return;
+ }
+
+ kClient = (struct HdfKeventClient *)client->priv;
+ if (kClient == NULL) {
+ return;
+ }
+
+ OsalMutexLock(&keventModule->clientMutex);
+ DListRemove(&kClient->listNode);
+ keventModule->clientCount--;
+ OsalMemFree(kClient);
+ client->priv = NULL;
+ OsalMutexUnlock(&keventModule->clientMutex);
+
+ HDF_LOGI("%s:kevnet usecount=%d", __func__, keventModule->clientCount);
+}
+
+static void HdfKeventDriverRelease(struct HdfDeviceObject *object)
+{
+ struct HdfKeventModule *keventModule = (struct HdfKeventModule *)object->priv;
+ if (keventModule == NULL) {
+ return;
+ }
+
+ unregister_pm_notifier(&keventModule->keventPmNotifier);
+ fb_unregister_client(&keventModule->keventPmNotifier);
+ OsalMutexDestroy(&keventModule->mutex);
+ OsalMutexDestroy(&keventModule->clientMutex);
+ OsalMemFree(keventModule);
+ object->priv = NULL;
+ return;
+}
+
+static int32_t HdfKeventDriverBind(struct HdfDeviceObject *dev)
+{
+ static struct IDeviceIoService keventService = {
+ .Open = HdfKeventDriverOpen,
+ .Dispatch = HdfKeventIoServiceDispatch,
+ .Release = HdfKeventDriverClose,
+ };
+ struct HdfKeventModule *keventModule = NULL;
+ if (dev == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ keventModule = (struct HdfKeventModule *)OsalMemCalloc(sizeof(struct HdfKeventModule));
+ if (keventModule == NULL) {
+ return HDF_ERR_MALLOC_FAIL;
+ }
+
+ if (OsalMutexInit(&keventModule->mutex) != HDF_SUCCESS) {
+ OsalMemFree(keventModule);
+ return HDF_FAILURE;
+ }
+
+ if (OsalMutexInit(&keventModule->clientMutex) != HDF_SUCCESS) {
+ OsalMutexDestroy(&keventModule->mutex);
+ OsalMemFree(keventModule);
+ return HDF_FAILURE;
+ }
+ DListHeadInit(&keventModule->waitList);
+ DListHeadInit(&keventModule->clientList);
+ keventModule->devObj = dev;
+ dev->priv = keventModule;
+ dev->service = &keventService;
+
+ return HDF_SUCCESS;
+}
+
+static int32_t HdfKeventDriverInit(struct HdfDeviceObject *dev)
+{
+ int32_t ret;
+ struct HdfKeventModule *keventModule = (struct HdfKeventModule *)dev->priv;
+
+ keventModule->keventPmNotifier.notifier_call = KeventPmNotifierFn;
+ ret = register_pm_notifier(&keventModule->keventPmNotifier);
+ if (ret != 0) {
+ HDF_LOGE("%s:failed to register pm notifier %d", __func__, ret);
+ } else {
+ HDF_LOGI("%s:register pm notifier success", __func__);
+ }
+
+ keventModule->fbNotifier.notifier_call = KeventFbNotifierFn;
+ ret = fb_register_client(&keventModule->fbNotifier);
+ if (ret != 0) {
+ HDF_LOGE("%s:failed to register fb notifier %d", __func__, ret);
+ unregister_pm_notifier(&keventModule->keventPmNotifier);
+ } else {
+ HDF_LOGI("%s:register fb notifier success", __func__);
+ }
+
+ g_keventModule = keventModule;
+ return ret;
+}
+
+static struct HdfDriverEntry g_hdfKeventDriverEntry = {
+ .moduleVersion = 1,
+ .moduleName = "HDF_KEVENT",
+ .Bind = HdfKeventDriverBind,
+ .Init = HdfKeventDriverInit,
+ .Release = HdfKeventDriverRelease,
+};
+
+HDF_INIT(g_hdfKeventDriverEntry);
\ No newline at end of file
diff --git a/adapter/khdf/linux/manager/src/sym_export.c b/adapter/khdf/linux/manager/src/sym_export.c
new file mode 100644
index 00000000..2f78eeab
--- /dev/null
+++ b/adapter/khdf/linux/manager/src/sym_export.c
@@ -0,0 +1,45 @@
+/*
+ * sym_export.c
+ *
+ * HDF symbol export file
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+EXPORT_SYMBOL(HdfDeviceSendEvent);
+EXPORT_SYMBOL(HdfDeviceSendEventToClient);
+EXPORT_SYMBOL(HdfDeviceGetServiceName);
+EXPORT_SYMBOL(HdfPmRegisterPowerListener);
+EXPORT_SYMBOL(HdfDeviceObjectAlloc);
+EXPORT_SYMBOL(HdfDeviceObjectRelease);
+EXPORT_SYMBOL(HdfDeviceObjectRegister);
+EXPORT_SYMBOL(HdfDeviceObjectPublishService);
+EXPORT_SYMBOL(HdfDeviceObjectSetServInfo);
+EXPORT_SYMBOL(HdfDeviceObjectUpdate);
+EXPORT_SYMBOL(DevmgrServiceGetInstance);
+EXPORT_SYMBOL(HdfSbufWriteInt32);
+EXPORT_SYMBOL(HdfSbufReadUint32);
+EXPORT_SYMBOL(HdfSbufReadString);
+EXPORT_SYMBOL(HdfUnregisterDriverEntry);
+EXPORT_SYMBOL(HdfRegisterDriverEntry);
+EXPORT_SYMBOL(HdfSbufReadInt32);
diff --git a/adapter/khdf/linux/model/audio/Kconfig b/adapter/khdf/linux/model/audio/Kconfig
new file mode 100644
index 00000000..e1beac5d
--- /dev/null
+++ b/adapter/khdf/linux/model/audio/Kconfig
@@ -0,0 +1,35 @@
+config DRIVERS_HDF_AUDIO
+ bool "Enable HDF Audio driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to choice HDF Audio driver.
+config DRIVERS_HDF_AUDIO_HI3516CODEC
+ bool "Enable HDF Audio Codec driver"
+ default n
+ depends on DRIVERS_HDF_AUDIO
+ help
+ Answer Y to choice HDF Audio Codec driver.
+
+config DRIVERS_HDF_AUDIO_RK3568
+ bool "Enable HDF Audio Codec driver"
+ default n
+ depends on DRIVERS_HDF_AUDIO
+ help
+ Answer Y to choice HDF Audio Codec driver.
+
+config DRIVERS_HDF_AUDIO_ANA_HEADSET
+ bool "Audio Headset support"
+ default n
+ depends on DRIVERS_HDF_AUDIO_RK3568
+ help
+ Audio Headset support:
+ support hook interrupt mode.
+ support hook adc mode.
+
+config DRIVERS_HDF_AUDIO_TEST
+ bool "Enable HDF Audio driver Test"
+ default n
+ depends on DRIVERS_HDF_AUDIO
+ help
+ Answer Y to choice HDF Audio driver Test.
diff --git a/adapter/khdf/linux/model/audio/Makefile b/adapter/khdf/linux/model/audio/Makefile
new file mode 100644
index 00000000..b1c01bfb
--- /dev/null
+++ b/adapter/khdf/linux/model/audio/Makefile
@@ -0,0 +1,101 @@
+#
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+KHDF_AUDIO_BASE_ROOT_DIR = ../../../../../../..
+KHDF_AUDIO_KHDF_ROOT_DIR = drivers/hdf/khdf
+KHDF_FRAMEWORK_ROOT_DIR = drivers/hdf/framework
+KHDF_AUDIO_ROOT_DIR = ../../../../../framework/model/audio
+KHDF_AUDIO_HI3516DV300_DIR = $(KHDF_AUDIO_BASE_ROOT_DIR)/device/board/hisilicon/hispark_taurus/audio_drivers
+KHDF_AUDIO_HI3516DV300_INC_DIR = drivers/hdf/framework/../../../device/board/hisilicon/hispark_taurus/audio_drivers
+KHDF_AUDIO_RK3568_DIR = $(KHDF_AUDIO_BASE_ROOT_DIR)/device/board/hihope/$(DEVICE_NAME)/audio_drivers
+KHDF_AUDIO_RK3568_INC_DIR = drivers/hdf/framework/../../../device/board/hihope/$(DEVICE_NAME)/audio_drivers
+
+obj-$(CONFIG_DRIVERS_HDF_AUDIO) += \
+ $(KHDF_AUDIO_ROOT_DIR)/core/src/audio_core.o \
+ $(KHDF_AUDIO_ROOT_DIR)/core/src/audio_host.o \
+ $(KHDF_AUDIO_ROOT_DIR)/core/src/audio_parse.o \
+ $(KHDF_AUDIO_ROOT_DIR)/common/src/audio_codec_base.o \
+ $(KHDF_AUDIO_ROOT_DIR)/common/src/audio_dsp_base.o \
+ $(KHDF_AUDIO_ROOT_DIR)/common/src/audio_dai_base.o \
+ $(KHDF_AUDIO_ROOT_DIR)/common/src/audio_platform_base.o \
+ $(KHDF_AUDIO_ROOT_DIR)/common/src/audio_dma_base.o \
+ $(KHDF_AUDIO_ROOT_DIR)/sapm/src/audio_sapm.o \
+ $(KHDF_AUDIO_ROOT_DIR)/dispatch/src/audio_stream_dispatch.o \
+ $(KHDF_AUDIO_ROOT_DIR)/dispatch/src/audio_control_dispatch.o
+
+obj-$(CONFIG_DRIVERS_HDF_AUDIO_HI3516CODEC) += \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/codec/tfa9879/src/tfa9879_codec_adapter.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/codec/tfa9879/src/tfa9879_codec_ops.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_adapter.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_impl.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/codec/hi3516/src/hi3516_codec_ops.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/dsp/src/dsp_adapter.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/dsp/src/dsp_ops.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_adapter.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dai_ops.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_aiao_impl.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_ops.o \
+ $(KHDF_AUDIO_HI3516DV300_DIR)/soc/src/hi3516_dma_adapter.o
+
+obj-$(CONFIG_DRIVERS_HDF_AUDIO_RK3568) += \
+ $(KHDF_AUDIO_RK3568_DIR)/codec/rk809_codec/src/rk809_codec_adapter.o \
+ $(KHDF_AUDIO_RK3568_DIR)/codec/rk809_codec/src/rk809_codec_impl.o \
+ $(KHDF_AUDIO_RK3568_DIR)/codec/rk809_codec/src/rk809_codec_linux_driver.o \
+ $(KHDF_AUDIO_RK3568_DIR)/dsp/src/rk3568_dsp_adapter.o \
+ $(KHDF_AUDIO_RK3568_DIR)/dsp/src/rk3568_dsp_ops.o \
+ $(KHDF_AUDIO_RK3568_DIR)/dai/src/rk3568_dai_adapter.o \
+ $(KHDF_AUDIO_RK3568_DIR)/dai/src/rk3568_dai_ops.o \
+ $(KHDF_AUDIO_RK3568_DIR)/dai/src/rk3568_dai_linux_driver.o \
+ $(KHDF_AUDIO_RK3568_DIR)/soc/src/rk3568_dma_adapter.o \
+ $(KHDF_AUDIO_RK3568_DIR)/soc/src/rk3568_dma_ops.o
+
+obj-$(CONFIG_DRIVERS_HDF_AUDIO_ANA_HEADSET) += \
+ $(KHDF_AUDIO_RK3568_DIR)/headset_monitor/src/analog_headset_base.o \
+ $(KHDF_AUDIO_RK3568_DIR)/headset_monitor/src/analog_headset_core.o \
+ $(KHDF_AUDIO_RK3568_DIR)/headset_monitor/src/analog_headset_gpio.o \
+ $(KHDF_AUDIO_RK3568_DIR)/headset_monitor/src/analog_headset_adc.o
+
+ccflags-$(CONFIG_DRIVERS_HDF_AUDIO) += -lm -lc -lgcc -std=gnu99 -Werror\
+ -I$(srctree)/$(KHDF_AUDIO_KHDF_ROOT_DIR)/osal/include \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/include/core \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/include/utils \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/include/osal \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/include/platform \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/include/config \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/include/audio \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/ability/sbuf/include \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/core/common/include/host \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/core/host/include \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/model/audio/core/include \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/model/audio/sapm/include \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/model/audio/dispatch/include \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/model/audio/common/include \
+ -I$(srctree)/bounds_checking_function/include
+
+ccflags-$(CONFIG_DRIVERS_HDF_AUDIO_HI3516CODEC) += \
+ -I$(srctree)/$(KHDF_AUDIO_HI3516DV300_INC_DIR)/codec/hi3516/include \
+ -I$(srctree)/$(KHDF_AUDIO_HI3516DV300_INC_DIR)/soc/include \
+ -I$(srctree)/$(KHDF_AUDIO_HI3516DV300_INC_DIR)/dsp/include \
+ -I$(srctree)/$(KHDF_AUDIO_HI3516DV300_INC_DIR)/codec/tfa9879/include
+
+ccflags-$(CONFIG_DRIVERS_HDF_AUDIO_RK3568) += \
+ -I$(srctree)/$(KHDF_AUDIO_RK3568_INC_DIR)/soc/include \
+ -I$(srctree)/$(KHDF_AUDIO_RK3568_INC_DIR)/dai/include \
+ -I$(srctree)/$(KHDF_AUDIO_RK3568_INC_DIR)/dsp/include \
+ -I$(srctree)/$(KHDF_AUDIO_RK3568_INC_DIR)/codec/rk809_codec/include \
+ -I$(srctree)/$(KHDF_AUDIO_RK3568_INC_DIR)/include
+
+ccflags-$(CONFIG_DRIVERS_HDF_AUDIO_ANA_HEADSET) += \
+ -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/model/input/driver \
+ -I$(srctree)/drivers/hdf/evdev \
+ -I$(srctree)/$(KHDF_AUDIO_RK3568_INC_DIR)/headset_monitor/include
diff --git a/adapter/khdf/linux/model/display/Kconfig b/adapter/khdf/linux/model/display/Kconfig
new file mode 100644
index 00000000..ad06d9fb
--- /dev/null
+++ b/adapter/khdf/linux/model/display/Kconfig
@@ -0,0 +1,24 @@
+config DRIVERS_HDF_DISP
+ bool "Enable HDF Display driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to choice HDF Display driver.
+config DRIVERS_HDF_LCDKIT
+ bool "Enable HDF Lcdkit driver"
+ default n
+ depends on DRIVERS_HDF_DISP
+ help
+ Answer Y to enable HDF Lcdkit driver.
+config DRIVERS_HDF_LCD_ICN9700
+ bool "Enable HDF Icn9700 driver"
+ default n
+ depends on DRIVERS_HDF_DISP
+ help
+ Answer Y to enable HDF Icn9700 driver.
+config DRIVERS_HDF_LCD_ST7789
+ bool "Enable HDF St7789 driver"
+ default n
+ depends on DRIVERS_HDF_DISP
+ help
+ Answer Y to enable HDF St7789 driver.
diff --git a/adapter/khdf/linux/model/display/Makefile b/adapter/khdf/linux/model/display/Makefile
new file mode 100644
index 00000000..5681b621
--- /dev/null
+++ b/adapter/khdf/linux/model/display/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+DISPLAY_ROOT_DIR = ../../../../../framework/model/display/driver
+
+ifeq ($(CONFIG_DRIVERS_HDF_DISP), y)
+obj-y += \
+ $(DISPLAY_ROOT_DIR)/hdf_disp.o \
+ $(DISPLAY_ROOT_DIR)/backlight/hdf_bl.o
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
+ifeq ($(CONFIG_ARCH_ROCKCHIP), y)
+obj-y += $(DISPLAY_ROOT_DIR)/hdf_drm_panel.o
+endif
+#endif
+
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_PWM) += \
+ $(DISPLAY_ROOT_DIR)/backlight/pwm_bl.o
+
+obj-$(CONFIG_ARCH_SPRD) += \
+ $(DISPLAY_ROOT_DIR)/panel/ili9881c_boe.o
+
+obj-$(CONFIG_ARCH_HI3516DV300) += \
+ $(DISPLAY_ROOT_DIR)/adapter_soc/hi35xx_disp.o
+
+obj-$(CONFIG_DRIVERS_HDF_LCDKIT) += \
+ $(DISPLAY_ROOT_DIR)/lcdkit/lite_lcdkit.o \
+ $(DISPLAY_ROOT_DIR)/lcdkit/lcdkit_parse_config.o
+obj-$(CONFIG_DRIVERS_HDF_LCD_ICN9700) += \
+ $(DISPLAY_ROOT_DIR)/panel/mipi_icn9700.o
+obj-$(CONFIG_DRIVERS_HDF_LCD_ST7789) += \
+ $(DISPLAY_ROOT_DIR)/panel/ssp_st7789.o
+obj-$(CONFIG_ARCH_ROCKCHIP) += \
+ $(DISPLAY_ROOT_DIR)/panel/ili9881_st_5p5.o
+
+ccflags-y += -lm -lc -lgcc \
+ -I$(srctree)/drivers/hdf/framework/model/display/driver \
+ -I$(srctree)/drivers/hdf/framework/model/display/driver/adapter_soc \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/model/display/driver/backlight \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/include \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/include/linux \
+ -I$(srctree)/include/drm
+ccflags-y +=-I$(srctree)/bounds_checking_function/include
+
+endif
\ No newline at end of file
diff --git a/adapter/khdf/linux/model/input/Kconfig b/adapter/khdf/linux/model/input/Kconfig
new file mode 100644
index 00000000..7257f0b0
--- /dev/null
+++ b/adapter/khdf/linux/model/input/Kconfig
@@ -0,0 +1,20 @@
+config DRIVERS_HDF_INPUT
+ bool "Enable HDF input driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to enable HDF input driver.
+
+config DRIVERS_HDF_TP_5P5_GT911
+ bool "Enable HDF tp 5P5 GT911 driver"
+ default n
+ depends on DRIVERS_HDF_INPUT
+ help
+ Answer Y to enable HDF TP 5P5 GT911 driver.
+
+config DRIVERS_HDF_TP_2P35_FT6236
+ bool "Enable HDF tp 2P35 FT6236 driver"
+ default n
+ depends on DRIVERS_HDF_INPUT
+ help
+ Answer Y to enable HDF TP 2P35 FT6236 driver.
diff --git a/adapter/khdf/linux/model/input/Makefile b/adapter/khdf/linux/model/input/Makefile
new file mode 100644
index 00000000..52eae07c
--- /dev/null
+++ b/adapter/khdf/linux/model/input/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+INPUT_ROOT_DIR = ../../../../../framework/model/input/driver
+
+obj-$(CONFIG_DRIVERS_HDF_INPUT) += \
+ $(INPUT_ROOT_DIR)/input_bus_ops/input_i2c_ops.o \
+ $(INPUT_ROOT_DIR)/hdf_input_device_manager.o \
+ $(INPUT_ROOT_DIR)/input_config_parser.o \
+ $(INPUT_ROOT_DIR)/event_hub.o \
+ $(INPUT_ROOT_DIR)/hdf_touch.o \
+ $(INPUT_ROOT_DIR)/hdf_key.o \
+ $(INPUT_ROOT_DIR)/hdf_hid_adapter.o
+
+obj-$(CONFIG_DRIVERS_HDF_TP_5P5_GT911) += \
+ $(INPUT_ROOT_DIR)/touchscreen/touch_gt911.o
+obj-$(CONFIG_DRIVERS_HDF_TP_2P35_FT6236) += \
+ $(INPUT_ROOT_DIR)/touchscreen/touch_ft6336.o
+
+ccflags-y +=-I$(srctree)/drivers/hdf/framework/model/input/driver \
+ -I$(srctree)/drivers/hdf/framework/model/input/driver/input_bus_ops \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/framework/core/host/include \
+ -I$(srctree)/drivers/hdf/framework/core/shared/include \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include
+ccflags-y +=-I$(srctree)/bounds_checking_function/include \
+ -I$(srctree)/drivers/hdf/evdev
diff --git a/adapter/khdf/linux/model/misc/dsoftbus/Kconfig b/adapter/khdf/linux/model/misc/dsoftbus/Kconfig
new file mode 100644
index 00000000..5c8e3aef
--- /dev/null
+++ b/adapter/khdf/linux/model/misc/dsoftbus/Kconfig
@@ -0,0 +1,24 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+config DRIVERS_HDF_DSOFTBUS
+ bool "Enable HDF dsoftbus driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ control HDF dsoftbus driver capability.
+
+config DSOFTBUS_WLAN_PARAM_MONITOR
+ bool "enable dsoftbus wlan parameter monitor"
+ default n
+ depends on DRIVERS_HDF_DSOFTBUS
+ help
+ control hdf dsoftbus wlan parameter monitor capability.
\ No newline at end of file
diff --git a/adapter/khdf/linux/model/misc/dsoftbus/Makefile b/adapter/khdf/linux/model/misc/dsoftbus/Makefile
new file mode 100644
index 00000000..f3e99309
--- /dev/null
+++ b/adapter/khdf/linux/model/misc/dsoftbus/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+DSOFTBUS_ROOT_DIR = ../../../../../../framework/model/misc/dsoftbus
+
+obj-$(CONFIG_DRIVERS_HDF_DSOFTBUS) += \
+ $(DSOFTBUS_ROOT_DIR)/src/hdf_dsoftbus_driver.o \
+ $(DSOFTBUS_ROOT_DIR)/src/module_manager.o
+ifeq ($(CONFIG_DSOFTBUS_WLAN_PARAM_MONITOR), y)
+obj-$(CONFIG_DRIVERS_HDF_DSOFTBUS) += $(DSOFTBUS_ROOT_DIR)/src/wlan_param_monitor.o
+ccflags-$(CONFIG_DRIVERS_HDF_DSOFTBUS) +=-DENABLE_WLAN_PARAM_MONITOR
+endif
+
+ccflags-y +=-I$(srctree)/drivers/hdf/framework/model/misc/dsoftbus/include \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/framework/core/host/include \
+ -I$(srctree)/drivers/hdf/framework/core/shared/include \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/model/misc/light/Kconfig b/adapter/khdf/linux/model/misc/light/Kconfig
new file mode 100755
index 00000000..b03ec308
--- /dev/null
+++ b/adapter/khdf/linux/model/misc/light/Kconfig
@@ -0,0 +1,17 @@
+# Copyright (c) 2022 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+config DRIVERS_HDF_LIGHT
+ bool "Enable HDF light driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to enable HDF light driver.
\ No newline at end of file
diff --git a/adapter/khdf/linux/model/misc/light/Makefile b/adapter/khdf/linux/model/misc/light/Makefile
new file mode 100755
index 00000000..08d35288
--- /dev/null
+++ b/adapter/khdf/linux/model/misc/light/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2022 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+LIGHT_ROOT_DIR = ../../../../../../framework/model/misc/light/driver
+
+obj-$(CONFIG_DRIVERS_HDF_LIGHT) += \
+ $(LIGHT_ROOT_DIR)/src/light_driver.o
+
+ccflags-y +=-I$(srctree)/drivers/hdf/framework/model/misc/light/driver/include \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/framework/core/host/include \
+ -I$(srctree)/drivers/hdf/framework/core/shared/include \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/model/misc/vibrator/Kconfig b/adapter/khdf/linux/model/misc/vibrator/Kconfig
new file mode 100644
index 00000000..62045f15
--- /dev/null
+++ b/adapter/khdf/linux/model/misc/vibrator/Kconfig
@@ -0,0 +1,25 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+config DRIVERS_HDF_VIBRATOR
+ bool "Enable HDF vibrator driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to enable HDF vibrator driver.
+
+config DRIVERS_HDF_VIBRATOR_LINEAR
+ bool "Enable HDF linear vibrator driver"
+ default n
+ depends on DRIVERS_HDF_VIBRATOR
+ help
+ Answer Y to enable HDF linear vibrator driver.
+
diff --git a/adapter/khdf/linux/model/misc/vibrator/Makefile b/adapter/khdf/linux/model/misc/vibrator/Makefile
new file mode 100644
index 00000000..d22cb4e8
--- /dev/null
+++ b/adapter/khdf/linux/model/misc/vibrator/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2022 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+VIBRATOR_ROOT_DIR = ../../../../../../../hdf_core/framework/model/misc/vibrator/driver
+VIBRATOR_ROOT_CHIPSET = ../../../../../../../peripheral/misc/vibrator
+
+obj-$(CONFIG_DRIVERS_HDF_VIBRATOR) += \
+ $(VIBRATOR_ROOT_DIR)/src/vibrator_driver.o \
+ $(VIBRATOR_ROOT_DIR)/src/vibrator_haptic.o
+obj-$(CONFIG_DRIVERS_HDF_VIBRATOR_LINEAR) += \
+ $(VIBRATOR_ROOT_CHIPSET)/chipset/vibrator_linear_driver.o
+
+
+ccflags-y +=-I$(srctree)/drivers/hdf/framework/model/misc/vibrator/driver/include \
+ -I$(srctree)/drivers/hdf/peripheral/misc/vibrator/chipset \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/framework/core/host/include \
+ -I$(srctree)/drivers/hdf/framework/core/shared/include \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/model/network/bluetooth/Kconfig b/adapter/khdf/linux/model/network/bluetooth/Kconfig
new file mode 100644
index 00000000..b9f2fecc
--- /dev/null
+++ b/adapter/khdf/linux/model/network/bluetooth/Kconfig
@@ -0,0 +1,7 @@
+config DRIVERS_HDF_BT
+ bool "Enable HDF Bluetooth"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to enable HDF bluetooth.
+
diff --git a/adapter/khdf/linux/model/network/bluetooth/Makefile b/adapter/khdf/linux/model/network/bluetooth/Makefile
new file mode 100644
index 00000000..faf8209c
--- /dev/null
+++ b/adapter/khdf/linux/model/network/bluetooth/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+MODULE_NAME := hdf_bt_model
+
+include drivers/hdf/khdf/model/network/bluetooth/env_config.mk
+
+HDF_BT_FRAMEWORKS_ROOT := ../../../../../../framework/model/network/bluetooth
+
+obj-$(CONFIG_DRIVERS_HDF_BT) += $(MODULE_NAME).o
+$(MODULE_NAME)-objs := $(HDF_BT_FRAMEWORKS_ROOT)/hdf_bt_core.o \
+ $(HDF_BT_FRAMEWORKS_ROOT)/hdf_chip.o \
+ $(HDF_BT_FRAMEWORKS_ROOT)/hdf_reset.o \
+ $(HDF_BT_FRAMEWORKS_ROOT)/hdf_power.o
+
+ccflags-$(CONFIG_DRIVERS_HDF_BT) += \
+ $(HDF_FRAMEWORKS_INC) \
+ $(HDF_BT_FRAMEWORKS_INC) \
+ $(SECURE_LIB_INC)
+
diff --git a/adapter/khdf/linux/model/network/bluetooth/env_config.mk b/adapter/khdf/linux/model/network/bluetooth/env_config.mk
new file mode 100644
index 00000000..755c8e96
--- /dev/null
+++ b/adapter/khdf/linux/model/network/bluetooth/env_config.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+HDF_FRAMEWORKS_INC := \
+ -I$(srctree)/./ \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/core/host/include \
+ -I$(srctree)/drivers/hdf/framework/core/manager/include \
+ -I$(srctree)/drivers/hdf/framework/core/shared/include \
+ -I$(srctree)/drivers/hdf/framework/include \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/support/platform/include \
+ -I$(srctree)/drivers/hdf/framework/support/platform/include/platform \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/drivers/hdf/khdf/config/include \
+ -I$(srctree)/include/hdf \
+ -I$(srctree)/include/hdf/osal \
+ -I$(srctree)/include/hdf/utils \
+ -I$(srctree)/drivers/hdf/framework/include/bluetooth
+
+HDF_BT_FRAMEWORKS_INC := \
+ -I$(srctree)/drivers/hdf/framework/model/network/bluetooth
+
+SECURE_LIB_INC := \
+ -I$(srctree)/bounds_checking_function/include
\ No newline at end of file
diff --git a/adapter/khdf/linux/model/network/wifi/Kconfig b/adapter/khdf/linux/model/network/wifi/Kconfig
new file mode 100644
index 00000000..207b2c5e
--- /dev/null
+++ b/adapter/khdf/linux/model/network/wifi/Kconfig
@@ -0,0 +1,53 @@
+config DRIVERS_HDF_WIFI
+ bool "Enable HDF wifi"
+ default n
+ depends on DRIVERS_HDF && DRIVERS_HDF_PLATFORM_SDIO
+ help
+ Answer Y to enable HDF wifi.
+
+config DRIVERS_HDF_WLAN_SDIO
+ bool "Enable HDF wlan sdio bus"
+ default n
+ depends on DRIVERS_HDF_WIFI
+ help
+ Answer Y to support HDF wlan sdio bus
+
+config DRIVERS_HDF_WLAN_USB
+ bool "Enable HDF wlan usb bus"
+ default n
+ depends on DRIVERS_HDF_WIFI
+ help
+ Answer Y to support HDF wlan usb bus
+
+config DRIVERS_HI3881
+ bool "Enable hi3881"
+ default n
+ depends on DRIVERS_HDF_WIFI
+ help
+ Answer Y to enable hi3881 wifi chip driver.
+
+config DRIVERS_HDF_NETDEV_EXT
+ bool "Get Linux net device from HDF"
+ default n
+ help
+ Get Linux net device from HDF
+
+config DRIVERS_RTL8723DU
+ bool "Enable Realtek 8723D USB WiFi(rtl8723du)"
+ default n
+ depends on DRIVERS_HDF_WIFI
+ select DRIVERS_HDF_WLAN_USB
+ select DRIVERS_HDF_NETDEV_EXT
+ help
+ Answer Y to enable rtl8723du wifi chip driver.
+
+config AP6XXX_WIFI6_HDF
+ tristate "support ap6xxx wifi6(80211ax) HDF"
+ depends on DRIVERS_HDF_WIFI
+ select CFG80211
+ select MAC80211
+ select DRIVERS_HDF_NETDEV_EXT
+ help
+ This driver supports wifi6 for ap6xxx HDF chipset.
+ This driver uses the kernel's wireless extensions subsystem.
+ If you choose to build a module, it'll be called dhd. Say M if unsure.
diff --git a/adapter/khdf/linux/model/network/wifi/Makefile b/adapter/khdf/linux/model/network/wifi/Makefile
new file mode 100644
index 00000000..f14323d6
--- /dev/null
+++ b/adapter/khdf/linux/model/network/wifi/Makefile
@@ -0,0 +1,76 @@
+#
+# Copyright (c) 2020-2022 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+MODULE_NAME := hdf_wifi_model
+
+HDF_DIR_PREFIX := ../../../../../../
+
+include drivers/hdf/khdf/model/network/wifi/hdfwifi.mk
+
+WAP_PATH := core/components/softap
+WSTA_PATH := core/components/sta
+WP2P_PATH := core/components/p2p
+WEAPOL_PATH := core/components/eapol
+NETDEV_PATH := ../common/netdevice
+MODULE_PATH := core/module
+QOS_PATH := platform/src/qos
+MESSAGE_PATH := platform/src/message
+PLATFORM_PATH := platform/src
+CORE_PATH := core
+IBUS_PATH := bus
+
+obj-$(CONFIG_DRIVERS_HDF_WIFI) += $(MODULE_NAME).o
+$(MODULE_NAME)-objs := $(HDF_WIFI_FRAMEWORKS_ROOT)/$(WAP_PATH)/ap.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(WEAPOL_PATH)/eapol.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(WSTA_PATH)/sta.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(WP2P_PATH)/p2p.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(NETDEV_PATH)/net_device.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(MODULE_PATH)/wifi_module.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(MODULE_PATH)/wifi_base.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(MODULE_PATH)/wifi_feature.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(CORE_PATH)/hdf_wifi_core.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(QOS_PATH)/flow_control.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(QOS_PATH)/flow_control_task.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(MESSAGE_PATH)/nodes/local_node.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(MESSAGE_PATH)/message_dispatcher.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(MESSAGE_PATH)/message_router.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(MESSAGE_PATH)/sidecar.o \
+ $(HDF_WIFI_KHDF_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wlan_queue.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wlan_priority_queue.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wifi_event.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wlan_chipdriver_manager.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wlan_config_parser.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wlan_power_manager.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wlan_product.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wlan_reset_manager.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(PLATFORM_PATH)/hdf_wlan_utils.o \
+ $(HDF_WIFI_FRAMEWORKS_ROOT)/$(IBUS_PATH)/hdf_ibus_intf.o \
+
+$(MODULE_NAME)-$(CONFIG_DRIVERS_HDF_WLAN_SDIO) += $(HDF_WIFI_FRAMEWORKS_ROOT)/$(IBUS_PATH)/hdf_sdio_intf.o
+$(MODULE_NAME)-$(CONFIG_DRIVERS_HDF_WLAN_USB) += $(HDF_WIFI_FRAMEWORKS_ROOT)/$(IBUS_PATH)/hdf_usb_intf.o
+
+ccflags-$(CONFIG_DRIVERS_HDF_WIFI) += \
+ $(HDF_FRAMEWORKS_INC) \
+ $(HDF_WIFI_FRAMEWORKS_INC) \
+ $(HDF_WIFI_ADAPTER_INC) \
+ $(SECURE_LIB_INC)
+
+HDF_WIFI_FLAGS +=-D_PRE_OS_VERSION_LINUX=1
+HDF_WIFI_FLAGS +=-D_PRE_OS_VERSION_LITEOS=2
+HDF_WIFI_FLAGS +=-D_PRE_OS_VERSION=_PRE_OS_VERSION_LINUX
+
+ccflags-$(CONFIG_DRIVERS_HDF_WIFI) += $(HDF_WIFI_FLAGS)
+
+obj-$(CONFIG_DRIVERS_HDF_WIFI) += vendor/
+
diff --git a/adapter/khdf/linux/model/network/wifi/hdfwifi.mk b/adapter/khdf/linux/model/network/wifi/hdfwifi.mk
new file mode 100755
index 00000000..2be27ef5
--- /dev/null
+++ b/adapter/khdf/linux/model/network/wifi/hdfwifi.mk
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+HDF_WIFI_FRAMEWORKS_ROOT = $(HDF_DIR_PREFIX)/framework/model/network/wifi
+HDF_WIFI_KHDF_FRAMEWORKS_ROOT = $(HDF_DIR_PREFIX)/adapter/khdf/linux/model/network/wifi
+HDF_FRAMEWORKS_INC := \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/core/host/include \
+ -I$(srctree)/drivers/hdf/framework/core/manager/include \
+ -I$(srctree)/drivers/hdf/framework/core/shared/include \
+ -I$(srctree)/drivers/hdf/framework/include \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/support/platform/include \
+ -I$(srctree)/drivers/hdf/framework/support/platform/include/platform \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/drivers/hdf/khdf/config/include \
+ -I$(srctree)/include/hdf \
+ -I$(srctree)/include/hdf/osal \
+ -I$(srctree)/include/hdf/utils
+
+HDF_WIFI_FRAMEWORKS_INC := \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/core/components/eapol \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/core/components/softap \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/core/components/sta \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/core/components/p2p \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/include \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/core \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/core/module \
+ -I$(srctree)/drivers/hdf/framework/model/network/common/netdevice \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/platform/include \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/platform/include/message \
+ -I$(srctree)/drivers/hdf/framework/model/network/wifi/client/include \
+ -I$(srctree)/drivers/hdf/framework/include/wifi \
+ -I$(srctree)/drivers/hdf/framework/include/net \
+ -I$(srctree)/drivers/hdf/frameworks/model/network/wifi/bus
+
+HDF_WIFI_ADAPTER_INC := \
+ -I$(srctree)/drivers/hdf/khdf/network/include
+
+HDF_WIFI_VENDOR_INC := \
+ -I$(srctree)/drivers/hdf/wifi
+
+SECURE_LIB_INC := \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/model/network/wifi/platform/src/hdf_wlan_queue.c b/adapter/khdf/linux/model/network/wifi/platform/src/hdf_wlan_queue.c
new file mode 100644
index 00000000..eb88be8d
--- /dev/null
+++ b/adapter/khdf/linux/model/network/wifi/platform/src/hdf_wlan_queue.c
@@ -0,0 +1,136 @@
+/*
+ * hdf_wlan_queue.c
+ *
+ * wlan queue of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "hdf_wlan_queue.h"
+#include "hdf_base.h"
+#include "hdf_log.h"
+#include "osal_mem.h"
+#include "osal_mutex.h"
+
+typedef struct {
+ HdfWlanQueue base;
+ OSAL_DECLARE_MUTEX(lock);
+ uint16_t elementCount;
+ uint16_t maxElements;
+ uint16_t tailIndex;
+ uint16_t headIndex;
+ void *elements[0];
+} HdfWlanQueueImpl;
+
+#define MAX_QUEUE_SIZE 30000
+
+HdfWlanQueue *CreateQueue(uint16_t maxQueueSize)
+{
+ int32_t ret;
+ HdfWlanQueueImpl *impl = NULL;
+ if (maxQueueSize > MAX_QUEUE_SIZE) {
+ HDF_LOGE("%s:Max queue size is %d", __func__, MAX_QUEUE_SIZE);
+ return NULL;
+ }
+ impl = OsalMemCalloc(sizeof(HdfWlanQueueImpl) + (sizeof(void *) * maxQueueSize));
+ if (impl == NULL) {
+ HDF_LOGE("%s:oom", __func__);
+ return NULL;
+ }
+ impl->maxElements = maxQueueSize;
+ ret = OsalMutexInit(&impl->lock);
+ if (ret != HDF_SUCCESS) {
+ OsalMemFree(impl);
+ return NULL;
+ }
+ return (HdfWlanQueue*)impl;
+}
+
+void DestroyQueue(HdfWlanQueue *queue)
+{
+ int32_t ret;
+ HdfWlanQueueImpl *impl = NULL;
+ if (queue == NULL) {
+ return;
+ }
+ impl = (HdfWlanQueueImpl *)queue;
+ ret = OsalMutexDestroy(&impl->lock);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: OsalSpinDestroy failed!ret=%d", __func__, ret);
+ }
+ OsalMemFree(impl);
+}
+
+void *PopQueue(HdfWlanQueue *queue)
+{
+ int32_t ret;
+ HdfWlanQueueImpl *impl = NULL;
+ void *result = NULL;
+ if (queue == NULL) {
+ return NULL;
+ }
+ impl = (HdfWlanQueueImpl *)queue;
+ if (queue == NULL) {
+ return NULL;
+ }
+ ret = OsalMutexLock(&impl->lock);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s:Get lock failed!ret=%d", __func__, ret);
+ return NULL;
+ }
+ if (impl->elementCount > 0) {
+ uint16_t headIndex = impl->headIndex;
+ result = impl->elements[headIndex++];
+ impl->headIndex = ((headIndex >= impl->maxElements) ? 0 : headIndex);
+ impl->elementCount--;
+ }
+ ret = OsalMutexUnlock(&impl->lock);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s:Release lock failed!ret=%d", __func__, ret);
+ }
+ return result;
+}
+
+int32_t PushQueue(HdfWlanQueue *queue, void *context)
+{
+ int32_t ret;
+ HdfWlanQueueImpl *impl = NULL;
+ uint16_t tailIndex;
+ if (queue == NULL) {
+ return HDF_FAILURE;
+ }
+ impl = (HdfWlanQueueImpl *)queue;
+ ret = OsalMutexLock(&impl->lock);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s:Get lock failed!ret=%d", __func__, ret);
+ return HDF_FAILURE;
+ }
+ do {
+ if (impl->elementCount >= impl->maxElements) {
+ HDF_LOGE("%s:queue full!", __func__);
+ ret = HDF_FAILURE;
+ break;
+ }
+
+ tailIndex = impl->tailIndex;
+ /* Saves the address of the element in the queue */
+ impl->elements[tailIndex++] = context;
+ impl->tailIndex = ((tailIndex >= impl->maxElements) ? 0 : tailIndex);
+ impl->elementCount++;
+ } while (false);
+ ret = OsalMutexUnlock(&impl->lock);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s:Release lock failed!ret=%d", __func__, ret);
+ }
+ return ret;
+}
diff --git a/adapter/khdf/linux/model/network/wifi/vendor/Makefile b/adapter/khdf/linux/model/network/wifi/vendor/Makefile
new file mode 100644
index 00000000..89f80dc6
--- /dev/null
+++ b/adapter/khdf/linux/model/network/wifi/vendor/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2020-2022 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+MODULE_NAME := hdf_vendor_wifi
+
+HDF_VENDOR_PREFIX := ../../../../../../../../
+
+include drivers/hdf/khdf/model/network/wifi/hdfwifi.mk
+
+obj-$(CONFIG_DRIVERS_HI3881) += hi3881/
+
+ifneq ($(CONFIG_AP6XXX_WIFI6_HDF),)
+RKWIFI_PATH := $(HDF_VENDOR_PREFIX)/device/board/$(PRODUCT_COMPANY)/$(DEVICE_NAME)/wifi
+obj-$(CONFIG_AP6XXX_WIFI6_HDF) += $(RKWIFI_PATH)/
+endif
+
+ifneq ($(CONFIG_DRIVERS_RTL8723DU),)
+obj-$(CONFIG_DRIVERS_RTL8723DU) += $(HDF_VENDOR_PREFIX)/$(KERNEL_SRC_DIR)/drivers/net/wireless/rtl/
+endif
diff --git a/adapter/khdf/linux/model/network/wifi/vendor/hi3881/Makefile b/adapter/khdf/linux/model/network/wifi/vendor/hi3881/Makefile
new file mode 100644
index 00000000..ad5bd4af
--- /dev/null
+++ b/adapter/khdf/linux/model/network/wifi/vendor/hi3881/Makefile
@@ -0,0 +1,122 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+MODULE_NAME := hi3881
+
+HDF_VENDOR_PREFIX := ../../../../../../../../../../
+
+include drivers/hdf/khdf/model/network/wifi/hdfwifi.mk
+
+INC_TOP_PATH := drivers/hdf/wifi/hi3881v100/
+VENDOR_WIFI_PATH := device/soc/hisilicon/common/platform/wifi/hi3881v100
+WIFI_DRIVER_DIR := driver
+HDF_WIFI_VENDOR_ROOT = $(HDF_VENDOR_PREFIX)/device/soc/hisilicon/common/platform/wifi/hi3881v100
+
+##################path of compile file :start###############
+#####wifi#####
+OAL_PATH := $(HDF_WIFI_VENDOR_ROOT)/$(WIFI_DRIVER_DIR)/oal/
+OAM_PATH := $(HDF_WIFI_VENDOR_ROOT)/$(WIFI_DRIVER_DIR)/oam/
+FRW_PATH := $(HDF_WIFI_VENDOR_ROOT)/$(WIFI_DRIVER_DIR)/frw/
+MAC_PATH := $(HDF_WIFI_VENDOR_ROOT)/$(WIFI_DRIVER_DIR)/mac/common/
+HMAC_PATH := $(HDF_WIFI_VENDOR_ROOT)/$(WIFI_DRIVER_DIR)/mac/hmac/
+HCC_PATH := $(HDF_WIFI_VENDOR_ROOT)/$(WIFI_DRIVER_DIR)/hcc/
+WAL_PATH := $(HDF_WIFI_VENDOR_ROOT)/$(WIFI_DRIVER_DIR)/wal/
+ADPATER_PATH := $(HDF_WIFI_VENDOR_ROOT)/$(WIFI_DRIVER_DIR)/hdfadapt/
+##################path of compile file :end###############
+
+ccflags-$(CONFIG_DRIVERS_HDF_WIFI) += \
+ $(HDF_FRAMEWORKS_INC) \
+ $(HDF_WIFI_FRAMEWORKS_INC) \
+ $(HDF_WIFI_ADAPTER_INC) \
+ $(HDF_WIFI_VENDOR_INC)/hi3881v100/adapter \
+ -I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/linuxkpi/include \
+ $(SECURE_LIB_INC)
+
+include drivers/hdf/khdf/model/network/wifi/vendor/hi3881/env_config.mk
+
+HI1131_HOST_CFLAGS += -Wextra -fsigned-char -fno-strict-aliasing -Wdate-time \
+ -Wformat=2 -Wshadow -fvisibility=hidden -fno-common -fstack-protector-strong
+
+HI1131_HOST_CFLAGS += -Wall
+HI1131_HOST_CFLAGS += $(HI1131_WIFI_CFLAGS)
+
+obj-$(CONFIG_DRIVERS_HI3881) += $(MODULE_NAME).o
+$(MODULE_NAME)-objs := $(HDF_WIFI_VENDOR_ROOT)/adapter/hdf_wlan_sdio_adapt.o
+
+####################################### platform module start #########################################
+oal-objs := oal_util.o oal_net.o oal_main.o oal_mem.o
+oal-objs += oal_cfg80211.o oal_sdio_host.o oal_kernel_file.o exception_rst.o \
+ plat_firmware.o plat_pm.o plat_pm_wlan.o plat_sdio.o oal_chr.o
+oal-objs := $(addprefix $(OAL_PATH),$(oal-objs))
+
+adapter-objs := hdfinit_3881.o net_adpater.o hdf_driver_register.o
+adapter-objs := $(addprefix $(ADPATER_PATH),$(adapter-objs))
+
+oam-objs := oam_main.o oam_log.o
+oam-objs := $(addprefix $(OAM_PATH),$(oam-objs))
+
+board-objs := plat_board_common_sdio.o
+board-objs := $(addprefix $(OAL_PATH),$(board-objs))
+
+frw-objs += frw_event.o frw_event_sched.o frw_main.o frw_task.o frw_timer.o
+frw-objs := $(addprefix $(FRW_PATH),$(frw-objs))
+
+plat-objs = $(oal-objs) $(oam-objs) $(board-objs) $(frw-objs) $(adapter-objs)
+####################################### platform module end #########################################
+
+####################################### wifi module start #########################################
+hmac-objs := hmac_11i.o hmac_blockack.o hmac_chan_mgmt.o hmac_config.o hmac_crypto_tkip.o hmac_event.o hmac_uapsd.o \
+ hmac_device.o hmac_encap_frame.o hmac_encap_frame_ap.o hmac_encap_frame_sta.o hmac_frag.o hmac_fsm.o \
+ hmac_mgmt_ap.o hmac_mgmt_bss_comm.o hmac_mgmt_classifier.o hmac_mgmt_sta.o hmac_protection.o hmac_user.o \
+ hmac_rx_data.o hmac_tx_data.o hmac_rx_filter.o hmac_scan.o hmac_sme_sta.o hmac_vap.o \
+ hmac_main.o
+
+ifeq ($(CFG_EDCA_OPT_AP), y)
+hmac-objs += hmac_edca_opt.o
+endif
+ifeq ($(CFG_P2P), y)
+hmac-objs += hmac_p2p.o
+endif
+ifeq ($(CFG_TCP_OPT), y)
+hmac-objs += hmac_tcp_opt.o
+endif
+ifeq ($(CFG_TX_CLASSIFY_LAN_TO_WLAN), y)
+hmac-objs += hmac_traffic_classify.o
+endif
+ifeq ($(CFG_WOW), y)
+hmac-objs += hmac_wow.o
+endif
+ifeq ($(CFG_ANY), y)
+hmac-objs += hmac_any.o
+endif
+ifeq ($(CFG_WAPI), y)
+hmac-objs += hmac_wapi.o hmac_wapi_wpi.o hmac_wapi_sms4.o
+endif
+hmac-objs := $(addprefix $(HMAC_PATH),$(hmac-objs))
+
+wal-objs := wal_customize.o wal_cfg80211.o wal_11d.o wal_hipriv.o wal_event_msg.o hi_wifi_driver_api.o wal_linux_flowctl.o wal_ioctl.o wal_event.o wal_scan.o wal_main.o wal_regdb.o wal_mac80211.o
+wal-objs := $(addprefix $(WAL_PATH),$(wal-objs))
+
+mac-objs := mac_data.o mac_device.o mac_frame.o mac_ie.o mac_user.o mac_vap.o mac_mib.o mac_resource.o mac_regdomain.o mac_pm_driver.o
+mac-objs := $(addprefix $(MAC_PATH),$(mac-objs))
+
+hcc-objs := hcc_comm.o hcc_task.o hcc_host.o hcc_hmac.o hmac_hcc_adapt.o
+hcc-objs := $(addprefix $(HCC_PATH),$(hcc-objs))
+
+wifi-objs += $(mac-objs) $(hmac-objs) $(wal-objs) $(hcc-objs)
+####################################### wifi module end #########################################
+
+$(MODULE_NAME)-objs += $(wifi-objs) $(plat-objs)
+
+ccflags-$(CONFIG_DRIVERS_HI3881) += $(HI1131_HOST_CFLAGS)
\ No newline at end of file
diff --git a/adapter/khdf/linux/model/network/wifi/vendor/hi3881/env_config.mk b/adapter/khdf/linux/model/network/wifi/vendor/hi3881/env_config.mk
new file mode 100644
index 00000000..c9256c01
--- /dev/null
+++ b/adapter/khdf/linux/model/network/wifi/vendor/hi3881/env_config.mk
@@ -0,0 +1,297 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+#####################################WiFi config######################################
+CFG_ANTI_INTERF = y
+CFG_CCA_OPT = y
+CFG_DBAC = y
+CFG_EDCA_OPT = y
+CFG_EDCA_OPT_AP = y
+CFG_SCHEDULE = y
+CFG_TRAFFIC_CTL = n
+CFG_TPC = y
+CFG_RF_1102CALI = y
+CFG_RF_110X_CALI_DPD = n
+CFG_NEW_IQ = y
+CFG_ALG_CFG = n
+CFG_HCC_TASK = y
+########################flash cut begin########################
+######## CFG_XXX_ROM can't be set to n ########
+CFG_P2P = y
+CFG_P2P_ROM = y
+CFG_WAPI = n
+CFG_WAPI_ROM = y
+CFG_WOW = y
+CFG_WOW_ROM = y
+CFG_REKEY_OFFLOAD = n
+CFG_REKEY_OFFLOAD_ROM = y
+CFG_PROMIS = y
+CFG_PROMIS_ROM = y
+CFG_MFG_TEST = y
+CFG_CE_MODE = y
+CFG_FCC_MODE = n
+CFG_MFG_FW = n
+########################flash cut end##########################
+CFG_BTCOEX_ROM = y
+CFG_ANY = n
+CFG_STA_PM = y
+CFG_MESH = n
+CFG_TCP_OPT = n
+CFG_TX_CLASSIFY_LAN_TO_WLAN = n
+CFG_UAPSD = y
+CFG_ARP_OFFLOAD = y
+CFG_DHCP_OFFLOAD = y
+CFG_LITEOS = n
+CFG_SIGMA = y
+CFG_HIPRIV = y
+
+######################################################################################
+HI1131_WIFI_CFLAGS +=-D_PRE_OS_VERSION_LINUX=1
+HI1131_WIFI_CFLAGS +=-D_PRE_OS_VERSION_LITEOS=2
+ifeq ($(CFG_LITEOS), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_OS_VERSION=_PRE_OS_VERSION_LITEOS
+else
+HI1131_WIFI_CFLAGS +=-D_PRE_OS_VERSION=_PRE_OS_VERSION_LINUX
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_HDF_LINUX
+
+HI1131_WIFI_CFLAGS +=-D_PRE_FRW_FEATURE_PROCESS_ENTITY_THREAD=0
+HI1131_WIFI_CFLAGS +=-D_PRE_FRW_FEATURE_PROCESS_ENTITY_TASKLET=1
+HI1131_WIFI_CFLAGS +=-D_PRE_FRW_FEATURE_PROCESS_ENTITY_TYPE=_PRE_FRW_FEATURE_PROCESS_ENTITY_THREAD
+
+#######################################HI1131#########################################
+HI1131_WIFI_CFLAGS +=-D_PRE_MULTI_CORE_MODE_SMP=1
+HI1131_WIFI_CFLAGS +=-D_PRE_MULTI_CORE_MODE_OFFLOAD_HMAC=2
+HI1131_WIFI_CFLAGS +=-D_PRE_MULTI_CORE_MODE_OFFLOAD_DMAC=3
+ifeq ($(LOSCFG_COMPILER_HI3861_FLASH), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_MULTI_CORE_MODE=_PRE_MULTI_CORE_MODE_SMP
+else
+HI1131_WIFI_CFLAGS +=-D_PRE_MULTI_CORE_MODE=_PRE_MULTI_CORE_MODE_OFFLOAD_DMAC
+endif
+
+HI1131_WIFI_CFLAGS +=-D_PRE_BIG_CPU_ENDIAN=0
+HI1131_WIFI_CFLAGS +=-D_PRE_LITTLE_CPU_ENDIAN=1
+HI1131_WIFI_CFLAGS +=-D_PRE_CPU_ENDIAN=_PRE_LITTLE_CPU_ENDIAN
+HI1131_WIFI_CFLAGS +=-D_HI_BOARD_FPGA=1
+HI1131_WIFI_CFLAGS +=-D_HI_BOARD_ASIC=2
+ifeq ($(LOSCFG_COMPILER_HI3861_ASIC), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_CHIP_VERSION=_HI_BOARD_ASIC
+else
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_CHIP_VERSION=_HI_BOARD_FPGA
+endif
+
+ifeq ($(QUICK_START),y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_QUICK_START
+endif
+ifeq ($(NO_32K),y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_NO_32K
+endif
+
+ifeq ($(BOARD_FUNC), DG)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FPGA_DIGITAL
+endif
+
+################################################################################
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_PMF
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_AUTORATE
+ifeq ($(CFG_SCHEDULE), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_SCHEDULE
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_PERFORM_TPC
+ifeq ($(CFG_TPC), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_TPC
+endif
+ifeq ($(CFG_DBAC), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_DBAC
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_DBAC_DYNAMIC_POLICY
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_AGGR_OPTIMIZE
+ifeq ($(CFG_CCA_OPT), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_CCA_OPT
+endif
+ifeq ($(CFG_EDCA_OPT), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_EDCA_OPT
+endif
+ifeq ($(CFG_EDCA_OPT_AP), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_EDCA_OPT_AP
+endif
+ifeq ($(CFG_ANTI_INTERF), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_ANTI_INTERF
+endif
+ifeq ($(CFG_TRAFFIC_CTL), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_TRAFFIC_CTL
+endif
+ifeq ($(CFG_ALG_CFG),y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_ALG_CFG
+endif
+ifeq ($(CFG_ALG_INTRF_MODE),y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_INTRF_MODE
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_ALG_CFG_ROM
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_FLOWCTRL
+ifeq ($(CFG_TX_CLASSIFY_LAN_TO_WLAN), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_TX_CLASSIFY_LAN_TO_WLAN
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_CLASSIFY
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_ALWAYS_TX
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_WPA
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_WPA2
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_AMPDU
+ifeq ($(CFG_ARP_OFFLOAD), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_ARP_OFFLOAD
+endif
+ifeq ($(CFG_DHCP_OFFLOAD), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_DHCP_OFFLOAD
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_DHCP_OFFLOAD_ROM
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_PKT_MEM_OPT
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_PM_FEATURE_FORCESLP_RESUME
+HI1131_WIFI_CFLAGS +=-D__BITS_PER_OAL_LONG=32
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_11D
+ifeq ($(CFG_NEW_IQ), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_NEW_IQ
+endif
+ifeq ($(CFG_P2P), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_P2P
+endif
+ifeq ($(CFG_P2P_ROM), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_P2P_ROM
+endif
+ifeq ($(CFG_ANY), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_ANY
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_ANY_ROM
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_CSI
+ifeq ($(CFG_STA_PM), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_STA_PM
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_STA_UAPSD
+ifeq ($(CFG_MESH), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_MESH
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_MESH_ROM
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_BW_HIEX
+ifeq ($(CFG_BTCOEX), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_BTCOEX
+endif
+ifeq ($(CFG_BTCOEX_ROM), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_BTCOEX_ROM
+endif
+ifeq ($(CFG_RF_110X_CALI_DPD), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_RF_110X_CALI_DPD
+endif
+ifeq ($(CFG_RF_1102CALI), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_RF_1102CALI
+endif
+ifeq ($(CFG_UAPSD), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_UAPSD
+endif
+ifeq ($(CFG_WAPI), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_WAPI
+endif
+ifeq ($(CFG_WAPI_ROM), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_WAPI_ROM
+endif
+ifeq ($(CFG_TCP_OPT), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_TCP_OPT
+endif
+
+HI1131_WIFI_CFLAGS +=-D_PRE_XTAL_FREQUENCY_COMPESATION_ENABLE
+
+################################SDIO MMC CONFIG#############################
+HI1131_WIFI_CFLAGS +=-DCONFIG_MMC
+HI1131_WIFI_CFLAGS +=-DCONFIG_PRINTK
+HI1131_WIFI_CFLAGS +=-D_PRE_FEATURE_NO_GPIO
+ifeq ($(CFG_REKEY_OFFLOAD), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_REKEY_OFFLOAD
+endif
+ifeq ($(CFG_REKEY_OFFLOAD_ROM), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_REKEY_OFFLOAD_ROM
+endif
+ifeq ($(CFG_WOW), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_WOW
+endif
+ifeq ($(CFG_WOW_ROM), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_WOW_ROM
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_HILINK
+ifeq ($(CFG_PROMIS), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_PROMIS
+endif
+ifeq ($(CFG_PROMIS_ROM), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_PROMIS_ROM
+endif
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_SMARTCONFIG_APP
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_TEMP_PROTECT
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_SINGLE_DEVICE
+
+ifeq ($(CFG_SIGMA), y)
+#sigma tool support
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_SIGMA
+endif
+
+ifeq ($(CFG_MFG_TEST), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_MFG_TEST
+endif
+
+ifeq ($(CFG_MFG_FW), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_MFG_FW
+endif
+
+ifeq ($(CFG_CE_MODE), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_CE_INITIAL_PARAMS_MODE
+endif
+
+ifeq ($(CFG_FCC_MODE), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_FCC_INITIAL_PARAMS_MODE
+endif
+
+ifeq ($(CFG_HIPRIV), y)
+#sdv test support
+HI1131_WIFI_CFLAGS +=-D_PRE_WLAN_FEATURE_HIPRIV
+ifeq ($(CFG_LITEOS), n)
+HI1131_WIFI_CFLAGS +=-D_PRE_CONFIG_CONN_HISI_SYSFS_SUPPORT
+else
+HI1131_WIFI_CFLAGS +=-DAT_DEBUG_CMD_SUPPORT
+endif
+endif
+
+################################WAIT MODIFIED SDIO##############################
+HI1131_WIFI_CFLAGS +=-D_PRE_FEATURE_SDIO=1
+HI1131_WIFI_CFLAGS +=-D_PRE_FEATURE_USB=2
+HI1131_WIFI_CFLAGS +=-D_PRE_FEATURE_CHANNEL_TYPE=_PRE_FEATURE_SDIO
+HI1131_WIFI_CFLAGS +=-DCONFIG_HI110X_SDIO_STD_CARD_SUPPORT
+
+################################HCC_TASK##############################
+ifeq ($(CFG_HCC_TASK), y)
+HI1131_WIFI_CFLAGS +=-D_PRE_FEATURE_HCC_TASK
+endif
+
+################################WIFI_DRIVER_DIR##############################
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/wal
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/oam
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/mac/hmac
+
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/mac/common
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/hcc
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/frw
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/oal
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/include
+
+################################device##############################
+HI1131_WIFI_CFLAGS +=-I$(srctree)/$(INC_TOP_PATH)/$(WIFI_DRIVER_DIR)/hdfadapt
+
+ifeq ($(LOSCFG_PLATFORM_HI3516EV300), y)
+HI1131_WIFI_CFLAGS +=-DHISI_WIFI_PLATFORM_HI3516EV300
+endif
\ No newline at end of file
diff --git a/adapter/khdf/linux/model/sensor/Kconfig b/adapter/khdf/linux/model/sensor/Kconfig
new file mode 100755
index 00000000..17ad0303
--- /dev/null
+++ b/adapter/khdf/linux/model/sensor/Kconfig
@@ -0,0 +1,138 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+config DRIVERS_HDF_SENSOR
+ bool "Enable HDF sensor driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to enable HDF sensor driver.
+
+config DRIVERS_HDF_SENSOR_ACCEL
+ bool "Enable HDF accel sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF accel sensor driver.
+config DRIVERS_HDF_SENSOR_ACCEL_BMI160
+ bool "Enable HDF accel bmi160 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_ACCEL
+ help
+ Answer Y to enable HDF accel bmi160 sensor driver.
+config DRIVERS_HDF_SENSOR_ACCEL_MXC6655XA
+ bool "Enable HDF accel mxc6655xa sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_ACCEL
+ help
+ Answer Y to enable HDF accel mxc6655xa sensor driver.
+config DRIVERS_HDF_SENSOR_PPG
+ bool "Enable HDF ppg sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF ppg sensor driver.
+config DRIVERS_HDF_SENSOR_PPG_CS1262
+ bool "Enable HDF ppg ppg cs1262 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_PPG
+ help
+ Answer Y to enable HDF ppg ppg cs1262 sensor driver.
+config DRIVERS_HDF_SENSOR_ALS
+ bool "Enable HDF als sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF als sensor driver.
+config DRIVERS_HDF_SENSOR_ALS_BH1745
+ bool "Enable HDF als bh1745 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_ALS
+ help
+ Answer Y to enable HDF als bh1745 sensor driver.
+config DRIVERS_HDF_SENSOR_GRAVITY
+ bool "Enable HDF gravity sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_ACCEL
+ help
+ Answer Y to enable HDF gravity sensor driver.
+config DRIVERS_HDF_SENSOR_GYRO
+ bool "Enable HDF gyro sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF gyro sensor driver.
+config DRIVERS_HDF_SENSOR_GYRO_BMI160
+ bool "Enable HDF gyro bmi160 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_GYRO
+ help
+ Answer Y to enable HDF gyro bmi160 sensor driver.
+config DRIVERS_HDF_SENSOR_PEDOMETER
+ bool "Enable HDF pedometer sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF pedometer sensor driver.
+config DRIVERS_HDF_SENSOR_PEDOMETER_BMI160
+ bool "Enable HDF pedometer bmi160 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_PEDOMETER
+ help
+ Answer Y to enable HDF pedometer bmi160 sensor driver.
+config DRIVERS_HDF_SENSOR_BAROMETER
+ bool "Enable HDF barometer sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF barometer sensor driver.
+config DRIVERS_HDF_SENSOR_BAROMETER_BMP180
+ bool "Enable HDF barometer bmp180 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_BAROMETER
+ help
+ Answer Y to enable HDF barometer bmp180 sensor driver.
+config DRIVERS_HDF_SENSOR_HALL
+ bool "Enable HDF hall sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF hall sensor driver.
+config DRIVERS_HDF_SENSOR_HALL_AK8789
+ bool "Enable HDF hall ak8789 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_HALL
+ help
+ Answer Y to enable HDF hall ak8789 sensor driver.
+config DRIVERS_HDF_SENSOR_MAGNETIC
+ bool "Enable HDF magnetic sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF magnetic sensor driver.
+config DRIVERS_HDF_SENSOR_MAGNETIC_LSM303
+ bool "Enable HDF magnetic lsm303 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_MAGNETIC
+ help
+ Answer Y to enable HDF magnetic lsm303 sensor driver.
+config DRIVERS_HDF_SENSOR_PROXIMITY
+ bool "Enable HDF proximity sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR
+ help
+ Answer Y to enable HDF proximity sensor driver.
+config DRIVERS_HDF_SENSOR_PROXIMITY_APDS9960
+ bool "Enable HDF proximity adps9960 sensor driver"
+ default n
+ depends on DRIVERS_HDF_SENSOR_PROXIMITY
+ help
+ Answer Y to enable HDF proximity apds9960 sensor driver.
diff --git a/adapter/khdf/linux/model/sensor/Makefile b/adapter/khdf/linux/model/sensor/Makefile
new file mode 100644
index 00000000..0fb2c252
--- /dev/null
+++ b/adapter/khdf/linux/model/sensor/Makefile
@@ -0,0 +1,92 @@
+# Copyright (c) 2022 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+SENSOR_ROOT_DIR = ../../../../../../hdf_core/framework/model/sensor/driver
+SENSOR_ROOT_CHIPSET = ../../../../../../peripheral/sensor
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR) += \
+ $(SENSOR_ROOT_DIR)/common/src/sensor_config_controller.o \
+ $(SENSOR_ROOT_DIR)/common/src/sensor_config_parser.o \
+ $(SENSOR_ROOT_DIR)/common/src/sensor_device_manager.o \
+ $(SENSOR_ROOT_DIR)/common/src/sensor_platform_if.o
+
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_ACCEL) += $(SENSOR_ROOT_DIR)/accel/sensor_accel_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_ACCEL_BMI160) += $(SENSOR_ROOT_CHIPSET)/chipset/accel/accel_bmi160.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_ACCEL_MXC6655XA) += $(SENSOR_ROOT_CHIPSET)/chipset/accel/accel_mxc6655xa.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_PPG) += $(SENSOR_ROOT_DIR)/ppg/sensor_ppg_driver.o \
+ $(SENSOR_ROOT_DIR)/ppg/sensor_ppg_config.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_PPG_CS1262) += $(SENSOR_ROOT_CHIPSET)/chipset/ppg/ppg_cs1262_spi.o \
+ $(SENSOR_ROOT_CHIPSET)/chipset/ppg/ppg_cs1262.o \
+ $(SENSOR_ROOT_CHIPSET)/chipset/ppg/ppg_cs1262_fw.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_ALS) += $(SENSOR_ROOT_DIR)/als/sensor_als_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_ALS_BH1745) += $(SENSOR_ROOT_CHIPSET)/chipset/als/als_bh1745.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_PROXIMITY) += $(SENSOR_ROOT_DIR)/proximity/sensor_proximity_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_PROXIMITY_APDS9960) += $(SENSOR_ROOT_CHIPSET)/chipset/proximity/proximity_apds9960.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_GYRO) += $(SENSOR_ROOT_DIR)/gyro/sensor_gyro_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_GYRO_BMI160) += $(SENSOR_ROOT_CHIPSET)/chipset/gyro/gyro_bmi160.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_BAROMETER) += $(SENSOR_ROOT_DIR)/barometer/sensor_barometer_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_BAROMETER_BMP180) += $(SENSOR_ROOT_CHIPSET)/chipset/barometer/barometer_bmp180.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_HALL) += $(SENSOR_ROOT_DIR)/hall/sensor_hall_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_HALL_AK8789) += $(SENSOR_ROOT_CHIPSET)/chipset/hall/hall_ak8789.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_MAGNETIC) += $(SENSOR_ROOT_DIR)/magnetic/sensor_magnetic_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_MAGNETIC_LSM303) += $(SENSOR_ROOT_CHIPSET)/chipset/magnetic/magnetic_lsm303.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_GRAVITY) += $(SENSOR_ROOT_DIR)/accel/sensor_gravity_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_PEDOMETER) += $(SENSOR_ROOT_DIR)/pedometer/sensor_pedometer_driver.o
+
+obj-$(CONFIG_DRIVERS_HDF_SENSOR_PEDOMETER_BMI160) += $(SENSOR_ROOT_CHIPSET)/chipset/pedometer/pedometer_bmi160.o
+
+ccflags-y += -I$(srctree)/drivers/hdf/framework/model/sensor/driver/include \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/common/include \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/accel \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/accel \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/ppg \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/ppg \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/als \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/als \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/gyro \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/gyro \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/pedometer \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/pedometer \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/barometer \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/barometer \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/hall \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/hall \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/magnetic \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/magnetic \
+ -I$(srctree)/drivers/hdf/framework/model/sensor/driver/proximity \
+ -I$(srctree)/drivers/hdf/peripheral/sensor/chipset/proximity \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/model/storage/Kconfig b/adapter/khdf/linux/model/storage/Kconfig
new file mode 100644
index 00000000..08059de3
--- /dev/null
+++ b/adapter/khdf/linux/model/storage/Kconfig
@@ -0,0 +1,17 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+config DRIVERS_HDF_STORAGE
+ bool "Enable HDF storage driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to enable HDF storage driver.
diff --git a/adapter/khdf/linux/model/storage/Makefile b/adapter/khdf/linux/model/storage/Makefile
new file mode 100644
index 00000000..5ef96899
--- /dev/null
+++ b/adapter/khdf/linux/model/storage/Makefile
@@ -0,0 +1,51 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+include drivers/hdf/khdf/platform/platform.mk
+
+STORAGE_ROOT_DIR = ../../../../../framework/model/storage
+
+ccflags-y +=-I$(srctree)/drivers/hdf/framework/model/storage/include/mmc \
+ -I$(srctree)/drivers/hdf/framework/model/storage/include/mtd \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/support/platform/include/fwk \
+ -I$(srctree)/drivers/hdf/framework/model/storage/include/mmc \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/bounds_checking_function/include
+
+obj-$(CONFIG_DRIVERS_HDF_STORAGE) += \
+ ./mmc_block_linux.o \
+ $(STORAGE_ROOT_DIR)/src/mmc/mmc_block.o \
+ $(STORAGE_ROOT_DIR)/src/mmc/mmc_core.o \
+ $(STORAGE_ROOT_DIR)/src/mmc/mmc_emmc.o \
+ $(STORAGE_ROOT_DIR)/src/mmc/mmc_sdio.o \
+ $(STORAGE_ROOT_DIR)/src/mmc/mmc_dispatch.o \
+ $(STORAGE_ROOT_DIR)/src/mmc/mmc_if.o \
+ $(STORAGE_ROOT_DIR)/src/mmc/mmc_protocol.o
+
+obj-y += $(STORAGE_ROOT_DIR)/src/mmc/emmc_if.o \
+ $(STORAGE_ROOT_DIR)/src/mmc/sdio_if.o \
+ ./emmc_adapter.o \
+ ./sdio_adapter.o
+
+ifeq ($(CONFIG_ARCH_HI3516DV300), y)
+ obj-y += \
+ ./vendor_adapter/hi35xx_mmc_adapter.o
+else
+ obj-y += \
+ ./mmc_adapter.o
+endif
\ No newline at end of file
diff --git a/adapter/khdf/linux/model/storage/emmc_adapter.c b/adapter/khdf/linux/model/storage/emmc_adapter.c
new file mode 100644
index 00000000..15451f2d
--- /dev/null
+++ b/adapter/khdf/linux/model/storage/emmc_adapter.c
@@ -0,0 +1,187 @@
+/*
+ * emmc_adapter.c
+ *
+ * linux emmc driver implement.
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include
+#include "device_resource_if.h"
+#include "hdf_log.h"
+#include "emmc_if.h"
+#include "mmc_corex.h"
+#include "mmc_emmc.h"
+
+#define HDF_LOG_TAG emmc_adapter_c
+
+struct mmc_host *GetMmcHost(int32_t slot);
+
+int32_t LinuxEmmcGetCid(struct EmmcDevice *dev, uint8_t *cid, uint32_t size)
+{
+ struct mmc_host *mmcHost = NULL;
+ struct MmcCntlr *cntlr = NULL;
+
+ if (dev == NULL || dev->mmc.cntlr == NULL) {
+ HDF_LOGE("LinuxEmmcGetCid: dev or cntlr is null.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (cid == NULL || size < EMMC_CID_LEN) {
+ HDF_LOGE("LinuxEmmcGetCid: cid is null or size is invalid.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ cntlr = dev->mmc.cntlr;
+ mmcHost = (struct mmc_host *)cntlr->priv;
+ if (mmcHost == NULL) {
+ HDF_LOGE("LinuxEmmcGetCid: mmcHost is NULL!");
+ return HDF_ERR_NOT_SUPPORT;
+ }
+ if (mmcHost->card == NULL) {
+ HDF_LOGE("LinuxEmmcGetCid: card is null.");
+ return HDF_ERR_NOT_SUPPORT;
+ }
+ if (memcpy_s(cid, sizeof(uint8_t) * size, (uint8_t *)(mmcHost->card->raw_cid),
+ sizeof(mmcHost->card->raw_cid)) != EOK) {
+ HDF_LOGE("LinuxEmmcGetCid: memcpy_s fail!");
+ return HDF_FAILURE;
+ }
+ return HDF_SUCCESS;
+}
+
+static struct EmmcDeviceOps g_emmcMethod = {
+ .getCid = LinuxEmmcGetCid,
+};
+
+static void LinuxEmmcDeleteCntlr(struct MmcCntlr *cntlr)
+{
+ if (cntlr == NULL) {
+ return;
+ }
+
+ if (cntlr->curDev != NULL) {
+ MmcDeviceRemove(cntlr->curDev);
+ OsalMemFree(cntlr->curDev);
+ }
+ MmcCntlrRemove(cntlr);
+ OsalMemFree(cntlr);
+}
+
+static int32_t LinuxEmmcCntlrParse(struct MmcCntlr *cntlr, struct HdfDeviceObject *obj)
+{
+ const struct DeviceResourceNode *node = NULL;
+ struct DeviceResourceIface *drsOps = NULL;
+ int32_t ret;
+
+ if (obj == NULL || cntlr == NULL) {
+ HDF_LOGE("LinuxEmmcCntlrParse: input para is NULL.");
+ return HDF_FAILURE;
+ }
+
+ node = obj->property;
+ if (node == NULL) {
+ HDF_LOGE("LinuxEmmcCntlrParse: drs node is NULL.");
+ return HDF_FAILURE;
+ }
+ drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
+ if (drsOps == NULL || drsOps->GetUint16 == NULL || drsOps->GetUint32 == NULL) {
+ HDF_LOGE("LinuxEmmcCntlrParse: invalid drs ops fail!");
+ return HDF_FAILURE;
+ }
+
+ ret = drsOps->GetUint16(node, "hostId", &(cntlr->index), 0);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxEmmcCntlrParse: read hostIndex fail!");
+ return ret;
+ }
+ ret = drsOps->GetUint32(node, "devType", &(cntlr->devType), 0);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxEmmcCntlrParse: read devType fail!");
+ return ret;
+ }
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxEmmcBind(struct HdfDeviceObject *obj)
+{
+ struct MmcCntlr *cntlr = NULL;
+ int32_t ret;
+
+ if (obj == NULL) {
+ HDF_LOGE("LinuxEmmcBind: Fail, obj is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));
+ if (cntlr == NULL) {
+ HDF_LOGE("LinuxEmmcBind: no mem for MmcCntlr.");
+ return HDF_ERR_MALLOC_FAIL;
+ }
+
+ cntlr->ops = NULL;
+ cntlr->hdfDevObj = obj;
+ obj->service = &cntlr->service;
+ ret = LinuxEmmcCntlrParse(cntlr, obj);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxEmmcBind: cntlr parse fail.");
+ goto _ERR;
+ }
+ cntlr->priv = (void *)GetMmcHost((int32_t)cntlr->index);
+
+ ret = MmcCntlrAdd(cntlr, false);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxEmmcBind: cntlr add fail.");
+ goto _ERR;
+ }
+
+ ret = MmcCntlrAllocDev(cntlr, (enum MmcDevType)cntlr->devType);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxEmmcBind: alloc dev fail.");
+ goto _ERR;
+ }
+ MmcDeviceAddOps(cntlr->curDev, &g_emmcMethod);
+ HDF_LOGD("LinuxEmmcBind: Success!");
+ return HDF_SUCCESS;
+
+_ERR:
+ LinuxEmmcDeleteCntlr(cntlr);
+ HDF_LOGE("LinuxEmmcBind: Fail!");
+ return HDF_FAILURE;
+}
+
+static int32_t LinuxEmmcInit(struct HdfDeviceObject *obj)
+{
+ (void)obj;
+
+ HDF_LOGD("LinuxEmmcInit: Success!");
+ return HDF_SUCCESS;
+}
+
+static void LinuxEmmcRelease(struct HdfDeviceObject *obj)
+{
+ if (obj == NULL) {
+ return;
+ }
+ LinuxEmmcDeleteCntlr((struct MmcCntlr *)obj->service);
+}
+
+struct HdfDriverEntry g_emmcDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = LinuxEmmcBind,
+ .Init = LinuxEmmcInit,
+ .Release = LinuxEmmcRelease,
+ .moduleName = "HDF_PLATFORM_EMMC",
+};
+HDF_INIT(g_emmcDriverEntry);
diff --git a/adapter/khdf/linux/model/storage/mmc_adapter.c b/adapter/khdf/linux/model/storage/mmc_adapter.c
new file mode 100644
index 00000000..449d93f2
--- /dev/null
+++ b/adapter/khdf/linux/model/storage/mmc_adapter.c
@@ -0,0 +1,37 @@
+/*
+ * mmc_adapter.c
+ *
+ * linux mmc driver implement.
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include "hdf_base.h"
+#include "hdf_log.h"
+
+#define HDF_LOG_TAG mmc_adapter_c
+
+struct mmc_host *GetMmcHost(int32_t slot)
+{
+ (void)slot;
+ HDF_LOGE("Vendor need to adapter GetMmcHost");
+ return NULL;
+}
+
+void SdioRescan(int32_t slot)
+{
+ (void)slot;
+ HDF_LOGE("Vendor need to adapter SdioRescan");
+ return;
+}
diff --git a/adapter/khdf/linux/model/storage/mmc_block_linux.c b/adapter/khdf/linux/model/storage/mmc_block_linux.c
new file mode 100644
index 00000000..a55c1870
--- /dev/null
+++ b/adapter/khdf/linux/model/storage/mmc_block_linux.c
@@ -0,0 +1,30 @@
+/*
+ * storage_block_linux.c
+ *
+ * storage block adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mmc_block.h"
+
+int32_t MmcBlockOsInit(struct MmcDevice *mmcDevice)
+{
+ (void)mmcDevice;
+ return HDF_SUCCESS;
+}
+
+void MmcBlockOsUninit(struct MmcDevice *mmcDevice)
+{
+ (void)mmcDevice;
+}
diff --git a/adapter/khdf/linux/model/storage/sdio_adapter.c b/adapter/khdf/linux/model/storage/sdio_adapter.c
new file mode 100644
index 00000000..276b1ede
--- /dev/null
+++ b/adapter/khdf/linux/model/storage/sdio_adapter.c
@@ -0,0 +1,601 @@
+/*
+ * sdio_adapter.c
+ *
+ * linux sdio driver implement.
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include "device_resource_if.h"
+#include "mmc_corex.h"
+#include "mmc_sdio.h"
+
+#define HDF_LOG_TAG sdio_adapter_c
+
+#define DATA_LEN_ONE_BYTE 1
+#define DATA_LEN_TWO_BYTES 2
+#define DATA_LEN_FOUR_BYTES 4
+#define MMC_SLOT_NUM 3
+#define SDIO_RESCAN_WAIT_TIME 40
+
+struct mmc_host *GetMmcHost(int32_t slot);
+void SdioRescan(int32_t slot);
+
+enum SleepTime {
+ MS_10 = 10,
+ MS_50 = 50,
+};
+
+static struct sdio_func *LinuxSdioGetFunc(struct SdioDevice *dev)
+{
+ if (dev == NULL) {
+ HDF_LOGE("LinuxSdioGetFunc: dev is null.");
+ return NULL;
+ }
+ return (struct sdio_func *)dev->sd.mmc.priv;
+}
+
+static int32_t LinuxSdioIncrAddrReadBytes(struct SdioDevice *dev,
+ uint8_t *data, uint32_t addr, uint32_t size)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+ int32_t ret = HDF_SUCCESS;
+ uint16_t *output16 = NULL;
+ uint32_t *output32 = NULL;
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioIncrAddrReadBytes: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if ((data == NULL) || (size == 0)) {
+ HDF_LOGE("LinuxSdioIncrAddrReadBytes: data or size is invalid.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (size == DATA_LEN_ONE_BYTE) {
+ *data = sdio_readb(func, addr, &ret);
+ return ret;
+ }
+ if (size == DATA_LEN_TWO_BYTES) {
+ output16 = (uint16_t *)data;
+ *output16 = sdio_readw(func, addr, &ret);
+ return ret;
+ }
+ if (size == DATA_LEN_FOUR_BYTES) {
+ output32 = (uint32_t *)data;
+ *output32 = sdio_readl(func, addr, &ret);
+ return ret;
+ }
+ return sdio_memcpy_fromio(func, data, addr, size);
+}
+
+static int32_t LinuxSdioIncrAddrWriteBytes(struct SdioDevice *dev,
+ uint8_t *data, uint32_t addr, uint32_t size)
+{
+ int32_t ret = HDF_SUCCESS;
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioIncrAddrWriteBytes: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if ((data == NULL) || (size == 0)) {
+ HDF_LOGE("LinuxSdioIncrAddrWriteBytes: data or size is invalid.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (size == DATA_LEN_ONE_BYTE) {
+ sdio_writeb(func, *data, addr, &ret);
+ return ret;
+ }
+ if (size == DATA_LEN_TWO_BYTES) {
+ sdio_writew(func, *(uint16_t *)data, addr, &ret);
+ return ret;
+ }
+ if (size == DATA_LEN_FOUR_BYTES) {
+ sdio_writel(func, *(uint32_t *)data, addr, &ret);
+ return ret;
+ }
+ return sdio_memcpy_toio(func, addr, data, size);
+}
+
+static int32_t LinuxSdioFixedAddrReadBytes(struct SdioDevice *dev,
+ uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioFixedAddrReadBytes: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if ((data == NULL) || (size == 0)) {
+ HDF_LOGE("LinuxSdioFixedAddrReadBytes: data or size is invalid.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (scatterLen > 0) {
+ HDF_LOGE("LinuxSdioFixedAddrReadBytes: not support!");
+ return HDF_ERR_NOT_SUPPORT;
+ }
+ return sdio_readsb(func, data, addr, size);
+}
+
+static int32_t LinuxSdioFixedAddrWriteBytes(struct SdioDevice *dev,
+ uint8_t *data, uint32_t addr, uint32_t size, uint32_t scatterLen)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioFixedAddrWriteBytes: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if ((data == NULL) || (size == 0)) {
+ HDF_LOGE("LinuxSdioFixedAddrReadBytes: data or size is invalid.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (scatterLen > 0) {
+ HDF_LOGE("LinuxSdioFixedAddrWriteBytes: not support!");
+ return HDF_ERR_NOT_SUPPORT;
+ }
+ return sdio_writesb(func, addr, data, size);
+}
+
+static int32_t LinuxSdioFunc0ReadBytes(struct SdioDevice *dev,
+ uint8_t *data, uint32_t addr, uint32_t size)
+{
+ int32_t ret = HDF_SUCCESS;
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioFunc0ReadBytes: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if ((data == NULL) || (size == 0)) {
+ HDF_LOGE("LinuxSdioFunc0ReadBytes: data or size is invalid.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ *data = sdio_f0_readb(func, addr, &ret);
+ return ret;
+}
+
+static int32_t LinuxSdioFunc0WriteBytes(struct SdioDevice *dev,
+ uint8_t *data, uint32_t addr, uint32_t size)
+{
+ int32_t ret = HDF_SUCCESS;
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioFunc0WriteBytes: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if ((data == NULL) || (size == 0)) {
+ HDF_LOGE("LinuxSdioFunc0WriteBytes: data or size is invalid.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ sdio_f0_writeb(func, *data, addr, &ret);
+ return ret;
+}
+
+static int32_t LinuxSdioSetBlockSize(struct SdioDevice *dev, uint32_t blockSize)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioSetBlockSize, func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ return sdio_set_block_size(func, blockSize);
+}
+
+static int32_t LinuxSdioGetCommonInfo(struct SdioDevice *dev,
+ SdioCommonInfo *info, uint32_t infoType)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioGetCommonInfo: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (info == NULL) {
+ HDF_LOGE("LinuxSdioGetCommonInfo: info is null.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+ if (infoType != SDIO_FUNC_INFO) {
+ HDF_LOGE("LinuxSdioGetCommonInfo: cur type %u is not support.", infoType);
+ return HDF_ERR_NOT_SUPPORT;
+ }
+
+ if (func->card == NULL) {
+ HDF_LOGE("LinuxSdioGetCommonInfo fail, card is null.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+ if (func->card->host == NULL) {
+ HDF_LOGE("LinuxSdioGetCommonInfo fail, host is null.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+ info->funcInfo.enTimeout = func->enable_timeout;
+ info->funcInfo.maxBlockNum = func->card->host->max_blk_count;
+ info->funcInfo.maxBlockSize = func->card->host->max_blk_size;
+ info->funcInfo.maxRequestSize = func->card->host->max_req_size;
+ info->funcInfo.funcNum = func->num;
+ info->funcInfo.irqCap = func->card->host->caps & MMC_CAP_SDIO_IRQ;
+ info->funcInfo.data = func;
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxSdioSetCommonInfo(struct SdioDevice *dev,
+ SdioCommonInfo *info, uint32_t infoType)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioSetCommonInfo: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (info == NULL) {
+ HDF_LOGE("LinuxSdioSetCommonInfo: info is null.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+ if (infoType != SDIO_FUNC_INFO) {
+ HDF_LOGE("LinuxSdioSetCommonInfo: cur type %u is not support.", infoType);
+ return HDF_ERR_NOT_SUPPORT;
+ }
+
+ if (func->card == NULL) {
+ HDF_LOGE("LinuxSdioSetCommonInfo fail, card is null.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+ if (func->card->host == NULL) {
+ HDF_LOGE("LinuxSdioSetCommonInfo fail, host is null.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+ func->enable_timeout = info->funcInfo.enTimeout;
+ func->card->host->max_blk_count = info->funcInfo.maxBlockNum;
+ func->card->host->max_blk_size = info->funcInfo.maxBlockSize;
+ func->card->host->max_req_size = info->funcInfo.maxRequestSize;
+ func->num = info->funcInfo.funcNum;
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxSdioFlushData(struct SdioDevice *dev)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioFlushData: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (func->card == NULL) {
+ HDF_LOGE("LinuxSdioFlushData: card is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ return mmc_sw_reset(func->card->host);
+}
+
+static int32_t LinuxSdioClaimHost(struct SdioDevice *dev)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioClaimHost: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ sdio_claim_host(func);
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxSdioReleaseHost(struct SdioDevice *dev)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioReleaseHost: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ sdio_release_host(func);
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxSdioEnableFunc(struct SdioDevice *dev)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioEnableFunc: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ return sdio_enable_func(func);
+}
+
+static int32_t LinuxSdioDisableFunc(struct SdioDevice *dev)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioDisableFunc: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ return sdio_disable_func(func);
+}
+
+static int32_t LinuxSdioClaimIrq(struct SdioDevice *dev, SdioIrqHandler *handler)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioClaimIrq: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (handler == NULL) {
+ HDF_LOGE("LinuxSdioClaimIrq: handler is null.");
+ return HDF_ERR_INVALID_PARAM;
+ }
+ return sdio_claim_irq(func, (sdio_irq_handler_t *)handler);
+}
+
+static int32_t LinuxSdioReleaseIrq(struct SdioDevice *dev)
+{
+ struct sdio_func *func = LinuxSdioGetFunc(dev);
+
+ if (func == NULL) {
+ HDF_LOGE("LinuxSdioReleaseIrq: func is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ return sdio_release_irq(func);
+}
+
+static struct sdio_func *LinuxSdioSearchFunc(uint32_t funcNum, uint16_t vendorId, uint16_t deviceId)
+{
+ struct mmc_card *card = NULL;
+ struct mmc_host *host = NULL;
+ struct sdio_func *func = NULL;
+ uint32_t i, j;
+
+ for (i = 0; i < MMC_SLOT_NUM; i++) {
+ host = GetMmcHost(i);
+ if (host == NULL) {
+ continue;
+ }
+ card = host->card;
+ if (card == NULL) {
+ continue;
+ }
+ for (j = 0; j <= card->sdio_funcs; j++) {
+ func = card->sdio_func[j];
+ if ((func != NULL) &&
+ (func->num == funcNum) &&
+ (func->vendor == vendorId) &&
+ (func->device == deviceId)) {
+ HDF_LOGD("LinuxSdioSearchFunc: find func!");
+ return func;
+ }
+ }
+ }
+
+ HDF_LOGE("LinuxSdioSearchFunc: get sdio func fail!");
+ return NULL;
+}
+
+static int32_t LinuxSdioFindFunc(struct SdioDevice *dev, struct SdioFunctionConfig *configData)
+{
+ if (dev == NULL || configData == NULL) {
+ HDF_LOGE("LinuxSdioFindFunc: dev or configData is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ dev->sd.mmc.priv = LinuxSdioSearchFunc(configData->funcNr, configData->vendorId, configData->deviceId);
+ if (dev->sd.mmc.priv == NULL) {
+ HDF_LOGE("LinuxSdioFindFunc: LinuxSdioSearchFunc fail.");
+ return HDF_ERR_NOT_SUPPORT;
+ }
+ return HDF_SUCCESS;
+}
+
+static struct SdioDeviceOps g_sdioDeviceOps = {
+ .incrAddrReadBytes = LinuxSdioIncrAddrReadBytes,
+ .incrAddrWriteBytes = LinuxSdioIncrAddrWriteBytes,
+ .fixedAddrReadBytes = LinuxSdioFixedAddrReadBytes,
+ .fixedAddrWriteBytes = LinuxSdioFixedAddrWriteBytes,
+ .func0ReadBytes = LinuxSdioFunc0ReadBytes,
+ .func0WriteBytes = LinuxSdioFunc0WriteBytes,
+ .setBlockSize = LinuxSdioSetBlockSize,
+ .getCommonInfo = LinuxSdioGetCommonInfo,
+ .setCommonInfo = LinuxSdioSetCommonInfo,
+ .flushData = LinuxSdioFlushData,
+ .enableFunc = LinuxSdioEnableFunc,
+ .disableFunc = LinuxSdioDisableFunc,
+ .claimIrq = LinuxSdioClaimIrq,
+ .releaseIrq = LinuxSdioReleaseIrq,
+ .findFunc = LinuxSdioFindFunc,
+ .claimHost = LinuxSdioClaimHost,
+ .releaseHost = LinuxSdioReleaseHost,
+};
+
+static bool LinuxSdioRescanFinish(struct MmcCntlr *cntlr)
+{
+ struct mmc_host *host = NULL;
+ struct mmc_card *card = NULL;
+
+ host = GetMmcHost(cntlr->index);
+ if (host == NULL) {
+ return false;
+ }
+
+ card = host->card;
+ if (card == NULL) {
+ return false;
+ }
+ if (card->sdio_funcs > 0) {
+ return true;
+ }
+ return false;
+}
+
+static int32_t LinuxSdioRescan(struct MmcCntlr *cntlr)
+{
+ bool rescanFinish = false;
+ uint32_t count = 0;
+
+ if (cntlr == NULL) {
+ HDF_LOGE("LinuxSdioRescan: cntlr is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ SdioRescan(cntlr->index);
+ while (rescanFinish == false && count < SDIO_RESCAN_WAIT_TIME) {
+ OsalMSleep(MS_50);
+ count++;
+ rescanFinish = LinuxSdioRescanFinish(cntlr);
+ }
+
+ if (rescanFinish == false) {
+ HDF_LOGE("LinuxSdioRescan: fail!");
+ return HDF_FAILURE;
+ }
+
+ OsalMSleep(MS_10);
+ return HDF_SUCCESS;
+}
+
+struct MmcCntlrOps g_sdioCntlrOps = {
+ .rescanSdioDev = LinuxSdioRescan,
+};
+
+static void LinuxSdioDeleteCntlr(struct MmcCntlr *cntlr)
+{
+ if (cntlr == NULL) {
+ return;
+ }
+
+ if (cntlr->curDev != NULL) {
+ MmcDeviceRemove(cntlr->curDev);
+ OsalMemFree(cntlr->curDev);
+ }
+ MmcCntlrRemove(cntlr);
+ OsalMemFree(cntlr);
+}
+
+static int32_t LinuxSdioCntlrParse(struct MmcCntlr *cntlr, struct HdfDeviceObject *obj)
+{
+ const struct DeviceResourceNode *node = NULL;
+ struct DeviceResourceIface *drsOps = NULL;
+ int32_t ret;
+
+ if (obj == NULL || cntlr == NULL) {
+ HDF_LOGE("LinuxSdioCntlrParse: input para is NULL.");
+ return HDF_FAILURE;
+ }
+
+ node = obj->property;
+ if (node == NULL) {
+ HDF_LOGE("LinuxSdioCntlrParse: drs node is NULL.");
+ return HDF_FAILURE;
+ }
+ drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
+ if (drsOps == NULL || drsOps->GetUint16 == NULL || drsOps->GetUint32 == NULL) {
+ HDF_LOGE("LinuxSdioCntlrParse: invalid drs ops fail!");
+ return HDF_FAILURE;
+ }
+
+ ret = drsOps->GetUint16(node, "hostId", &(cntlr->index), 0);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxSdioCntlrParse: read hostIndex fail!");
+ return ret;
+ }
+ ret = drsOps->GetUint32(node, "devType", &(cntlr->devType), 0);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxSdioCntlrParse: read devType fail!");
+ return ret;
+ }
+ HDF_LOGD("LinuxSdioCntlrParse: hostIndex = %d, devType = %d.", cntlr->index, cntlr->devType);
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxSdioBind(struct HdfDeviceObject *obj)
+{
+ struct MmcCntlr *cntlr = NULL;
+ int32_t ret;
+
+ if (obj == NULL) {
+ HDF_LOGE("LinuxSdioBind: Fail, obj is NULL.");
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ cntlr = (struct MmcCntlr *)OsalMemCalloc(sizeof(struct MmcCntlr));
+ if (cntlr == NULL) {
+ HDF_LOGE("LinuxSdioBind: no mem for MmcCntlr.");
+ return HDF_ERR_MALLOC_FAIL;
+ }
+
+ cntlr->ops = &g_sdioCntlrOps;
+ cntlr->hdfDevObj = obj;
+ obj->service = &cntlr->service;
+ /* init cntlr. */
+ ret = LinuxSdioCntlrParse(cntlr, obj);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxSdioBind: cntlr parse fail.");
+ goto _ERR;
+ }
+
+ ret = MmcCntlrAdd(cntlr, false);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxSdioBind: cntlr add fail.");
+ goto _ERR;
+ }
+
+ ret = MmcCntlrAllocDev(cntlr, (enum MmcDevType)cntlr->devType);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("LinuxSdioBind: alloc dev fail.");
+ goto _ERR;
+ }
+ MmcDeviceAddOps(cntlr->curDev, &g_sdioDeviceOps);
+ HDF_LOGD("LinuxSdioBind: Success!");
+ return HDF_SUCCESS;
+
+_ERR:
+ LinuxSdioDeleteCntlr(cntlr);
+ HDF_LOGE("LinuxSdioBind: Fail!");
+ return HDF_FAILURE;
+}
+
+static int32_t LinuxSdioInit(struct HdfDeviceObject *obj)
+{
+ (void)obj;
+ HDF_LOGD("LinuxSdioInit: Success!");
+ return HDF_SUCCESS;
+}
+
+static void LinuxSdioRelease(struct HdfDeviceObject *obj)
+{
+ if (obj == NULL) {
+ return;
+ }
+ LinuxSdioDeleteCntlr((struct MmcCntlr *)obj->service);
+}
+
+struct HdfDriverEntry g_sdioDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = LinuxSdioBind,
+ .Init = LinuxSdioInit,
+ .Release = LinuxSdioRelease,
+ .moduleName = "HDF_PLATFORM_SDIO",
+};
+HDF_INIT(g_sdioDriverEntry);
diff --git a/adapter/khdf/linux/model/storage/vendor_adapter/hi35xx_mmc_adapter.c b/adapter/khdf/linux/model/storage/vendor_adapter/hi35xx_mmc_adapter.c
new file mode 100644
index 00000000..2951cb4b
--- /dev/null
+++ b/adapter/khdf/linux/model/storage/vendor_adapter/hi35xx_mmc_adapter.c
@@ -0,0 +1,38 @@
+/*
+ * hi35xx_mmc_adapter.c
+ *
+ * hi35xx linux mmc driver implement.
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include "hdf_base.h"
+#include "hdf_log.h"
+
+#define HDF_LOG_TAG hi35xx_mmc_adapter_c
+
+struct mmc_host *himci_get_mmc_host(int32_t slot);
+void hisi_sdio_rescan(int slot);
+
+struct mmc_host *GetMmcHost(int32_t slot)
+{
+ HDF_LOGD("hi35xx GetMmcHost entry");
+ return himci_get_mmc_host(slot);
+}
+
+void SdioRescan(int slot)
+{
+ HDF_LOGD("hi35xx SdioRescan entry");
+ hisi_sdio_rescan(slot);
+}
diff --git a/adapter/khdf/linux/model/usb/device/Kconfig b/adapter/khdf/linux/model/usb/device/Kconfig
new file mode 100644
index 00000000..eb473b36
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/device/Kconfig
@@ -0,0 +1,6 @@
+config DRIVERS_HDF_USB_F_GENERIC
+ bool "Enable F_GENERIC driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to choice HDF USB F_GENERIC driver.
diff --git a/adapter/khdf/linux/model/usb/device/Makefile b/adapter/khdf/linux/model/usb/device/Makefile
new file mode 100644
index 00000000..84f36685
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/device/Makefile
@@ -0,0 +1,14 @@
+
+obj-$(CONFIG_DRIVERS_HDF_USB_F_GENERIC) += f_generic.o
+
+ccflags-y += -lm -lc -lgcc \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/include \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/bounds_checking_function/include
+
diff --git a/adapter/khdf/linux/model/usb/device/configfs.h b/adapter/khdf/linux/model/usb/device/configfs.h
new file mode 100644
index 00000000..766a4137
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/device/configfs.h
@@ -0,0 +1,38 @@
+/*
+ * configfs.h
+ *
+ * usb configfs adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef USB__GADGET__CONFIGFS__H
+#define USB__GADGET__CONFIGFS__H
+
+#include
+
+void unregister_gadget_item(struct config_item *item);
+
+struct config_group *usb_os_desc_prepare_interf_dir(
+ struct config_group *parent,
+ int n_interf,
+ struct usb_os_desc **desc,
+ char **names,
+ struct module *owner);
+
+static inline struct usb_os_desc *to_usb_os_desc(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct usb_os_desc, group);
+}
+
+#endif /* USB__GADGET__CONFIGFS__H */
diff --git a/adapter/khdf/linux/model/usb/device/f_generic.c b/adapter/khdf/linux/model/usb/device/f_generic.c
new file mode 100644
index 00000000..1b640c36
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/device/f_generic.c
@@ -0,0 +1,3832 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * f_fs.c -- user mode file system API for USB composite function controllers
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Author: Michal Nazarewicz
+ *
+ * Based on inode.c (GadgetFS) which was:
+ * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003 Agilent Technologies
+ */
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "u_generic.h"
+#include "u_f.h"
+#include "u_os_desc.h"
+#include "configfs.h"
+#include "hdf_log.h"
+
+#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
+
+/* Reference counter handling */
+static void ffs_data_get(struct ffs_data *ffs);
+static void ffs_data_put(struct ffs_data *ffs);
+/* Creates new ffs_data object. */
+static struct ffs_data *__must_check ffs_data_new(const char *dev_name)
+ __attribute__((malloc));
+
+/* Called with ffs->mutex held; take over ownership of data. */
+static int __must_check
+__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
+static int __must_check
+__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
+
+/* The function structure ***************************************************/
+
+struct ffs_ep;
+
+struct ffs_function {
+ struct usb_configuration *conf;
+ struct usb_gadget *gadget;
+ struct ffs_data *ffs;
+
+ struct ffs_ep *eps;
+ u8 eps_revmap[16];
+ short *interfaces_nums;
+
+ struct usb_function function;
+};
+static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
+{
+ return container_of(f, struct ffs_function, function);
+}
+static inline enum ffs_setup_state ffs_setup_state_clear_cancelled(struct ffs_data *ffs)
+{
+ return (enum ffs_setup_state)
+ cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP);
+}
+static void ffs_func_eps_disable(struct ffs_function *func);
+static int __must_check ffs_func_eps_enable(struct ffs_function *func);
+
+static int ffs_func_bind(struct usb_configuration *,
+ struct usb_function *);
+static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
+static void ffs_func_disable(struct usb_function *);
+static int ffs_func_setup(struct usb_function *,
+ const struct usb_ctrlrequest *);
+static bool ffs_func_req_match(struct usb_function *,
+ const struct usb_ctrlrequest *,
+ bool config0);
+static void ffs_func_suspend(struct usb_function *);
+static void ffs_func_resume(struct usb_function *);
+
+static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
+static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
+
+/* The endpoints structures *************************************************/
+struct ffs_ep {
+ struct usb_ep *ep; /* P: ffs->eps_lock */
+ struct usb_request *req; /* P: epfile->mutex */
+
+ /* [0]: full speed, [1]: high speed, [2]: super speed */
+ struct usb_endpoint_descriptor *descs[3];
+
+ u8 num;
+
+ int status; /* P: epfile->mutex */
+};
+
+struct ffs_epfile {
+ /* Protects ep->ep and ep->req. */
+ struct mutex mutex;
+ struct list_head memory_list;
+ struct ffs_data *ffs;
+ struct ffs_ep *ep; /* P: ffs->eps_lock */
+ /*
+ * Buffer for holding data from partial reads which may happen since
+ * we’re rounding user read requests to a multiple of a max packet size.
+ *
+ * The pointer is initialised with NULL value and may be set by
+ * __ffs_epfile_read_data function to point to a temporary buffer.
+ *
+ * In normal operation, calls to __ffs_epfile_read_buffered will consume
+ * data from said buffer and eventually free it. Importantly, while the
+ * function is using the buffer, it sets the pointer to NULL. This is
+ * all right since __ffs_epfile_read_data and __ffs_epfile_read_buffered
+ * can never run concurrently (they are synchronised by epfile->mutex)
+ * so the latter will not assign a new value to the pointer.
+ *
+ * Meanwhile ffs_func_eps_disable frees the buffer (if the pointer is
+ * valid) and sets the pointer to READ_BUFFER_DROP value. This special
+ * value is crux of the synchronisation between ffs_func_eps_disable and
+ * __ffs_epfile_read_data.
+ *
+ * Once __ffs_epfile_read_data is about to finish it will try to set the
+ * pointer back to its old value (as described above), but seeing as the
+ * pointer is not-NULL (namely READ_BUFFER_DROP) it will instead free
+ * the buffer.
+ *
+ * == State transitions ==
+ *
+ * • ptr == NULL: (initial state)
+ * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP
+ * ◦ __ffs_epfile_read_buffered: nop
+ * ◦ __ffs_epfile_read_data allocates temp buffer: go to ptr == buf
+ * ◦ reading finishes: n/a, not in ‘and reading’ state
+ * • ptr == DROP:
+ * ◦ __ffs_epfile_read_buffer_free: nop
+ * ◦ __ffs_epfile_read_buffered: go to ptr == NULL
+ * ◦ __ffs_epfile_read_data allocates temp buffer: free buf, nop
+ * ◦ reading finishes: n/a, not in ‘and reading’ state
+ * • ptr == buf:
+ * ◦ __ffs_epfile_read_buffer_free: free buf, go to ptr == DROP
+ * ◦ __ffs_epfile_read_buffered: go to ptr == NULL and reading
+ * ◦ __ffs_epfile_read_data: n/a, __ffs_epfile_read_buffered
+ * is always called first
+ * ◦ reading finishes: n/a, not in ‘and reading’ state
+ * • ptr == NULL and reading:
+ * ◦ __ffs_epfile_read_buffer_free: go to ptr == DROP and reading
+ * ◦ __ffs_epfile_read_buffered: n/a, mutex is held
+ * ◦ __ffs_epfile_read_data: n/a, mutex is held
+ * ◦ reading finishes and …
+ * … all data read: free buf, go to ptr == NULL
+ * … otherwise: go to ptr == buf and reading
+ * • ptr == DROP and reading:
+ * ◦ __ffs_epfile_read_buffer_free: nop
+ * ◦ __ffs_epfile_read_buffered: n/a, mutex is held
+ * ◦ __ffs_epfile_read_data: n/a, mutex is held
+ * ◦ reading finishes: free buf, go to ptr == DROP
+ */
+ struct ffs_buffer *read_buffer;
+#define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN))
+
+ char name[MAX_NAMELEN];
+ dev_t devno;
+ struct cdev cdev;
+ struct device *device;
+
+ unsigned char in; /* P: ffs->eps_lock */
+ unsigned char isoc; /* P: ffs->eps_lock */
+
+ struct kfifo reqEventFifo;
+ wait_queue_head_t wait_que;
+
+ unsigned char _pad;
+};
+
+struct ffs_buffer {
+ size_t length;
+ char *data;
+ char storage[];
+};
+
+/* ffs_io_data structure ***************************************************/
+
+struct ffs_io_data {
+ uint32_t aio;
+ uint32_t read;
+ uint32_t len;
+ uint32_t timeout;
+ uint64_t buf;
+ uint32_t actual;
+ int status;
+ struct tasklet_struct task;
+ struct usb_ep *ep;
+ struct usb_request *req;
+ struct ffs_epfile *epfile;
+ struct ffs_data *ffs;
+};
+
+struct ffs_desc_helper {
+ struct ffs_data *ffs;
+ unsigned interfaces_count;
+ unsigned eps_count;
+};
+
+static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
+static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
+
+/* Devices management *******************************************************/
+
+DEFINE_MUTEX(ffs_lock_adapter);
+EXPORT_SYMBOL_GPL(ffs_lock_adapter);
+
+static struct ffs_dev *_ffs_find_dev(const char *name);
+static struct ffs_dev *_ffs_alloc_dev(void);
+static void _ffs_free_dev(struct ffs_dev *dev);
+static void *ffs_acquire_dev(const char *dev_name);
+static void ffs_release_dev(struct ffs_data *ffs_data);
+static int ffs_ready(struct ffs_data *ffs);
+static void ffs_closed(struct ffs_data *ffs);
+
+/* Misc helper functions ****************************************************/
+
+static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
+ __attribute__((warn_unused_result, nonnull));
+static char *ffs_prepare_buffer(const char __user *buf, size_t len)
+ __attribute__((warn_unused_result, nonnull));
+
+struct class *ffs_class;
+static char *ffs_devnode(struct device *dev, umode_t *mode)
+{
+ if (mode)
+ *mode = 0666;
+ return kasprintf(GFP_KERNEL, "functionfs/%s", dev_name(dev));
+}
+
+/* Control file aka ep0 *****************************************************/
+static struct ffs_memory *generic_find_ep0_memory_area(struct ffs_data *ffs, uint64_t buf, uint32_t len)
+{
+ struct ffs_memory *ffsm = NULL;
+ struct ffs_memory *iter = NULL;
+ uint64_t buf_start = buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ffs->mem_lock, flags);
+ list_for_each_entry(iter, &ffs->memory_list, memlist) {
+ if (buf_start >= iter->vm_start &&
+ buf_start < iter->vm_start + iter->size) {
+ if (len <= iter->vm_start + iter->size - buf_start) {
+ ffsm = iter;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&ffs->mem_lock, flags);
+ return ffsm;
+}
+
+static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ffs_data *ffs = req->context;
+
+ complete(&ffs->ep0req_completion);
+
+ ffs->setup_state = FFS_NO_SETUP;
+}
+
+static void ffs_ep0_async_io_complete(struct usb_ep *_ep, struct usb_request *req)
+{
+ struct ffs_io_data *io_data = req->context;
+ struct ffs_data *ffs = io_data->ffs;
+ ENTER();
+
+ io_data->status = io_data->req->status;
+ io_data->actual = io_data->req->actual;
+ kfifo_in(&ffs->reqEventFifo, &io_data->buf, sizeof(struct UsbFnReqEvent));
+ wake_up_all(&ffs->wait_que);
+
+ list_del(&req->list);
+ usb_ep_free_request(io_data->ep, io_data->req);
+ kfree(io_data);
+
+}
+
+static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
+ __releases(&ffs->ev.waitq.lock)
+{
+ struct usb_request *req = ffs->ep0req;
+ int ret;
+
+ req->zero = len < le16_to_cpu(ffs->ev.setup.wLength);
+
+ spin_unlock_irq(&ffs->ev.waitq.lock);
+
+ req->buf = data;
+ req->length = len;
+
+ /*
+ * UDC layer requires to provide a buffer even for ZLP, but should
+ * not use it at all. Let's provide some poisoned pointer to catch
+ * possible bug in the driver.
+ */
+ if (req->buf == NULL)
+ req->buf = (void *)0xDEADBABE;
+
+ reinit_completion(&ffs->ep0req_completion);
+
+ ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
+ if (unlikely(ret < 0))
+ return ret;
+
+ ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
+ if (unlikely(ret)) {
+ usb_ep_dequeue(ffs->gadget->ep0, req);
+ return -EINTR;
+ }
+
+ ffs->setup_state = FFS_NO_SETUP;
+ return req->status ? req->status : req->actual;
+}
+
+static int __ffs_ep0_stall(struct ffs_data *ffs)
+{
+ if (ffs->ev.can_stall) {
+ pr_vdebug("ep0 stall\n");
+ usb_ep_set_halt(ffs->gadget->ep0);
+ ffs->setup_state = FFS_NO_SETUP;
+ return -EL2HLT;
+ } else {
+ pr_debug("bogus ep0 stall!\n");
+ return -ESRCH;
+ }
+}
+
+static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, size_t len, loff_t *ptr)
+{
+ struct ffs_data *ffs = file->private_data;
+ ssize_t ret;
+ char *data = NULL;
+
+ ENTER();
+
+ /* Fast check if setup was canceled */
+ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
+ return -EIDRM;
+
+ /* Acquire mutex */
+ ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+ if (unlikely(ret < 0))
+ return ret;
+
+ /* Check state */
+ switch (ffs->state) {
+ case FFS_READ_DESCRIPTORS:
+ case FFS_READ_STRINGS:
+ /* Copy data */
+ if (unlikely(len < 16)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ data = ffs_prepare_buffer(buf, len);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
+ break;
+ }
+
+ /* Handle data */
+ if (ffs->state == FFS_READ_DESCRIPTORS) {
+ pr_info("read descriptors\n");
+ ret = __ffs_data_got_descs(ffs, data, len);
+ if (unlikely(ret < 0))
+ break;
+
+ ffs->state = FFS_READ_STRINGS;
+ ret = len;
+ } else {
+ pr_info("read strings\n");
+ ret = __ffs_data_got_strings(ffs, data, len);
+ if (unlikely(ret < 0))
+ break;
+
+ ret = ffs_epfiles_create(ffs);
+ if (unlikely(ret)) {
+ ffs->state = FFS_CLOSING;
+ break;
+ }
+
+ ffs->state = FFS_ACTIVE;
+ mutex_unlock(&ffs->mutex);
+
+ ret = ffs_ready(ffs);
+ if (unlikely(ret < 0)) {
+ ffs->state = FFS_CLOSING;
+ return ret;
+ }
+
+ return len;
+ }
+ break;
+
+ case FFS_ACTIVE:
+ data = NULL;
+ /*
+ * We're called from user space, we can use _irq
+ * rather then _irqsave
+ */
+ spin_lock_irq(&ffs->ev.waitq.lock);
+ switch (ffs_setup_state_clear_cancelled(ffs)) {
+ case FFS_SETUP_CANCELLED:
+ ret = -EIDRM;
+ goto done_spin;
+
+ case FFS_NO_SETUP:
+ ret = -ESRCH;
+ goto done_spin;
+
+ case FFS_SETUP_PENDING:
+ break;
+ }
+
+ /* FFS_SETUP_PENDING */
+ if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
+ spin_unlock_irq(&ffs->ev.waitq.lock);
+ ret = __ffs_ep0_stall(ffs);
+ break;
+ }
+
+ /* FFS_SETUP_PENDING and not stall */
+ len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+
+ spin_unlock_irq(&ffs->ev.waitq.lock);
+
+ data = ffs_prepare_buffer(buf, len);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
+ break;
+ }
+
+ spin_lock_irq(&ffs->ev.waitq.lock);
+
+ /*
+ * We are guaranteed to be still in FFS_ACTIVE state
+ * but the state of setup could have changed from
+ * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need
+ * to check for that. If that happened we copied data
+ * from user space in vain but it's unlikely.
+ *
+ * For sure we are not in FFS_NO_SETUP since this is
+ * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
+ * transition can be performed and it's protected by
+ * mutex.
+ */
+ if (ffs_setup_state_clear_cancelled(ffs) ==
+ FFS_SETUP_CANCELLED) {
+ ret = -EIDRM;
+done_spin:
+ spin_unlock_irq(&ffs->ev.waitq.lock);
+ } else {
+ /* unlocks spinlock */
+ ret = __ffs_ep0_queue_wait(ffs, data, len);
+ }
+ kfree(data);
+ break;
+
+ default:
+ ret = -EBADFD;
+ break;
+ }
+
+ mutex_unlock(&ffs->mutex);
+ return ret;
+}
+
+/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
+static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, size_t n)
+ __releases(&ffs->ev.waitq.lock)
+{
+ /*
+ * n cannot be bigger than ffs->ev.count, which cannot be bigger than
+ * size of ffs->ev.types array (which is four) so that's how much space
+ * we reserve.
+ */
+ struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
+ const size_t size = n * sizeof *events;
+ unsigned i = 0;
+ int32_t ret;
+
+ ret = memset_s(events, size, 0, size);
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s:%{public}d memset_s failed", __func__, __LINE__);
+ return ret;
+ }
+
+ do {
+ events[i].type = ffs->ev.types[i];
+ if (events[i].type == FUNCTIONFS_SETUP) {
+ events[i].u.setup = ffs->ev.setup;
+ ffs->setup_state = FFS_SETUP_PENDING;
+ }
+ } while (++i < n);
+
+ ffs->ev.count -= n;
+ if (ffs->ev.count)
+ memmove_s(ffs->ev.types, ffs->ev.count * sizeof *ffs->ev.types, ffs->ev.types + n,
+ ffs->ev.count * sizeof *ffs->ev.types);
+
+ spin_unlock_irq(&ffs->ev.waitq.lock);
+ mutex_unlock(&ffs->mutex);
+
+ return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size;
+}
+
+static ssize_t ffs_ep0_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
+{
+ struct ffs_data *ffs = file->private_data;
+ char *data = NULL;
+ size_t n;
+ int ret;
+
+ ENTER();
+
+ /* Fast check if setup was canceled */
+ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
+ return -EIDRM;
+
+ /* Acquire mutex */
+ ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+ if (unlikely(ret < 0))
+ return ret;
+
+ /* Check state */
+ if (ffs->state != FFS_ACTIVE) {
+ ret = -EBADFD;
+ goto done_mutex;
+ }
+
+ /*
+ * We're called from user space, we can use _irq rather then
+ * _irqsave
+ */
+ spin_lock_irq(&ffs->ev.waitq.lock);
+
+ switch (ffs_setup_state_clear_cancelled(ffs)) {
+ case FFS_SETUP_CANCELLED:
+ ret = -EIDRM;
+ break;
+
+ case FFS_NO_SETUP:
+ n = len / sizeof(struct usb_functionfs_event);
+ if (unlikely(!n)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
+ ffs->ev.count)) {
+ ret = -EINTR;
+ break;
+ }
+
+ /* unlocks spinlock */
+ return __ffs_ep0_read_events(ffs, buf,
+ min(n, (size_t)ffs->ev.count));
+
+ case FFS_SETUP_PENDING:
+ if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
+ spin_unlock_irq(&ffs->ev.waitq.lock);
+ ret = __ffs_ep0_stall(ffs);
+ goto done_mutex;
+ }
+
+ len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+
+ spin_unlock_irq(&ffs->ev.waitq.lock);
+
+ if (likely(len)) {
+ data = kmalloc(len, GFP_KERNEL);
+ if (unlikely(!data)) {
+ ret = -ENOMEM;
+ goto done_mutex;
+ }
+ }
+
+ spin_lock_irq(&ffs->ev.waitq.lock);
+
+ /* See ffs_ep0_write() */
+ if (ffs_setup_state_clear_cancelled(ffs) ==
+ FFS_SETUP_CANCELLED) {
+ ret = -EIDRM;
+ break;
+ }
+
+ /* unlocks spinlock */
+ ret = __ffs_ep0_queue_wait(ffs, data, len);
+ if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len)))
+ ret = -EFAULT;
+ goto done_mutex;
+
+ default:
+ ret = -EBADFD;
+ break;
+ }
+
+ spin_unlock_irq(&ffs->ev.waitq.lock);
+done_mutex:
+ mutex_unlock(&ffs->mutex);
+ kfree(data);
+ return ret;
+}
+
+static int ffs_ep0_open(struct inode *inode, struct file *file)
+{
+ struct ffs_data *ffs = container_of(inode->i_cdev, struct ffs_data, cdev);
+ ENTER();
+
+ if (unlikely(ffs->state == FFS_CLOSING))
+ return -EBUSY;
+
+ file->private_data = ffs;
+ return 0;
+}
+
+static int ffs_ep0_release(struct inode *inode, struct file *file)
+{
+ ENTER();
+ return 0;
+}
+
+static ssize_t ffs_ep0_iorw(struct file *file, struct ffs_io_data *io_data)
+{
+ struct ffs_data *ffs = file->private_data;
+ struct usb_request *req = NULL;
+ ssize_t ret, data_len = io_data->len;
+ bool interrupted = false;
+ struct ffs_memory *ffsm = NULL;
+
+ /* Are we still active? */
+ if (WARN_ON(ffs->state != FFS_ACTIVE))
+ return -ENODEV;
+ ffsm = generic_find_ep0_memory_area(ffs, io_data->buf, data_len);
+ if (ffsm == NULL)
+ {
+ return -ENODEV;
+ }
+ if (!io_data->aio) {
+ reinit_completion(&ffs->ep0req_completion);
+
+ req = ffs->ep0req;
+ req->buf = (void *)(ffsm->mem + io_data->buf - ffsm->vm_start);
+ req->length = data_len;
+ req->complete = ffs_ep0_complete;
+
+ ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
+ if (unlikely(ret < 0))
+ goto error;
+
+ if (io_data->timeout > 0) {
+ ret = wait_for_completion_interruptible_timeout(&ffs->ep0req_completion, io_data->timeout);
+ if (ret < 0) {
+ /*
+ * To avoid race condition with ffs_epfile_io_complete,
+ * dequeue the request first then check
+ * status. usb_ep_dequeue API should guarantee no race
+ * condition with req->complete callback.
+ */
+ usb_ep_dequeue(ffs->gadget->ep0, req);
+ wait_for_completion(&ffs->ep0req_completion);
+ interrupted = req->status < 0;
+ } else if (ret == 0) {
+ ret = -EBUSY;
+ usb_ep_dequeue(ffs->gadget->ep0, req);
+ wait_for_completion(&ffs->ep0req_completion);
+ goto error;
+ }
+ } else {
+ ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
+ if (ret < 0) {
+ usb_ep_dequeue(ffs->gadget->ep0, req);
+ wait_for_completion(&ffs->ep0req_completion);
+ interrupted = req->status < 0;
+ }
+ }
+
+ if (interrupted) {
+ ret = -EINTR;
+ } else {
+ ret = req->actual;
+ }
+ goto error;
+ }
+ else if (!(req = usb_ep_alloc_request(ffs->gadget->ep0, GFP_ATOMIC))) {
+ ret = -ENOMEM;
+ }
+ else {
+ req->buf = (void *)(ffsm->mem + io_data->buf - ffsm->vm_start);
+ req->length = data_len;
+
+ io_data->ep = ffs->gadget->ep0;
+ io_data->req = req;
+ io_data->ffs = ffs;
+
+ req->context = io_data;
+ req->complete = ffs_ep0_async_io_complete;
+ list_add(&req->list, &ffs->ep0req->list);
+ ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
+ if (unlikely(ret)) {
+ usb_ep_free_request(ffs->gadget->ep0, req);
+ goto error;
+ }
+
+ ret = -EIOCBQUEUED;
+ }
+
+error:
+ return ret;
+}
+
+static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
+{
+ struct ffs_data *ffs = file->private_data;
+ long ret = 0;
+ unsigned int copied = 0;
+ struct ffs_memory *ffsm = NULL;
+ struct generic_memory mem;
+
+ ENTER();
+
+ switch (code) {
+ case FUNCTIONFS_ENDPOINT_QUEUE_INIT:
+ ret = kfifo_alloc(&ffs->reqEventFifo, MAX_REQUEST * sizeof(struct UsbFnReqEvent), GFP_KERNEL);
+ break;
+ case FUNCTIONFS_ENDPOINT_QUEUE_DEL:
+ kfifo_free(&ffs->reqEventFifo);
+ break;
+ case FUNCTIONFS_ENDPOINT_RELEASE_BUF:
+ if (copy_from_user(&mem, (void __user *)value, sizeof(mem)))
+ {
+ pr_info("copy from user failed\n");
+ return -EFAULT;
+ }
+ ffsm = generic_find_ep0_memory_area(ffs, mem.buf, mem.size);
+ if (ffsm == NULL)
+ {
+ return -EFAULT;
+ }
+ list_del(&ffsm->memlist);
+ kfree((void *)ffsm->mem);
+ kfree(ffsm);
+ break;
+ case FUNCTIONFS_ENDPOINT_READ:
+ case FUNCTIONFS_ENDPOINT_WRITE:
+ {
+ struct IoData myIoData;
+ struct ffs_io_data io_data, *p = &io_data;
+ ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
+ if (unlikely(ret)) {
+ return -EFAULT;
+ }
+ if (myIoData.aio) {
+ p = kmalloc(sizeof(io_data), GFP_KERNEL);
+ if (unlikely(!p))
+ return -ENOMEM;
+ } else {
+ ret = memset_s(p, sizeof(*p), 0, sizeof(*p));
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s:%{public}d memset_s failed", __func__, __LINE__);
+ return ret;
+ }
+ }
+ ret = memcpy_s(p, sizeof(*p), &myIoData, sizeof(struct IoData));
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s:%{public}d memcpy_s failed", __func__, __LINE__);
+ return ret;
+ }
+
+ ret = ffs_ep0_iorw(file, p);
+ if (ret == -EIOCBQUEUED) {
+ return 0;
+ }
+ if (p->aio)
+ kfree(p);
+ return ret;
+ }
+ case FUNCTIONFS_ENDPOINT_RW_CANCEL:
+ {
+ struct usb_request *req;
+ struct IoData myIoData;
+ ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
+ if (unlikely(ret)) {
+ return -EFAULT;
+ }
+ ffsm = generic_find_ep0_memory_area(ffs, myIoData.buf, myIoData.len);
+ if (ffsm == NULL)
+ {
+ return -EFAULT;
+ }
+ list_for_each_entry(req, &ffs->ep0req->list, list) {
+ if (req->buf == (void *)(ffsm->mem + myIoData.buf - ffsm->vm_start)) {
+ usb_ep_dequeue(ffs->gadget->ep0, req);
+ return 0;
+ }
+ }
+ return -EFAULT;
+ }
+ case FUNCTIONFS_ENDPOINT_GET_REQ_STATUS:
+ {
+ struct usb_request *req;
+ struct IoData myIoData;
+ ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
+ if (unlikely(ret)) {
+ return -EFAULT;
+ }
+ ffsm = generic_find_ep0_memory_area(ffs, myIoData.buf, myIoData.len);
+ if (ffsm == NULL)
+ {
+ return -EFAULT;
+ }
+ list_for_each_entry(req, &ffs->ep0req->list, list) {
+ if (req->buf == (void *)(ffsm->mem + myIoData.buf - ffsm->vm_start)) {
+ return req->status;
+ }
+ }
+ return -EFAULT;
+ }
+ case FUNCTIONFS_ENDPOINT_GET_EP0_EVENT:
+ if (!kfifo_is_empty(&ffs->reqEventFifo)) {
+ ret = kfifo_to_user(&ffs->reqEventFifo, (void __user *)value,
+ sizeof(struct UsbFnReqEvent), &copied) == 0 ? copied : -1;
+ if (ret > 0) {
+ ffs->setup_state = FFS_NO_SETUP;
+ return ret;
+ }
+ }
+
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long ffs_ep0_compat_ioctl(struct file *file, unsigned code,
+ unsigned long value)
+{
+ return ffs_ep0_ioctl(file, code, value);
+}
+#endif
+
+static __poll_t ffs_ep0_poll(struct file *file, poll_table *wait)
+{
+ struct ffs_data *ffs = file->private_data;
+ __poll_t mask = EPOLLWRNORM;
+ int ret;
+
+ ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
+ if (unlikely(ret < 0))
+ return mask;
+
+ switch (ffs->state) {
+ case FFS_READ_DESCRIPTORS:
+ case FFS_READ_STRINGS:
+ mask |= EPOLLOUT;
+ break;
+
+ case FFS_ACTIVE:
+ switch (ffs->setup_state) {
+ case FFS_NO_SETUP:
+ poll_wait(file, &ffs->ev.waitq, wait);
+ if (ffs->ev.count)
+ mask |= EPOLLIN;
+ break;
+
+ case FFS_SETUP_PENDING:
+ case FFS_SETUP_CANCELLED:
+ poll_wait(file, &ffs->wait_que, wait);
+ if (!kfifo_is_empty(&ffs->reqEventFifo))
+ {
+ mask |= EPOLLOUT;
+ }
+ break;
+ }
+ case FFS_CLOSING:
+ break;
+ case FFS_DEACTIVATED:
+ break;
+ }
+
+ mutex_unlock(&ffs->mutex);
+
+ return mask;
+}
+
+static int ffs_ep0_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct ffs_data *ffs = file->private_data;
+ size_t size = vma->vm_end - vma->vm_start;
+ unsigned long flags;
+ struct ffs_memory *ffsm = NULL;
+ void *virt_mem = NULL;
+
+ if (ffs == NULL) {
+ pr_info("Invalid private parameter!\n");
+ return -EINVAL;
+ }
+ virt_mem = kmalloc(size, GFP_KERNEL);
+ if (virt_mem == NULL)
+ {
+ pr_info("%s alloc memory failed!\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ ffsm = kmalloc(sizeof(struct ffs_memory), GFP_KERNEL);
+ if (ffsm == NULL)
+ {
+ pr_info("%s alloc memory failed!\n", __FUNCTION__);
+ goto error_free_mem;
+ }
+ if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(virt_mem)>>PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ goto error_free_ffsm;
+ }
+ ffsm->mem = (uint64_t)virt_mem;
+ ffsm->size = size;
+ ffsm->vm_start = vma->vm_start;
+ INIT_LIST_HEAD(&ffsm->memlist);
+ spin_lock_irqsave(&ffs->mem_lock, flags);
+ list_add_tail(&ffsm->memlist, &ffs->memory_list);
+ spin_unlock_irqrestore(&ffs->mem_lock, flags);
+ return 0;
+error_free_ffsm:
+ kfree(ffsm);
+error_free_mem:
+ kfree(virt_mem);
+ return -1;
+}
+
+static const struct file_operations ffs_ep0_operations = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = ffs_ep0_open,
+ .write = ffs_ep0_write,
+ .read = ffs_ep0_read,
+ .release = ffs_ep0_release,
+ .unlocked_ioctl = ffs_ep0_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ffs_ep0_compat_ioctl,
+#endif
+ .poll = ffs_ep0_poll,
+ .mmap = ffs_ep0_mmap,
+};
+
+/* "Normal" endpoints operations ********************************************/
+static struct ffs_memory *generic_find_memory_area(struct ffs_epfile *epfile, uint64_t buf, uint32_t len)
+{
+ struct ffs_memory *ffsm = NULL, *iter = NULL;
+ uint64_t buf_start = buf;
+
+ list_for_each_entry(iter, &epfile->memory_list, memlist) {
+ if (buf_start >= iter->vm_start &&
+ buf_start < iter->vm_start + iter->size) {
+ if (len <= iter->vm_start + iter->size - buf_start) {
+ ffsm = iter;
+ break;
+ }
+ }
+ }
+ return ffsm;
+}
+
+static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
+{
+ ENTER();
+ if (likely(req->context)) {
+ struct ffs_ep *ep = _ep->driver_data;
+ ep->status = req->status ? req->status : req->actual;
+ complete(req->context);
+ }
+}
+
+static void epfile_task_proc(unsigned long context)
+{
+ struct ffs_io_data *io_data = (struct ffs_io_data *)context;
+ struct ffs_epfile *epfile = io_data->epfile;
+ unsigned long flags;
+
+ spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
+ io_data->status = io_data->req->status;
+ io_data->actual = io_data->req->actual;
+ kfifo_in(&epfile->reqEventFifo, &io_data->buf, sizeof(struct UsbFnReqEvent));
+ list_del(&io_data->req->list);
+ usb_ep_free_request(io_data->ep, io_data->req);
+ kfree(io_data);
+ spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
+ wake_up_all(&epfile->wait_que);
+}
+
+static void ffs_epfile_async_io_complete(struct usb_ep *_ep, struct usb_request *req)
+{
+ struct ffs_io_data *io_data = req->context;
+
+ tasklet_init(&io_data->task, epfile_task_proc, (uintptr_t)io_data);
+ tasklet_schedule(&io_data->task);
+
+}
+
+static int ffs_epfile_open(struct inode *inode, struct file *file)
+{
+ struct ffs_epfile *epfile = container_of(inode->i_cdev, struct ffs_epfile, cdev);
+ ENTER();
+ if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+ return -ENODEV;
+
+ file->private_data = epfile;
+ return 0;
+}
+
+static int ffs_epfile_release(struct inode *inode, struct file *file)
+{
+ ENTER();
+ return 0;
+}
+
+static int ffs_epfile_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct ffs_epfile *epfile = file->private_data;
+ size_t size = vma->vm_end - vma->vm_start;
+ struct ffs_memory *ffsm = NULL;
+ unsigned long flags;
+ void *virt_mem = NULL;
+
+ if (epfile == NULL)
+ {
+ pr_info("Invalid private parameter!\n");
+ return -EINVAL;
+ }
+ virt_mem = kmalloc(size, GFP_KERNEL);
+ if (virt_mem == NULL)
+ {
+ pr_info("%s alloc memory failed!\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ ffsm = kmalloc(sizeof(struct ffs_memory), GFP_KERNEL);
+ if (ffsm == NULL)
+ {
+ pr_info("%s alloc memory failed!\n", __FUNCTION__);
+ goto error_free_mem;
+ }
+ if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(virt_mem)>>PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ {
+ goto error_free_ffsm;
+ }
+ ffsm->mem = (uint64_t)virt_mem;
+ ffsm->size = size;
+ ffsm->vm_start = vma->vm_start;
+ INIT_LIST_HEAD(&ffsm->memlist);
+ spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
+ list_add_tail(&ffsm->memlist, &epfile->memory_list);
+ spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
+
+ return 0;
+error_free_ffsm:
+ kfree(ffsm);
+error_free_mem:
+ kfree(virt_mem);
+
+ return -1;
+}
+
+static ssize_t ffs_epfile_iorw(struct file *file, struct ffs_io_data *io_data)
+{
+ struct ffs_epfile *epfile = file->private_data;
+ struct usb_request *req = NULL;
+ struct ffs_ep *ep = NULL;
+ struct ffs_memory *ffsm = NULL;
+ ssize_t ret, data_len = -EINVAL;
+ int halt;
+
+ /* Are we still active? */
+ if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+ return -ENODEV;
+
+ /* Wait for endpoint to be enabled */
+ ep = epfile->ep;
+ if (!ep) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(
+ epfile->ffs->wait, (ep = epfile->ep));
+ if (ret)
+ return -EINTR;
+ }
+
+ /* Do we halt? */
+ halt = (!io_data->read == !epfile->in);
+ if (halt && epfile->isoc)
+ return -EINVAL;
+
+ /* We will be using request and read_buffer */
+ ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
+ if (unlikely(ret))
+ goto error;
+
+ /* Allocate & copy */
+ if (!halt) {
+ struct usb_gadget *gadget;
+ /*
+ * if we _do_ wait above, the epfile->ffs->gadget might be NULL
+ * before the waiting completes, so do not assign to 'gadget'
+ * earlier
+ */
+ gadget = epfile->ffs->gadget;
+
+ spin_lock_irq(&epfile->ffs->eps_lock);
+ /* In the meantime, endpoint got disabled or changed. */
+ if (epfile->ep != ep) {
+ ret = -ESHUTDOWN;
+ goto error_lock;
+ }
+ data_len = io_data->len;
+ /*
+ * Controller may require buffer size to be aligned to
+ * maxpacketsize of an out endpoint.
+ */
+ if (io_data->read)
+ data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ }
+
+ spin_lock_irq(&epfile->ffs->eps_lock);
+ ffsm = generic_find_memory_area(epfile, io_data->buf, io_data->len);
+ if (ffsm == NULL)
+ {
+ return -EFAULT;
+ }
+ if (epfile->ep != ep) {
+ /* In the meantime, endpoint got disabled or changed. */
+ ret = -ESHUTDOWN;
+ }
+ else if (halt) {
+ ret = usb_ep_set_halt(ep->ep);
+ if (!ret)
+ ret = -EBADMSG;
+ }
+ else if (!io_data->aio) {
+ DECLARE_COMPLETION_ONSTACK(done);
+ bool interrupted = false;
+
+ req = ep->req;
+ req->buf = (void *)(ffsm->mem + io_data->buf - ffsm->vm_start);
+ req->length = data_len;
+
+ req->context = &done;
+ req->complete = ffs_epfile_io_complete;
+
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ if (unlikely(ret < 0))
+ goto error_lock;
+
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ if (io_data->timeout > 0) {
+ ret = wait_for_completion_interruptible_timeout(&done, io_data->timeout);
+ if (ret < 0) {
+ /*
+ * To avoid race condition with ffs_epfile_io_complete,
+ * dequeue the request first then check
+ * status. usb_ep_dequeue API should guarantee no race
+ * condition with req->complete callback.
+ */
+ usb_ep_dequeue(ep->ep, req);
+ wait_for_completion(&done);
+ interrupted = ep->status < 0;
+ } else if (ret == 0) {
+ ret = -EBUSY;
+ usb_ep_dequeue(ep->ep, req);
+ wait_for_completion(&done);
+ goto error_mutex;
+ }
+ } else {
+ ret = wait_for_completion_interruptible(&done);
+ if (ret < 0) {
+ usb_ep_dequeue(ep->ep, req);
+ wait_for_completion(&done);
+ interrupted = ep->status < 0;
+ }
+ }
+
+ if (interrupted) {
+ ret = -EINTR;
+ } else {
+ ret = req->actual;
+ }
+ goto error_mutex;
+ }
+ else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) {
+ ret = -ENOMEM;
+ }
+ else {
+ req->buf = (void *)(ffsm->mem + io_data->buf - ffsm->vm_start);
+ req->length = data_len;
+
+ io_data->ep = ep->ep;
+ io_data->req = req;
+ io_data->epfile = epfile;
+
+ req->context = io_data;
+ req->complete = ffs_epfile_async_io_complete;
+ list_add(&req->list, &ep->req->list);
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
+ if (unlikely(ret)) {
+ usb_ep_free_request(ep->ep, req);
+ goto error_lock;
+ }
+
+ ret = -EIOCBQUEUED;
+ }
+
+error_lock:
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+error_mutex:
+ mutex_unlock(&epfile->mutex);
+error:
+ return ret;
+}
+
+static long ffs_epfile_ioctl(struct file *file, unsigned code, unsigned long value)
+{
+ struct ffs_epfile *epfile = file->private_data;
+ struct ffs_ep *ep = epfile->ep;
+ int ret = 0;
+ struct generic_memory mem;
+ struct ffs_memory *ffsm = NULL;
+
+ ENTER();
+
+ if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+ return -ENODEV;
+
+ spin_lock_irq(&epfile->ffs->eps_lock);
+
+ switch (code) {
+ case FUNCTIONFS_ENDPOINT_QUEUE_INIT:
+ ret = kfifo_alloc(&epfile->reqEventFifo, MAX_REQUEST * sizeof(struct UsbFnReqEvent), GFP_KERNEL);
+ break;
+ case FUNCTIONFS_ENDPOINT_QUEUE_DEL:
+ kfifo_free(&epfile->reqEventFifo);
+ break;
+ case FUNCTIONFS_ENDPOINT_RELEASE_BUF:
+ if (copy_from_user(&mem, (void __user *)value, sizeof(mem)))
+ {
+ pr_info("copy from user failed\n");
+ return -EFAULT;
+ }
+ ffsm = generic_find_memory_area(epfile, mem.buf, mem.size);
+ if (ffsm == NULL)
+ {
+ return -EFAULT;
+ }
+ list_del(&ffsm->memlist);
+ kfree((void *)ffsm->mem);
+ kfree(ffsm);
+ break;
+ case FUNCTIONFS_ENDPOINT_READ:
+ case FUNCTIONFS_ENDPOINT_WRITE:
+ {
+ struct IoData myIoData;
+ struct ffs_io_data io_data, *p = &io_data;
+ ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
+ if (unlikely(ret)) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return -EFAULT;
+ }
+ if (myIoData.aio) {
+ p = kmalloc(sizeof(io_data), GFP_KERNEL);
+ if (unlikely(!p)) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return -ENOMEM;
+ }
+ } else {
+ ret = memset_s(p, sizeof(*p), 0, sizeof(*p));
+ if (ret != EOK) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ HDF_LOGE("%{public}s:%{public}d memset_s failed", __func__, __LINE__);
+ return ret;
+ }
+
+ }
+ ret = memcpy_s(p, sizeof(*p), &myIoData, sizeof(struct IoData));
+ if (ret != EOK) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ HDF_LOGE("%{public}s:%{public}d memcpy_s failed", __func__, __LINE__);
+ return ret;
+ }
+
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ ret = ffs_epfile_iorw(file, p);
+ if (ret == -EIOCBQUEUED) {
+ return 0;
+ }
+ if (p->aio)
+ kfree(p);
+ return ret;
+ }
+ case FUNCTIONFS_ENDPOINT_RW_CANCEL:
+ {
+ struct usb_request *req;
+ struct IoData myIoData;
+ if (!ep) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return -EFAULT;
+ }
+ ret = copy_from_user(&myIoData, (void __user *)value, sizeof(struct IoData));
+ if (unlikely(ret)) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return -EFAULT;
+ }
+ ffsm = generic_find_memory_area(epfile, myIoData.buf, myIoData.len);
+ if (ffsm == NULL)
+ {
+ return -EFAULT;
+ }
+ list_for_each_entry(req, &epfile->ep->req->list, list) {
+ if (req->buf == (void *)(ffsm->mem + myIoData.buf - ffsm->vm_start)) {
+ usb_ep_dequeue(epfile->ep->ep, req);
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return 0;
+ }
+ }
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return -EFAULT;
+ }
+ case FUNCTIONFS_ENDPOINT_GET_REQ_STATUS:
+ {
+ struct usb_request *req;
+ struct IoData myIoData;
+ if (!ep) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return -EFAULT;
+ }
+ ret = copy_from_user(&myIoData,(void __user *)value, sizeof(struct IoData));
+ if (unlikely(ret)) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return -EFAULT;
+ }
+ ffsm = generic_find_memory_area(epfile, myIoData.buf, myIoData.len);
+ if (ffsm == NULL)
+ {
+ return -EFAULT;
+ }
+ list_for_each_entry(req, &epfile->ep->req->list, list) {
+ if (req->buf == (void *)(ffsm->mem + myIoData.buf - ffsm->vm_start)) {
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return req->status;
+ }
+ }
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ return -EFAULT;
+ }
+ case FUNCTIONFS_FIFO_STATUS:
+ ret = usb_ep_fifo_status(epfile->ep->ep);
+ break;
+ case FUNCTIONFS_FIFO_FLUSH:
+ usb_ep_fifo_flush(epfile->ep->ep);
+ ret = 0;
+ break;
+ case FUNCTIONFS_CLEAR_HALT:
+ ret = usb_ep_clear_halt(epfile->ep->ep);
+ break;
+ case FUNCTIONFS_ENDPOINT_REVMAP:
+ ret = epfile->ep->num;
+ break;
+ case FUNCTIONFS_ENDPOINT_DESC:
+ {
+ int desc_idx;
+ int i;
+ struct usb_endpoint_descriptor *desc;
+
+ switch (epfile->ffs->speed) {
+ case USB_SPEED_SUPER:
+ desc_idx = 2;
+ break;
+ case USB_SPEED_HIGH:
+ desc_idx = 1;
+ break;
+ default:
+ desc_idx = 1;
+ }
+ for (i = 0; i < epfile->ffs->eps_count; i++) {
+ if (epfile->ffs->epfiles + i == epfile)
+ break;
+ }
+ ep = epfile->ffs->eps + i;
+ desc = ep->descs[desc_idx];
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ ret = copy_to_user((void __user *)value, desc, desc->bLength);
+ if (ret)
+ ret = -EFAULT;
+ return ret;
+ }
+ default:
+ ret = -ENOTTY;
+ }
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+
+ return ret;
+}
+
+static ssize_t ffs_epfile_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
+{
+ int status = 0;
+ unsigned int copied = 0;
+ unsigned long flags;
+ struct ffs_epfile *epfile = file->private_data;
+ ENTER();
+ if (kfifo_is_empty(&epfile->reqEventFifo)) {
+ return 0;
+ }
+ spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
+ status = kfifo_to_user(&epfile->reqEventFifo, buf, count, &copied) == 0 ? copied : -1;
+ spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
+
+ return status;
+}
+
+static ssize_t ffs_epfile_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
+{
+ return count;
+}
+
+static unsigned int ffs_epfile_poll(struct file *file, struct poll_table_struct * wait)
+{
+ unsigned int mask = 0;
+ struct ffs_epfile *epfile = file->private_data;
+ ENTER();
+ poll_wait(file, &epfile->wait_que, wait);
+ if (!kfifo_is_empty(&epfile->reqEventFifo)) {
+ mask |= POLLIN;
+ }
+ return mask;
+}
+
+#ifdef CONFIG_COMPAT
+static long ffs_epfile_compat_ioctl(struct file *file, unsigned code,
+ unsigned long value)
+{
+ return ffs_epfile_ioctl(file, code, value);
+}
+#endif
+
+static const struct file_operations ffs_epfile_operations = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .mmap = ffs_epfile_mmap,
+ .read = ffs_epfile_read,
+ .write = ffs_epfile_write,
+ .poll = ffs_epfile_poll,
+ .open = ffs_epfile_open,
+ .release = ffs_epfile_release,
+ .unlocked_ioctl = ffs_epfile_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ffs_epfile_compat_ioctl,
+#endif
+};
+
+/* ffs_data and ffs_function construction and destruction code **************/
+static void ffs_data_clear(struct ffs_data *ffs);
+static void ffs_data_reset(struct ffs_data *ffs);
+static dev_t g_dev;
+#define MAX_EP_DEV 10
+static long usbfn_ioctl(struct file *file, unsigned int cmd, unsigned long value)
+{
+ long ret;
+ ENTER();
+ switch(cmd)
+ {
+ case FUNCTIONFS_NEWFN:
+ {
+ struct ffs_dev *ffs_dev;
+ struct ffs_data *ffs;
+ struct FuncNew newfn;
+ char nameEp0[MAX_NAMELEN];
+ ret = copy_from_user(&newfn, (void __user *)value, sizeof(struct FuncNew ));
+ if (unlikely(ret)) {
+ return -EFAULT;
+ }
+ ffs = ffs_data_new(newfn.name);
+ if (unlikely(!ffs)) {
+ return (-ENOMEM);
+ }
+
+ ret = memcpy_s(ffs->dev_name, MAX_NAMELEN, newfn.name, newfn.nameLen);
+ if (ret != EOK) {
+ ffs_data_put(ffs);
+ HDF_LOGE("%{public}s:%{public}d memcpy_s failed", __func__, __LINE__);
+ return ret;
+ }
+
+ if (unlikely(!ffs->dev_name)) {
+ ffs_data_put(ffs);
+ return (-ENOMEM);
+ }
+
+ if (sprintf_s(nameEp0, MAX_NAMELEN, "%s.ep%u", ffs->dev_name, 0) < 0) {
+ ffs_data_put(ffs);
+ return -EFAULT;
+ }
+ ffs_dev = ffs_acquire_dev(newfn.name);
+ if (IS_ERR(ffs_dev)) {
+ ffs_data_put(ffs);
+ return (-ENODEV);
+ }
+ ffs->private_data = ffs_dev;
+
+ ret = alloc_chrdev_region(&g_dev, 0, MAX_EP_DEV, nameEp0);
+ if (ret < 0) {
+ ffs_release_dev(ffs);
+ ffs_data_put(ffs);
+ return -EBUSY;
+ }
+ cdev_init(&ffs->cdev, &ffs_ep0_operations);
+ ffs->devno = MKDEV(MAJOR(g_dev), 0);
+ ret = cdev_add(&ffs->cdev, ffs->devno, 1);
+ if (ret) {
+ ffs_release_dev(ffs);
+ ffs_data_put(ffs);
+ return -EBUSY;
+ }
+
+ ffs->fn_device = device_create(ffs_class, NULL, ffs->devno, NULL, nameEp0);
+ if (IS_ERR(ffs->fn_device)) {
+ cdev_del(&ffs->cdev);
+ ffs_release_dev(ffs);
+ ffs_data_put(ffs);
+ return -EBUSY;
+ }
+ return 0;
+ }
+ case FUNCTIONFS_DELFN:
+ {
+ struct FuncNew newfn;
+ struct ffs_data *ffs;
+ struct ffs_dev *ffs_dev;
+ ret = copy_from_user(&newfn, (void __user *)value, sizeof(struct FuncNew ));
+ if (unlikely(ret)) {
+ return -EFAULT;
+ }
+
+ ffs_dev = _ffs_find_dev(newfn.name);
+ if (IS_ERR(ffs_dev)) {
+ return -EFAULT;
+ }
+ ffs = ffs_dev->ffs_data;
+ device_destroy(ffs_class, ffs->devno);
+ cdev_del(&ffs->cdev);
+ unregister_chrdev_region(g_dev, MAX_EP_DEV);
+ ffs_release_dev(ffs);
+ ffs_data_clear(ffs);
+ destroy_workqueue(ffs->io_completion_wq);
+ kfree(ffs);
+ return 0;
+ }
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+static int usbfn_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int usbfn_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static struct file_operations usbfn_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = usbfn_ioctl,
+ .open = usbfn_open,
+ .release = usbfn_release,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = usbfn_ioctl,
+#endif
+};
+
+static struct miscdevice usbfn_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "usbfn",
+ .fops = &usbfn_fops,
+};
+
+/* Driver's main init/cleanup functions *************************************/
+static int functionfs_init(void)
+{
+ int ret;
+
+ ENTER();
+ ret = misc_register(&usbfn_misc);
+ if (likely(!ret))
+ pr_info("file system registered\n");
+ else
+ pr_err("failed registering file system (%d)\n", ret);
+
+ ffs_class = class_create(THIS_MODULE, "functionfs");
+ if (IS_ERR(ffs_class))
+ return PTR_ERR(ffs_class);
+
+ ffs_class->devnode = ffs_devnode;
+
+ return ret;
+}
+
+static void functionfs_cleanup(void)
+{
+ ENTER();
+ class_destroy(ffs_class);
+ misc_deregister(&usbfn_misc);
+}
+
+static void ffs_data_get(struct ffs_data *ffs)
+{
+ ENTER();
+ refcount_inc(&ffs->ref);
+}
+
+static void ffs_data_put(struct ffs_data *ffs)
+{
+ ENTER();
+ if (unlikely(refcount_dec_and_test(&ffs->ref))) {
+ pr_info("%s(): freeing\n", __func__);
+ ffs_data_clear(ffs);
+ BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+ swait_active(&ffs->ep0req_completion.wait) ||
+#else
+ waitqueue_active(&ffs->ep0req_completion.wait) ||
+#endif
+ waitqueue_active(&ffs->wait) ||
+ waitqueue_active(&ffs->wait_que));
+ destroy_workqueue(ffs->io_completion_wq);
+ kfree(ffs);
+ }
+}
+
+static struct ffs_data *ffs_data_new(const char *dev_name)
+{
+ struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
+ if (unlikely(!ffs))
+ return NULL;
+
+ ENTER();
+
+ ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name);
+ if (!ffs->io_completion_wq) {
+ kfree(ffs);
+ return NULL;
+ }
+
+ refcount_set(&ffs->ref, 1);
+ atomic_set(&ffs->opened, 0);
+ ffs->state = FFS_READ_DESCRIPTORS;
+ mutex_init(&ffs->mutex);
+ spin_lock_init(&ffs->eps_lock);
+ spin_lock_init(&ffs->mem_lock);
+ init_waitqueue_head(&ffs->ev.waitq);
+ init_waitqueue_head(&ffs->wait);
+ init_waitqueue_head(&ffs->wait_que);
+ init_completion(&ffs->ep0req_completion);
+ INIT_LIST_HEAD(&ffs->memory_list);
+ ffs->ev.can_stall = 1;
+
+ return ffs;
+}
+
+static void ffs_data_clear(struct ffs_data *ffs)
+{
+ ENTER();
+
+ ffs_closed(ffs);
+
+ BUG_ON(ffs->gadget);
+
+ if (ffs->epfiles)
+ ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+
+ if (ffs->ffs_eventfd)
+ eventfd_ctx_put(ffs->ffs_eventfd);
+
+ kfree(ffs->raw_descs_data);
+ kfree(ffs->raw_strings);
+ kfree(ffs->stringtabs);
+}
+
+static void ffs_data_reset(struct ffs_data *ffs)
+{
+ ENTER();
+
+ ffs_data_clear(ffs);
+
+ ffs->epfiles = NULL;
+ ffs->raw_descs_data = NULL;
+ ffs->raw_descs = NULL;
+ ffs->raw_strings = NULL;
+ ffs->stringtabs = NULL;
+
+ ffs->raw_descs_length = 0;
+ ffs->fs_descs_count = 0;
+ ffs->hs_descs_count = 0;
+ ffs->ss_descs_count = 0;
+
+ ffs->strings_count = 0;
+ ffs->interfaces_count = 0;
+ ffs->eps_count = 0;
+
+ ffs->ev.count = 0;
+
+ ffs->state = FFS_READ_DESCRIPTORS;
+ ffs->setup_state = FFS_NO_SETUP;
+ ffs->flags = 0;
+}
+
+static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
+{
+ struct usb_gadget_strings **lang;
+ int first_id;
+
+ ENTER();
+
+ if (WARN_ON(ffs->state != FFS_ACTIVE
+ || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
+ return -EBADFD;
+
+ first_id = usb_string_ids_n(cdev, ffs->strings_count);
+ if (unlikely(first_id < 0))
+ return first_id;
+
+ ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
+ if (unlikely(!ffs->ep0req))
+ return -ENOMEM;
+ ffs->ep0req->complete = ffs_ep0_complete;
+ ffs->ep0req->context = ffs;
+ INIT_LIST_HEAD(&ffs->ep0req->list);
+
+ lang = ffs->stringtabs;
+ if (lang) {
+ for (; *lang; ++lang) {
+ struct usb_string *str = (*lang)->strings;
+ int id = first_id;
+ for (; str->s; ++id, ++str)
+ str->id = id;
+ }
+ }
+
+ ffs->gadget = cdev->gadget;
+ ffs->speed = cdev->gadget->speed;
+ ffs_data_get(ffs);
+ return 0;
+}
+
+static void functionfs_unbind(struct ffs_data *ffs)
+{
+ ENTER();
+
+ if (!WARN_ON(!ffs->gadget)) {
+ usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
+ ffs->ep0req = NULL;
+ ffs->gadget = NULL;
+ clear_bit(FFS_FL_BOUND, &ffs->flags);
+ ffs_data_put(ffs);
+ }
+}
+
+static int ffs_epfiles_create(struct ffs_data *ffs)
+{
+ struct ffs_epfile *epfile = NULL, *epfiles = NULL;
+ unsigned int i, count ,ret;
+
+ ENTER();
+
+ count = ffs->eps_count;
+ epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
+ if (!epfiles)
+ return -ENOMEM;
+
+ epfile = epfiles;
+ for (i = 1; i <= count; ++i, ++epfile) {
+ epfile->ffs = ffs;
+ mutex_init(&epfile->mutex);
+ INIT_LIST_HEAD(&epfile->memory_list);
+ init_waitqueue_head(&epfile->wait_que);
+ if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR) {
+ if (sprintf_s(epfile->name, MAX_NAMELEN, "%s.ep%02x", ffs->dev_name, ffs->eps_addrmap[i]) < 0) {
+ return -EFAULT;
+ }
+ } else {
+ if (sprintf_s(epfile->name, MAX_NAMELEN, "%s.ep%u", ffs->dev_name, i) < 0) {
+ return -EFAULT;
+ }
+ }
+
+ cdev_init(&epfile->cdev, &ffs_epfile_operations);
+ epfile->devno=MKDEV(MAJOR(ffs->devno), i);
+ ret = cdev_add(&epfile->cdev, epfile->devno, 1);
+ if (ret)
+ {
+ ffs_epfiles_destroy(epfiles, i - 1);
+ return -EBUSY;
+ }
+
+ epfile->device = device_create(ffs_class, NULL, epfile->devno, NULL, epfile->name);
+ if (IS_ERR(epfile->device))
+ {
+ cdev_del(&epfile->cdev);
+ ffs_epfiles_destroy(epfiles, i - 1);
+ return -EBUSY;
+ }
+ }
+
+ ffs->epfiles = epfiles;
+ return 0;
+}
+
+static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
+{
+ struct ffs_epfile *epfile = epfiles;
+
+ ENTER();
+
+ for (; count; --count, ++epfile) {
+ BUG_ON(mutex_is_locked(&epfile->mutex));
+ device_destroy(ffs_class, epfile->devno);
+ cdev_del(&epfile->cdev);
+ }
+
+ kfree(epfiles);
+}
+
+static void ffs_func_eps_disable(struct ffs_function *func)
+{
+ struct ffs_ep *ep = func->eps;
+ struct ffs_epfile *epfile = func->ffs->epfiles;
+ unsigned count = func->ffs->eps_count;
+ unsigned long flags;
+
+ spin_lock_irqsave(&func->ffs->eps_lock, flags);
+ while (count--) {
+ /* pending requests get nuked */
+ if (likely(ep->ep))
+ usb_ep_disable(ep->ep);
+ ++ep;
+
+ if (epfile) {
+ epfile->ep = NULL;
+ ++epfile;
+ }
+ }
+ spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+}
+
+static int ffs_func_eps_enable(struct ffs_function *func)
+{
+ struct ffs_data *ffs = func->ffs;
+ struct ffs_ep *ep = func->eps;
+ struct ffs_epfile *epfile = ffs->epfiles;
+ unsigned count = ffs->eps_count;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&func->ffs->eps_lock, flags);
+ while(count--) {
+ ep->ep->driver_data = ep;
+
+ ret = config_ep_by_speed(func->gadget, &func->function, ep->ep);
+ if (ret) {
+ pr_err("%s: config_ep_by_speed(%s) returned %d\n",
+ __func__, ep->ep->name, ret);
+ break;
+ }
+
+ ret = usb_ep_enable(ep->ep);
+ if (likely(!ret)) {
+ epfile->ep = ep;
+ epfile->in = usb_endpoint_dir_in(ep->ep->desc);
+ epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
+ } else {
+ break;
+ }
+
+ ++ep;
+ ++epfile;
+ }
+
+ wake_up_interruptible(&ffs->wait);
+ spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
+ return ret;
+}
+
+/* Parsing and building descriptors and strings *****************************/
+
+/*
+ * This validates if data pointed by data is a valid USB descriptor as
+ * well as record how many interfaces, endpoints and strings are
+ * required by given configuration. Returns address after the
+ * descriptor or NULL if data is invalid.
+ */
+enum ffs_entity_type {
+ FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
+};
+
+enum ffs_os_desc_type {
+ FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP
+};
+
+typedef int (*ffs_entity_callback)(enum ffs_entity_type entity, u8 *valuep,
+ struct usb_descriptor_header *desc,
+ void *priv);
+
+typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
+ struct usb_os_desc_header *h, void *data,
+ unsigned len, void *priv);
+
+static int __must_check ffs_do_single_desc(char *data, unsigned len,
+ ffs_entity_callback entity,
+ void *priv)
+{
+ struct usb_descriptor_header *_ds = (void *)data;
+ u8 length;
+ int ret;
+
+ ENTER();
+
+ /* At least two bytes are required: length and type */
+ if (len < 2) {
+ pr_vdebug("descriptor too short\n");
+ return -EINVAL;
+ }
+
+ /* If we have at least as many bytes as the descriptor takes? */
+ length = _ds->bLength;
+ if (len < length) {
+ pr_vdebug("descriptor longer then available data\n");
+ return -EINVAL;
+ }
+
+#define __entity_check_INTERFACE(val) 1
+#define __entity_check_STRING(val) (val)
+#define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK)
+#define __entity(type, val) do { \
+ pr_vdebug("entity " #type "(%02x)\n", (val)); \
+ if (unlikely(!__entity_check_ ##type(val))) { \
+ pr_vdebug("invalid entity's value\n"); \
+ return -EINVAL; \
+ } \
+ ret = entity(FFS_ ##type, &val, _ds, priv); \
+ if (unlikely(ret < 0)) { \
+ pr_debug("entity " #type "(%02x); ret = %d\n", \
+ (val), ret); \
+ return ret; \
+ } \
+ } while (0)
+
+ /* Parse descriptor depending on type. */
+ switch (_ds->bDescriptorType) {
+ case USB_DT_DEVICE:
+ case USB_DT_CONFIG:
+ case USB_DT_STRING:
+ case USB_DT_DEVICE_QUALIFIER:
+ /* function can't have any of those */
+ pr_vdebug("descriptor reserved for gadget: %d\n",
+ _ds->bDescriptorType);
+ return -EINVAL;
+
+ case USB_DT_INTERFACE: {
+ struct usb_interface_descriptor *ds = (void *)_ds;
+ pr_vdebug("interface descriptor\n");
+ if (length != sizeof *ds)
+ goto inv_length;
+
+ __entity(INTERFACE, ds->bInterfaceNumber);
+ if (ds->iInterface)
+ __entity(STRING, ds->iInterface);
+ }
+ break;
+
+ case USB_DT_ENDPOINT: {
+ struct usb_endpoint_descriptor *ds = (void *)_ds;
+ pr_vdebug("endpoint descriptor\n");
+ if (length != USB_DT_ENDPOINT_SIZE &&
+ length != USB_DT_ENDPOINT_AUDIO_SIZE)
+ goto inv_length;
+ __entity(ENDPOINT, ds->bEndpointAddress);
+ }
+ break;
+
+ case HID_DT_HID:
+ pr_vdebug("hid descriptor\n");
+ if (length != sizeof(struct hid_descriptor))
+ goto inv_length;
+ break;
+
+ case USB_DT_OTG:
+ if (length != sizeof(struct usb_otg_descriptor))
+ goto inv_length;
+ break;
+
+ case USB_DT_INTERFACE_ASSOCIATION: {
+ struct usb_interface_assoc_descriptor *ds = (void *)_ds;
+ pr_vdebug("interface association descriptor\n");
+ if (length != sizeof *ds)
+ goto inv_length;
+ if (ds->iFunction)
+ __entity(STRING, ds->iFunction);
+ }
+ break;
+
+ case USB_DT_SS_ENDPOINT_COMP:
+ pr_vdebug("EP SS companion descriptor\n");
+ if (length != sizeof(struct usb_ss_ep_comp_descriptor))
+ goto inv_length;
+ break;
+
+ case USB_DT_OTHER_SPEED_CONFIG:
+ case USB_DT_INTERFACE_POWER:
+ case USB_DT_DEBUG:
+ case USB_DT_SECURITY:
+ case USB_DT_CS_RADIO_CONTROL:
+ pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
+ break;
+ default:
+ /* We should never be here */
+ pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
+ break;
+inv_length:
+ pr_vdebug("invalid length: %d (descriptor %d)\n",
+ _ds->bLength, _ds->bDescriptorType);
+ return -EINVAL;
+ }
+
+#undef __entity
+#undef __entity_check_DESCRIPTOR
+#undef __entity_check_INTERFACE
+#undef __entity_check_STRING
+#undef __entity_check_ENDPOINT
+
+ return length;
+}
+
+static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
+ ffs_entity_callback entity, void *priv)
+{
+ const unsigned _len = len;
+ uintptr_t num = 0;
+
+ ENTER();
+
+ for (;;) {
+ int ret;
+
+ if (num == count)
+ data = NULL;
+
+ /* Record "descriptor" entity */
+ ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
+ if (unlikely(ret < 0)) {
+ pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
+ num, ret);
+ return ret;
+ }
+
+ if (!data)
+ return _len - len;
+
+ ret = ffs_do_single_desc(data, len, entity, priv);
+ if (unlikely(ret < 0)) {
+ pr_debug("%s returns %d\n", __func__, ret);
+ return ret;
+ }
+
+ len -= ret;
+ data += ret;
+ ++num;
+ }
+}
+
+static int __ffs_data_do_entity(enum ffs_entity_type type,
+ u8 *valuep, struct usb_descriptor_header *desc,
+ void *priv)
+{
+ struct ffs_desc_helper *helper = priv;
+ struct usb_endpoint_descriptor *d = NULL;
+
+ ENTER();
+
+ switch (type) {
+ case FFS_DESCRIPTOR:
+ break;
+
+ case FFS_INTERFACE:
+ /*
+ * Interfaces are indexed from zero so if we
+ * encountered interface "n" then there are at least
+ * "n+1" interfaces.
+ */
+ if (*valuep >= helper->interfaces_count)
+ helper->interfaces_count = *valuep + 1;
+ break;
+
+ case FFS_STRING:
+ /*
+ * Strings are indexed from 1 (0 is reserved
+ * for languages list)
+ */
+ if (*valuep > helper->ffs->strings_count)
+ helper->ffs->strings_count = *valuep;
+ break;
+
+ case FFS_ENDPOINT:
+ d = (void *)desc;
+ helper->eps_count++;
+ if (helper->eps_count >= FFS_MAX_EPS_COUNT)
+ return -EINVAL;
+ /* Check if descriptors for any speed were already parsed */
+ if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
+ helper->ffs->eps_addrmap[helper->eps_count] =
+ d->bEndpointAddress;
+ else if (helper->ffs->eps_addrmap[helper->eps_count] !=
+ d->bEndpointAddress)
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
+ struct usb_os_desc_header *desc)
+{
+ u16 bcd_version = le16_to_cpu(desc->bcdVersion);
+ u16 w_index = le16_to_cpu(desc->wIndex);
+
+ if (bcd_version != 1) {
+ pr_vdebug("unsupported os descriptors version: %d",
+ bcd_version);
+ return -EINVAL;
+ }
+ switch (w_index) {
+ case 0x4:
+ *next_type = FFS_OS_DESC_EXT_COMPAT;
+ break;
+ case 0x5:
+ *next_type = FFS_OS_DESC_EXT_PROP;
+ break;
+ default:
+ pr_vdebug("unsupported os descriptor type: %d", w_index);
+ return -EINVAL;
+ }
+
+ return sizeof(*desc);
+}
+
+/*
+ * Process all extended compatibility/extended property descriptors
+ * of a feature descriptor
+ */
+static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
+ enum ffs_os_desc_type type,
+ u16 feature_count,
+ ffs_os_desc_callback entity,
+ void *priv,
+ struct usb_os_desc_header *h)
+{
+ int ret;
+ const unsigned _len = len;
+
+ ENTER();
+
+ /* loop over all ext compat/ext prop descriptors */
+ while (feature_count--) {
+ ret = entity(type, h, data, len, priv);
+ if (unlikely(ret < 0)) {
+ pr_debug("bad OS descriptor, type: %d\n", type);
+ return ret;
+ }
+ data += ret;
+ len -= ret;
+ }
+ return _len - len;
+}
+
+/* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */
+static int __must_check ffs_do_os_descs(unsigned count,
+ char *data, unsigned len,
+ ffs_os_desc_callback entity, void *priv)
+{
+ const unsigned _len = len;
+ unsigned long num = 0;
+
+ ENTER();
+
+ for (num = 0; num < count; ++num) {
+ int ret;
+ enum ffs_os_desc_type type;
+ u16 feature_count;
+ struct usb_os_desc_header *desc = (void *)data;
+
+ if (len < sizeof(*desc))
+ return -EINVAL;
+
+ /*
+ * Record "descriptor" entity.
+ * Process dwLength, bcdVersion, wIndex, get b/wCount.
+ * Move the data pointer to the beginning of extended
+ * compatibilities proper or extended properties proper
+ * portions of the data
+ */
+ if (le32_to_cpu(desc->dwLength) > len)
+ return -EINVAL;
+
+ ret = __ffs_do_os_desc_header(&type, desc);
+ if (unlikely(ret < 0)) {
+ pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
+ num, ret);
+ return ret;
+ }
+ /*
+ * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??"
+ */
+ feature_count = le16_to_cpu(desc->wCount);
+ if (type == FFS_OS_DESC_EXT_COMPAT &&
+ (feature_count > 255 || desc->Reserved))
+ return -EINVAL;
+ len -= ret;
+ data += ret;
+
+ /*
+ * Process all function/property descriptors
+ * of this Feature Descriptor
+ */
+ ret = ffs_do_single_os_desc(data, len, type,
+ feature_count, entity, priv, desc);
+ if (unlikely(ret < 0)) {
+ pr_debug("%s returns %d\n", __func__, ret);
+ return ret;
+ }
+
+ len -= ret;
+ data += ret;
+ }
+ return _len - len;
+}
+
+/**
+ * Validate contents of the buffer from userspace related to OS descriptors.
+ */
+static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
+ struct usb_os_desc_header *h, void *data,
+ unsigned len, void *priv)
+{
+ struct ffs_data *ffs = priv;
+ u8 length;
+
+ ENTER();
+
+ switch (type) {
+ case FFS_OS_DESC_EXT_COMPAT: {
+ struct usb_ext_compat_desc *d = data;
+ int i;
+
+ if (len < sizeof(*d) ||
+ d->bFirstInterfaceNumber >= ffs->interfaces_count)
+ return -EINVAL;
+ if (d->Reserved1 != 1) {
+ /*
+ * According to the spec, Reserved1 must be set to 1
+ * but older kernels incorrectly rejected non-zero
+ * values. We fix it here to avoid returning EINVAL
+ * in response to values we used to accept.
+ */
+ pr_debug("usb_ext_compat_desc::Reserved1 forced to 1\n");
+ d->Reserved1 = 1;
+ }
+ for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
+ if (d->Reserved2[i])
+ return -EINVAL;
+
+ length = sizeof(struct usb_ext_compat_desc);
+ }
+ break;
+ case FFS_OS_DESC_EXT_PROP: {
+ struct usb_ext_prop_desc *d = data;
+ u32 type, pdl;
+ u16 pnl;
+
+ if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
+ return -EINVAL;
+ length = le32_to_cpu(d->dwSize);
+ if (len < length)
+ return -EINVAL;
+ type = le32_to_cpu(d->dwPropertyDataType);
+ if (type < USB_EXT_PROP_UNICODE ||
+ type > USB_EXT_PROP_UNICODE_MULTI) {
+ pr_vdebug("unsupported os descriptor property type: %d",
+ type);
+ return -EINVAL;
+ }
+ pnl = le16_to_cpu(d->wPropertyNameLength);
+ if (length < 14 + pnl) {
+ pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n",
+ length, pnl, type);
+ return -EINVAL;
+ }
+ pdl = le32_to_cpu(*(__le32 *)((u8 *)data + 10 + pnl));
+ if (length != 14 + pnl + pdl) {
+ pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
+ length, pnl, pdl, type);
+ return -EINVAL;
+ }
+ ++ffs->ms_os_descs_ext_prop_count;
+ /* property name reported to the host as "WCHAR"s */
+ ffs->ms_os_descs_ext_prop_name_len += pnl * 2;
+ ffs->ms_os_descs_ext_prop_data_len += pdl;
+ }
+ break;
+ default:
+ pr_vdebug("unknown descriptor: %d\n", type);
+ return -EINVAL;
+ }
+ return length;
+}
+
+static int __ffs_data_got_descs(struct ffs_data *ffs,
+ char *const _data, size_t len)
+{
+ char *data = _data, *raw_descs = NULL;
+ unsigned os_descs_count = 0, counts[3], flags;
+ int ret = -EINVAL, i;
+ struct ffs_desc_helper helper;
+
+ ENTER();
+
+ if (get_unaligned_le32(data + 4) != len)
+ goto error;
+
+ switch (get_unaligned_le32(data)) {
+ case FUNCTIONFS_DESCRIPTORS_MAGIC:
+ flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
+ data += 8;
+ len -= 8;
+ break;
+ case FUNCTIONFS_DESCRIPTORS_MAGIC_V2:
+ flags = get_unaligned_le32(data + 8);
+ ffs->user_flags = flags;
+ if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
+ FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC |
+ FUNCTIONFS_HAS_MS_OS_DESC |
+ FUNCTIONFS_VIRTUAL_ADDR |
+ FUNCTIONFS_EVENTFD |
+ FUNCTIONFS_ALL_CTRL_RECIP |
+ FUNCTIONFS_CONFIG0_SETUP)) {
+ ret = -ENOSYS;
+ goto error;
+ }
+ data += 12;
+ len -= 12;
+ break;
+ default:
+ goto error;
+ }
+
+ if (flags & FUNCTIONFS_EVENTFD) {
+ if (len < 4)
+ goto error;
+ ffs->ffs_eventfd =
+ eventfd_ctx_fdget((int)get_unaligned_le32(data));
+ if (IS_ERR(ffs->ffs_eventfd)) {
+ ret = PTR_ERR(ffs->ffs_eventfd);
+ ffs->ffs_eventfd = NULL;
+ goto error;
+ }
+ data += 4;
+ len -= 4;
+ }
+
+ /* Read fs_count, hs_count and ss_count (if present) */
+ for (i = 0; i < 3; ++i) {
+ if (!(flags & (1 << i))) {
+ counts[i] = 0;
+ } else if (len < 4) {
+ goto error;
+ } else {
+ counts[i] = get_unaligned_le32(data);
+ data += 4;
+ len -= 4;
+ }
+ }
+ if (flags & (1 << i)) {
+ if (len < 4) {
+ goto error;
+ }
+ os_descs_count = get_unaligned_le32(data);
+ data += 4;
+ len -= 4;
+ }
+
+ /* Read descriptors */
+ raw_descs = data;
+ helper.ffs = ffs;
+ for (i = 0; i < 3; ++i) {
+ if (!counts[i])
+ continue;
+ helper.interfaces_count = 0;
+ helper.eps_count = 0;
+ ret = ffs_do_descs(counts[i], data, len,
+ __ffs_data_do_entity, &helper);
+ if (ret < 0)
+ goto error;
+ if (!ffs->eps_count && !ffs->interfaces_count) {
+ ffs->eps_count = helper.eps_count;
+ ffs->interfaces_count = helper.interfaces_count;
+ } else {
+ if (ffs->eps_count != helper.eps_count) {
+ ret = -EINVAL;
+ goto error;
+ }
+ if (ffs->interfaces_count != helper.interfaces_count) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ data += ret;
+ len -= ret;
+ }
+ if (os_descs_count) {
+ ret = ffs_do_os_descs(os_descs_count, data, len,
+ __ffs_data_do_os_desc, ffs);
+ if (ret < 0)
+ goto error;
+ data += ret;
+ len -= ret;
+ }
+
+ if (raw_descs == data || len) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ffs->raw_descs_data = _data;
+ ffs->raw_descs = raw_descs;
+ ffs->raw_descs_length = data - raw_descs;
+ ffs->fs_descs_count = counts[0];
+ ffs->hs_descs_count = counts[1];
+ ffs->ss_descs_count = counts[2];
+ ffs->ms_os_descs_count = os_descs_count;
+
+ return 0;
+
+error:
+ kfree(_data);
+ return ret;
+}
+
+static int __ffs_data_got_strings(struct ffs_data *ffs,
+ char *const _data, size_t len)
+{
+ u32 str_count, needed_count, lang_count;
+ struct usb_gadget_strings **stringtabs = NULL, *t = NULL;
+ const char *data = _data;
+ struct usb_string *s = NULL;
+
+ ENTER();
+
+ if (unlikely(len < 16 ||
+ get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
+ get_unaligned_le32(data + 4) != len))
+ goto error;
+ str_count = get_unaligned_le32(data + 8);
+ lang_count = get_unaligned_le32(data + 12);
+
+ /* if one is zero the other must be zero */
+ if (unlikely(!str_count != !lang_count))
+ goto error;
+
+ /* Do we have at least as many strings as descriptors need? */
+ needed_count = ffs->strings_count;
+ if (unlikely(str_count < needed_count))
+ goto error;
+
+ /*
+ * If we don't need any strings just return and free all
+ * memory.
+ */
+ if (!needed_count) {
+ kfree(_data);
+ return 0;
+ }
+
+ /* Allocate everything in one chunk so there's less maintenance. */
+ {
+ unsigned i = 0;
+ vla_group(d);
+ vla_item(d, struct usb_gadget_strings *, stringtabs,
+ lang_count + 1);
+ vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
+ vla_item(d, struct usb_string, strings,
+ lang_count*(needed_count+1));
+
+ char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
+
+ if (unlikely(!vlabuf)) {
+ kfree(_data);
+ return -ENOMEM;
+ }
+
+ /* Initialize the VLA pointers */
+ stringtabs = vla_ptr(vlabuf, d, stringtabs);
+ t = vla_ptr(vlabuf, d, stringtab);
+ i = lang_count;
+ do {
+ *stringtabs++ = t++;
+ } while (--i);
+ *stringtabs = NULL;
+
+ /* stringtabs = vlabuf = d_stringtabs for later kfree */
+ stringtabs = vla_ptr(vlabuf, d, stringtabs);
+ t = vla_ptr(vlabuf, d, stringtab);
+ s = vla_ptr(vlabuf, d, strings);
+ }
+
+ /* For each language */
+ data += 16;
+ len -= 16;
+
+ do { /* lang_count > 0 so we can use do-while */
+ unsigned needed = needed_count;
+
+ if (unlikely(len < 3))
+ goto error_free;
+ t->language = get_unaligned_le16(data);
+ t->strings = s;
+ ++t;
+
+ data += 2;
+ len -= 2;
+
+ /* For each string */
+ do { /* str_count > 0 so we can use do-while */
+ size_t length = strnlen(data, len);
+
+ if (unlikely(length == len))
+ goto error_free;
+
+ /*
+ * User may provide more strings then we need,
+ * if that's the case we simply ignore the
+ * rest
+ */
+ if (likely(needed)) {
+ /*
+ * s->id will be set while adding
+ * function to configuration so for
+ * now just leave garbage here.
+ */
+ s->s = data;
+ --needed;
+ ++s;
+ }
+
+ data += length + 1;
+ len -= length + 1;
+ } while (--str_count);
+
+ s->id = 0; /* terminator */
+ s->s = NULL;
+ ++s;
+
+ } while (--lang_count);
+
+ /* Some garbage left? */
+ if (unlikely(len))
+ goto error_free;
+
+ /* Done! */
+ ffs->stringtabs = stringtabs;
+ ffs->raw_strings = _data;
+
+ return 0;
+
+error_free:
+ kfree(stringtabs);
+error:
+ kfree(_data);
+ return -EINVAL;
+}
+
+/* Events handling and management *******************************************/
+static void __ffs_event_add(struct ffs_data *ffs,
+ enum usb_functionfs_event_type type)
+{
+ enum usb_functionfs_event_type rem_type1, rem_type2 = type;
+ int neg = 0;
+
+ /*
+ * Abort any unhandled setup
+ *
+ * We do not need to worry about some cmpxchg() changing value
+ * of ffs->setup_state without holding the lock because when
+ * state is FFS_SETUP_PENDING cmpxchg() in several places in
+ * the source does nothing.
+ */
+ if (ffs->setup_state == FFS_SETUP_PENDING)
+ ffs->setup_state = FFS_SETUP_CANCELLED;
+
+ /*
+ * Logic of this function guarantees that there are at most four pending
+ * evens on ffs->ev.types queue. This is important because the queue
+ * has space for four elements only and __ffs_ep0_read_events function
+ * depends on that limit as well. If more event types are added, those
+ * limits have to be revisited or guaranteed to still hold.
+ */
+ switch (type) {
+ case FUNCTIONFS_RESUME:
+ rem_type2 = FUNCTIONFS_SUSPEND;
+ /* FALL THROUGH */
+ case FUNCTIONFS_SUSPEND:
+ case FUNCTIONFS_SETUP:
+ rem_type1 = type;
+ /* Discard all similar events */
+ break;
+
+ case FUNCTIONFS_BIND:
+ case FUNCTIONFS_UNBIND:
+ case FUNCTIONFS_DISABLE:
+ case FUNCTIONFS_ENABLE:
+ /* Discard everything other then power management. */
+ rem_type1 = FUNCTIONFS_SUSPEND;
+ rem_type2 = FUNCTIONFS_RESUME;
+ neg = 1;
+ break;
+
+ default:
+ WARN(1, "%d: unknown event, this should not happen\n", type);
+ return;
+ }
+
+ {
+ u8 *ev = ffs->ev.types, *out = ev;
+ unsigned n = ffs->ev.count;
+ for (; n; --n, ++ev)
+ if ((*ev == rem_type1 || *ev == rem_type2) == neg)
+ *out++ = *ev;
+ else
+ pr_vdebug("purging event %d\n", *ev);
+ ffs->ev.count = out - ffs->ev.types;
+ }
+
+ pr_vdebug("adding event %d\n", type);
+ ffs->ev.types[ffs->ev.count++] = type;
+ wake_up_locked(&ffs->ev.waitq);
+ if (ffs->ffs_eventfd)
+ eventfd_signal(ffs->ffs_eventfd, 1);
+}
+
+static void ffs_event_add(struct ffs_data *ffs,
+ enum usb_functionfs_event_type type)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
+ __ffs_event_add(ffs, type);
+ spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
+}
+
+/* Bind/unbind USB function hooks *******************************************/
+
+static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
+ if (ffs->eps_addrmap[i] == endpoint_address)
+ return i;
+ return -ENOENT;
+}
+
+static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
+ struct usb_descriptor_header *desc,
+ void *priv)
+{
+ struct usb_endpoint_descriptor *ds = (void *)desc;
+ struct ffs_function *func = priv;
+ struct ffs_ep *ffs_ep = NULL;
+ unsigned ep_desc_id;
+ int idx;
+ static const char *speed_names[] = { "full", "high", "super" };
+
+ if (type != FFS_DESCRIPTOR)
+ return 0;
+
+ /*
+ * If ss_descriptors is not NULL, we are reading super speed
+ * descriptors; if hs_descriptors is not NULL, we are reading high
+ * speed descriptors; otherwise, we are reading full speed
+ * descriptors.
+ */
+ if (func->function.ss_descriptors) {
+ ep_desc_id = 2;
+ func->function.ss_descriptors[(uintptr_t)valuep] = desc;
+ } else if (func->function.hs_descriptors) {
+ ep_desc_id = 1;
+ func->function.hs_descriptors[(uintptr_t)valuep] = desc;
+ } else {
+ ep_desc_id = 0;
+ func->function.fs_descriptors[(uintptr_t)valuep] = desc;
+ }
+
+ if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return 0;
+
+ idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
+ if (idx < 0)
+ return idx;
+
+ ffs_ep = func->eps + idx;
+
+ if (unlikely(ffs_ep->descs[ep_desc_id])) {
+ pr_err("two %sspeed descriptors for EP %d\n",
+ speed_names[ep_desc_id],
+ ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ return -EINVAL;
+ }
+ ffs_ep->descs[ep_desc_id] = ds;
+
+ ffs_dump_mem(": Original ep desc", ds, ds->bLength);
+ if (ffs_ep->ep) {
+ ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
+ if (!ds->wMaxPacketSize)
+ ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
+ } else {
+ struct usb_request *req = NULL;
+ struct usb_ep *ep = NULL;
+ u8 bEndpointAddress;
+
+ /*
+ * We back up bEndpointAddress because autoconfig overwrites
+ * it with physical endpoint address.
+ */
+ bEndpointAddress = ds->bEndpointAddress;
+ pr_vdebug("autoconfig\n");
+ ep = usb_ep_autoconfig(func->gadget, ds);
+ if (unlikely(!ep))
+ return -ENOTSUPP;
+ ep->driver_data = func->eps + idx;
+
+ req = usb_ep_alloc_request(ep, GFP_KERNEL);
+ if (unlikely(!req))
+ return -ENOMEM;
+
+ ffs_ep->ep = ep;
+ ffs_ep->req = req;
+ INIT_LIST_HEAD(&ffs_ep->req->list);
+ func->eps_revmap[ds->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK] = idx + 1;
+ /*
+ * If we use virtual address mapping, we restore
+ * original bEndpointAddress value.
+ */
+ if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
+ ds->bEndpointAddress = bEndpointAddress;
+ }
+ ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
+
+ return 0;
+}
+
+static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
+ struct usb_descriptor_header *desc,
+ void *priv)
+{
+ struct ffs_function *func = priv;
+ unsigned idx;
+ u8 newValue;
+
+ switch (type) {
+ default:
+ case FFS_DESCRIPTOR:
+ /* Handled in previous pass by __ffs_func_bind_do_descs() */
+ return 0;
+
+ case FFS_INTERFACE:
+ idx = *valuep;
+ if (func->interfaces_nums[idx] < 0) {
+ int id = usb_interface_id(func->conf, &func->function);
+ if (unlikely(id < 0))
+ return id;
+ func->interfaces_nums[idx] = id;
+ }
+ newValue = func->interfaces_nums[idx];
+ break;
+
+ case FFS_STRING:
+ /* String' IDs are allocated when fsf_data is bound to cdev */
+ newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
+ break;
+
+ case FFS_ENDPOINT:
+ /*
+ * USB_DT_ENDPOINT are handled in
+ * __ffs_func_bind_do_descs().
+ */
+ if (desc->bDescriptorType == USB_DT_ENDPOINT)
+ return 0;
+
+ idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
+ if (unlikely(!func->eps[idx].ep))
+ return -EINVAL;
+
+ {
+ struct usb_endpoint_descriptor **descs;
+ descs = func->eps[idx].descs;
+ newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
+ }
+ break;
+ }
+
+ pr_vdebug("%02x -> %02x\n", *valuep, newValue);
+ *valuep = newValue;
+ return 0;
+}
+
+static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
+ struct usb_os_desc_header *h, void *data,
+ unsigned len, void *priv)
+{
+ int ret;
+ struct ffs_function *func = priv;
+ u8 length = 0;
+
+ switch (type) {
+ case FFS_OS_DESC_EXT_COMPAT: {
+ struct usb_ext_compat_desc *desc = data;
+ struct usb_os_desc_table *t;
+
+ t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
+ t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
+ ret = memcpy_s(t->os_desc->ext_compat_id, ARRAY_SIZE(desc->CompatibleID) + ARRAY_SIZE(desc->SubCompatibleID),
+ &desc->CompatibleID, ARRAY_SIZE(desc->CompatibleID) + ARRAY_SIZE(desc->SubCompatibleID));
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s:%{public}d memcpy_s failed", __func__, __LINE__);
+ return ret;
+ }
+
+ length = sizeof(*desc);
+ }
+ break;
+ case FFS_OS_DESC_EXT_PROP: {
+ struct usb_ext_prop_desc *desc = data;
+ struct usb_os_desc_table *t;
+ struct usb_os_desc_ext_prop *ext_prop;
+ char *ext_prop_name;
+ char *ext_prop_data;
+
+ t = &func->function.os_desc_table[h->interface];
+ t->if_id = func->interfaces_nums[h->interface];
+
+ ext_prop = func->ffs->ms_os_descs_ext_prop_avail;
+ func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop);
+
+ ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
+ ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
+ ext_prop->data_len = le32_to_cpu(*(__le32 *)
+ usb_ext_prop_data_len_ptr(data, ext_prop->name_len));
+ length = ext_prop->name_len + ext_prop->data_len + 14;
+
+ ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail;
+ func->ffs->ms_os_descs_ext_prop_name_avail +=
+ ext_prop->name_len;
+
+ ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
+ func->ffs->ms_os_descs_ext_prop_data_avail +=
+ ext_prop->data_len;
+ ret = memcpy_s(ext_prop_data, ext_prop->data_len, usb_ext_prop_data_ptr(data, ext_prop->name_len),
+ ext_prop->data_len);
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s:%{public}d memcpy_s failed", __func__, __LINE__);
+ return ret;
+ }
+ /* unicode data reported to the host as "WCHAR"s */
+ switch (ext_prop->type) {
+ case USB_EXT_PROP_UNICODE:
+ case USB_EXT_PROP_UNICODE_ENV:
+ case USB_EXT_PROP_UNICODE_LINK:
+ case USB_EXT_PROP_UNICODE_MULTI:
+ ext_prop->data_len *= 2;
+ break;
+ }
+ ext_prop->data = ext_prop_data;
+
+ ret = memcpy_s(ext_prop_name, ext_prop->name_len, usb_ext_prop_name_ptr(data),
+ ext_prop->name_len);
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s:%{public}d memcpy_s failed", __func__, __LINE__);
+ return ret;
+ }
+ /* property name reported to the host as "WCHAR"s */
+ ext_prop->name_len *= 2;
+ ext_prop->name = ext_prop_name;
+
+ t->os_desc->ext_prop_len +=
+ ext_prop->name_len + ext_prop->data_len + 14;
+ ++t->os_desc->ext_prop_count;
+ list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop);
+ }
+ break;
+ default:
+ pr_vdebug("unknown descriptor: %d\n", type);
+ }
+
+ return length;
+}
+
+static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
+ struct usb_configuration *c)
+{
+ struct ffs_function *func = ffs_func_from_usb(f);
+ struct f_fs_opts *ffs_opts =
+ container_of(f->fi, struct f_fs_opts, func_inst);
+ int ret;
+
+ ENTER();
+
+ /*
+ * Legacy gadget triggers binding in functionfs_ready_callback,
+ * which already uses locking; taking the same lock here would
+ * cause a deadlock.
+ *
+ * Configfs-enabled gadgets however do need ffs_dev_lock.
+ */
+ if (!ffs_opts->no_configfs)
+ ffs_dev_lock();
+ ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV;
+ func->ffs = ffs_opts->dev->ffs_data;
+ if (!ffs_opts->no_configfs)
+ ffs_dev_unlock();
+ if (ret)
+ return ERR_PTR(ret);
+
+ func->conf = c;
+ func->gadget = c->cdev->gadget;
+
+ /*
+ * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
+ * configurations are bound in sequence with list_for_each_entry,
+ * in each configuration its functions are bound in sequence
+ * with list_for_each_entry, so we assume no race condition
+ * with regard to ffs_opts->bound access
+ */
+ if (!ffs_opts->refcnt) {
+ ret = functionfs_bind(func->ffs, c->cdev);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+ ffs_opts->refcnt++;
+ func->function.strings = func->ffs->stringtabs;
+
+ return ffs_opts;
+}
+
+static int _ffs_func_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct ffs_function *func = ffs_func_from_usb(f);
+ struct ffs_data *ffs = func->ffs;
+
+ const int full = !!func->ffs->fs_descs_count;
+ const int high = !!func->ffs->hs_descs_count;
+ const int super = !!func->ffs->ss_descs_count;
+
+ int fs_len, hs_len, ss_len, ret, i;
+ struct ffs_ep *eps_ptr = NULL;
+ struct usb_descriptor_header *des_head = NULL;
+ struct usb_interface_descriptor *intf_ctl = NULL;
+ struct usb_interface_descriptor *intf_data = NULL;
+ /* Make it a single chunk, less management later on */
+ vla_group(d);
+ vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count);
+ vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs,
+ full ? ffs->fs_descs_count + 1 : 0);
+ vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs,
+ high ? ffs->hs_descs_count + 1 : 0);
+ vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
+ super ? ffs->ss_descs_count + 1 : 0);
+ vla_item_with_sz(d, short, inums, ffs->interfaces_count);
+ vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table,
+ c->cdev->use_os_string ? ffs->interfaces_count : 0);
+ vla_item_with_sz(d, char[16], ext_compat,
+ c->cdev->use_os_string ? ffs->interfaces_count : 0);
+ vla_item_with_sz(d, struct usb_os_desc, os_desc,
+ c->cdev->use_os_string ? ffs->interfaces_count : 0);
+ vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop,
+ ffs->ms_os_descs_ext_prop_count);
+ vla_item_with_sz(d, char, ext_prop_name,
+ ffs->ms_os_descs_ext_prop_name_len);
+ vla_item_with_sz(d, char, ext_prop_data,
+ ffs->ms_os_descs_ext_prop_data_len);
+ vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
+ char *vlabuf = NULL;
+
+ ENTER();
+
+ /* Has descriptors only for speeds gadget does not support */
+ if (unlikely(!(full | high | super)))
+ return -ENOTSUPP;
+
+ /* Allocate a single chunk, less management later on */
+ vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL);
+ if (unlikely(!vlabuf))
+ return -ENOMEM;
+
+ ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
+ ffs->ms_os_descs_ext_prop_name_avail =
+ vla_ptr(vlabuf, d, ext_prop_name);
+ ffs->ms_os_descs_ext_prop_data_avail =
+ vla_ptr(vlabuf, d, ext_prop_data);
+
+ /* Copy descriptors */
+ ret = memcpy_s(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs_length, ffs->raw_descs, ffs->raw_descs_length);
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s:%{public}d memcpy_s failed", __func__, __LINE__);
+ return ret;
+ }
+
+ ret = memset_s(vla_ptr(vlabuf, d, inums), d_inums__sz, 0xff, d_inums__sz);
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s:%{public}d memset_s failed", __func__, __LINE__);
+ return ret;
+ }
+
+ eps_ptr = vla_ptr(vlabuf, d, eps);
+ for (i = 0; i < ffs->eps_count; i++)
+ eps_ptr[i].num = -1;
+
+ /* Save pointers
+ * d_eps == vlabuf, func->eps used to kfree vlabuf later
+ */
+ func->eps = vla_ptr(vlabuf, d, eps);
+ func->interfaces_nums = vla_ptr(vlabuf, d, inums);
+
+ /*
+ * Go through all the endpoint descriptors and allocate
+ * endpoints first, so that later we can rewrite the endpoint
+ * numbers without worrying that it may be described later on.
+ */
+ if (likely(full)) {
+ func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs);
+ fs_len = ffs_do_descs(ffs->fs_descs_count,
+ vla_ptr(vlabuf, d, raw_descs),
+ d_raw_descs__sz,
+ __ffs_func_bind_do_descs, func);
+ if (unlikely(fs_len < 0)) {
+ ret = fs_len;
+ goto error;
+ }
+ } else {
+ fs_len = 0;
+ }
+ if (likely(high)) {
+ func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs);
+ hs_len = ffs_do_descs(ffs->hs_descs_count,
+ vla_ptr(vlabuf, d, raw_descs) + fs_len,
+ d_raw_descs__sz - fs_len,
+ __ffs_func_bind_do_descs, func);
+ if (unlikely(hs_len < 0)) {
+ ret = hs_len;
+ goto error;
+ }
+ } else {
+ hs_len = 0;
+ }
+ if (likely(super)) {
+ func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
+ ss_len = ffs_do_descs(ffs->ss_descs_count,
+ vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
+ d_raw_descs__sz - fs_len - hs_len,
+ __ffs_func_bind_do_descs, func);
+ if (unlikely(ss_len < 0)) {
+ ret = ss_len;
+ goto error;
+ }
+ } else {
+ ss_len = 0;
+ }
+ /*
+ * Now handle interface numbers allocation and interface and
+ * endpoint numbers rewriting. We can do that in one go
+ * now.
+ */
+ ret = ffs_do_descs(ffs->fs_descs_count +
+ (high ? ffs->hs_descs_count : 0) +
+ (super ? ffs->ss_descs_count : 0),
+ vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,
+ __ffs_func_bind_do_nums, func);
+ if (unlikely(ret < 0))
+ goto error;
+
+ func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
+ if (c->cdev->use_os_string) {
+ for (i = 0; i < ffs->interfaces_count; ++i) {
+ struct usb_os_desc *desc;
+
+ desc = func->function.os_desc_table[i].os_desc =
+ vla_ptr(vlabuf, d, os_desc) +
+ i * sizeof(struct usb_os_desc);
+ desc->ext_compat_id =
+ vla_ptr(vlabuf, d, ext_compat) + i * 16;
+ INIT_LIST_HEAD(&desc->ext_prop);
+ }
+ ret = ffs_do_os_descs(ffs->ms_os_descs_count,
+ vla_ptr(vlabuf, d, raw_descs) +
+ fs_len + hs_len + ss_len,
+ d_raw_descs__sz - fs_len - hs_len -
+ ss_len,
+ __ffs_func_bind_do_os_desc, func);
+ if (unlikely(ret < 0))
+ goto error;
+ }
+ func->function.os_desc_n =
+ c->cdev->use_os_string ? ffs->interfaces_count : 0;
+
+ for (i = 0; i< func->ffs->fs_descs_count; i++) {
+ des_head = func->function.fs_descriptors[i];
+ if (des_head->bDescriptorType == USB_DT_INTERFACE) {
+ struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)des_head;
+ if (intf->bNumEndpoints > 0) {
+ if (intf_ctl == NULL) {
+ intf_ctl = intf;
+ } else {
+ intf_data = intf;
+ break;
+ }
+ }
+ }
+ }
+ for (i = 0; i< func->ffs->fs_descs_count; i++) {
+ des_head = func->function.fs_descriptors[i];
+ if (des_head->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) {
+ struct usb_interface_assoc_descriptor *a_dec = (struct usb_interface_assoc_descriptor *)des_head;
+ a_dec->bFirstInterface = intf_ctl->bInterfaceNumber;
+ } else if (des_head->bDescriptorType == USB_DT_CS_INTERFACE) {
+ struct usb_cdc_header_desc *cs_des = (struct usb_cdc_header_desc *)des_head;
+ if (cs_des->bDescriptorSubType == USB_CDC_CALL_MANAGEMENT_TYPE) {
+ struct usb_cdc_call_mgmt_descriptor *mgmt_des = (struct usb_cdc_call_mgmt_descriptor *)des_head;
+ mgmt_des->bDataInterface = intf_data->bInterfaceNumber;
+ } else if (cs_des->bDescriptorSubType == USB_CDC_UNION_TYPE) {
+ struct usb_cdc_union_desc *union_des = (struct usb_cdc_union_desc *)des_head;
+ union_des->bMasterInterface0 = intf_ctl->bInterfaceNumber;
+ union_des->bSlaveInterface0 = intf_data->bInterfaceNumber;
+ } else if (cs_des->bDescriptorSubType == USB_CDC_ETHERNET_TYPE) {
+ struct usb_cdc_ether_desc *ether_des = (struct usb_cdc_ether_desc *)des_head;
+ ether_des->iMACAddress = intf_ctl->iInterface + 1;
+ }
+ }
+ }
+ for (i = 0; i< func->ffs->hs_descs_count; i++) {
+ des_head = func->function.hs_descriptors[i];
+ if (des_head->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) {
+ struct usb_interface_assoc_descriptor *a_dec = (struct usb_interface_assoc_descriptor *)des_head;
+ a_dec->bFirstInterface = intf_ctl->bInterfaceNumber;
+ } else if (des_head->bDescriptorType == USB_DT_CS_INTERFACE) {
+ struct usb_cdc_header_desc *cs_des = (struct usb_cdc_header_desc *)des_head;
+ if (cs_des->bDescriptorSubType == USB_CDC_CALL_MANAGEMENT_TYPE) {
+ struct usb_cdc_call_mgmt_descriptor *mgmt_des = (struct usb_cdc_call_mgmt_descriptor *)des_head;
+ mgmt_des->bDataInterface = intf_data->bInterfaceNumber;
+ } else if (cs_des->bDescriptorSubType == USB_CDC_UNION_TYPE) {
+ struct usb_cdc_union_desc *union_des = (struct usb_cdc_union_desc *)des_head;
+ union_des->bMasterInterface0 = intf_ctl->bInterfaceNumber;
+ union_des->bSlaveInterface0 = intf_data->bInterfaceNumber;
+ } else if (cs_des->bDescriptorSubType == USB_CDC_ETHERNET_TYPE) {
+ struct usb_cdc_ether_desc *ether_des = (struct usb_cdc_ether_desc *)des_head;
+ ether_des->iMACAddress = intf_ctl->iInterface + 1;
+ }
+ }
+ }
+ for (i = 0; i< func->ffs->ss_descs_count; i++) {
+ des_head = func->function.ss_descriptors[i];
+ if (des_head->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) {
+ struct usb_interface_assoc_descriptor *a_dec = (struct usb_interface_assoc_descriptor *)des_head;
+ a_dec->bFirstInterface = intf_ctl->bInterfaceNumber;
+ } else if (des_head->bDescriptorType == USB_DT_CS_INTERFACE) {
+ struct usb_cdc_header_desc *cs_des = (struct usb_cdc_header_desc *)des_head;
+ if (cs_des->bDescriptorSubType == USB_CDC_CALL_MANAGEMENT_TYPE) {
+ struct usb_cdc_call_mgmt_descriptor *mgmt_des = (struct usb_cdc_call_mgmt_descriptor *)des_head;
+ mgmt_des->bDataInterface = intf_data->bInterfaceNumber;
+ } else if (cs_des->bDescriptorSubType == USB_CDC_UNION_TYPE) {
+ struct usb_cdc_union_desc *union_des = (struct usb_cdc_union_desc *)des_head;
+ union_des->bMasterInterface0 = intf_ctl->bInterfaceNumber;
+ union_des->bSlaveInterface0 = intf_data->bInterfaceNumber;
+ } else if (cs_des->bDescriptorSubType == USB_CDC_ETHERNET_TYPE) {
+ struct usb_cdc_ether_desc *ether_des = (struct usb_cdc_ether_desc *)des_head;
+ ether_des->iMACAddress = intf_ctl->iInterface + 1;
+ }
+ }
+ }
+ /* And we're done */
+ ffs->eps = func->eps;
+ ffs_event_add(ffs, FUNCTIONFS_BIND);
+ return 0;
+
+error:
+ /* XXX Do we need to release all claimed endpoints here? */
+ return ret;
+}
+
+static int ffs_func_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c);
+ struct ffs_function *func = ffs_func_from_usb(f);
+ int ret;
+
+ if (IS_ERR(ffs_opts))
+ return PTR_ERR(ffs_opts);
+
+ ret = _ffs_func_bind(c, f);
+ if (ret && !--ffs_opts->refcnt)
+ functionfs_unbind(func->ffs);
+
+ return ret;
+}
+
+/* Other USB function hooks *************************************************/
+static void ffs_reset_work(struct work_struct *work)
+{
+ struct ffs_data *ffs = container_of(work,
+ struct ffs_data, reset_work);
+ ffs_data_reset(ffs);
+}
+
+static int ffs_func_set_alt(struct usb_function *f,
+ unsigned interface, unsigned alt)
+{
+ struct ffs_function *func = ffs_func_from_usb(f);
+ struct ffs_data *ffs = func->ffs;
+ int ret = 0, intf;
+
+ if (alt != (unsigned)-1) {
+ intf = ffs_func_revmap_intf(func, interface);
+ if (unlikely(intf < 0))
+ return intf;
+ }
+
+ if (ffs->func)
+ ffs_func_eps_disable(ffs->func);
+
+ if (ffs->state == FFS_DEACTIVATED) {
+ ffs->state = FFS_CLOSING;
+ INIT_WORK(&ffs->reset_work, ffs_reset_work);
+ schedule_work(&ffs->reset_work);
+ return -ENODEV;
+ }
+
+ if (ffs->state != FFS_ACTIVE)
+ return -ENODEV;
+
+ if (alt == (unsigned)-1) {
+ ffs->func = NULL;
+ ffs_event_add(ffs, FUNCTIONFS_DISABLE);
+ return 0;
+ }
+
+ ffs->func = func;
+ ret = ffs_func_eps_enable(func);
+ if (likely(ret >= 0))
+ ffs_event_add(ffs, FUNCTIONFS_ENABLE);
+ return ret;
+}
+
+static void ffs_func_disable(struct usb_function *f)
+{
+ ffs_func_set_alt(f, 0, (unsigned)-1);
+}
+
+static int ffs_func_setup(struct usb_function *f, const struct usb_ctrlrequest *creq)
+{
+ struct ffs_function *func = ffs_func_from_usb(f);
+ struct ffs_data *ffs = func->ffs;
+ unsigned long flags;
+ int ret;
+
+ ENTER();
+
+ pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
+ pr_vdebug("creq->bRequest = %02x\n", creq->bRequest);
+ pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue));
+ pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex));
+ pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength));
+
+ /*
+ * Most requests directed to interface go through here
+ * (notable exceptions are set/get interface) so we need to
+ * handle them. All other either handled by composite or
+ * passed to usb_configuration->setup() (if one is set). No
+ * matter, we will handle requests directed to endpoint here
+ * as well (as it's straightforward). Other request recipient
+ * types are only handled when the user flag FUNCTIONFS_ALL_CTRL_RECIP
+ * is being used.
+ */
+ if (ffs->state != FFS_ACTIVE)
+ return -ENODEV;
+
+ switch (creq->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_INTERFACE:
+ ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
+ if (unlikely(ret < 0))
+ return ret;
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
+ if (unlikely(ret < 0))
+ return ret;
+ if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
+ ret = func->ffs->eps_addrmap[ret];
+ break;
+
+ default:
+ if (func->ffs->user_flags & FUNCTIONFS_ALL_CTRL_RECIP)
+ ret = le16_to_cpu(creq->wIndex);
+ else
+ return -EOPNOTSUPP;
+ }
+
+ spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
+ ffs->ev.setup = *creq;
+ ffs->ev.setup.wIndex = cpu_to_le16(ret);
+ __ffs_event_add(ffs, FUNCTIONFS_SETUP);
+ spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
+
+ return creq->wLength == 0 ? USB_GADGET_DELAYED_STATUS : 0;
+}
+
+static bool ffs_func_req_match(struct usb_function *f,
+ const struct usb_ctrlrequest *creq,
+ bool config0)
+{
+ struct ffs_function *func = ffs_func_from_usb(f);
+
+ if (config0 && !(func->ffs->user_flags & FUNCTIONFS_CONFIG0_SETUP))
+ return false;
+
+ switch (creq->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_INTERFACE:
+ return (ffs_func_revmap_intf(func,
+ le16_to_cpu(creq->wIndex)) >= 0);
+ case USB_RECIP_ENDPOINT:
+ return (ffs_func_revmap_ep(func,
+ le16_to_cpu(creq->wIndex)) >= 0);
+ default:
+ return (bool) (func->ffs->user_flags &
+ FUNCTIONFS_ALL_CTRL_RECIP);
+ }
+}
+
+static void ffs_func_suspend(struct usb_function *f)
+{
+ ENTER();
+ ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
+}
+
+static void ffs_func_resume(struct usb_function *f)
+{
+ ENTER();
+ ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
+}
+
+/* Endpoint and interface numbers reverse mapping ***************************/
+static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
+{
+ num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
+ return num ? num : -EDOM;
+}
+
+static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
+{
+ short *nums = func->interfaces_nums;
+ unsigned count = func->ffs->interfaces_count;
+
+ for (; count; --count, ++nums) {
+ if (*nums >= 0 && *nums == intf)
+ return nums - func->interfaces_nums;
+ }
+
+ return -EDOM;
+}
+
+/* Devices management *******************************************************/
+static LIST_HEAD(ffs_devices);
+
+static struct ffs_dev *_ffs_do_find_dev(const char *name)
+{
+ struct ffs_dev *dev = NULL;
+
+ if (!name)
+ return NULL;
+
+ list_for_each_entry(dev, &ffs_devices, entry) {
+ if (!dev->name)
+ return NULL;
+ if (strcmp(dev->name, name) == 0)
+ return dev;
+ }
+
+ return NULL;
+}
+
+/*
+ * ffs_lock must be taken by the caller of this function
+ */
+static struct ffs_dev *_ffs_get_single_dev(void)
+{
+ struct ffs_dev *dev = NULL;
+
+ if (list_is_singular(&ffs_devices)) {
+ dev = list_first_entry(&ffs_devices, struct ffs_dev, entry);
+ if (dev->single)
+ return dev;
+ }
+
+ return NULL;
+}
+
+/*
+ * ffs_lock must be taken by the caller of this function
+ */
+static struct ffs_dev *_ffs_find_dev(const char *name)
+{
+ struct ffs_dev *dev;
+
+ dev = _ffs_get_single_dev();
+ if (dev)
+ return dev;
+
+ return _ffs_do_find_dev(name);
+}
+
+/* Configfs support *********************************************************/
+static inline struct f_fs_opts *to_ffs_opts(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct f_fs_opts,
+ func_inst.group);
+}
+
+static void ffs_attr_release(struct config_item *item)
+{
+ struct f_fs_opts *opts = to_ffs_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations ffs_item_ops = {
+ .release = ffs_attr_release,
+};
+
+static const struct config_item_type ffs_func_type = {
+ .ct_item_ops = &ffs_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* Function registration interface ******************************************/
+static void ffs_free_inst(struct usb_function_instance *f)
+{
+ struct f_fs_opts *opts;
+
+ opts = to_f_fs_opts(f);
+ ffs_dev_lock();
+ _ffs_free_dev(opts->dev);
+ ffs_dev_unlock();
+ kfree(opts);
+}
+
+static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
+{
+ char name_dev[MAX_NAMELEN] = {0};
+ if (snprintf_s(name_dev, MAX_NAMELEN, MAX_NAMELEN - 1, "%s.%s", FUNCTION_GENERIC, name) < 0) {
+ return -EFAULT;
+ }
+ if (strlen(name_dev) >= sizeof_field(struct ffs_dev, name))
+ return -ENAMETOOLONG;
+ return ffs_name_dev_adapter(to_f_fs_opts(fi)->dev, name_dev);
+}
+
+static struct usb_function_instance *ffs_alloc_inst(void)
+{
+ struct f_fs_opts *opts = NULL;
+ struct ffs_dev *dev = NULL;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ opts->func_inst.set_inst_name = ffs_set_inst_name;
+ opts->func_inst.free_func_inst = ffs_free_inst;
+ ffs_dev_lock();
+ dev = _ffs_alloc_dev();
+ ffs_dev_unlock();
+ if (IS_ERR(dev)) {
+ kfree(opts);
+ return ERR_CAST(dev);
+ }
+ opts->dev = dev;
+ dev->opts = opts;
+
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &ffs_func_type);
+ return &opts->func_inst;
+}
+
+static void ffs_free(struct usb_function *f)
+{
+ kfree(ffs_func_from_usb(f));
+}
+
+static void ffs_func_unbind(struct usb_configuration *c,
+ struct usb_function *f)
+{
+ struct ffs_function *func = ffs_func_from_usb(f);
+ struct ffs_data *ffs = func->ffs;
+ struct f_fs_opts *opts =
+ container_of(f->fi, struct f_fs_opts, func_inst);
+ struct ffs_ep *ep = func->eps;
+ unsigned count = ffs->eps_count;
+ unsigned long flags;
+
+ ENTER();
+ if (ffs->func == func) {
+ ffs_func_eps_disable(func);
+ ffs->func = NULL;
+ }
+
+ if (!--opts->refcnt)
+ functionfs_unbind(ffs);
+
+ /* cleanup after autoconfig */
+ spin_lock_irqsave(&func->ffs->eps_lock, flags);
+ while (count--) {
+ if (ep->ep && ep->req)
+ usb_ep_free_request(ep->ep, ep->req);
+ ep->req = NULL;
+ ++ep;
+ }
+ spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+ kfree(func->eps);
+ func->eps = NULL;
+ /*
+ * eps, descriptors and interfaces_nums are allocated in the
+ * same chunk so only one free is required.
+ */
+ func->function.fs_descriptors = NULL;
+ func->function.hs_descriptors = NULL;
+ func->function.ss_descriptors = NULL;
+ func->interfaces_nums = NULL;
+
+ ffs_event_add(ffs, FUNCTIONFS_UNBIND);
+}
+
+static int ffs_func_get_alt(struct usb_function *f, unsigned intf)
+{
+ if (intf == 0)
+ return 0;
+ return 1;
+}
+
+static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
+{
+ struct ffs_function *func = NULL;
+
+ ENTER();
+
+ func = kzalloc(sizeof(*func), GFP_KERNEL);
+ if (unlikely(!func))
+ return ERR_PTR(-ENOMEM);
+
+ func->function.name = "FunctionFS Adapter";
+
+ func->function.bind = ffs_func_bind;
+ func->function.unbind = ffs_func_unbind;
+ func->function.set_alt = ffs_func_set_alt;
+ func->function.get_alt = ffs_func_get_alt;
+ func->function.disable = ffs_func_disable;
+ func->function.setup = ffs_func_setup;
+ func->function.req_match = ffs_func_req_match;
+ func->function.suspend = ffs_func_suspend;
+ func->function.resume = ffs_func_resume;
+ func->function.free_func = ffs_free;
+
+ return &func->function;
+}
+
+/*
+ * ffs_lock must be taken by the caller of this function
+ */
+static struct ffs_dev *_ffs_alloc_dev(void)
+{
+ struct ffs_dev *dev = NULL;
+ int ret;
+
+ if (_ffs_get_single_dev())
+ return ERR_PTR(-EBUSY);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ if (list_empty(&ffs_devices)) {
+ ret = functionfs_init();
+ if (ret) {
+ kfree(dev);
+ return ERR_PTR(ret);
+ }
+ }
+
+ list_add(&dev->entry, &ffs_devices);
+
+ return dev;
+}
+
+int ffs_name_dev_adapter(struct ffs_dev *dev, const char *name)
+{
+ struct ffs_dev *existing = NULL;
+ int ret = 0;
+
+ ffs_dev_lock();
+
+ existing = _ffs_do_find_dev(name);
+ if (!existing)
+ strlcpy(dev->name, name, ARRAY_SIZE(dev->name));
+ else if (existing != dev)
+ ret = -EBUSY;
+
+ ffs_dev_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ffs_name_dev_adapter);
+
+int ffs_single_dev_adapter(struct ffs_dev *dev)
+{
+ int ret;
+
+ ret = 0;
+ ffs_dev_lock();
+
+ if (!list_is_singular(&ffs_devices))
+ ret = -EBUSY;
+ else
+ dev->single = true;
+
+ ffs_dev_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ffs_single_dev_adapter);
+/*
+ * ffs_lock must be taken by the caller of this function
+ */
+static void _ffs_free_dev(struct ffs_dev *dev)
+{
+ list_del(&dev->entry);
+
+ /* Clear the private_data pointer to stop incorrect dev access */
+ if (dev->ffs_data)
+ dev->ffs_data->private_data = NULL;
+
+ kfree(dev);
+ if (list_empty(&ffs_devices))
+ functionfs_cleanup();
+}
+
+static void *ffs_acquire_dev(const char *dev_name)
+{
+ struct ffs_dev *ffs_dev = NULL;
+
+ ENTER();
+ ffs_dev_lock();
+
+ ffs_dev = _ffs_find_dev(dev_name);
+ if (!ffs_dev)
+ ffs_dev = ERR_PTR(-ENOENT);
+ else if (ffs_dev->mounted)
+ ffs_dev = ERR_PTR(-EBUSY);
+ else if (ffs_dev->ffs_acquire_dev_callback &&
+ ffs_dev->ffs_acquire_dev_callback(ffs_dev))
+ ffs_dev = ERR_PTR(-ENOENT);
+ else
+ ffs_dev->mounted = true;
+
+ ffs_dev_unlock();
+ return ffs_dev;
+}
+
+static void ffs_release_dev(struct ffs_data *ffs_data)
+{
+ struct ffs_dev *ffs_dev = NULL;
+
+ ENTER();
+ ffs_dev_lock();
+
+ ffs_dev = ffs_data->private_data;
+ if (ffs_dev) {
+ ffs_dev->mounted = false;
+
+ if (ffs_dev->ffs_release_dev_callback)
+ ffs_dev->ffs_release_dev_callback(ffs_dev);
+ }
+
+ ffs_dev_unlock();
+}
+
+static int ffs_ready(struct ffs_data *ffs)
+{
+ struct ffs_dev *ffs_obj = NULL;
+ int ret = 0;
+
+ ENTER();
+ ffs_dev_lock();
+
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (WARN_ON(ffs_obj->desc_ready)) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ ffs_obj->desc_ready = true;
+ ffs_obj->ffs_data = ffs;
+
+ if (ffs_obj->ffs_ready_callback) {
+ ret = ffs_obj->ffs_ready_callback(ffs);
+ if (ret)
+ goto done;
+ }
+
+ set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
+done:
+ ffs_dev_unlock();
+ return ret;
+}
+
+static void ffs_closed(struct ffs_data *ffs)
+{
+ struct ffs_dev *ffs_obj = NULL;
+ struct f_fs_opts *opts = NULL;
+ struct config_item *ci = NULL;
+
+ ENTER();
+ ffs_dev_lock();
+
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj)
+ goto done;
+
+ ffs_obj->desc_ready = false;
+ ffs_obj->ffs_data = NULL;
+
+ if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
+ ffs_obj->ffs_closed_callback)
+ ffs_obj->ffs_closed_callback(ffs);
+
+ if (ffs_obj->opts)
+ opts = ffs_obj->opts;
+ else
+ goto done;
+
+ if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent
+ || !kref_read(&opts->func_inst.group.cg_item.ci_kref))
+ goto done;
+
+ ci = opts->func_inst.group.cg_item.ci_parent->ci_parent;
+ ffs_dev_unlock();
+
+ if (test_bit(FFS_FL_BOUND, &ffs->flags))
+ unregister_gadget_item(ci);
+ return;
+done:
+ ffs_dev_unlock();
+}
+
+/* Misc helper functions ****************************************************/
+static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
+{
+ return nonblock
+ ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN
+ : mutex_lock_interruptible(mutex);
+}
+
+static char *ffs_prepare_buffer(const char __user *buf, size_t len)
+{
+ char *data = NULL;
+
+ if (unlikely(!len))
+ return NULL;
+
+ data = kmalloc(len, GFP_KERNEL);
+ if (unlikely(!data))
+ return ERR_PTR(-ENOMEM);
+
+ if (unlikely(copy_from_user(data, buf, len))) {
+ kfree(data);
+ return ERR_PTR(-EFAULT);
+ }
+
+ pr_vdebug("Buffer from user space:\n");
+ ffs_dump_mem("", data, len);
+
+ return data;
+}
+
+DECLARE_USB_FUNCTION_INIT(f_generic, ffs_alloc_inst, ffs_alloc);
+MODULE_LICENSE("GPL");
diff --git a/adapter/khdf/linux/model/usb/device/u_f.h b/adapter/khdf/linux/model/usb/device/u_f.h
new file mode 100644
index 00000000..09f90447
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/device/u_f.h
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * u_f.h
+ *
+ * Utility definitions for USB functions
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz
+ */
+
+#ifndef __U_F_H__
+#define __U_F_H__
+
+#include
+
+/* Variable Length Array Macros **********************************************/
+#define vla_group(groupname) size_t groupname##__next = 0
+#define vla_group_size(groupname) groupname##__next
+
+#define vla_item(groupname, type, name, n) \
+ size_t groupname##_##name##__offset = ({ \
+ size_t align_mask = __alignof__(type) - 1; \
+ size_t offset = (groupname##__next + align_mask) & ~align_mask;\
+ size_t size = (n) * sizeof(type); \
+ groupname##__next = offset + size; \
+ offset; \
+ })
+
+#define vla_item_with_sz(groupname, type, name, n) \
+ size_t groupname##_##name##__sz = (n) * sizeof(type); \
+ size_t groupname##_##name##__offset = ({ \
+ size_t align_mask = __alignof__(type) - 1; \
+ size_t offset = (groupname##__next + align_mask) & ~align_mask;\
+ size_t size = groupname##_##name##__sz; \
+ groupname##__next = offset + size; \
+ offset; \
+ })
+
+#define vla_ptr(ptr, groupname, name) \
+ ((void *) ((char *)ptr + groupname##_##name##__offset))
+
+struct usb_ep;
+struct usb_request;
+
+/**
+ * alloc_ep_req - returns a usb_request allocated by the gadget driver and
+ * allocates the request's buffer.
+ *
+ * @ep: the endpoint to allocate a usb_request
+ * @len: usb_requests's buffer suggested size
+ *
+ * In case @ep direction is OUT, the @len will be aligned to ep's
+ * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use
+ * usb_requests's length (req->length) to refer to the allocated buffer size.
+ * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req().
+ */
+struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len);
+
+/* Frees a usb_request previously allocated by alloc_ep_req() */
+static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+ WARN_ON(req->buf == NULL);
+ kfree(req->buf);
+ req->buf = NULL;
+ usb_ep_free_request(ep, req);
+}
+
+#endif /* __U_F_H__ */
diff --git a/adapter/khdf/linux/model/usb/device/u_generic.h b/adapter/khdf/linux/model/usb/device/u_generic.h
new file mode 100644
index 00000000..621f71e1
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/device/u_generic.h
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * u_fs.h
+ *
+ * Utility definitions for the FunctionFS
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz
+ */
+
+#ifndef U_GENERIC_H
+#define U_GENERIC_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef VERBOSE_DEBUG
+#ifndef pr_vdebug
+# define pr_vdebug pr_debug
+#endif /* pr_vdebug */
+# define ffs_dump_mem(prefix, ptr, len) \
+ print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
+#else
+#ifndef pr_vdebug
+# define pr_vdebug(...) do { } while (0)
+#endif /* pr_vdebug */
+# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
+#endif /* VERBOSE_DEBUG */
+
+#define ENTER() pr_vdebug("%s()\n", __func__)
+
+#define MAX_REQUEST 64
+#define MAX_NAMELEN 64
+#define FUNCTION_GENERIC "f_generic"
+
+struct FuncNew {
+ uint32_t nameLen;
+ char name[MAX_NAMELEN];
+};
+
+struct IoData {
+ uint32_t aio;
+ uint32_t read;
+ uint32_t len;
+ uint32_t timeout;
+ uint64_t buf;
+};
+
+struct UsbFnReqEvent {
+ uint64_t buf;
+ uint32_t actual;
+ int status;
+};
+
+struct ffs_memory{
+ uint64_t mem;
+ uint64_t vm_start;
+ uint32_t size;
+ struct list_head memlist;
+};
+
+struct generic_memory{
+ uint32_t size;
+ uint64_t buf;
+};
+
+
+#define FUNCTIONFS_NEWFN _IOW('g', 60, struct FuncNew)
+#define FUNCTIONFS_DELFN _IOW('g', 61, struct FuncNew)
+#define FUNCTIONFS_ENDPOINT_GET_REQ_STATUS _IOW('g', 48, struct IoData)
+#define FUNCTIONFS_ENDPOINT_WRITE _IOW('g', 49, struct IoData)
+#define FUNCTIONFS_ENDPOINT_READ _IOW('g', 50, struct IoData)
+#define FUNCTIONFS_ENDPOINT_RW_CANCEL _IOW('g', 51, struct IoData)
+#define FUNCTIONFS_ENDPOINT_QUEUE_INIT _IO('g', 52)
+#define FUNCTIONFS_ENDPOINT_QUEUE_DEL _IO('g', 53)
+#define FUNCTIONFS_ENDPOINT_RELEASE_BUF _IOR('g', 54, struct generic_memory)
+#define FUNCTIONFS_ENDPOINT_GET_EP0_EVENT _IOR('g', 56, struct UsbFnReqEvent)
+
+struct f_fs_opts;
+
+struct ffs_dev {
+ struct ffs_data *ffs_data;
+ struct f_fs_opts *opts;
+ struct list_head entry;
+
+ char name[MAX_NAMELEN];
+
+ bool mounted;
+ bool desc_ready;
+ bool single;
+
+ int (*ffs_ready_callback)(struct ffs_data *ffs);
+ void (*ffs_closed_callback)(struct ffs_data *ffs);
+ void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
+ void (*ffs_release_dev_callback)(struct ffs_dev *dev);
+};
+
+extern struct mutex ffs_lock_adapter;
+
+static inline void ffs_dev_lock(void)
+{
+ mutex_lock(&ffs_lock_adapter);
+}
+
+static inline void ffs_dev_unlock(void)
+{
+ mutex_unlock(&ffs_lock_adapter);
+}
+
+int ffs_name_dev_adapter(struct ffs_dev *dev, const char *name);
+int ffs_single_dev_adapter(struct ffs_dev *dev);
+
+struct ffs_epfile;
+struct ffs_function;
+
+enum ffs_state {
+ /*
+ * Waiting for descriptors and strings.
+ *
+ * In this state no open(2), read(2) or write(2) on epfiles
+ * may succeed (which should not be the problem as there
+ * should be no such files opened in the first place).
+ */
+ FFS_READ_DESCRIPTORS,
+ FFS_READ_STRINGS,
+
+ /*
+ * We've got descriptors and strings. We are or have called
+ * functionfs_ready_callback(). functionfs_bind() may have
+ * been called but we don't know.
+ *
+ * This is the only state in which operations on epfiles may
+ * succeed.
+ */
+ FFS_ACTIVE,
+
+ /*
+ * Function is visible to host, but it's not functional. All
+ * setup requests are stalled and transfers on another endpoints
+ * are refused. All epfiles, except ep0, are deleted so there
+ * is no way to perform any operations on them.
+ *
+ * This state is set after closing all functionfs files, when
+ * mount parameter "no_disconnect=1" has been set. Function will
+ * remain in deactivated state until filesystem is umounted or
+ * ep0 is opened again. In the second case functionfs state will
+ * be reset, and it will be ready for descriptors and strings
+ * writing.
+ *
+ * This is useful only when functionfs is composed to gadget
+ * with another function which can perform some critical
+ * operations, and it's strongly desired to have this operations
+ * completed, even after functionfs files closure.
+ */
+ FFS_DEACTIVATED,
+
+ /*
+ * All endpoints have been closed. This state is also set if
+ * we encounter an unrecoverable error. The only
+ * unrecoverable error is situation when after reading strings
+ * from user space we fail to initialise epfiles or
+ * functionfs_ready_callback() returns with error (<0).
+ *
+ * In this state no open(2), read(2) or write(2) (both on ep0
+ * as well as epfile) may succeed (at this point epfiles are
+ * unlinked and all closed so this is not a problem; ep0 is
+ * also closed but ep0 file exists and so open(2) on ep0 must
+ * fail).
+ */
+ FFS_CLOSING
+};
+
+enum ffs_setup_state {
+ /* There is no setup request pending. */
+ FFS_NO_SETUP,
+ /*
+ * User has read events and there was a setup request event
+ * there. The next read/write on ep0 will handle the
+ * request.
+ */
+ FFS_SETUP_PENDING,
+ /*
+ * There was event pending but before user space handled it
+ * some other event was introduced which canceled existing
+ * setup. If this state is set read/write on ep0 return
+ * -EIDRM. This state is only set when adding event.
+ */
+ FFS_SETUP_CANCELLED
+};
+
+struct ffs_data {
+ struct usb_gadget *gadget;
+ struct list_head entry;
+ struct list_head memory_list;
+ /*
+ * Protect access read/write operations, only one read/write
+ * at a time. As a consequence protects ep0req and company.
+ * While setup request is being processed (queued) this is
+ * held.
+ */
+ struct mutex mutex;
+
+ /*
+ * Protect access to endpoint related structures (basically
+ * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
+ * endpoint zero.
+ */
+ spinlock_t eps_lock;
+ spinlock_t mem_lock;
+
+ /*
+ * XXX REVISIT do we need our own request? Since we are not
+ * handling setup requests immediately user space may be so
+ * slow that another setup will be sent to the gadget but this
+ * time not to us but another function and then there could be
+ * a race. Is that the case? Or maybe we can use cdev->req
+ * after all, maybe we just need some spinlock for that?
+ */
+ struct usb_request *ep0req; /* P: mutex */
+ struct completion ep0req_completion; /* P: mutex */
+
+ /* reference counter */
+ refcount_t ref;
+ /* how many files are opened (EP0 and others) */
+ atomic_t opened;
+
+ /* EP0 state */
+ enum ffs_state state;
+
+ /*
+ * Possible transitions:
+ * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock
+ * happens only in ep0 read which is P: mutex
+ * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock
+ * happens only in ep0 i/o which is P: mutex
+ * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELLED -- P: ev.waitq.lock
+ * + FFS_SETUP_CANCELLED -> FFS_NO_SETUP -- cmpxchg
+ *
+ * This field should never be accessed directly and instead
+ * ffs_setup_state_clear_cancelled function should be used.
+ */
+ enum ffs_setup_state setup_state;
+
+ /* Events & such. */
+ struct {
+ u8 types[4];
+ unsigned short count;
+ /* XXX REVISIT need to update it in some places, or do we? */
+ unsigned short can_stall;
+ struct usb_ctrlrequest setup;
+
+ wait_queue_head_t waitq;
+ } ev; /* the whole structure, P: ev.waitq.lock */
+
+ /* Flags */
+ unsigned long flags;
+#define FFS_FL_CALL_CLOSED_CALLBACK 0
+#define FFS_FL_BOUND 1
+
+ /* For waking up blocked threads when function is enabled. */
+ wait_queue_head_t wait;
+
+ /* Active function */
+ struct ffs_function *func;
+
+
+ char dev_name[MAX_NAMELEN];
+ struct cdev cdev;
+ dev_t devno;
+ struct device *fn_device;
+
+ struct kfifo reqEventFifo;
+ wait_queue_head_t wait_que;
+ /* Private data for our user (ie. gadget). Managed by user. */
+ void *private_data;
+ /* filled by __ffs_data_got_descs() */
+ /*
+ * raw_descs is what you kfree, real_descs points inside of raw_descs,
+ * where full speed, high speed and super speed descriptors start.
+ * real_descs_length is the length of all those descriptors.
+ */
+ const void *raw_descs_data;
+ const void *raw_descs;
+ unsigned raw_descs_length;
+ unsigned fs_descs_count;
+ unsigned hs_descs_count;
+ unsigned ss_descs_count;
+ unsigned ms_os_descs_count;
+ unsigned ms_os_descs_ext_prop_count;
+ unsigned ms_os_descs_ext_prop_name_len;
+ unsigned ms_os_descs_ext_prop_data_len;
+ void *ms_os_descs_ext_prop_avail;
+ void *ms_os_descs_ext_prop_name_avail;
+ void *ms_os_descs_ext_prop_data_avail;
+
+ unsigned user_flags;
+
+#define FFS_MAX_EPS_COUNT 31
+ u8 eps_addrmap[FFS_MAX_EPS_COUNT];
+
+ unsigned short strings_count;
+ unsigned short interfaces_count;
+ unsigned short eps_count;
+ unsigned short _pad1;
+
+ /* filled by __ffs_data_got_strings() */
+ /* ids in stringtabs are set in functionfs_bind() */
+ const void *raw_strings;
+ struct usb_gadget_strings **stringtabs;
+
+ /*
+ * File system's super block, write once when file system is
+ * mounted.
+ */
+ struct super_block *sb;
+
+ /* File permissions, written once when fs is mounted */
+ struct ffs_file_perms {
+ umode_t mode;
+ kuid_t uid;
+ kgid_t gid;
+ } file_perms;
+
+ struct eventfd_ctx *ffs_eventfd;
+ struct workqueue_struct *io_completion_wq;
+ bool no_disconnect;
+ struct work_struct reset_work;
+
+ /*
+ * The endpoint files, filled by ffs_epfiles_create(),
+ * destroyed by ffs_epfiles_destroy().
+ */
+ struct ffs_epfile *epfiles;
+ struct ffs_ep *eps;
+ enum usb_device_speed speed;
+};
+
+
+struct f_fs_opts {
+ struct usb_function_instance func_inst;
+ struct ffs_dev *dev;
+ unsigned refcnt;
+ bool no_configfs;
+};
+
+static inline struct f_fs_opts *to_f_fs_opts(struct usb_function_instance *fi)
+{
+ return container_of(fi, struct f_fs_opts, func_inst);
+}
+
+#endif /* U_GENERIC_H */
diff --git a/adapter/khdf/linux/model/usb/device/u_os_desc.h b/adapter/khdf/linux/model/usb/device/u_os_desc.h
new file mode 100644
index 00000000..f6f2d1dc
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/device/u_os_desc.h
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * u_os_desc.h
+ *
+ * Utility definitions for "OS Descriptors" support
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz
+ */
+
+#ifndef __U_OS_DESC_H__
+#define __U_OS_DESC_H__
+
+#include
+#include
+#include "securec.h"
+#include "hdf_log.h"
+
+#define USB_EXT_PROP_DW_SIZE 0
+#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE 4
+#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH 8
+#define USB_EXT_PROP_B_PROPERTY_NAME 10
+#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH 10
+#define USB_EXT_PROP_B_PROPERTY_DATA 14
+
+#define USB_EXT_PROP_RESERVED 0
+#define USB_EXT_PROP_UNICODE 1
+#define USB_EXT_PROP_UNICODE_ENV 2
+#define USB_EXT_PROP_BINARY 3
+#define USB_EXT_PROP_LE32 4
+#define USB_EXT_PROP_BE32 5
+#define USB_EXT_PROP_UNICODE_LINK 6
+#define USB_EXT_PROP_UNICODE_MULTI 7
+
+static inline u8 *__usb_ext_prop_ptr(u8 *buf, size_t offset)
+{
+ return buf + offset;
+}
+
+static inline u8 *usb_ext_prop_size_ptr(u8 *buf)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_SIZE);
+}
+
+static inline u8 *usb_ext_prop_type_ptr(u8 *buf)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_PROPERTY_DATA_TYPE);
+}
+
+static inline u8 *usb_ext_prop_name_len_ptr(u8 *buf)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_W_PROPERTY_NAME_LENGTH);
+}
+
+static inline u8 *usb_ext_prop_name_ptr(u8 *buf)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_NAME);
+}
+
+static inline u8 *usb_ext_prop_data_len_ptr(u8 *buf, size_t off)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + off);
+}
+
+static inline u8 *usb_ext_prop_data_ptr(u8 *buf, size_t off)
+{
+ return __usb_ext_prop_ptr(buf, USB_EXT_PROP_B_PROPERTY_DATA + off);
+}
+
+static inline void usb_ext_prop_put_size(u8 *buf, int dw_size)
+{
+ put_unaligned_le32(dw_size, usb_ext_prop_size_ptr(buf));
+}
+
+static inline void usb_ext_prop_put_type(u8 *buf, int type)
+{
+ put_unaligned_le32(type, usb_ext_prop_type_ptr(buf));
+}
+
+static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl)
+{
+ int result;
+
+ put_unaligned_le16(pnl, usb_ext_prop_name_len_ptr(buf));
+ result = utf8s_to_utf16s(name, strlen(name), UTF16_LITTLE_ENDIAN,
+ (wchar_t *) usb_ext_prop_name_ptr(buf), pnl - 2);
+ if (result < 0)
+ return result;
+
+ put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl - 2]);
+
+ return pnl;
+}
+
+static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const u8 *data, int data_len)
+{
+ int32_t ret;
+ put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl));
+ ret = memcpy_s(usb_ext_prop_data_ptr(buf, pnl), data_len, data, data_len);
+ if (ret != EOK) {
+ HDF_LOGE("%{public}s: %{public}d memset_s failed", __func__, __LINE__);
+ }
+}
+
+static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string, int data_len)
+{
+ int result;
+ put_unaligned_le32(data_len, usb_ext_prop_data_len_ptr(buf, pnl));
+ result = utf8s_to_utf16s(string, data_len >> 1, UTF16_LITTLE_ENDIAN,
+ (wchar_t *) usb_ext_prop_data_ptr(buf, pnl), data_len - 2);
+ if (result < 0)
+ return result;
+
+ put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len - 2]);
+
+ return data_len;
+}
+
+#endif /* __U_OS_DESC_H__ */
diff --git a/adapter/khdf/linux/model/usb/host/Kconfig b/adapter/khdf/linux/model/usb/host/Kconfig
new file mode 100755
index 00000000..710f80db
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/host/Kconfig
@@ -0,0 +1,17 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+config DRIVERS_HDF_USB_PNP_NOTIFY
+ bool "Enable HDF USB PNP Notify driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to choice HDF USB PNP Notify driver.
diff --git a/adapter/khdf/linux/model/usb/host/Makefile b/adapter/khdf/linux/model/usb/host/Makefile
new file mode 100644
index 00000000..86dfad1a
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/host/Makefile
@@ -0,0 +1,28 @@
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+USB_PNP_NOTIFY_ROOT_DIR = ./
+obj-$(CONFIG_DRIVERS_HDF_USB_PNP_NOTIFY) += \
+ $(USB_PNP_NOTIFY_ROOT_DIR)/src/usb_pnp_notify.o
+
+ccflags-y += -lm -lc -lgcc \
+ -I$(srctree)/drivers/hdf/khdf/model/usb/host/include \
+ -I$(srctree)/drivers/hdf/framework/include/utils \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/drivers/hdf/framework/include/core \
+ -I$(srctree)/drivers/hdf/framework/core/common/include/host \
+ -I$(srctree)/drivers/hdf/framework/core/shared/include \
+ -I$(srctree)/drivers/hdf/framework/include \
+ -I$(srctree)/drivers/hdf/framework/include/osal \
+ -I$(srctree)/drivers/hdf/framework/include/platform \
+ -I$(srctree)/drivers/hdf/framework/include/config \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/model/usb/host/include/usb_pnp_notify.h b/adapter/khdf/linux/model/usb/host/include/usb_pnp_notify.h
new file mode 100644
index 00000000..d1c37655
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/host/include/usb_pnp_notify.h
@@ -0,0 +1,84 @@
+/*
+ * usb_pnp_notify.h
+ *
+ * usb pnp notify adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef USB_PNP_NOTIFY_H
+#define USB_PNP_NOTIFY_H
+
+#include "hdf_base.h"
+#include "hdf_dlist.h"
+#include "hdf_usb_pnp_manage.h"
+#include "osal_mutex.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* __cplusplus */
+
+#define USB_PNP_NOTIFY_MSLEEP_TIME (10)
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+
+typedef enum {
+ USB_INFO_NORMAL_TYPE,
+ USB_INFO_ID_TYPE,
+ USB_INFO_DEVICE_ADDRESS_TYPE,
+} UsbInfoQueryParaType;
+
+typedef enum {
+ USB_PNP_DEVICE_INIT_STATUS,
+ USB_PNP_DEVICE_ADD_STATUS,
+ USB_PNP_DEVICE_REMOVE_STATUS,
+ USB_PNP_DEVICE_INTERFACE_STATUS,
+} UsbPnpDeviceStatus;
+
+struct UsbPnpDeviceInfo {
+ int32_t id;
+ struct OsalMutex lock;
+ UsbPnpDeviceStatus status;
+ struct DListHead list;
+ bool interfaceRemoveStatus[USB_PNP_INFO_MAX_INTERFACES];
+ struct UsbPnpNotifyMatchInfoTable info;
+};
+
+struct UsbInfoQueryPara {
+ UsbInfoQueryParaType type;
+ union {
+ int32_t id;
+ uint64_t usbDevAddr;
+ struct {
+ int32_t devNum;
+ int32_t busNum;
+ };
+ };
+};
+
+union UsbPnpDeviceInfoData {
+ struct usb_device *usbDev;
+ struct UsbPnpAddRemoveInfo *infoData;
+};
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif /* USB_PNP_NOTIFY_H */
diff --git a/adapter/khdf/linux/model/usb/host/src/usb_pnp_notify.c b/adapter/khdf/linux/model/usb/host/src/usb_pnp_notify.c
new file mode 100644
index 00000000..c857b91b
--- /dev/null
+++ b/adapter/khdf/linux/model/usb/host/src/usb_pnp_notify.c
@@ -0,0 +1,928 @@
+/*
+ * usb_pnp_notify.c
+ *
+ * usb pnp notify adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "usb_pnp_notify.h"
+#include
+#include
+#include
+#include
+#include "hdf_device_desc.h"
+#include "hdf_log.h"
+#include "osal_mem.h"
+#include "securec.h"
+
+#define HDF_LOG_TAG USB_PNP_NOTIFY
+#ifndef USB_GADGET_ADD
+#define USB_GADGET_ADD 0x0005
+#endif
+#ifndef USB_GADGET_REMOVE
+#define USB_GADGET_REMOVE 0x0006
+#endif
+
+static wait_queue_head_t g_usbPnpNotifyReportWait;
+static wait_queue_head_t g_gadgetPnpNotifyReportWait;
+static struct task_struct *g_usbPnpNotifyReportThread = NULL;
+static struct task_struct *g_gadgetPnpNotifyReportThread = NULL;
+static enum UsbPnpNotifyServiceCmd g_usbPnpNotifyCmdType = USB_PNP_NOTIFY_ADD_INTERFACE;
+static enum UsbPnpNotifyRemoveType g_usbPnpNotifyRemoveType = USB_PNP_NOTIFY_REMOVE_BUS_DEV_NUM;
+static uint8_t g_gadgetPnpNotifyType = 0;
+static uint64_t g_preAcion = 0;
+struct OsalMutex g_usbSendEventLock;
+struct OsalMutex g_gadgetSendEventLock;
+struct usb_device *g_usbDevice = NULL;
+struct UsbPnpAddRemoveInfo g_usbPnpInfo;
+struct DListHead g_usbPnpInfoListHead;
+#if USB_PNP_NOTIFY_TEST_MODE == true
+struct UsbPnpNotifyMatchInfoTable *g_testUsbPnpInfo = NULL;
+#endif
+
+static struct UsbPnpDeviceInfo *UsbPnpNotifyCreateInfo(void)
+{
+ struct UsbPnpDeviceInfo *infoTemp = NULL;
+ static int32_t idNum = 1;
+ int32_t ret;
+
+ infoTemp = (struct UsbPnpDeviceInfo *)OsalMemCalloc(sizeof(struct UsbPnpDeviceInfo));
+ if (infoTemp == NULL) {
+ HDF_LOGE("%s:%d OsalMemAlloc failed", __func__, __LINE__);
+ return NULL;
+ }
+
+ if (idNum == INT32_MAX) {
+ idNum = 1;
+ }
+ infoTemp->id = idNum;
+ OsalMutexInit(&infoTemp->lock);
+ infoTemp->status = USB_PNP_DEVICE_INIT_STATUS;
+ DListHeadInit(&infoTemp->list);
+ DListInsertTail(&infoTemp->list, &g_usbPnpInfoListHead);
+ idNum++;
+
+ return infoTemp;
+}
+
+static struct UsbPnpDeviceInfo *UsbPnpNotifyFindInfo(struct UsbInfoQueryPara queryPara)
+{
+ struct UsbPnpDeviceInfo *infoPos = NULL;
+ struct UsbPnpDeviceInfo *infoTemp = NULL;
+ bool findFlag = false;
+
+ if (DListIsEmpty(&g_usbPnpInfoListHead)) {
+ HDF_LOGE("%s:%d usb pnp list head is empty.", __func__, __LINE__);
+ return NULL;
+ }
+
+ DLIST_FOR_EACH_ENTRY_SAFE(infoPos, infoTemp, &g_usbPnpInfoListHead, struct UsbPnpDeviceInfo, list) {
+ switch (queryPara.type) {
+ case USB_INFO_NORMAL_TYPE:
+ if ((infoPos->info.devNum == queryPara.devNum) && (infoPos->info.busNum == queryPara.busNum)) {
+ findFlag = true;
+ }
+ break;
+ case USB_INFO_ID_TYPE:
+ if (infoPos->id == queryPara.id) {
+ findFlag = true;
+ }
+ break;
+ case USB_INFO_DEVICE_ADDRESS_TYPE:
+ if (infoPos->info.usbDevAddr == queryPara.usbDevAddr) {
+ findFlag = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (findFlag) {
+ break;
+ }
+ }
+
+ if (!findFlag) {
+ HDF_LOGE("%s:%d the usb pnp info to be find does not exist.", __func__, __LINE__);
+ return NULL;
+ }
+ return infoPos;
+}
+
+static HDF_STATUS UsbPnpNotifyDestroyInfo(struct UsbPnpDeviceInfo *deviceInfo)
+{
+ HDF_STATUS ret = HDF_SUCCESS;
+ struct UsbPnpDeviceInfo *infoPos = NULL;
+ struct UsbPnpDeviceInfo *infoTemp = NULL;
+ bool findFlag = false;
+
+ if (deviceInfo == NULL) {
+ ret = HDF_FAILURE;
+ HDF_LOGE("%s:%d the deviceInfo is NULL, ret=%d ", __func__, __LINE__, ret);
+ return ret;
+ }
+
+ if (DListIsEmpty(&g_usbPnpInfoListHead)) {
+ HDF_LOGI("%s:%d the g_usbPnpInfoListHead is empty.", __func__, __LINE__);
+ return HDF_SUCCESS;
+ }
+
+ DLIST_FOR_EACH_ENTRY_SAFE(infoPos, infoTemp, &g_usbPnpInfoListHead, struct UsbPnpDeviceInfo, list) {
+ if (infoPos->id == deviceInfo->id) {
+ findFlag = true;
+ DListRemove(&infoPos->list);
+ OsalMemFree((void *)infoPos);
+ infoPos = NULL;
+ break;
+ }
+ }
+
+ if (!findFlag) {
+ ret = HDF_FAILURE;
+ HDF_LOGE("%s:%d the deviceInfoto be destroyed does not exist, ret=%d ", __func__, __LINE__, ret);
+ }
+
+ return ret;
+}
+
+static int32_t UsbPnpNotifyAddInitInfo(struct UsbPnpDeviceInfo *deviceInfo, union UsbPnpDeviceInfoData infoData)
+{
+ int32_t ret = HDF_SUCCESS;
+ uint8_t i;
+
+ deviceInfo->info.usbDevAddr = (uint64_t)infoData.usbDev;
+ deviceInfo->info.devNum = infoData.usbDev->devnum;
+ if (infoData.usbDev->bus == NULL) {
+ HDF_LOGE("%s infoData.usbDev->bus is NULL", __func__);
+ ret = HDF_ERR_INVALID_PARAM;
+ goto OUT;
+ }
+ deviceInfo->info.busNum = infoData.usbDev->bus->busnum;
+
+ deviceInfo->info.deviceInfo.vendorId = le16_to_cpu(infoData.usbDev->descriptor.idVendor);
+ deviceInfo->info.deviceInfo.productId = le16_to_cpu(infoData.usbDev->descriptor.idProduct);
+ deviceInfo->info.deviceInfo.bcdDeviceLow = le16_to_cpu(infoData.usbDev->descriptor.bcdDevice);
+ deviceInfo->info.deviceInfo.bcdDeviceHigh = le16_to_cpu(infoData.usbDev->descriptor.bcdDevice);
+ deviceInfo->info.deviceInfo.deviceClass = infoData.usbDev->descriptor.bDeviceClass;
+ deviceInfo->info.deviceInfo.deviceSubClass = infoData.usbDev->descriptor.bDeviceSubClass;
+ deviceInfo->info.deviceInfo.deviceProtocol = infoData.usbDev->descriptor.bDeviceProtocol;
+
+ if (infoData.usbDev->actconfig == NULL) {
+ HDF_LOGE("%s infoData.usbDev->actconfig is NULL", __func__);
+ ret = HDF_ERR_INVALID_PARAM;
+ goto OUT;
+ }
+ deviceInfo->info.numInfos = infoData.usbDev->actconfig->desc.bNumInterfaces;
+ for (i = 0; i < deviceInfo->info.numInfos; i++) {
+ if ((infoData.usbDev->actconfig->interface[i] == NULL) ||
+ (infoData.usbDev->actconfig->interface[i]->cur_altsetting == NULL)) {
+ HDF_LOGE("%{public}s interface[%{public}hhu] or interface[%{public}hhu]->cur_altsetting is NULL",
+ __func__, i, i);
+ ret = HDF_ERR_INVALID_PARAM;
+ goto OUT;
+ }
+ deviceInfo->info.interfaceInfo[i].interfaceClass =
+ infoData.usbDev->actconfig->interface[i]->cur_altsetting->desc.bInterfaceClass;
+ deviceInfo->info.interfaceInfo[i].interfaceSubClass =
+ infoData.usbDev->actconfig->interface[i]->cur_altsetting->desc.bInterfaceSubClass;
+ deviceInfo->info.interfaceInfo[i].interfaceProtocol =
+ infoData.usbDev->actconfig->interface[i]->cur_altsetting->desc.bInterfaceProtocol;
+ deviceInfo->info.interfaceInfo[i].interfaceNumber =
+ infoData.usbDev->actconfig->interface[i]->cur_altsetting->desc.bInterfaceNumber;
+
+ HDF_LOGI("%s:%d i=%d, interfaceInfo=0x%x-0x%x-0x%x-0x%x",
+ __func__, __LINE__, i, deviceInfo->info.interfaceInfo[i].interfaceClass,
+ deviceInfo->info.interfaceInfo[i].interfaceSubClass,
+ deviceInfo->info.interfaceInfo[i].interfaceProtocol,
+ deviceInfo->info.interfaceInfo[i].interfaceNumber);
+ }
+
+OUT:
+ return ret;
+}
+
+static void UsbPnpNotifyAddInterfaceInitInfo(struct UsbPnpDeviceInfo *deviceInfo,
+ union UsbPnpDeviceInfoData infoData, struct UsbPnpNotifyMatchInfoTable *infoTable)
+{
+ uint8_t i;
+ uint8_t j;
+
+ for (i = 0; i < deviceInfo->info.numInfos; i++) {
+ if ((infoData.infoData->interfaceClass == deviceInfo->info.interfaceInfo[i].interfaceClass)
+ && (infoData.infoData->interfaceSubClass == deviceInfo->info.interfaceInfo[i].interfaceSubClass)
+ && (infoData.infoData->interfaceProtocol == deviceInfo->info.interfaceInfo[i].interfaceProtocol)
+ && (infoData.infoData->interfaceNumber == deviceInfo->info.interfaceInfo[i].interfaceNumber)) {
+ if (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_INTERFACE) {
+ deviceInfo->interfaceRemoveStatus[i] = true;
+ } else if (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_ADD_INTERFACE) {
+ deviceInfo->interfaceRemoveStatus[i] = false;
+ }
+ }
+ }
+
+ if (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_INTERFACE) {
+ infoTable->numInfos = 1;
+ infoTable->interfaceInfo[0].interfaceClass = infoData.infoData->interfaceClass;
+ infoTable->interfaceInfo[0].interfaceSubClass = infoData.infoData->interfaceSubClass;
+ infoTable->interfaceInfo[0].interfaceProtocol = infoData.infoData->interfaceProtocol;
+ infoTable->interfaceInfo[0].interfaceNumber = infoData.infoData->interfaceNumber;
+ } else {
+ for (i = 0, j = 0; i < deviceInfo->info.numInfos; i++) {
+ if (deviceInfo->interfaceRemoveStatus[i] == true) {
+ HDF_LOGI("%s:%d j=%hhu deviceInfo->interfaceRemoveStatus[%hhu] is true!", __func__, __LINE__, j, i);
+ continue;
+ }
+ infoTable->interfaceInfo[j].interfaceClass = deviceInfo->info.interfaceInfo[i].interfaceClass;
+ infoTable->interfaceInfo[j].interfaceSubClass = deviceInfo->info.interfaceInfo[i].interfaceSubClass;
+ infoTable->interfaceInfo[j].interfaceProtocol = deviceInfo->info.interfaceInfo[i].interfaceProtocol;
+ infoTable->interfaceInfo[j].interfaceNumber = deviceInfo->info.interfaceInfo[i].interfaceNumber;
+ j++;
+
+ HDF_LOGI("%s:%d i=%hhu, j=%hhu, interfaceInfo=0x%x-0x%x-0x%x-0x%x",
+ __func__, __LINE__, i, j - 1, infoTable->interfaceInfo[j - 1].interfaceClass,
+ infoTable->interfaceInfo[j - 1].interfaceSubClass,
+ infoTable->interfaceInfo[j - 1].interfaceProtocol,
+ infoTable->interfaceInfo[j - 1].interfaceNumber);
+ }
+ infoTable->numInfos = j;
+ }
+}
+
+static int32_t UsbPnpNotifyInitInfo(
+ struct HdfSBuf *sbuf, struct UsbPnpDeviceInfo *deviceInfo, union UsbPnpDeviceInfoData infoData)
+{
+ int32_t ret = HDF_SUCCESS;
+ const void *data = NULL;
+
+ if ((g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_ADD_INTERFACE) ||
+ (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_INTERFACE)) {
+ static struct UsbPnpNotifyMatchInfoTable infoTable;
+
+ infoTable.usbDevAddr = deviceInfo->info.usbDevAddr;
+ infoTable.devNum = deviceInfo->info.devNum;
+ infoTable.busNum = deviceInfo->info.busNum;
+ infoTable.deviceInfo.vendorId = deviceInfo->info.deviceInfo.vendorId;
+ infoTable.deviceInfo.productId = deviceInfo->info.deviceInfo.productId;
+ infoTable.deviceInfo.bcdDeviceLow = deviceInfo->info.deviceInfo.bcdDeviceLow;
+ infoTable.deviceInfo.bcdDeviceHigh = deviceInfo->info.deviceInfo.bcdDeviceHigh;
+ infoTable.deviceInfo.deviceClass = deviceInfo->info.deviceInfo.deviceClass;
+ infoTable.deviceInfo.deviceSubClass = deviceInfo->info.deviceInfo.deviceSubClass;
+ infoTable.deviceInfo.deviceProtocol = deviceInfo->info.deviceInfo.deviceProtocol;
+ infoTable.removeType = g_usbPnpNotifyRemoveType;
+
+ UsbPnpNotifyAddInterfaceInitInfo(deviceInfo, infoData, &infoTable);
+
+ data = (const void *)(&infoTable);
+ } else if (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REPORT_INTERFACE) {
+ ret = UsbPnpNotifyAddInitInfo(deviceInfo, infoData);
+ if (ret != HDF_SUCCESS) {
+ goto OUT;
+ }
+
+ data = (const void *)(&deviceInfo->info);
+ } else {
+ data = (const void *)(&deviceInfo->info);
+ }
+
+ if (!HdfSbufWriteBuffer(sbuf, data, sizeof(struct UsbPnpNotifyMatchInfoTable))) {
+ HDF_LOGE("%s:%d sbuf write data failed", __func__, __LINE__);
+ ret = HDF_FAILURE;
+ goto OUT;
+ }
+
+OUT:
+ return ret;
+}
+
+static int32_t UsbPnpNotifyGetDeviceInfo(void *eventData, union UsbPnpDeviceInfoData *pnpInfoData,
+ struct UsbPnpDeviceInfo **deviceInfo)
+{
+ struct UsbInfoQueryPara infoQueryPara;
+
+ if ((g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_ADD_INTERFACE)
+ || (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_INTERFACE)) {
+ pnpInfoData->infoData = (struct UsbPnpAddRemoveInfo *)eventData;
+ } else {
+ pnpInfoData->usbDev = (struct usb_device *)eventData;
+ }
+
+ if ((g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_ADD_INTERFACE)
+ || (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_INTERFACE)) {
+ infoQueryPara.type = USB_INFO_NORMAL_TYPE;
+ infoQueryPara.devNum = pnpInfoData->infoData->devNum;
+ infoQueryPara.busNum = pnpInfoData->infoData->busNum;
+ *deviceInfo = UsbPnpNotifyFindInfo(infoQueryPara);
+ } else if ((g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_ADD_DEVICE)
+ || (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_DEVICE)) {
+ infoQueryPara.type = USB_INFO_DEVICE_ADDRESS_TYPE;
+ infoQueryPara.usbDevAddr = (uint64_t)pnpInfoData->usbDev;
+ *deviceInfo = UsbPnpNotifyFindInfo(infoQueryPara);
+ } else {
+ *deviceInfo = UsbPnpNotifyCreateInfo();
+ }
+
+ if (*deviceInfo == NULL) {
+ HDF_LOGE("%s:%d create or find info failed", __func__, __LINE__);
+ return HDF_FAILURE;
+ }
+
+ (*deviceInfo)->info.removeType = g_usbPnpNotifyRemoveType;
+
+ return HDF_SUCCESS;
+}
+
+static int32_t UsbPnpNotifyHdfSendEvent(const struct HdfDeviceObject *deviceObject,
+ void *eventData)
+{
+ int32_t ret;
+ struct UsbPnpDeviceInfo *deviceInfo = NULL;
+ struct HdfSBuf *data = NULL;
+ union UsbPnpDeviceInfoData pnpInfoData;
+
+ if ((deviceObject == NULL) || (eventData == NULL)) {
+ HDF_LOGE("%s deviceObject=%p or eventData=%p is NULL", __func__, deviceObject, eventData);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ data = HdfSbufObtainDefaultSize();
+ if (data == NULL) {
+ HDF_LOGE("%s:%d InitDataBlock failed", __func__, __LINE__);
+ return HDF_FAILURE;
+ }
+
+ ret = UsbPnpNotifyGetDeviceInfo(eventData, &pnpInfoData, &deviceInfo);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s:%d UsbPnpNotifyGetDeviceInfo failed, ret=%d", __func__, __LINE__, ret);
+ goto ERROR_DEVICE_INFO;
+ }
+
+ ret = UsbPnpNotifyInitInfo(data, deviceInfo, pnpInfoData);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s:%d UsbPnpNotifyInitInfo failed, ret=%d", __func__, __LINE__, ret);
+ goto OUT;
+ }
+
+ HDF_LOGI("%s:%d report one device information, %d usbDevAddr=%llu, devNum=%d, busNum=%d, infoTable=%d-0x%x-0x%x!",
+ __func__, __LINE__, g_usbPnpNotifyCmdType, deviceInfo->info.usbDevAddr, deviceInfo->info.devNum,
+ deviceInfo->info.busNum, deviceInfo->info.numInfos, deviceInfo->info.deviceInfo.vendorId,
+ deviceInfo->info.deviceInfo.productId);
+
+ OsalMutexLock(&deviceInfo->lock);
+ if (deviceInfo->status == USB_PNP_DEVICE_INIT_STATUS) {
+ ret = HdfDeviceSendEvent(deviceObject, g_usbPnpNotifyCmdType, data);
+ if (ret != HDF_SUCCESS) {
+ OsalMutexUnlock(&deviceInfo->lock);
+ HDF_LOGE("%s:%d HdfDeviceSendEvent ret=%d", __func__, __LINE__, ret);
+ goto OUT;
+ }
+ deviceInfo->status = USB_PNP_DEVICE_ADD_STATUS;
+ } else {
+ ret = HDF_ERR_INVALID_OBJECT;
+ }
+ OsalMutexUnlock(&deviceInfo->lock);
+
+OUT:
+ if ((ret != HDF_SUCCESS) || (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_DEVICE)) {
+ if (UsbPnpNotifyDestroyInfo(deviceInfo) != HDF_SUCCESS) {
+ HDF_LOGE("%s:%d UsbPnpNotifyDestroyInfo fail", __func__, __LINE__);
+ }
+ }
+ERROR_DEVICE_INFO:
+ HdfSbufRecycle(data);
+ return ret;
+}
+
+#if USB_PNP_NOTIFY_TEST_MODE == true
+static void TestReadPnpInfo(struct HdfSBuf *data)
+{
+ uint32_t infoSize;
+ bool flag;
+
+ flag = HdfSbufReadBuffer(data, (const void **)(&g_testUsbPnpInfo), &infoSize);
+ if ((!flag) || (g_testUsbPnpInfo == NULL)) {
+ HDF_LOGE("%s: fail to read g_testUsbPnpInfo, flag=%d", __func__, flag);
+ return;
+ }
+
+ HDF_LOGI("%s:%d infoSize=%d read success!", __func__, __LINE__, infoSize);
+}
+
+static void TestPnpNotifyFillInfoTable(struct UsbPnpNotifyMatchInfoTable *infoTable)
+{
+ int8_t i;
+
+ infoTable->usbDevAddr = g_testUsbPnpInfo->usbDevAddr;
+ infoTable->devNum = g_testUsbPnpInfo->devNum;
+ if (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_TEST) {
+ infoTable->busNum = -1;
+ } else {
+ infoTable->busNum = g_testUsbPnpInfo->busNum;
+ }
+
+ infoTable->deviceInfo.vendorId = g_testUsbPnpInfo->deviceInfo.vendorId;
+ infoTable->deviceInfo.productId = g_testUsbPnpInfo->deviceInfo.productId;
+ infoTable->deviceInfo.bcdDeviceLow = g_testUsbPnpInfo->deviceInfo.bcdDeviceLow;
+ infoTable->deviceInfo.bcdDeviceHigh = g_testUsbPnpInfo->deviceInfo.bcdDeviceHigh;
+ infoTable->deviceInfo.deviceClass = g_testUsbPnpInfo->deviceInfo.deviceClass;
+ infoTable->deviceInfo.deviceSubClass = g_testUsbPnpInfo->deviceInfo.deviceSubClass;
+ infoTable->deviceInfo.deviceProtocol = g_testUsbPnpInfo->deviceInfo.deviceProtocol;
+
+ infoTable->removeType = g_usbPnpNotifyRemoveType;
+
+ if (g_usbPnpNotifyCmdType != USB_PNP_NOTIFY_REMOVE_TEST) {
+ infoTable->numInfos = g_testUsbPnpInfo->numInfos;
+ for (i = 0; i < infoTable->numInfos; i++) {
+ infoTable->interfaceInfo[i].interfaceClass = g_testUsbPnpInfo->interfaceInfo[i].interfaceClass;
+ infoTable->interfaceInfo[i].interfaceSubClass = g_testUsbPnpInfo->interfaceInfo[i].interfaceSubClass;
+ infoTable->interfaceInfo[i].interfaceProtocol = g_testUsbPnpInfo->interfaceInfo[i].interfaceProtocol;
+ infoTable->interfaceInfo[i].interfaceNumber = g_testUsbPnpInfo->interfaceInfo[i].interfaceNumber;
+ }
+ }
+}
+
+static int32_t TestPnpNotifyHdfSendEvent(const struct HdfDeviceObject *deviceObject)
+{
+ struct UsbPnpNotifyMatchInfoTable infoTable;
+ struct HdfSBuf *data = NULL;
+
+ if ((deviceObject == NULL) || (g_testUsbPnpInfo == NULL)) {
+ HDF_LOGE("%s deviceObject=%px or g_testUsbPnpInfo=%px is NULL", __func__, deviceObject, g_testUsbPnpInfo);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ data = HdfSbufObtainDefaultSize();
+ if (data == NULL) {
+ HDF_LOGE("%s InitDataBlock failed", __func__);
+ return HDF_FAILURE;
+ }
+
+ TestPnpNotifyFillInfoTable(&infoTable);
+
+ if (!HdfSbufWriteBuffer(data, (const void *)(&infoTable), sizeof(struct UsbPnpNotifyMatchInfoTable))) {
+ HDF_LOGE("%s: sbuf write infoTable failed", __func__);
+ goto OUT;
+ }
+
+ HDF_LOGI("%s: report one device information, %d usbDev=%llu, devNum=%d, busNum=%d, infoTable=%d-0x%x-0x%x!", \
+ __func__, g_usbPnpNotifyCmdType, infoTable.usbDevAddr, infoTable.devNum, infoTable.busNum, \
+ infoTable.numInfos, infoTable.deviceInfo.vendorId, infoTable.deviceInfo.productId);
+
+ int32_t ret = HdfDeviceSendEvent(deviceObject, g_usbPnpNotifyCmdType, data);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: HdfDeviceSendEvent error=%d", __func__, ret);
+ goto OUT;
+ }
+
+ HdfSbufRecycle(data);
+ return ret;
+
+OUT:
+ HdfSbufRecycle(data);
+ return HDF_FAILURE;
+}
+#endif
+
+static int32_t GadgetPnpNotifyHdfSendEvent(const struct HdfDeviceObject *deviceObject)
+{
+ if (deviceObject == NULL) {
+ HDF_LOGE("%s deviceObject is null", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ struct HdfSBuf *data = NULL;
+ data = HdfSbufObtainDefaultSize();
+ if (data == NULL) {
+ HDF_LOGE("%s:%d InitDataBlock failed", __func__, __LINE__);
+ return HDF_FAILURE;
+ }
+ if (!HdfSbufWriteUint8(data, g_gadgetPnpNotifyType)) {
+ HDF_LOGE("%s, UsbEcmRead HdfSbufWriteInt8 error", __func__);
+ HdfSbufRecycle(data);
+ return HDF_FAILURE;
+ }
+ int32_t ret = HdfDeviceSendEvent(deviceObject, g_gadgetPnpNotifyType, data);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s:%d HdfDeviceSendEvent ret = %d", __func__, __LINE__, ret);
+ }
+
+ HdfSbufRecycle(data);
+ return ret;
+}
+
+static int32_t UsbPnpNotifyFirstReport(struct usb_device *usbDev, void *data)
+{
+ int32_t ret;
+ if (data == NULL) {
+ HDF_LOGE("%{pubilc}s:%{pubilc}d data is NULL", __func__, __LINE__);
+ return HDF_FAILURE;
+ }
+
+ struct HdfDeviceIoClient *client = (struct HdfDeviceIoClient *)data;
+
+ ret = UsbPnpNotifyHdfSendEvent(client->device, usbDev);
+
+ HDF_LOGI("%s: report all device information!", __func__);
+
+ return ret;
+}
+
+static int32_t UsbPnpNotifyReportThread(void* arg)
+{
+ int32_t ret;
+ struct HdfDeviceObject *deviceObject = (struct HdfDeviceObject *)arg;
+
+ while (!kthread_should_stop()) {
+#if USB_PNP_NOTIFY_TEST_MODE == false
+ ret = wait_event_interruptible(g_usbPnpNotifyReportWait, g_usbDevice != NULL);
+#else
+ ret = wait_event_interruptible(g_usbPnpNotifyReportWait,
+ ((g_usbDevice != NULL) || (g_testUsbPnpInfo != NULL)));
+#endif
+ if (!ret) {
+ HDF_LOGI("%s: UsbPnpNotifyReportThread start!", __func__);
+ }
+
+ OsalMutexLock(&g_usbSendEventLock);
+#if USB_PNP_NOTIFY_TEST_MODE == true
+ if ((g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_ADD_TEST) || \
+ (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_TEST)) {
+ ret = TestPnpNotifyHdfSendEvent(deviceObject);
+ } else {
+#endif
+ if ((g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_ADD_INTERFACE)
+ || (g_usbPnpNotifyCmdType == USB_PNP_NOTIFY_REMOVE_INTERFACE)) {
+ ret = UsbPnpNotifyHdfSendEvent(deviceObject, &g_usbPnpInfo);
+ } else {
+ ret = UsbPnpNotifyHdfSendEvent(deviceObject, g_usbDevice);
+ }
+#if USB_PNP_NOTIFY_TEST_MODE == true
+ }
+#endif
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGI("%s: UsbPnpNotifyHdfSendEvent error=%d!", __func__, ret);
+ }
+
+ g_usbDevice = NULL;
+#if USB_PNP_NOTIFY_TEST_MODE == true
+ g_testUsbPnpInfo = NULL;
+#endif
+ OsalMutexUnlock(&g_usbSendEventLock);
+
+ msleep(USB_PNP_NOTIFY_MSLEEP_TIME);
+ }
+
+ HDF_LOGI("%s: usb pnp notify handle kthread exiting!", __func__);
+
+ return 0;
+}
+
+static int32_t GadgetPnpNotifyReportThread(void* arg)
+{
+ int32_t ret;
+ struct HdfDeviceObject *deviceObject = (struct HdfDeviceObject *)arg;
+
+ while (!kthread_should_stop()) {
+ ret = wait_event_interruptible(g_gadgetPnpNotifyReportWait,
+ (g_gadgetPnpNotifyType != 0));
+ if (!ret) {
+ HDF_LOGI("%s: GadgetPnpNotifyReportThread start!", __func__);
+ }
+ OsalMutexLock(&g_gadgetSendEventLock);
+ ret = GadgetPnpNotifyHdfSendEvent(deviceObject);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGI("%s: UsbPnpNotifyHdfSendEvent error=%d!", __func__, ret);
+ }
+ g_gadgetPnpNotifyType = 0;
+ OsalMutexUnlock(&g_gadgetSendEventLock);
+ msleep(USB_PNP_NOTIFY_MSLEEP_TIME);
+ }
+
+ HDF_LOGI("%s: gadget pnp notify handle kthread exiting!", __func__);
+
+ return 0;
+}
+
+static int32_t UsbPnpNotifyCallback(struct notifier_block *self, unsigned long action, void *dev)
+{
+ int32_t ret;
+ struct UsbInfoQueryPara infoQueryPara;
+ struct UsbPnpDeviceInfo *deviceInfo = NULL;
+ union UsbPnpDeviceInfoData pnpInfoData;
+
+ HDF_LOGI("%s: action=0x%lx", __func__, action);
+
+ switch (action) {
+ case USB_DEVICE_ADD:
+ pnpInfoData.usbDev = dev;
+ deviceInfo = UsbPnpNotifyCreateInfo();
+ if (deviceInfo == NULL) {
+ HDF_LOGE("%s:%d USB_DEVICE_ADD create info failed", __func__, __LINE__);
+ } else {
+ ret = UsbPnpNotifyAddInitInfo(deviceInfo, pnpInfoData);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s:%d USB_DEVICE_ADD UsbPnpNotifyAddInitInfo error", __func__, __LINE__);
+ } else {
+ OsalMutexLock(&g_usbSendEventLock);
+ g_usbDevice = dev;
+ g_usbPnpNotifyCmdType = USB_PNP_NOTIFY_ADD_DEVICE;
+ OsalMutexUnlock(&g_usbSendEventLock);
+ wake_up_interruptible(&g_usbPnpNotifyReportWait);
+ }
+ }
+ break;
+ case USB_DEVICE_REMOVE:
+ infoQueryPara.type = USB_INFO_DEVICE_ADDRESS_TYPE;
+ infoQueryPara.usbDevAddr = (uint64_t)dev;
+ deviceInfo = UsbPnpNotifyFindInfo(infoQueryPara);
+ if (deviceInfo == NULL) {
+ HDF_LOGE("%s:%d USB_DEVICE_REMOVE find info failed", __func__, __LINE__);
+ } else {
+ OsalMutexLock(&deviceInfo->lock);
+ if (deviceInfo->status != USB_PNP_DEVICE_INIT_STATUS) {
+ deviceInfo->status = USB_PNP_DEVICE_INIT_STATUS;
+ } else {
+ deviceInfo->status = USB_PNP_DEVICE_REMOVE_STATUS;
+ }
+ OsalMutexUnlock(&deviceInfo->lock);
+ OsalMutexLock(&g_usbSendEventLock);
+ g_usbDevice = dev;
+ g_usbPnpNotifyCmdType = USB_PNP_NOTIFY_REMOVE_DEVICE;
+ g_usbPnpNotifyRemoveType = USB_PNP_NOTIFY_REMOVE_BUS_DEV_NUM;
+ OsalMutexUnlock(&g_usbSendEventLock);
+ wake_up_interruptible(&g_usbPnpNotifyReportWait);
+ }
+ break;
+ case USB_GADGET_ADD:
+ case USB_GADGET_REMOVE:
+ OsalMutexLock(&g_gadgetSendEventLock);
+ if (g_preAcion == action) {
+ OsalMutexUnlock(&g_gadgetSendEventLock);
+ break;
+ }
+ if (action == USB_GADGET_ADD) {
+ g_gadgetPnpNotifyType = USB_PNP_DRIVER_GADGET_ADD;
+ } else {
+ g_gadgetPnpNotifyType = USB_PNP_DRIVER_GADGET_REMOVE;
+ }
+ OsalMutexUnlock(&g_gadgetSendEventLock);
+ HDF_LOGI("%s:%d g_gadgetPnpNotifyType = %hhu", __func__, __LINE__, g_gadgetPnpNotifyType);
+ wake_up_interruptible(&g_gadgetPnpNotifyReportWait);
+ g_preAcion = action;
+ break;
+ default:
+ HDF_LOGI("%s: the action = 0x%lx is not defined!", __func__, action);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block g_usbPnpNotifyNb = {
+ .notifier_call = UsbPnpNotifyCallback,
+};
+
+static void UsbPnpNotifyReadPnpInfo(struct HdfSBuf *data)
+{
+ struct UsbInfoQueryPara infoQueryPara;
+ struct UsbPnpDeviceInfo *deviceInfo = NULL;
+ struct UsbPnpAddRemoveInfo *usbPnpInfo = NULL;
+ uint32_t infoSize;
+ bool flag;
+
+ flag = HdfSbufReadBuffer(data, (const void **)(&usbPnpInfo), &infoSize);
+ if ((!flag) || (usbPnpInfo == NULL)) {
+ HDF_LOGE("%s: fail to read g_usbPnpInfo, flag=%d", __func__, flag);
+ return;
+ }
+
+ g_usbPnpInfo.devNum = usbPnpInfo->devNum;
+ g_usbPnpInfo.busNum = usbPnpInfo->busNum;
+ g_usbPnpInfo.interfaceNumber = usbPnpInfo->interfaceNumber;
+ g_usbPnpInfo.interfaceClass = usbPnpInfo->interfaceClass;
+ g_usbPnpInfo.interfaceSubClass = usbPnpInfo->interfaceSubClass;
+ g_usbPnpInfo.interfaceProtocol = usbPnpInfo->interfaceProtocol;
+
+ g_usbDevice = (struct usb_device *)&g_usbPnpInfo;
+
+ infoQueryPara.type = USB_INFO_NORMAL_TYPE;
+ infoQueryPara.devNum = usbPnpInfo->devNum;
+ infoQueryPara.busNum = usbPnpInfo->busNum;
+ deviceInfo = UsbPnpNotifyFindInfo(infoQueryPara);
+ if (deviceInfo == NULL) {
+ HDF_LOGE("%s:%d add or remove interface find info failed", __func__, __LINE__);
+ } else {
+ OsalMutexLock(&deviceInfo->lock);
+ if (deviceInfo->status != USB_PNP_DEVICE_INIT_STATUS) {
+ deviceInfo->status = USB_PNP_DEVICE_INIT_STATUS;
+ } else {
+ deviceInfo->status = USB_PNP_DEVICE_INTERFACE_STATUS;
+ }
+ OsalMutexUnlock(&deviceInfo->lock);
+ }
+
+ HDF_LOGI("%s:%d infoSize=%d g_usbPnpInfo=%px-%d-%d-%d-%d-%d-%d read success!",
+ __func__, __LINE__, infoSize, &g_usbPnpInfo, g_usbPnpInfo.devNum, g_usbPnpInfo.busNum,
+ g_usbPnpInfo.interfaceNumber, g_usbPnpInfo.interfaceClass, g_usbPnpInfo.interfaceSubClass,
+ g_usbPnpInfo.interfaceProtocol);
+}
+
+static int32_t UsbPnpGetDevices(struct HdfSBuf *reply)
+{
+ int32_t ret = HDF_SUCCESS;
+ struct UsbPnpDeviceInfo *infoPos = NULL;
+ struct UsbPnpDeviceInfo *infoTemp = NULL;
+
+ if (DListIsEmpty(&g_usbPnpInfoListHead)) {
+ return ret;
+ }
+ DLIST_FOR_EACH_ENTRY_SAFE(infoPos, infoTemp, &g_usbPnpInfoListHead, struct UsbPnpDeviceInfo, list){
+ if (!HdfSbufWriteInt32(reply, infoPos->info.busNum)) {
+ break;
+ }
+ if (!HdfSbufWriteInt32(reply, infoPos->info.devNum)) {
+ break;
+ }
+ if (!HdfSbufWriteUint8(reply, infoPos->info.deviceInfo.deviceClass)) {
+ break;
+ }
+ if (!HdfSbufWriteUint8(reply, infoPos->info.deviceInfo.deviceSubClass)) {
+ break;
+ }
+ if (!HdfSbufWriteUint8(reply, infoPos->info.deviceInfo.deviceProtocol)) {
+ break;
+ }
+ if (!HdfSbufWriteUint8(reply, infoPos->status)) {
+ break;
+ }
+ }
+ return ret;
+}
+
+static int32_t UsbPnpNotifyDispatch(struct HdfDeviceIoClient *client, int32_t cmd,
+ struct HdfSBuf *data, struct HdfSBuf *reply)
+{
+ int32_t ret = HDF_SUCCESS;
+
+ HDF_LOGI("%s: received cmd = %d", __func__, cmd);
+
+ OsalMutexLock(&g_usbSendEventLock);
+ if (USB_PNP_DRIVER_GETDEVICES != cmd) {
+ g_usbPnpNotifyCmdType = cmd;
+ }
+
+ switch (cmd) {
+ case USB_PNP_NOTIFY_ADD_INTERFACE:
+ UsbPnpNotifyReadPnpInfo(data);
+ wake_up_interruptible(&g_usbPnpNotifyReportWait);
+ break;
+ case USB_PNP_NOTIFY_REMOVE_INTERFACE:
+ UsbPnpNotifyReadPnpInfo(data);
+ g_usbPnpNotifyRemoveType = USB_PNP_NOTIFY_REMOVE_INTERFACE_NUM;
+ wake_up_interruptible(&g_usbPnpNotifyReportWait);
+ break;
+ case USB_PNP_NOTIFY_REPORT_INTERFACE:
+ usb_for_each_dev((void *)client, UsbPnpNotifyFirstReport);
+ break;
+#if USB_PNP_NOTIFY_TEST_MODE == true
+ case USB_PNP_NOTIFY_ADD_TEST:
+ TestReadPnpInfo(data);
+ wake_up_interruptible(&g_usbPnpNotifyReportWait);
+ break;
+ case USB_PNP_NOTIFY_REMOVE_TEST:
+ TestReadPnpInfo(data);
+ g_usbPnpNotifyRemoveType = g_testUsbPnpInfo->removeType;
+ wake_up_interruptible(&g_usbPnpNotifyReportWait);
+ break;
+#endif
+ case USB_PNP_DRIVER_GETDEVICES:
+ UsbPnpGetDevices(reply);
+ break;
+ default:
+ ret = HDF_ERR_NOT_SUPPORT;
+ break;
+ }
+ OsalMutexUnlock(&g_usbSendEventLock);
+
+ if (!HdfSbufWriteInt32(reply, INT32_MAX)) {
+ HDF_LOGE("%s: reply int32 fail", __func__);
+ }
+
+ return ret;
+}
+
+static int32_t UsbPnpNotifyBind(struct HdfDeviceObject *device)
+{
+ static struct IDeviceIoService pnpNotifyService = {
+ .Dispatch = UsbPnpNotifyDispatch,
+ };
+
+ HDF_LOGI("%s: Enter!", __func__);
+
+ if (device == NULL) {
+ HDF_LOGE("%s: device is NULL!", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ device->service = &pnpNotifyService;
+
+ return HDF_SUCCESS;
+}
+
+static int32_t UsbPnpNotifyInit(struct HdfDeviceObject *device)
+{
+ static bool firstInitFlag = true;
+
+ HDF_LOGI("%s: Enter!", __func__);
+
+ if (device == NULL) {
+ HDF_LOGE("%s: device is NULL", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ if (firstInitFlag) {
+ firstInitFlag = false;
+ DListHeadInit(&g_usbPnpInfoListHead);
+ }
+
+ init_waitqueue_head(&g_usbPnpNotifyReportWait);
+ init_waitqueue_head(&g_gadgetPnpNotifyReportWait);
+
+ OsalMutexInit(&g_usbSendEventLock);
+ OsalMutexInit(&g_gadgetSendEventLock);
+
+ /* Add a new notify for usb pnp notify module. */
+ usb_register_notify(&g_usbPnpNotifyNb);
+
+ /* Create thread to handle send usb interface information. */
+ if (NULL == g_usbPnpNotifyReportThread) {
+ g_usbPnpNotifyReportThread = kthread_run(UsbPnpNotifyReportThread,
+ (void *)device, "usb pnp notify handle kthread");
+ if (g_usbPnpNotifyReportThread == NULL) {
+ HDF_LOGE("%s: kthread_run g_usbPnpNotifyReportThread is NULL", __func__);
+ }
+ } else {
+ HDF_LOGI("%s: g_usbPnpNotifyReportThread is already running!", __func__);
+ }
+
+ /* Create thread to handle gadeget information. */
+ if (NULL == g_gadgetPnpNotifyReportThread) {
+ g_gadgetPnpNotifyReportThread = kthread_run(GadgetPnpNotifyReportThread,
+ (void *)device, "gadget pnp notify handle kthread");
+ if (g_usbPnpNotifyReportThread == NULL) {
+ HDF_LOGE("%s: kthread_run g_usbPnpNotifyReportThread is NULL", __func__);
+ }
+ } else {
+ HDF_LOGI("%s: g_devPnpNotifyReportThread is already running!", __func__);
+ }
+
+ return HDF_SUCCESS;
+}
+
+static void UsbPnpNotifyRelease(struct HdfDeviceObject *device)
+{
+ if (device == NULL) {
+ HDF_LOGI("%s: device is null", __func__);
+ return;
+ }
+
+ if (g_usbPnpNotifyReportThread == NULL) {
+ HDF_LOGI("%s: g_usbPnpNotifyReportThread is not running!", __func__);
+ } else {
+ kthread_stop(g_usbPnpNotifyReportThread);
+ }
+ if (g_gadgetPnpNotifyReportThread == NULL) {
+ HDF_LOGI("%s: g_usbPnpNotifyReportThread is not running!", __func__);
+ } else {
+ kthread_stop(g_gadgetPnpNotifyReportThread);
+ }
+
+ usb_unregister_notify(&g_usbPnpNotifyNb);
+
+ OsalMutexDestroy(&g_usbSendEventLock);
+ OsalMutexDestroy(&g_gadgetSendEventLock);
+
+ HDF_LOGI("%s: release done!", __func__);
+
+ return;
+}
+
+struct HdfDriverEntry g_usbPnpNotifyEntry = {
+ .moduleVersion = 1,
+ .Bind = UsbPnpNotifyBind,
+ .Init = UsbPnpNotifyInit,
+ .Release = UsbPnpNotifyRelease,
+ .moduleName = "HDF_USB_PNP_NOTIFY",
+};
+
+HDF_INIT(g_usbPnpNotifyEntry);
diff --git a/adapter/khdf/linux/network/Makefile b/adapter/khdf/linux/network/Makefile
new file mode 100644
index 00000000..e6891c59
--- /dev/null
+++ b/adapter/khdf/linux/network/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+obj-$(CONFIG_DRIVERS_HDF_WIFI) += src/
\ No newline at end of file
diff --git a/adapter/khdf/linux/network/include/net_device_adapter.h b/adapter/khdf/linux/network/include/net_device_adapter.h
new file mode 100644
index 00000000..f124752d
--- /dev/null
+++ b/adapter/khdf/linux/network/include/net_device_adapter.h
@@ -0,0 +1,41 @@
+/*
+ * net_device_adapter.h
+ *
+ * net device adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HDF_NET_DEVICE_ADAPTER_FULL_H
+#define HDF_NET_DEVICE_ADAPTER_FULL_H
+
+#include
+#include
+
+#include "net_device_impl.h"
+
+/**
+ * data sending results, just define locked here, ok and busy reference linux definition for enum netdev_tx.
+ */
+#define NETDEV_TX_LOCKED 0x20
+
+int32_t RegisterNetDeviceImpl(struct NetDeviceImpl *ndImpl);
+int32_t UnRegisterNetDeviceImpl(struct NetDeviceImpl *ndImpl);
+
+struct FullNetDevicePriv {
+ struct net_device *dev;
+ struct NetDeviceImpl *impl;
+};
+
+#endif /* HDF_NET_DEVICE_ADAPTER_FULL_H */
+
diff --git a/adapter/khdf/linux/network/include/net_device_types_adapter.h b/adapter/khdf/linux/network/include/net_device_types_adapter.h
new file mode 100644
index 00000000..bbb0a34d
--- /dev/null
+++ b/adapter/khdf/linux/network/include/net_device_types_adapter.h
@@ -0,0 +1,32 @@
+/*
+ * net_device_types_adapter.h
+ *
+ * net device types adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HDF_NET_DEVICE_TYPTES_ADAPTER_FULL_H
+#define HDF_NET_DEVICE_TYPTES_ADAPTER_FULL_H
+
+#include
+#include
+
+typedef int32_t NetDevTxResult;
+
+/**
+ * data sending results, just define locked here, ok and busy reference linux definition for enum netdev_tx.
+ */
+#define NETDEV_TX_LOCKED 0x20
+
+#endif /* HDF_NET_DEVICE_TYPTES_ADAPTER_FULL_H */
diff --git a/adapter/khdf/linux/network/include/netbuf_adapter.h b/adapter/khdf/linux/network/include/netbuf_adapter.h
new file mode 100644
index 00000000..a9f5df3f
--- /dev/null
+++ b/adapter/khdf/linux/network/include/netbuf_adapter.h
@@ -0,0 +1,69 @@
+/*
+ * netbuf_adapter.h
+ *
+ * net buffer adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/**
+ * @addtogroup WLAN
+ * @{
+ *
+ * @brief Provides cross-OS migration, component adaptation, and modular assembly and compilation.
+ *
+ * Based on the unified APIs provided by the WLAN module, developers of the Hardware Driver Interface
+ * (HDI) are capable of creating, disabling, scanning for, and connecting to WLAN hotspots, managing WLAN chips,
+ * network devices, and power, and applying for, releasing, and moving network data buffers.
+ *
+ * @since 1.0
+ * @version 1.0
+ */
+
+#ifndef _HDF_NETBUF_ADAPTER_H
+#define _HDF_NETBUF_ADAPTER_H
+
+#include
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* __cplusplus */
+
+/**
+ * @brief Enumerates the segments of a network data buffer.
+ *
+ * The entire network data buffer is divided into three segments: a header, data, and a tail.
+ * The header and tail are used to extend both ends of the data segment.
+ *
+ * @since 1.0
+ */
+enum {
+ E_HEAD_BUF, /**< Header buffer segment */
+ E_DATA_BUF, /**< Data segment */
+ E_TAIL_BUF, /**< Tail buffer segment */
+ MAX_BUF_NUM /**< Maximum number of buffer segments */
+};
+
+typedef struct sk_buff NetBuf;
+typedef struct sk_buff_head NetBufQueue;
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif
+/** @} */
diff --git a/adapter/khdf/linux/network/src/Makefile b/adapter/khdf/linux/network/src/Makefile
new file mode 100644
index 00000000..e8b18f85
--- /dev/null
+++ b/adapter/khdf/linux/network/src/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+obj-$(CONFIG_DRIVERS_HDF_WIFI) += net_device_adapter.o netbuf_adapter.o
+
+ccflags-$(CONFIG_DRIVERS_HDF_WIFI) += \
+ -I$(srctree)/drivers/hdf/framework/model/network/common/netdevice \
+ -I$(srctree)/drivers/hdf/framework/include/net\
+ -I$(srctree)/drivers/hdf/khdf/network/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/include/hdf/wifi \
+ -I$(srctree)/include/hdf/utils \
+ -I$(srctree)/include/hdf/osal \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/network/src/net_device_adapter.c b/adapter/khdf/linux/network/src/net_device_adapter.c
new file mode 100644
index 00000000..4b8ede6e
--- /dev/null
+++ b/adapter/khdf/linux/network/src/net_device_adapter.c
@@ -0,0 +1,341 @@
+/*
+ * net_device_adapter.c
+ *
+ * net device adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "net_device_adapter.h"
+#include
+#include
+#include
+#include "net_device.h"
+#include "net_device_impl.h"
+#include "osal_mem.h"
+#include "securec.h"
+
+#define HDF_LOG_TAG NetDeviceFull
+
+static int32_t NetDevXmitCheck(struct sk_buff *skb, struct net_device *dev)
+{
+ struct FullNetDevicePriv *priv = NULL;
+
+ if (dev == NULL || skb == NULL) {
+ HDF_LOGE("%s : dev = NUll or skb = NULL!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ priv = (struct FullNetDevicePriv *)netdev_priv(dev);
+ if (priv == NULL || priv->dev == NULL || priv->impl == NULL) {
+ HDF_LOGE("%s fail : priv NULL!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ return HDF_SUCCESS;
+}
+
+static netdev_tx_t NetDevXmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct FullNetDevicePriv *priv = NULL;
+ struct NetDevice *netDev = NULL;
+ struct NetDeviceInterFace *netDevIf = NULL;
+
+ if (NetDevXmitCheck(skb, dev) != HDF_SUCCESS) {
+ NetBufFree(skb);
+ return NETDEV_TX_OK;
+ }
+ priv = (struct FullNetDevicePriv *)netdev_priv(dev);
+ netDev = priv->impl->netDevice;
+
+ skb->dev = dev;
+ netDevIf = netDev->netDeviceIf;
+ if (netDevIf != NULL && netDevIf->xmit != NULL) {
+ netDevIf->xmit(netDev, skb);
+ } else {
+ HDF_LOGE("%s fail : netdevIf = null or xmit = null!", __func__);
+ NetBufFree(skb);
+ }
+ return NETDEV_TX_OK;
+}
+
+static int NetDevChangeMtu(struct net_device *dev, int mtu)
+{
+ if (mtu > WLAN_MAX_MTU || mtu < WLAN_MIN_MTU || dev == NULL) {
+ return -EINVAL;
+ }
+
+ dev->mtu = (uint32_t)mtu;
+ return HDF_SUCCESS;
+}
+
+static int NetDevOpen(struct net_device *dev)
+{
+ if (dev == NULL) {
+ return -EINVAL;
+ }
+
+ netif_start_queue(dev);
+ return HDF_SUCCESS;
+}
+
+static int NetDevStop(struct net_device *dev)
+{
+ if (dev == NULL) {
+ return -EINVAL;
+ }
+
+ netif_stop_queue(dev);
+ return HDF_SUCCESS;
+}
+
+static struct net_device_ops g_netDeviceOps = {
+ .ndo_start_xmit = NetDevXmit,
+ .ndo_change_mtu = NetDevChangeMtu,
+ .ndo_open = NetDevOpen,
+ .ndo_stop = NetDevStop
+};
+
+static struct net_device *CreateNetDevice(struct NetDevice *hdfDev)
+{
+ struct net_device *dev = NULL;
+
+ dev = alloc_etherdev(sizeof(struct FullNetDevicePriv));
+ if (dev == NULL) {
+ return NULL;
+ }
+
+ if (memcpy_s(dev->name, IFNAMSIZ, hdfDev->name, IFNAMSIZ) != EOK) {
+ free_netdev(dev);
+ return NULL;
+ }
+ dev->mtu = DEFAULT_MTU;
+ dev->netdev_ops = &g_netDeviceOps;
+
+ return dev;
+}
+
+static void DestroyNetDevice(struct net_device *dev)
+{
+ free_netdev(dev);
+}
+
+static struct net_device *GetDevFromDevImpl(const struct NetDeviceImpl *impl)
+{
+ struct FullNetDevicePriv *priv = NULL;
+
+ if (impl == NULL || impl->osPrivate == NULL) {
+ return NULL;
+ }
+ priv = (struct FullNetDevicePriv *)impl->osPrivate;
+ return priv->dev;
+}
+
+static int32_t NetDevInit(struct NetDeviceImpl *impl)
+{
+ struct FullNetDevicePriv *priv = NULL;
+ struct net_device *dev = NULL;
+
+ if (impl == NULL || impl->netDevice == NULL) {
+ HDF_LOGE("%s fail: impl null , netDevice null", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ dev = CreateNetDevice(impl->netDevice);
+ if (dev == NULL) {
+ HDF_LOGE("%s fail : CreateNetDevice fail!", __func__);
+ return HDF_FAILURE;
+ }
+
+ priv = (struct FullNetDevicePriv *)netdev_priv(dev);
+ priv->dev = dev;
+ priv->impl = impl;
+ impl->osPrivate = (void *)priv;
+ HDF_LOGI("%s Success!", __func__);
+
+ return HDF_SUCCESS;
+}
+
+static int32_t NetDevDeInit(struct NetDeviceImpl *impl)
+{
+ struct FullNetDevicePriv *priv = NULL;
+
+ if (impl == NULL) {
+ HDF_LOGE("netdevice linux deinit already free.");
+ return HDF_SUCCESS;
+ }
+ if (impl->osPrivate != NULL) {
+ priv = (struct FullNetDevicePriv *)impl->osPrivate;
+ DestroyNetDevice(priv->dev);
+ impl->osPrivate = NULL;
+ }
+ HDF_LOGI("net device linux deinit success!");
+
+ return HDF_SUCCESS;
+}
+
+static int32_t NetDevAdd(struct NetDeviceImpl *impl)
+{
+ struct net_device *dev = NULL;
+ int ret;
+
+ if ((dev = GetDevFromDevImpl(impl)) == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+ if (impl->netDevice == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (memcpy_s(dev->dev_addr, ETH_ALEN, impl->netDevice->macAddr,
+ MAC_ADDR_SIZE) != EOK) {
+ HDF_LOGE("%s : memcpy fail!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ dev->needed_headroom = impl->netDevice->neededHeadRoom;
+ dev->needed_tailroom = impl->netDevice->neededTailRoom;
+
+ if ((ret = register_netdev(dev)) < 0) {
+ HDF_LOGE("%s : register_netdev fail!,ret=%d", __func__, ret);
+ return HDF_FAILURE;
+ }
+
+ HDF_LOGI("%s success!!", __func__);
+ return HDF_SUCCESS;
+}
+
+static int32_t NetDevDelete(struct NetDeviceImpl *impl)
+{
+ struct FullNetDevicePriv *priv = NULL;
+ struct net_device *dev = NULL;
+
+ if (impl == NULL || impl->osPrivate == NULL) {
+ HDF_LOGE("%s fail : impl = null or osPrivate = null!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ priv = (struct FullNetDevicePriv *)impl->osPrivate;
+
+ dev = priv->dev;
+ if (dev != NULL) {
+ unregister_netdev(dev);
+ }
+ HDF_LOGI("%s success!", __func__);
+ return HDF_SUCCESS;
+}
+
+static int32_t NetDevSetStatus(struct NetDeviceImpl *impl,
+ NetIfStatus status)
+{
+ struct net_device *dev = GetDevFromDevImpl(impl);
+ int32_t ret;
+
+ if (dev == NULL) {
+ HDF_LOGE("%s fail : net dev null!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ rtnl_lock();
+ if (status == NETIF_DOWN) {
+ dev_close(dev);
+ ret = HDF_SUCCESS;
+ } else if (status == NETIF_UP) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
+ ret = dev_open(dev, NULL);
+#else
+ ret = dev_open(dev);
+#endif
+ } else {
+ HDF_LOGE("%s fail : status error!", __func__);
+ rtnl_unlock();
+ return HDF_ERR_INVALID_PARAM;
+ }
+ rtnl_unlock();
+
+ if (!ret) {
+ return HDF_SUCCESS;
+ }
+ HDF_LOGE("%s fail ret = %d!", __func__, ret);
+ return HDF_FAILURE;
+}
+
+static int32_t NetDevReceive(struct NetDeviceImpl *impl,
+ NetBuf *buff, ReceiveFlag flag)
+{
+ struct net_device *dev = GetDevFromDevImpl(impl);
+
+ if (dev == NULL) {
+ HDF_LOGE("%s fail : dev = null!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (flag >= MAX_RECEIVE_FLAG || buff == NULL) {
+ HDF_LOGE("%s fail : flag = %d or buff = null!", __func__, flag);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ buff->dev = dev;
+ buff->protocol = eth_type_trans(buff, dev);
+ if (flag & IN_INTERRUPT) {
+ netif_rx(buff);
+ } else {
+ netif_rx_ni(buff);
+ }
+ return HDF_SUCCESS;
+}
+
+int32_t NetDevChangeMacAddr(struct NetDeviceImpl *impl)
+{
+ struct net_device *dev = NULL;
+
+ if ((dev = GetDevFromDevImpl(impl)) == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+ if (impl->netDevice == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (memcpy_s(dev->dev_addr, ETH_ALEN, impl->netDevice->macAddr, MAC_ADDR_SIZE) != EOK) {
+ HDF_LOGE("%s : memcpy fail!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ return HDF_SUCCESS;
+}
+
+static struct NetDeviceImplOp g_ndImplOps = {
+ .init = NetDevInit,
+ .deInit = NetDevDeInit,
+ .add = NetDevAdd,
+ .delete = NetDevDelete,
+ .setStatus = NetDevSetStatus,
+ .receive = NetDevReceive,
+ .changeMacAddr = NetDevChangeMacAddr,
+};
+
+int32_t RegisterNetDeviceImpl(struct NetDeviceImpl *ndImpl)
+{
+ if (ndImpl == NULL) {
+ HDF_LOGE("%s fail : impl = null!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ ndImpl->interFace = &g_ndImplOps;
+ HDF_LOGI("register full netdevice impl success.");
+ return HDF_SUCCESS;
+}
+
+int32_t UnRegisterNetDeviceImpl(struct NetDeviceImpl *ndImpl)
+{
+ if (ndImpl == NULL) {
+ HDF_LOGI("%s already unregister!", __func__);
+ return HDF_SUCCESS;
+ }
+ ndImpl->interFace = NULL;
+ HDF_LOGI("%s success.", __func__);
+ return HDF_SUCCESS;
+}
diff --git a/adapter/khdf/linux/network/src/netbuf_adapter.c b/adapter/khdf/linux/network/src/netbuf_adapter.c
new file mode 100644
index 00000000..7cd08084
--- /dev/null
+++ b/adapter/khdf/linux/network/src/netbuf_adapter.c
@@ -0,0 +1,441 @@
+/*
+ * netbuf_adapter.c
+ *
+ * net buffer adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "netbuf_adapter.h"
+
+#include "hdf_base.h"
+#include "hdf_netbuf.h"
+#include "securec.h"
+
+/**
+ * @brief Initializes a network data buffer queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ *
+ * @since 1.0
+ */
+void NetBufQueueInit(NetBufQueue *q)
+{
+ skb_queue_head_init(q);
+}
+
+/**
+ * @brief Obtains the size of a network data buffer queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ *
+ * @return Returns the size of the network data buffer queue.
+ *
+ * @since 1.0
+ */
+uint32_t NetBufQueueSize(const NetBufQueue *q)
+{
+ return skb_queue_len(q);
+}
+
+/**
+ * @brief Checks whether the network data buffer queue is empty.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ *
+ * @return Returns true if the queue is empty; returns false otherwise.
+ *
+ * @since 1.0
+ */
+bool NetBufQueueIsEmpty(const NetBufQueue *q)
+{
+ return skb_queue_empty(q);
+}
+
+/**
+ * @brief Adds a network data buffer to the tail of a queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ * @param nb Indicates the pointer to the network data buffer.
+ *
+ * @since 1.0
+ */
+void NetBufQueueEnqueue(NetBufQueue *q, NetBuf *nb)
+{
+ skb_queue_tail(q, nb);
+}
+
+/**
+ * @brief Adds a network data buffer to the header of a queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ * @param nb Indicates the pointer to the network data buffer.
+ *
+ * @since 1.0
+ */
+void NetBufQueueEnqueueHead(NetBufQueue *q, NetBuf *nb)
+{
+ skb_queue_head(q, nb);
+}
+
+/**
+ * @brief Obtains a network data buffer from the header of a queue and deletes it from the queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ *
+ * @return Returns the pointer to the first network data buffer if the queue is not empty;
+ * returns NULL otherwise.
+ *
+ * @since 1.0
+ */
+NetBuf *NetBufQueueDequeue(NetBufQueue *q)
+{
+ return skb_dequeue(q);
+}
+
+/**
+ * @brief Obtains a network data buffer from the tail of a queue and deletes it from the queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ *
+ * @return Returns the pointer to the last network data buffer if the queue is not empty;
+ * returns NULL otherwise.
+ *
+ * @since 1.0
+ */
+NetBuf *NetBufQueueDequeueTail(NetBufQueue *q)
+{
+ return skb_dequeue_tail(q);
+}
+
+/**
+ * @brief Obtains the network data buffer from the header of a queue, without deleting it from the queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ *
+ * @return Returns the pointer to the first network data buffer if the queue is not empty;
+ * returns NULL otherwise.
+ *
+ * @since 1.0
+ */
+NetBuf *NetBufQueueAtHead(const NetBufQueue *q)
+{
+ return skb_peek(q);
+}
+
+/**
+ * @brief Obtains the network data buffer from the tail of a queue, without deleting it from the queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ *
+ * @return Returns the pointer to the last network data buffer if the queue is not empty;
+ * returns NULL otherwise.
+ *
+ * @since 1.0
+ */
+NetBuf *NetBufQueueAtTail(const NetBufQueue *q)
+{
+ return skb_peek_tail(q);
+}
+
+/**
+ * @brief Clears a network data buffer queue and releases the network data buffer in the queue.
+ *
+ * @param q Indicates the pointer to the network data buffer queue.
+ *
+ * @since 1.0
+ */
+void NetBufQueueClear(NetBufQueue *q)
+{
+ skb_queue_purge(q);
+}
+
+/**
+ * @brief Moves all network data buffers from one queue to another and clears the source queue.
+ *
+ * @param q Indicates the pointer to the target network data buffer queue.
+ * @param add Indicates the pointer to the source network data buffer queue.
+ *
+ * @since 1.0
+ */
+void NetBufQueueConcat(NetBufQueue *q, NetBufQueue *add)
+{
+ skb_queue_splice_init(add, q);
+}
+
+/**
+ * @brief Applies for a network data buffer.
+ *
+ * @param size Indicates the size of the network data buffer.
+ *
+ * @return Returns the pointer to the network data buffer if the operation is successful;
+ * returns NULL otherwise.
+ *
+ * @since 1.0
+ */
+NetBuf *NetBufAlloc(uint32_t size)
+{
+ return dev_alloc_skb(size);
+}
+
+/**
+ * @brief Releases a network data buffer.
+ *
+ * @param nb Indicates the pointer to the network data buffer.
+ *
+ * @since 1.0
+ */
+void NetBufFree(NetBuf *nb)
+{
+ kfree_skb(nb);
+}
+
+/**
+ * @brief Obtains the actual data length of the data segment of a network data buffer.
+ *
+ * @param nb Indicates the pointer to the network data buffer.
+ *
+ * @return Returns the actual data length of the data segment.
+ *
+ * @since 1.0
+ */
+uint32_t NetBufGetDataLen(const NetBuf *nb)
+{
+ if (nb == NULL) {
+ return 0;
+ }
+ return nb->len;
+}
+
+/**
+ * @brief Adjusts the size of a network data buffer space.
+ *
+ * This function is used to apply for a new network data buffer based on the configured reserved space and
+ * the size of the source network data buffer, and copy the actual data to the new network data buffer.
+ *
+ * @param nb Indicates the pointer to the network data buffer.
+ * @param head Indicates the size of the header buffer segment reserved.
+ * @param tail Indicates the size of the tail buffer segment reserved.
+ *
+ * @return Returns 0 if the operation is successful; returns a non-zero value otherwise.
+ *
+ * @since 1.0
+ */
+int32_t NetBufResizeRoom(NetBuf *nb, uint32_t head, uint32_t tail)
+{
+ return pskb_expand_head(nb, head, tail, GFP_ATOMIC);
+}
+
+/**
+ * @brief Performs operations based on the segment ID of a network data buffer.
+ * The function is opposite to that of {@link NetBufPop}.
+ *
+ * Description:
+ * ID Type | Result
+ * -------|---------
+ * E_HEAD_BUF | The length of the header buffer segment is increased and the length of the data segment is reduced.
+ * E_DATA_BUF | The length of the data segment is increased and the length of the tail buffer segment is reduced.
+ * E_TAIL_BUF | The length of the tail buffer segment is increased and the length of the data segment is reduced.
+ *
+ * @param nb Indicates the pointer to the network data buffer.
+ * @param id Indicates the buffer segment ID.
+ * @param len Indicates the operation length.
+ *
+ * @return Returns the start address of the data segment if the operation is successful;
+ * returns NULL if the operation length exceeds the space of a specified buffer segment.
+ *
+ * @since 1.0
+ */
+void *NetBufPush(NetBuf *nb, uint32_t id, uint32_t len)
+{
+ if (nb == NULL) {
+ return NULL;
+ }
+
+ switch (id) {
+ case E_HEAD_BUF:
+ nb->data += len;
+ break;
+ case E_DATA_BUF:
+ nb->tail += len;
+ nb->len += len;
+ break;
+ case E_TAIL_BUF:
+ if (unlikely(len > nb->len) || unlikely(len > nb->tail)) {
+ return NULL;
+ }
+
+ nb->tail -= len;
+ nb->len -= len;
+ break;
+ default:
+ break;
+ }
+
+ return nb->data;
+}
+
+/**
+ * @brief Performs operations based on the segment ID of a network data buffer.
+ * The function is opposite to that of {@link NetBufPush}.
+ *
+ * Description:
+ * ID Type | Result
+ * -------|---------
+ * E_HEAD_BUF | The length of the header buffer segment is reduced and the length of the data segment is increased.
+ * E_DATA_BUF| The length of the data segment is reduced and the length of the tail buffer segment is increased.
+ * E_TAIL_BUF | The length of the tail buffer segment is reduced and the length of the data segment is increased.
+ *
+ * @param nb Indicates the pointer to the network data buffer.
+ * @param id Indicates the buffer segment ID.
+ * @param len Indicates the operation length.
+ *
+ * @return Returns the start address of the data segment if the operation is successful;
+ * returns NULL if the operation length exceeds the space of a specified buffer segment.
+ *
+ * @since 1.0
+ */
+void *NetBufPop(NetBuf *nb, uint32_t id, uint32_t len)
+{
+ if (nb == NULL) {
+ return NULL;
+ }
+
+ switch (id) {
+ case E_HEAD_BUF:
+ if (unlikely(len > nb->data)) {
+ return NULL;
+ }
+ nb->data -= len;
+ nb->len += len;
+ break;
+ case E_DATA_BUF:
+ if (unlikely(len > nb->len)) {
+ return NULL;
+ }
+ nb->data += len;
+ nb->len -= len;
+ break;
+ case E_TAIL_BUF:
+ nb->tail += len;
+ nb->len += len;
+ break;
+ default:
+ break;
+ }
+
+ return nb->data;
+}
+
+/**
+ * @brief Obtains the address of a specified buffer segment in a network data buffer.
+ *
+ * @param nb Indicates the pointer to the network data buffer.
+ * @param id Indicates the buffer segment ID.
+ *
+ * @return Returns the address of the specified buffer segment if the operation is successful;
+ * returns NULL if the buffer segment ID is invalid.
+ *
+ * @since 1.0
+ */
+uint8_t *NetBufGetAddress(const NetBuf *nb, uint32_t id)
+{
+ uint8_t *addr = NULL;
+
+ if (nb == NULL) {
+ return addr;
+ }
+
+ switch (id) {
+ case E_HEAD_BUF:
+ addr = nb->head;
+ break;
+ case E_DATA_BUF:
+ addr = nb->data;
+ break;
+ case E_TAIL_BUF:
+ addr = skb_tail_pointer(nb);
+ break;
+ default:
+ break;
+ }
+
+ return addr;
+}
+
+/**
+ * @brief Obtains the size of a specified buffer segment space in a network data buffer.
+ *
+ * @param nb Indicates the pointer to the network data buffer.
+ * @param id Indicates the buffer segment ID.
+ *
+ * @return Returns the size of the specified buffer segment space if the operation is successful;
+ * returns NULL if the buffer segment ID is invalid.
+ *
+ * @since 1.0
+ */
+uint32_t NetBufGetRoom(const NetBuf *nb, uint32_t id)
+{
+ uint32_t size = 0;
+
+ if (nb == NULL) {
+ return size;
+ }
+
+ switch (id) {
+ case E_HEAD_BUF:
+ size = skb_headroom(nb);
+ break;
+ case E_DATA_BUF:
+ size = skb_is_nonlinear(nb) ?
+ 0 : (skb_tail_pointer(nb) - nb->data);
+ break;
+ case E_TAIL_BUF:
+ size = skb_tailroom(nb);
+ break;
+ default:
+ break;
+ }
+
+ return size;
+}
+
+/**
+ * @brief Copies data in a network data buffer to another network data buffer.
+ *
+ * @param nb Indicates the pointer to the network data buffer.
+ * @param cnb Indicates the pointer to the target network data buffer.
+ *
+ * @return Returns 0 if the operation is successful; returns a non-zero value otherwise.
+ *
+ * @since 1.0
+ */
+int32_t NetBufConcat(NetBuf *nb, NetBuf *cnb)
+{
+ uint32_t tailroom = skb_tailroom(nb) < 0 ? 0 : skb_tailroom(nb);
+
+ if (cnb == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (tailroom < cnb->len) {
+ return HDF_FAILURE;
+ }
+ if (memcpy_s(skb_tail_pointer(nb), tailroom, cnb->data, cnb->len) != EOK) {
+ return HDF_FAILURE;
+ }
+
+ skb_put(nb, cnb->len);
+ NetBufFree(cnb);
+ return HDF_SUCCESS;
+}
diff --git a/adapter/khdf/linux/osal/Makefile b/adapter/khdf/linux/osal/Makefile
new file mode 100644
index 00000000..2ace0de6
--- /dev/null
+++ b/adapter/khdf/linux/osal/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+obj-y += src/
\ No newline at end of file
diff --git a/adapter/khdf/linux/osal/include/hdf_log_adapter.h b/adapter/khdf/linux/osal/include/hdf_log_adapter.h
new file mode 100644
index 00000000..cc01e73c
--- /dev/null
+++ b/adapter/khdf/linux/osal/include/hdf_log_adapter.h
@@ -0,0 +1,55 @@
+/*
+ * hdf_log_adapter.h
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HDF_LOG_ADAPTER_H
+#define HDF_LOG_ADAPTER_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define _HDF_FMT_TAG(TAG, LEVEL) "[" #LEVEL "/" #TAG "] "
+#define HDF_FMT_TAG(TAG, LEVEL) _HDF_FMT_TAG(TAG, LEVEL)
+#define HDF_LOG_BUF_SIZE 256
+
+bool deal_format(const char *fmt, char *str, size_t size);
+
+#define HDF_LOG_WRAPPER(fmt, args...) \
+ do { \
+ char tmp_fmt[HDF_LOG_BUF_SIZE] = {0}; \
+ if (deal_format(fmt, tmp_fmt, sizeof(tmp_fmt))) \
+ printk(tmp_fmt, ##args); \
+ } while (0)
+
+#define HDF_LOGV_WRAPPER(fmt, args...) HDF_LOG_WRAPPER(KERN_DEBUG HDF_FMT_TAG(HDF_LOG_TAG, V) fmt "\r\n", ## args)
+
+#define HDF_LOGD_WRAPPER(fmt, args...) HDF_LOG_WRAPPER(KERN_DEBUG HDF_FMT_TAG(HDF_LOG_TAG, D) fmt "\r\n", ## args)
+
+#define HDF_LOGI_WRAPPER(fmt, args...) HDF_LOG_WRAPPER(KERN_INFO HDF_FMT_TAG(HDF_LOG_TAG, I) fmt "\r\n", ## args)
+
+#define HDF_LOGW_WRAPPER(fmt, args...) HDF_LOG_WRAPPER(KERN_WARNING HDF_FMT_TAG(HDF_LOG_TAG, W) fmt "\r\n", ## args)
+
+#define HDF_LOGE_WRAPPER(fmt, args...) HDF_LOG_WRAPPER(KERN_ERR HDF_FMT_TAG(HDF_LOG_TAG, E) fmt "\r\n", ## args)
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* HDF_LOG_ADAPTER_H */
+
diff --git a/adapter/khdf/linux/osal/include/hdf_types.h b/adapter/khdf/linux/osal/include/hdf_types.h
new file mode 100644
index 00000000..c8624ced
--- /dev/null
+++ b/adapter/khdf/linux/osal/include/hdf_types.h
@@ -0,0 +1,25 @@
+/*
+ * hdf_types.h
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef HDF_TYPE_H
+#define HDF_TYPE_H
+
+#include
+#include
+
+#endif /* HDF_TYPE_H */
diff --git a/adapter/khdf/linux/osal/include/osal_atomic_def.h b/adapter/khdf/linux/osal/include/osal_atomic_def.h
new file mode 100644
index 00000000..28122aa3
--- /dev/null
+++ b/adapter/khdf/linux/osal/include/osal_atomic_def.h
@@ -0,0 +1,45 @@
+/*
+ * osal_atomic_def.h
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef OSAL_ATOMIC_DEF_H
+#define OSAL_ATOMIC_DEF_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define OsalAtomicReadWrapper(v) atomic_read((const atomic_t *)(v))
+#define OsalAtomicSetWrapper(v, value) atomic_set((atomic_t *)(v), value)
+#define OsalAtomicIncWrapper(v) atomic_inc((atomic_t *)(v))
+#define OsalAtomicIncRetWrapper(v) atomic_inc_return((atomic_t *)(v))
+#define OsalAtomicDecWrapper(v) atomic_dec((atomic_t *)(v))
+#define OsalAtomicDecRetWrapper(v) atomic_dec_return((atomic_t *)(v))
+
+#define OsalTestBitWrapper(nr, addr) test_bit(nr, addr)
+#define OsalTestSetBitWrapper(nr, addr) test_and_change_bit(nr, addr)
+#define OsalTestClearBitWrapper(nr, addr) test_and_clear_bit(nr, addr)
+#define OsalClearBitWrapper(nr, addr) clear_bit(nr, addr)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* OSAL_ATOMIC_DEF_H */
+
diff --git a/adapter/khdf/linux/osal/include/osal_cdev_adapter.h b/adapter/khdf/linux/osal/include/osal_cdev_adapter.h
new file mode 100644
index 00000000..ef06aa5a
--- /dev/null
+++ b/adapter/khdf/linux/osal/include/osal_cdev_adapter.h
@@ -0,0 +1,29 @@
+/*
+ * osal_cdev_adapter.h
+ *
+ * osal driver
+ *
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef OSAL_CDEV_ADAPTER_DEF_H
+#define OSAL_CDEV_ADAPTER_DEF_H
+
+#include
+#include
+#include
+#include
+#include
+
+#endif /* OSAL_CDEV_ADAPTER_DEF_H */
+
diff --git a/adapter/khdf/linux/osal/include/osal_io_adapter.h b/adapter/khdf/linux/osal/include/osal_io_adapter.h
new file mode 100644
index 00000000..253113c9
--- /dev/null
+++ b/adapter/khdf/linux/osal/include/osal_io_adapter.h
@@ -0,0 +1,26 @@
+/*
+ * osal_io.h
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef OSAL_LINUX_IO_ADAPTER_H
+#define OSAL_LINUX_IO_ADAPTER_H
+
+#include
+#include
+
+#endif /* OSAL_LINUX_IO_ADAPTER_H */
+
diff --git a/adapter/khdf/linux/osal/include/osal_math.h b/adapter/khdf/linux/osal/include/osal_math.h
new file mode 100644
index 00000000..c5057d6f
--- /dev/null
+++ b/adapter/khdf/linux/osal/include/osal_math.h
@@ -0,0 +1,39 @@
+/*
+ * osal_math.h
+ *
+ * osal mathematics
+ *
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef OSAL_MATH_H
+#define OSAL_MATH_H
+
+#include
+#include "hdf_base.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+static inline int64_t OsalDivS64(int64_t dividend, int32_t divisor)
+{
+ return (int64_t)div_s64(dividend, divisor);
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* OSAL_MATH_H */
+
diff --git a/adapter/khdf/linux/osal/include/osal_uaccess.h b/adapter/khdf/linux/osal/include/osal_uaccess.h
new file mode 100644
index 00000000..01023c2a
--- /dev/null
+++ b/adapter/khdf/linux/osal/include/osal_uaccess.h
@@ -0,0 +1,44 @@
+/*
+ * osal_uaccess.h
+ *
+ * osal driver
+ *
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef OSAL_UACCESS_DEF_H
+#define OSAL_UACCESS_DEF_H
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+static inline size_t CopyToUser(void __user *to, const void *from, size_t len)
+{
+ return (size_t)copy_to_user(to, from, (unsigned long)len);
+}
+
+static inline size_t CopyFromUser(void *to, const void __user *from, size_t len)
+{
+ return (size_t)copy_from_user(to, from, (unsigned long)len);
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* OSAL_UACCESS_DEF_H */
+
diff --git a/adapter/khdf/linux/osal/src/Makefile b/adapter/khdf/linux/osal/src/Makefile
new file mode 100644
index 00000000..3ce1c732
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/Makefile
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+obj-y += osal_workqueue.o osal_thread.o osal_firmware.o osal_irq.o osal_mem.o osal_mutex.o osal_sem.o osal_spinlock.o \
+ osal_time.o osal_file.o osal_timer.o osal_cdev.o osal_deal_log_format.o
+ccflags-y +=-I$(srctree)/include/hdf \
+ -I$(srctree)/include/hdf/osal \
+ -I$(srctree)/include/hdf/utils \
+ -I$(srctree)/drivers/hdf/framework/utils/include \
+ -I$(srctree)/drivers/hdf/khdf/osal/include \
+ -I$(srctree)/bounds_checking_function/include
diff --git a/adapter/khdf/linux/osal/src/osal_cdev.c b/adapter/khdf/linux/osal/src/osal_cdev.c
new file mode 100644
index 00000000..c1a05b8f
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_cdev.c
@@ -0,0 +1,269 @@
+/*
+ * osal_cdev.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include
+#include
+#include
+#include "osal_cdev.h"
+#include "hdf_log.h"
+#include "osal_file.h"
+#include "osal_mem.h"
+#include "osal_uaccess.h"
+
+#define HDF_LOG_TAG osal_cdev
+
+#define HDF_MAJOR 231
+#define HDF_MINOR_START 0
+#define HDF_MAX_CHAR_DEVICES 1024
+
+static DEFINE_IDA(hdf_vnode_ids);
+
+struct OsalCdev {
+ struct device dev;
+ struct cdev cdev;
+ struct file_operations fops;
+ const struct OsalCdevOps* opsImpl;
+ void* priv;
+};
+
+static const char* StringRfindChar(const char* str, char chr)
+{
+ const char* p = NULL;
+ if (str == NULL) {
+ return NULL;
+ }
+
+ p = str + strlen(str);
+ while (p >= str) {
+ if (*p == chr) {
+ return p;
+ }
+ p--;
+ }
+
+ return NULL;
+}
+
+static char* hdfDevnode(struct device* dev, umode_t* mode)
+{
+ (void)mode;
+ return kasprintf(GFP_KERNEL, "hdf/%s", dev_name(dev));
+}
+
+static bool g_hdfClassInitted = false;
+
+struct class g_hdfClass = {
+ .name = "hdf",
+ .devnode = hdfDevnode,
+};
+
+static dev_t g_hdfDevt = 0;
+
+static int HdfClassInit(void)
+{
+ int ret;
+
+ if (g_hdfClassInitted) {
+ return HDF_SUCCESS;
+ }
+
+ ret = class_register(&g_hdfClass);
+ if (ret) {
+ HDF_LOGE("failed to register hdf class");
+ return ret;
+ }
+ HDF_LOGI("register hdf class success");
+
+ ret = alloc_chrdev_region(&g_hdfDevt, HDF_MINOR_START, HDF_MAX_CHAR_DEVICES, "hdf");
+ if (ret) {
+ HDF_LOGE("failed to alloc hdf char major");
+ class_unregister(&g_hdfClass);
+ return ret;
+ }
+
+ g_hdfClassInitted = true;
+ return HDF_SUCCESS;
+}
+
+static void HdfVnodeDevRelease(struct device* dev)
+{
+ (void)dev;
+}
+
+static int RegisterDev(struct OsalCdev* cdev, const char* devName)
+{
+ int devMinor;
+ int ret;
+
+ ret = HdfClassInit();
+ if (ret != HDF_SUCCESS) {
+ return ret;
+ }
+
+ devMinor = ida_simple_get(&hdf_vnode_ids, HDF_MINOR_START, HDF_MAX_CHAR_DEVICES, GFP_KERNEL);
+ if (devMinor < 0) {
+ HDF_LOGE("failed to get hdf dev minor");
+ return HDF_DEV_ERR_NO_DEVICE;
+ }
+
+ dev_set_name(&cdev->dev, "%s", devName);
+ cdev->dev.devt = MKDEV(MAJOR(g_hdfDevt), devMinor);
+ cdev->dev.class = &g_hdfClass;
+ cdev->dev.parent = NULL;
+ cdev->dev.release = HdfVnodeDevRelease;
+ device_initialize(&cdev->dev);
+
+ cdev_init(&cdev->cdev, &cdev->fops);
+
+ ret = cdev_add(&cdev->cdev, cdev->dev.devt, 1);
+ if (ret) {
+ ida_simple_remove(&hdf_vnode_ids, devMinor);
+ HDF_LOGE("failed to add hdf cdev(%s)\n", devName);
+ return ret;
+ }
+
+ ret = device_add(&cdev->dev);
+ if (ret) {
+ HDF_LOGE("device(%s) add failed\n", devName);
+ cdev_del(&cdev->cdev);
+ ida_simple_remove(&hdf_vnode_ids, devMinor);
+ return ret;
+ }
+
+ HDF_LOGI("add cdev %s success\n", devName);
+ return 0;
+}
+
+static loff_t OsalCdevSeek(struct file* filep, loff_t offset, int whence)
+{
+ struct OsalCdev* dev = container_of(filep->f_inode->i_cdev, struct OsalCdev, cdev);
+ return dev->opsImpl->seek(filep, offset, whence);
+}
+
+static ssize_t OsalCdevRead(struct file* filep, char __user* buf, size_t buflen, loff_t* offset)
+{
+ struct OsalCdev* dev = container_of(filep->f_inode->i_cdev, struct OsalCdev, cdev);
+ return dev->opsImpl->read(filep, buf, buflen, offset);
+}
+
+static ssize_t OsalCdevWrite(struct file* filep, const char __user* buf, size_t buflen, loff_t* offset)
+{
+ struct OsalCdev* dev = container_of(filep->f_inode->i_cdev, struct OsalCdev, cdev);
+ return dev->opsImpl->write(filep, buf, buflen, offset);
+}
+
+static unsigned int OsalCdevPoll(struct file* filep, struct poll_table_struct* pollTable)
+{
+ struct OsalCdev* dev = container_of(filep->f_inode->i_cdev, struct OsalCdev, cdev);
+ return dev->opsImpl->poll(filep, pollTable);
+}
+
+static long OsalCdevIoctl(struct file* filep, unsigned int cmd, unsigned long arg)
+{
+ struct OsalCdev* dev = container_of(filep->f_inode->i_cdev, struct OsalCdev, cdev);
+ return dev->opsImpl->ioctl(filep, cmd, arg);
+}
+
+static int OsalCdevOpen(struct inode* inode, struct file* filep)
+{
+ struct OsalCdev* dev = container_of(inode->i_cdev, struct OsalCdev, cdev);
+ return dev->opsImpl->open(dev, filep);
+}
+
+static int OsalCdevRelease(struct inode* inode, struct file* filep)
+{
+ struct OsalCdev* dev = container_of(inode->i_cdev, struct OsalCdev, cdev);
+ return dev->opsImpl->release(dev, filep);
+}
+
+static void AssignFileOps(struct file_operations* fops, const struct OsalCdevOps* src)
+{
+ fops->llseek = src->seek != NULL ? OsalCdevSeek : NULL;
+ fops->read = src->read != NULL ? OsalCdevRead : NULL;
+ fops->write = src->write != NULL ? OsalCdevWrite : NULL;
+ fops->poll = src->poll != NULL ? OsalCdevPoll : NULL;
+ fops->unlocked_ioctl = src->ioctl != NULL ? OsalCdevIoctl : NULL;
+ fops->open = src->open != NULL ? OsalCdevOpen : NULL;
+ fops->release = src->release != NULL ? OsalCdevRelease : NULL;
+#ifdef CONFIG_COMPAT
+ fops->compat_ioctl = src->ioctl != NULL ? OsalCdevIoctl : NULL;
+#endif
+}
+
+struct OsalCdev* OsalAllocCdev(const struct OsalCdevOps* fops)
+{
+ struct OsalCdev* cdev = OsalMemCalloc(sizeof(struct OsalCdev));
+ if (cdev == NULL) {
+ return NULL;
+ }
+
+ AssignFileOps(&cdev->fops, fops);
+ cdev->opsImpl = fops;
+
+ return cdev;
+}
+
+int OsalRegisterCdev(struct OsalCdev* cdev, const char* name, unsigned int mode, void* priv)
+{
+ const char* lastSlash;
+ int ret;
+ (void)mode;
+ if (cdev == NULL || name == NULL) {
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ lastSlash = StringRfindChar(name, '/');
+ ret = RegisterDev(cdev, (lastSlash == NULL) ? name : (lastSlash + 1));
+ if (ret == HDF_SUCCESS) {
+ cdev->priv = priv;
+ }
+
+ return ret;
+}
+
+void OsalUnregisterCdev(struct OsalCdev* cdev)
+{
+ if (cdev == NULL) {
+ return;
+ }
+ device_del(&cdev->dev);
+ cdev_del(&cdev->cdev);
+ ida_simple_remove(&hdf_vnode_ids, MINOR(cdev->dev.devt));
+}
+
+void OsalFreeCdev(struct OsalCdev* cdev)
+{
+ if (cdev != NULL) {
+ OsalMemFree(cdev);
+ }
+}
+
+void* OsalGetCdevPriv(struct OsalCdev* cdev)
+{
+ return cdev != NULL ? cdev->priv : NULL;
+}
+
+void OsalSetFilePriv(struct file* filep, void* priv)
+{
+ if (filep != NULL) {
+ filep->private_data = priv;
+ }
+}
+void* OsalGetFilePriv(struct file* filep)
+{
+ return filep != NULL ? filep->private_data : NULL;
+}
diff --git a/adapter/khdf/linux/osal/src/osal_deal_log_format.c b/adapter/khdf/linux/osal/src/osal_deal_log_format.c
new file mode 100644
index 00000000..7036bae4
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_deal_log_format.c
@@ -0,0 +1,70 @@
+/*
+ * osal_deal_log_format.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include "securec.h"
+
+#define NUMBER 2
+static const char *g_property[NUMBER] = { "%{private}", "%{public}" };
+static size_t g_property_len[NUMBER] = { 10, 9 };
+
+/* remove "{private}" and "{public}" from fmt and copy the rest to dest */
+bool deal_format(const char *fmt, char *dest, size_t size)
+{
+ const char *ptr = fmt;
+ const char *ptr_cur = ptr;
+ errno_t ret;
+ size_t index = 0;
+ size_t i;
+
+ if (fmt == NULL || dest == NULL || size == 0 || strlen(fmt) >= (size - 1)) {
+ printk("%s invalid para", __func__);
+ return false;
+ }
+
+ while (ptr_cur != NULL && *ptr_cur != '\0') {
+ if (*ptr_cur != '%') {
+ ptr_cur++;
+ continue;
+ }
+ for (i = 0; i < NUMBER; i++) {
+ if (strncmp(ptr_cur, g_property[i], g_property_len[i]) != 0)
+ continue;
+
+ /* add 1 is for to copy char '%' */
+ ret = strncpy_s(&dest[index], size - index, ptr, ptr_cur - ptr + 1);
+ if (ret != EOK) {
+ printk("%s strncpy_s error %d", __func__, ret);
+ return false;
+ }
+ index += (ptr_cur - ptr + 1);
+ ptr = ptr_cur + g_property_len[i];
+ ptr_cur = ptr;
+ break;
+ }
+ if (i == NUMBER)
+ ptr_cur++;
+ }
+ ret = strcat_s(&dest[index], size - index, ptr);
+ if (ret != EOK) {
+ printk("%s strcat_s error %d", __func__, ret);
+ return false;
+ }
+ return true;
+}
+EXPORT_SYMBOL(deal_format);
diff --git a/adapter/khdf/linux/osal/src/osal_file.c b/adapter/khdf/linux/osal/src/osal_file.c
new file mode 100644
index 00000000..e459206d
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_file.c
@@ -0,0 +1,125 @@
+/*
+ * osal_file.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_file.h"
+#include
+#include
+#include "hdf_log.h"
+
+#define HDF_LOG_TAG osal_file
+
+int32_t OsalFileOpen(OsalFile *file, const char *path, int flags, uint32_t rights)
+{
+ struct file *fp = NULL;
+
+ if (file == NULL || path == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ file->realFile = (void *)fp;
+
+ fp = filp_open(path, flags, rights);
+ if (IS_ERR_OR_NULL(fp)) {
+ HDF_LOGE("%s open file fail %d %u", __func__, flags, rights);
+ return HDF_FAILURE;
+ }
+
+ file->realFile = (void *)fp;
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalFileOpen);
+
+ssize_t OsalFileWrite(OsalFile *file, const void *string, uint32_t length)
+{
+ ssize_t ret;
+ loff_t pos;
+ struct file *fp = NULL;
+
+ if (file == NULL || IS_ERR_OR_NULL(file->realFile) || string == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ fp = (struct file *)file->realFile;
+ pos = fp->f_pos;
+ ret = kernel_write(fp, string, length, &pos);
+ if (ret < 0) {
+ HDF_LOGE("%s write file length %u fail %d", __func__, length, ret);
+ return HDF_FAILURE;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(OsalFileWrite);
+
+void OsalFileClose(OsalFile *file)
+{
+ struct file *fp = NULL;
+
+ if (file == NULL || IS_ERR_OR_NULL(file->realFile)) {
+ HDF_LOGE("%s invalid param", __func__);
+ return;
+ }
+ fp = (struct file *)file->realFile;
+ filp_close(fp, NULL);
+ file->realFile = NULL;
+}
+EXPORT_SYMBOL(OsalFileClose);
+
+ssize_t OsalFileRead(OsalFile *file, void *buf, uint32_t length)
+{
+ ssize_t ret;
+ loff_t pos;
+ struct file *fp = NULL;
+
+ if (file == NULL || IS_ERR_OR_NULL(file->realFile) || buf == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ fp = (struct file *)file->realFile;
+ pos = fp->f_pos;
+ ret = kernel_read(fp, buf, length, &pos);
+ if (ret < 0) {
+ HDF_LOGE("%s read file length %u fail %d", __func__, length, ret);
+ return HDF_FAILURE;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(OsalFileRead);
+
+off_t OsalFileLseek(OsalFile *file, off_t offset, int32_t whence)
+{
+ off_t ret;
+ struct file *fp = NULL;
+
+ if (file == NULL || IS_ERR_OR_NULL(file->realFile)) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ fp = (struct file *)file->realFile;
+ ret = vfs_llseek(fp, offset, whence);
+ if (ret < 0) {
+ HDF_LOGE("%s lseek file fail %ld %d", __func__, offset, whence);
+ return HDF_FAILURE;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(OsalFileLseek);
+
diff --git a/adapter/khdf/linux/osal/src/osal_firmware.c b/adapter/khdf/linux/osal/src/osal_firmware.c
new file mode 100644
index 00000000..5ce6b660
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_firmware.c
@@ -0,0 +1,91 @@
+/*
+ * osal_firmware.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_firmware.h"
+#include
+#include
+#include
+#include "hdf_log.h"
+
+#define HDF_LOG_TAG osal_fw
+
+int32_t OsalRequestFirmware(struct OsalFirmware *fwPara,
+ const char *fwName, void *device)
+{
+ const struct firmware *fw = NULL;
+ int ret;
+
+ if (fwPara == NULL || fwName == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ ret = request_firmware(&fw, fwName, device);
+ if (ret < 0) {
+ fwPara->fwSize = 0;
+ fwPara->para = NULL;
+ HDF_LOGE("%s failure to request firmware file", __func__);
+ return HDF_FAILURE;
+ }
+ fwPara->fwSize = fw->size;
+ fwPara->para = (void *)fw;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalRequestFirmware);
+
+int32_t OsalSeekFirmware(struct OsalFirmware *fwPara, uint32_t offset)
+{
+ (void)fwPara;
+ (void)offset;
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSeekFirmware);
+
+int32_t OsalReadFirmware(struct OsalFirmware *fwPara, struct OsalFwBlock *block)
+{
+ struct firmware *fw = NULL;
+
+ if (fwPara == NULL || fwPara->para == NULL || block == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ fw = (struct firmware *)fwPara->para;
+ block->data = (uint8_t *)fw->data;
+ block->dataSize = fwPara->fwSize;
+ block->curOffset = 0;
+ block->endFlag = true;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalReadFirmware);
+
+int32_t OsalReleaseFirmware(struct OsalFirmware *fwPara)
+{
+ if (fwPara == NULL || fwPara->para == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ release_firmware((struct firmware *)fwPara->para);
+ fwPara->para = NULL;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalReleaseFirmware);
diff --git a/adapter/khdf/linux/osal/src/osal_irq.c b/adapter/khdf/linux/osal/src/osal_irq.c
new file mode 100644
index 00000000..0b024be0
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_irq.c
@@ -0,0 +1,70 @@
+/*
+ * osal_irq.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_irq.h"
+#include
+#include
+#include "hdf_log.h"
+
+#define HDF_LOG_TAG osal_irq
+
+int32_t OsalRegisterIrq(uint32_t irq,
+ uint32_t config, OsalIRQHandle handle, const char *name, void *data)
+{
+ uint32_t ret;
+ const char *irq_name = NULL;
+
+ irq_name = (name != NULL) ? name : "hdf_irq";
+
+ ret = request_threaded_irq(irq, NULL, (irq_handler_t)handle,
+ config | IRQF_ONESHOT | IRQF_NO_SUSPEND, irq_name, data);
+ if (ret != 0) {
+ HDF_LOGE("%s fail %u", __func__, ret);
+ return HDF_FAILURE;
+ }
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalRegisterIrq);
+
+int32_t OsalUnregisterIrq(uint32_t irq, void *dev)
+{
+ disable_irq(irq);
+
+ free_irq(irq, dev);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalUnregisterIrq);
+
+int32_t OsalEnableIrq(uint32_t irq)
+{
+ enable_irq(irq);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalEnableIrq);
+
+int32_t OsalDisableIrq(uint32_t irq)
+{
+ disable_irq(irq);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalDisableIrq);
+
diff --git a/adapter/khdf/linux/osal/src/osal_mem.c b/adapter/khdf/linux/osal/src/osal_mem.c
new file mode 100644
index 00000000..7ebfc1fa
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_mem.c
@@ -0,0 +1,167 @@
+/*
+ * osal_mem.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_mem.h"
+#include
+#include
+#include
+#include
+#include "hdf_log.h"
+#include "securec.h"
+
+#define HDF_LOG_TAG osal_mem
+
+#define KMALLOC_SIZE 0x20000
+
+struct mem_hdr {
+ uint32_t type;
+ uint32_t offset;
+};
+
+struct mem_block {
+ struct mem_hdr hdr;
+ uint8_t mem[0];
+};
+
+enum {
+ TYPE_KMALLOC = 0xa5a5a5a1,
+ TYPE_VMALLOC = 0xa5a5a5a2,
+};
+
+static void *osal_mem_alloc(size_t size, uint32_t *type)
+{
+ char *base = NULL;
+ const uint32_t mng_size = sizeof(struct mem_block);
+ if (size > (SIZE_MAX - mng_size)) {
+ HDF_LOGE("%s invalid param %zu", __func__, size);
+ return NULL;
+ }
+
+ if (size > (KMALLOC_SIZE - mng_size)) {
+ base = (char *)vmalloc(size + mng_size);
+ *type = TYPE_VMALLOC;
+ } else {
+ base = (char *)kmalloc(size + mng_size, GFP_KERNEL);
+ *type = TYPE_KMALLOC;
+ }
+
+ return base;
+}
+
+void *OsalMemAlloc(size_t size)
+{
+ void *buf = NULL;
+ char *base = NULL;
+ struct mem_block *block = NULL;
+ const uint32_t mng_size = sizeof(*block);
+ uint32_t type;
+
+ if (size == 0) {
+ HDF_LOGE("%s invalid param", __func__);
+ return NULL;
+ }
+
+ base = osal_mem_alloc(size, &type);
+ if (base == NULL) {
+ HDF_LOGE("%s malloc fail %d", __func__, size);
+ return NULL;
+ }
+
+ block = (struct mem_block *)base;
+ block->hdr.type = type;
+ block->hdr.offset = 0;
+
+ buf = (void *)(base + mng_size);
+
+ return buf;
+}
+EXPORT_SYMBOL(OsalMemAlloc);
+
+void *OsalMemCalloc(size_t size)
+{
+ void *buf = NULL;
+
+ if (size == 0) {
+ HDF_LOGE("%s invalid param", __func__);
+ return NULL;
+ }
+
+ buf = OsalMemAlloc(size);
+ if (buf != NULL)
+ (void)memset_s(buf, size, 0, size);
+
+ return buf;
+}
+EXPORT_SYMBOL(OsalMemCalloc);
+
+void *OsalMemAllocAlign(size_t alignment, size_t size)
+{
+ char *base = NULL;
+ char *buf = NULL;
+ struct mem_block *block = NULL;
+ const uint32_t mng_size = sizeof(*block);
+ uint32_t type;
+ uint32_t offset;
+ char *aligned_ptr = NULL;
+
+ if (size == 0 || (alignment == 0) || ((alignment & (alignment - 1)) != 0) ||
+ ((alignment % sizeof(void *)) != 0) || size > (SIZE_MAX - alignment)) {
+ HDF_LOGE("%s invalid param align:%zu,size:%zu", __func__, alignment, size);
+ return NULL;
+ }
+
+ base = osal_mem_alloc(size + alignment, &type);
+ if (base == NULL) {
+ HDF_LOGE("%s malloc fail %d", __func__, size);
+ return NULL;
+ }
+
+ buf = base + mng_size;
+ aligned_ptr = (char *)(uintptr_t)(((size_t)(uintptr_t)buf + alignment - 1) & ~(alignment - 1));
+ offset = aligned_ptr - buf;
+ block = (struct mem_block *)(base + offset);
+ block->hdr.type = type;
+ block->hdr.offset = offset;
+
+ return aligned_ptr;
+}
+EXPORT_SYMBOL(OsalMemAllocAlign);
+
+void OsalMemFree(void *buf)
+{
+ uint32_t type;
+ char *base = NULL;
+ struct mem_block *block = NULL;
+
+ if (buf == NULL) {
+ return;
+ }
+
+ block = (struct mem_block *)((char *)buf - (char *)&((struct mem_block *)0)->mem);
+ type = block->hdr.type;
+ base = (char *)block - block->hdr.offset;
+
+ if (type == TYPE_KMALLOC)
+ kfree(base);
+ else if (type == TYPE_VMALLOC)
+ vfree(base);
+ else
+ HDF_LOGE("%s block : type %u fail", __func__, type);
+}
+EXPORT_SYMBOL(OsalMemFree);
+
diff --git a/adapter/khdf/linux/osal/src/osal_mutex.c b/adapter/khdf/linux/osal/src/osal_mutex.c
new file mode 100644
index 00000000..18095407
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_mutex.c
@@ -0,0 +1,102 @@
+/*
+ * osal_mutex.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_mutex.h"
+#include
+#include
+#include "hdf_log.h"
+#include "osal_mem.h"
+
+#define HDF_LOG_TAG osal_mutex
+
+int32_t OsalMutexInit(struct OsalMutex *mutex)
+{
+ struct mutex *mutex_tmp = NULL;
+
+ if (mutex == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ mutex_tmp = (struct mutex *)OsalMemCalloc(sizeof(*mutex_tmp));
+ if (mutex_tmp == NULL) {
+ HDF_LOGE("malloc fail");
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ mutex_init(mutex_tmp);
+ mutex->realMutex = (void *)mutex_tmp;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalMutexInit);
+
+int32_t OsalMutexDestroy(struct OsalMutex *mutex)
+{
+ if (mutex == NULL || mutex->realMutex == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ mutex_destroy((struct mutex *)mutex->realMutex);
+ OsalMemFree(mutex->realMutex);
+ mutex->realMutex = NULL;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalMutexDestroy);
+
+int32_t OsalMutexLock(struct OsalMutex *mutex)
+{
+ if (mutex == NULL || mutex->realMutex == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ mutex_lock((struct mutex *)mutex->realMutex);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalMutexLock);
+
+int32_t OsalMutexTimedLock(struct OsalMutex *mutex, uint32_t mSec)
+{
+ if (mutex == NULL || mutex->realMutex == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ (void)mSec;
+ mutex_lock((struct mutex *)mutex->realMutex);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalMutexTimedLock);
+
+int32_t OsalMutexUnlock(struct OsalMutex *mutex)
+{
+ if (mutex == NULL || mutex->realMutex == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ mutex_unlock((struct mutex *)mutex->realMutex);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalMutexUnlock);
+
diff --git a/adapter/khdf/linux/osal/src/osal_sem.c b/adapter/khdf/linux/osal/src/osal_sem.c
new file mode 100644
index 00000000..f42187f2
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_sem.c
@@ -0,0 +1,105 @@
+/*
+ * osal_sem.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_sem.h"
+#include
+#include
+#include
+#include
+#include "hdf_log.h"
+#include "osal_mem.h"
+
+#define HDF_LOG_TAG osal_sem
+
+int32_t OsalSemInit(struct OsalSem *sem, uint32_t value)
+{
+ struct semaphore *sem_tmp = NULL;
+
+ if (sem == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ sem_tmp = (struct semaphore *)OsalMemCalloc(sizeof(*sem_tmp));
+ if (sem_tmp == NULL) {
+ HDF_LOGE("%s malloc fail", __func__);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ sema_init(sem_tmp, value);
+ sem->realSemaphore = (void *)sem_tmp;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSemInit);
+
+int32_t OsalSemWait(struct OsalSem *sem, uint32_t millisec)
+{
+ int32_t ret;
+
+ if (sem == NULL || sem->realSemaphore == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (millisec == HDF_WAIT_FOREVER) {
+ do {
+ ret = down_interruptible((struct semaphore *)sem->realSemaphore);
+ } while (ret == -EINTR);
+ } else {
+ ret = down_timeout((struct semaphore *)sem->realSemaphore, msecs_to_jiffies(millisec));
+ if (ret != 0) {
+ if (ret == -ETIME) {
+ return HDF_ERR_TIMEOUT;
+ } else {
+ HDF_LOGE("%s time_out %u %d", __func__, millisec, ret);
+ return HDF_FAILURE;
+ }
+ }
+ }
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSemWait);
+
+int32_t OsalSemPost(struct OsalSem *sem)
+{
+ if (sem == NULL || sem->realSemaphore == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ up((struct semaphore *)sem->realSemaphore);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSemPost);
+
+int32_t OsalSemDestroy(struct OsalSem *sem)
+{
+ if (sem == NULL || sem->realSemaphore == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ OsalMemFree(sem->realSemaphore);
+ sem->realSemaphore = NULL;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSemDestroy);
+
diff --git a/adapter/khdf/linux/osal/src/osal_spinlock.c b/adapter/khdf/linux/osal/src/osal_spinlock.c
new file mode 100644
index 00000000..0bb1d475
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_spinlock.c
@@ -0,0 +1,143 @@
+/*
+ * osal_spinlock.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_spinlock.h"
+#include
+#include
+#include "hdf_log.h"
+#include "osal_mem.h"
+
+#define HDF_LOG_TAG osal_spinlock
+
+int32_t OsalSpinInit(OsalSpinlock *spinlock)
+{
+ spinlock_t *spin_tmp = NULL;
+
+ if (spinlock == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ spin_tmp = (spinlock_t *)OsalMemCalloc(sizeof(*spin_tmp));
+ if (spin_tmp == NULL) {
+ HDF_LOGE("malloc fail");
+ spinlock->realSpinlock = NULL;
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ spin_lock_init(spin_tmp);
+ spinlock->realSpinlock = (void *)spin_tmp;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSpinInit);
+
+int32_t OsalSpinDestroy(OsalSpinlock *spinlock)
+{
+ if (spinlock == NULL || spinlock->realSpinlock == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ OsalMemFree(spinlock->realSpinlock);
+ spinlock->realSpinlock = NULL;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSpinDestroy);
+
+int32_t OsalSpinLock(OsalSpinlock *spinlock)
+{
+ if (spinlock == NULL || spinlock->realSpinlock == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ spin_lock((spinlock_t *)spinlock->realSpinlock);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSpinLock);
+
+int32_t OsalSpinUnlock(OsalSpinlock *spinlock)
+{
+ if (spinlock == NULL || spinlock->realSpinlock == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ spin_unlock((spinlock_t *)spinlock->realSpinlock);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSpinUnlock);
+
+int32_t OsalSpinLockIrq(OsalSpinlock *spinlock)
+{
+ if (spinlock == NULL || spinlock->realSpinlock == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ spin_lock_irq((spinlock_t *)spinlock->realSpinlock);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSpinLockIrq);
+
+int32_t OsalSpinUnlockIrq(OsalSpinlock *spinlock)
+{
+ if (spinlock == NULL || spinlock->realSpinlock == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ spin_unlock_irq((spinlock_t *)spinlock->realSpinlock);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSpinUnlockIrq);
+
+int32_t OsalSpinLockIrqSave(OsalSpinlock *spinlock, uint32_t *flags)
+{
+ unsigned long temp = 0;
+
+ if (spinlock == NULL || spinlock->realSpinlock == NULL || flags == NULL) {
+ HDF_LOGE("%s invalid param %d", __func__, __LINE__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ spin_lock_irqsave((spinlock_t *)spinlock->realSpinlock, temp);
+ *flags = temp;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSpinLockIrqSave);
+
+int32_t OsalSpinUnlockIrqRestore(OsalSpinlock *spinlock, uint32_t *flags)
+{
+ if (spinlock == NULL || spinlock->realSpinlock == NULL || flags == NULL) {
+ HDF_LOGE("%s invalid param %d", __func__, __LINE__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ spin_unlock_irqrestore((spinlock_t *)spinlock->realSpinlock, *flags);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalSpinUnlockIrqRestore);
+
diff --git a/adapter/khdf/linux/osal/src/osal_thread.c b/adapter/khdf/linux/osal/src/osal_thread.c
new file mode 100644
index 00000000..b2fb28df
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_thread.c
@@ -0,0 +1,177 @@
+/*
+ * osal_thread.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_thread.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "hdf_log.h"
+#include "osal_mem.h"
+#include "securec.h"
+
+#define HDF_LOG_TAG osal_thread
+#define OSAL_INVALID_CPU_ID UINT_MAX
+
+struct thread_wrapper {
+ OsalThreadEntry thread_entry;
+ void *entry_para;
+ struct task_struct *task;
+ uint32_t cpu_id;
+};
+
+enum {
+ OSAL_PRIORITY_MIDDLE = 50,
+ OSAL_PRIORITY_HIGH = 90,
+ OSAL_PRIORITY_HIGHEST = 99,
+};
+
+static int osal_thread_entry(void *para)
+{
+ int ret = -1;
+
+ struct thread_wrapper *wrapper = (struct thread_wrapper *)para;
+ if (wrapper == NULL || wrapper->thread_entry == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ } else {
+ ret = wrapper->thread_entry(wrapper->entry_para);
+ }
+
+ do_exit(ret);
+ return ret;
+}
+
+int32_t OsalThreadCreate(struct OsalThread *thread, OsalThreadEntry thread_entry, void *entry_para)
+{
+ struct thread_wrapper *wrapper = NULL;
+
+ if (thread == NULL || thread_entry == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ thread->realThread = NULL;
+ wrapper = (struct thread_wrapper *)OsalMemCalloc(sizeof(*wrapper));
+ if (wrapper == NULL) {
+ HDF_LOGE("%s malloc fail", __func__);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+
+ wrapper->entry_para = entry_para;
+ wrapper->thread_entry = thread_entry;
+ wrapper->cpu_id = OSAL_INVALID_CPU_ID;
+ thread->realThread = wrapper;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalThreadCreate);
+
+int32_t OsalThreadBind(struct OsalThread *thread, unsigned int cpu_id)
+{
+ struct thread_wrapper *wrapper = NULL;
+
+ if (thread == NULL || thread->realThread == NULL) {
+ HDF_LOGE("%s invalid parameter %d\n", __func__, __LINE__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ wrapper = (struct thread_wrapper *)thread->realThread;
+ wrapper->cpu_id = cpu_id;
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalThreadBind);
+
+int32_t OsalThreadStart(struct OsalThread *thread, const struct OsalThreadParam *param)
+{
+ int32_t ret;
+ struct sched_param sched_para;
+ int32_t policy = SCHED_FIFO;
+ struct task_struct *task = NULL;
+ struct thread_wrapper *wrapper = NULL;
+
+ if (thread == NULL || thread->realThread == NULL || param == NULL || param->name == NULL) {
+ HDF_LOGE("%s invalid parameter\n", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ (void)memset_s(&sched_para, sizeof(sched_para), 0, sizeof(sched_para));
+
+ if (param->priority == OSAL_THREAD_PRI_HIGHEST)
+ sched_para.sched_priority = OSAL_PRIORITY_HIGHEST;
+ else if (param->priority == OSAL_THREAD_PRI_HIGH)
+ sched_para.sched_priority = OSAL_PRIORITY_HIGH;
+ else if (param->priority == OSAL_THREAD_PRI_DEFAULT)
+ sched_para.sched_priority = OSAL_PRIORITY_MIDDLE;
+ else
+ policy = SCHED_NORMAL;
+
+ wrapper = (struct thread_wrapper *)thread->realThread;
+ task = kthread_create(osal_thread_entry, wrapper, param->name);
+ if (IS_ERR(task)) {
+ ret = PTR_ERR(task);
+ HDF_LOGE("%s kthread_create fail %d", __func__, ret);
+ return HDF_FAILURE;
+ }
+ if (wrapper->cpu_id != OSAL_INVALID_CPU_ID) {
+ kthread_bind(task, wrapper->cpu_id);
+ }
+ wake_up_process(task);
+ if (policy == SCHED_FIFO) {
+ if (sched_setscheduler(task, policy, &sched_para)) {
+ HDF_LOGE("%s sched_setscheduler fail", __func__);
+ kthread_stop(task);
+ return HDF_FAILURE;
+ }
+ }
+
+ wrapper->task = task;
+
+ return HDF_SUCCESS;
+}
+
+EXPORT_SYMBOL(OsalThreadStart);
+
+int32_t OsalThreadSuspend(struct OsalThread *thread)
+{
+ return HDF_ERR_NOT_SUPPORT;
+}
+EXPORT_SYMBOL(OsalThreadSuspend);
+
+int32_t OsalThreadDestroy(struct OsalThread *thread)
+{
+ if (thread == NULL || thread->realThread == NULL) {
+ HDF_LOGE("%s invalid parameter\n", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ OsalMemFree(thread->realThread);
+ thread->realThread = NULL;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalThreadDestroy);
+
+int32_t OsalThreadResume(struct OsalThread *thread)
+{
+ return HDF_ERR_NOT_SUPPORT;
+}
+EXPORT_SYMBOL(OsalThreadResume);
+
diff --git a/adapter/khdf/linux/osal/src/osal_time.c b/adapter/khdf/linux/osal/src/osal_time.c
new file mode 100644
index 00000000..20d121ec
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_time.c
@@ -0,0 +1,110 @@
+/*
+ * osal_time.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_time.h"
+#include
+#include
+#include
+#include
+#include
+#include "hdf_log.h"
+#include "osal_math.h"
+#include "securec.h"
+
+#define HDF_LOG_TAG osal_time
+
+#define TM_SINCE_YEAR 1900
+#define TM_MINUTE_UNIT 60
+
+int32_t OsalGetTime(OsalTimespec *time)
+{
+ struct timespec64 ts;
+
+ if (time == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ (void)memset_s(&ts, sizeof(ts), 0, sizeof(ts));
+ ktime_get_ts64(&ts);
+ time->sec = ts.tv_sec;
+ time->usec = ts.tv_nsec / HDF_KILO_UNIT;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalGetTime);
+
+int32_t OsalDiffTime(const OsalTimespec *start, const OsalTimespec *end, OsalTimespec *diff)
+{
+ uint32_t usec = 0;
+ uint32_t sec = 0;
+ if (start == NULL || end == NULL || diff == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (start->sec > end->sec) {
+ HDF_LOGE("%s start time later then end time", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ if (end->usec < start->usec) {
+ usec = (HDF_KILO_UNIT * HDF_KILO_UNIT);
+ sec = 1;
+ }
+ diff->usec = usec + end->usec - start->usec;
+ diff->sec = end->sec - start->sec - sec;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalDiffTime);
+
+void OsalSleep(uint32_t sec)
+{
+ msleep(sec * HDF_KILO_UNIT);
+}
+EXPORT_SYMBOL(OsalSleep);
+
+void OsalMSleep(uint32_t mSec)
+{
+ msleep(mSec);
+}
+EXPORT_SYMBOL(OsalMSleep);
+
+void OsalUDelay(uint32_t us)
+{
+ udelay(us);
+}
+EXPORT_SYMBOL(OsalUDelay);
+
+void OsalMDelay(uint32_t ms)
+{
+ mdelay(ms);
+}
+EXPORT_SYMBOL(OsalMDelay);
+
+uint64_t OsalGetSysTimeMs()
+{
+ OsalTimespec time;
+
+ (void)memset_s(&time, sizeof(time), 0, sizeof(time));
+ (void)OsalGetTime(&time);
+
+ return (time.sec * HDF_KILO_UNIT + OsalDivS64(time.usec, HDF_KILO_UNIT));
+}
+EXPORT_SYMBOL(OsalGetSysTimeMs);
diff --git a/adapter/khdf/linux/osal/src/osal_timer.c b/adapter/khdf/linux/osal/src/osal_timer.c
new file mode 100644
index 00000000..1b926f31
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_timer.c
@@ -0,0 +1,184 @@
+/*
+ * osal_timer.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "osal_timer.h"
+#include
+#include
+#include
+#include
+#include "hdf_log.h"
+#include "osal_mem.h"
+#include "osal_mutex.h"
+
+#define HDF_LOG_TAG osal_timer
+
+typedef enum {
+ OSAL_TIMER_ONCE,
+ OSAL_TIMER_LOOP,
+} OsalTimerMode;
+
+struct osal_ktimer {
+ uintptr_t arg;
+ struct timer_list timer;
+ OsalTimerFunc func;
+ uint32_t msec;
+ struct OsalMutex mutex;
+ OsalTimerMode mode;
+ bool stop_flag;
+};
+
+static void osal_timer_callback(struct timer_list *arg)
+{
+ struct osal_ktimer *ktimer = NULL;
+ uint32_t msec;
+ OsalTimerMode mode;
+ bool stop_flag = false;
+
+ if (arg == NULL) {
+ HDF_LOGI("%s timer is stopped", __func__);
+ return;
+ }
+
+ ktimer = from_timer(ktimer, arg, timer);
+
+ OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER);
+ mode = ktimer->mode;
+ stop_flag = ktimer->stop_flag;
+ OsalMutexUnlock(&ktimer->mutex);
+
+ if (!stop_flag) {
+ ktimer->func(ktimer->arg);
+ OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER);
+ msec = ktimer->msec;
+ OsalMutexUnlock(&ktimer->mutex);
+ if (mode == OSAL_TIMER_LOOP) {
+ ktimer->timer.expires = jiffies + msecs_to_jiffies(msec);
+ mod_timer(&ktimer->timer, ktimer->timer.expires);
+ }
+ } else {
+ del_timer(&ktimer->timer);
+ OsalMutexDestroy(&ktimer->mutex);
+ OsalMemFree(ktimer);
+ HDF_LOGI("%s timer is stop", __func__);
+ }
+}
+
+int32_t OsalTimerCreate(OsalTimer *timer, uint32_t interval, OsalTimerFunc func, uintptr_t arg)
+{
+ struct osal_ktimer *ktimer = NULL;
+
+ if (func == NULL || timer == NULL || interval == 0) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ ktimer = (struct osal_ktimer *)OsalMemCalloc(sizeof(*ktimer));
+ if (ktimer == NULL) {
+ HDF_LOGE("%s malloc fail", __func__);
+ timer->realTimer = NULL;
+ return HDF_ERR_MALLOC_FAIL;
+ }
+
+ ktimer->arg = arg;
+ ktimer->func = func;
+ ktimer->msec = interval;
+ ktimer->stop_flag = false;
+ OsalMutexInit(&ktimer->mutex);
+ timer->realTimer = (void *)ktimer;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalTimerCreate);
+
+static int32_t OsalTimerStart(OsalTimer *timer, OsalTimerMode mode)
+{
+ struct osal_ktimer *ktimer = NULL;
+ struct timer_list *timer_id = NULL;
+
+ if (timer == NULL || timer->realTimer == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ ktimer = (struct osal_ktimer *)timer->realTimer;
+ timer_id = &ktimer->timer;
+ timer_setup(timer_id, osal_timer_callback, 0);
+ ktimer->mode = mode;
+ timer_id->expires = jiffies + msecs_to_jiffies(ktimer->msec);
+ add_timer(timer_id);
+
+ return HDF_SUCCESS;
+}
+
+int32_t OsalTimerStartOnce(OsalTimer *timer)
+{
+ return OsalTimerStart(timer, OSAL_TIMER_ONCE);
+}
+EXPORT_SYMBOL(OsalTimerStartOnce);
+
+int32_t OsalTimerStartLoop(OsalTimer *timer)
+{
+ return OsalTimerStart(timer, OSAL_TIMER_LOOP);
+}
+
+EXPORT_SYMBOL(OsalTimerStartLoop);
+
+int32_t OsalTimerSetTimeout(OsalTimer *timer, uint32_t interval)
+{
+ struct osal_ktimer *ktimer = NULL;
+
+ if (timer == NULL || timer->realTimer == NULL || interval == 0) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ ktimer = (struct osal_ktimer *)timer->realTimer;
+ if (ktimer->msec == interval)
+ return HDF_SUCCESS;
+
+ OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER);
+ ktimer->msec = interval;
+ OsalMutexUnlock(&ktimer->mutex);
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalTimerSetTimeout);
+
+int32_t OsalTimerDelete(OsalTimer *timer)
+{
+ struct osal_ktimer *ktimer = NULL;
+
+ if (timer == NULL || timer->realTimer == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ ktimer = (struct osal_ktimer *)timer->realTimer;
+ OsalMutexTimedLock(&ktimer->mutex, HDF_WAIT_FOREVER);
+ ktimer->stop_flag = true;
+ OsalMutexUnlock(&ktimer->mutex);
+
+ if (ktimer->mode == OSAL_TIMER_ONCE)
+ mod_timer(&ktimer->timer, ktimer->timer.expires);
+
+ timer->realTimer = NULL;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(OsalTimerDelete);
+
diff --git a/adapter/khdf/linux/osal/src/osal_workqueue.c b/adapter/khdf/linux/osal/src/osal_workqueue.c
new file mode 100644
index 00000000..102fdf20
--- /dev/null
+++ b/adapter/khdf/linux/osal/src/osal_workqueue.c
@@ -0,0 +1,213 @@
+/*
+ * osal_workqueue.c
+ *
+ * osal driver
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "hdf_workqueue.h"
+#include
+#include "hdf_log.h"
+#include "osal_mem.h"
+
+#define HDF_LOG_TAG hdf_workqueue
+
+struct WorkWrapper {
+ struct delayed_work work;
+ HdfWorkFunc workFunc;
+ void *para;
+};
+
+int32_t HdfWorkQueueInit(HdfWorkQueue *queue, char *name)
+{
+ HDF_LOGD("%s entry", __func__);
+
+ if (queue == NULL || name == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ queue->realWorkQueue = create_singlethread_workqueue(name);
+ if (queue->realWorkQueue == NULL) {
+ HDF_LOGE("%s create queue fail", __func__);
+ return HDF_FAILURE;
+ }
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(HdfWorkQueueInit);
+
+static void WorkEntry(struct work_struct *work)
+{
+ struct WorkWrapper *wrapper = NULL;
+ if (work != NULL) {
+ wrapper = (struct WorkWrapper *)work;
+ if (wrapper->workFunc != NULL)
+ wrapper->workFunc(wrapper->para);
+ else
+ HDF_LOGE("%s routine null", __func__);
+ } else {
+ HDF_LOGE("%s work null", __func__);
+ }
+}
+
+int32_t HdfWorkInit(HdfWork *work, HdfWorkFunc func, void *para)
+{
+ struct work_struct *realWork = NULL;
+ struct WorkWrapper *wrapper = NULL;
+
+ if (work == NULL || func == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ work->realWork = NULL;
+
+ wrapper = (struct WorkWrapper *)OsalMemCalloc(sizeof(*wrapper));
+ if (wrapper == NULL) {
+ HDF_LOGE("%s malloc fail", __func__);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ realWork = &(wrapper->work.work);
+ wrapper->workFunc = func;
+ wrapper->para = para;
+
+ INIT_WORK(realWork, WorkEntry);
+ work->realWork = wrapper;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(HdfWorkInit);
+
+int32_t HdfDelayedWorkInit(HdfWork *work, HdfWorkFunc func, void *para)
+{
+ struct delayed_work *realWork = NULL;
+ struct WorkWrapper *wrapper = NULL;
+
+ if (work == NULL || func == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ work->realWork = NULL;
+
+ wrapper = (struct WorkWrapper *)OsalMemCalloc(sizeof(*wrapper));
+ if (wrapper == NULL) {
+ HDF_LOGE("%s malloc fail", __func__);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ realWork = &(wrapper->work);
+ wrapper->workFunc = func;
+ wrapper->para = para;
+
+ INIT_DELAYED_WORK(realWork, WorkEntry);
+ work->realWork = wrapper;
+
+ return HDF_SUCCESS;
+}
+EXPORT_SYMBOL(HdfDelayedWorkInit);
+
+void HdfWorkDestroy(HdfWork *work)
+{
+ if (work == NULL || work->realWork == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return;
+ }
+
+ OsalMemFree(work->realWork);
+ work->realWork = NULL;
+
+ return;
+}
+EXPORT_SYMBOL(HdfWorkDestroy);
+
+void HdfDelayedWorkDestroy(HdfWork *work)
+{
+ if (work == NULL || work->realWork == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return;
+ }
+
+ return HdfWorkDestroy(work);
+}
+EXPORT_SYMBOL(HdfDelayedWorkDestroy);
+
+void HdfWorkQueueDestroy(HdfWorkQueue *queue)
+{
+ if (queue == NULL || queue->realWorkQueue == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return;
+ }
+
+ destroy_workqueue(queue->realWorkQueue);
+
+ return;
+}
+EXPORT_SYMBOL(HdfWorkQueueDestroy);
+
+bool HdfAddWork(HdfWorkQueue *queue, HdfWork *work)
+{
+ if (queue == NULL || queue->realWorkQueue == NULL || work == NULL || work->realWork == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return false;
+ }
+
+ return queue_work(queue->realWorkQueue, &((struct WorkWrapper *)work->realWork)->work.work);
+}
+EXPORT_SYMBOL(HdfAddWork);
+
+bool HdfAddDelayedWork(HdfWorkQueue *queue, HdfWork *work, uint32_t ms)
+{
+ if (queue == NULL || queue->realWorkQueue == NULL || work == NULL || work->realWork == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return false;
+ }
+
+ return queue_delayed_work(queue->realWorkQueue, &((struct WorkWrapper *)work->realWork)->work,
+ msecs_to_jiffies((unsigned long)ms));
+}
+EXPORT_SYMBOL(HdfAddDelayedWork);
+
+unsigned int HdfWorkBusy(HdfWork *work)
+{
+ if (work == NULL || work->realWork == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return 0;
+ }
+
+ return work_busy(&((struct WorkWrapper *)work->realWork)->work.work);
+}
+EXPORT_SYMBOL(HdfWorkBusy);
+
+bool HdfCancelWorkSync(HdfWork *work)
+{
+ if (work == NULL || work->realWork == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return false;
+ }
+
+ return cancel_work_sync(&((struct WorkWrapper *)work->realWork)->work.work);
+}
+EXPORT_SYMBOL(HdfCancelWorkSync);
+
+bool HdfCancelDelayedWorkSync(HdfWork *work)
+{
+ if (work == NULL || work->realWork == NULL) {
+ HDF_LOGE("%s invalid para", __func__);
+ return false;
+ }
+
+ return cancel_delayed_work_sync(&((struct WorkWrapper *)work->realWork)->work);
+}
+EXPORT_SYMBOL(HdfCancelDelayedWorkSync);
+
diff --git a/adapter/khdf/linux/patch_hdf.sh b/adapter/khdf/linux/patch_hdf.sh
new file mode 100755
index 00000000..127654fd
--- /dev/null
+++ b/adapter/khdf/linux/patch_hdf.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+set -e
+
+OHOS_SOURCE_ROOT=$1
+KERNEL_BUILD_ROOT=$2
+HDF_PATCH_FILE=$3
+
+ln_list=(
+ $OHOS_SOURCE_ROOT/drivers/hdf_core/adapter/khdf/linux drivers/hdf/khdf
+ $OHOS_SOURCE_ROOT/drivers/hdf_core/framework drivers/hdf/framework
+ $OHOS_SOURCE_ROOT/drivers/hdf_core/framework/include include/hdf
+)
+
+cp_list=(
+ $OHOS_SOURCE_ROOT/third_party/bounds_checking_function ./
+ $OHOS_SOURCE_ROOT/device/soc/hisilicon/common/platform/wifi drivers/hdf/
+ $OHOS_SOURCE_ROOT/third_party/FreeBSD/sys/dev/evdev drivers/hdf/
+)
+
+function copy_external_compents()
+{
+ for ((i=0; i<${#cp_list[*]}; i+=2))
+ do
+ dst_dir=${cp_list[$(expr $i + 1)]}/${cp_list[$i]##*/}
+ mkdir -p $dst_dir
+ [ -d ${cp_list[$i]}/ ] && cp -arfL ${cp_list[$i]}/* $dst_dir/
+ done
+}
+
+function ln_hdf_repos()
+{
+ for ((i=0; i<${#ln_list[*]}; i+=2))
+ do
+ ln -sf ${ln_list[$i]} ${ln_list[$(expr $i + 1)]}
+ done
+}
+
+function main()
+{
+ cd $KERNEL_BUILD_ROOT
+ patch -p1 < $HDF_PATCH_FILE
+ ln_hdf_repos
+ copy_external_compents
+ cd -
+}
+
+main
diff --git a/adapter/khdf/linux/platform/Kconfig b/adapter/khdf/linux/platform/Kconfig
new file mode 100644
index 00000000..5047d4ae
--- /dev/null
+++ b/adapter/khdf/linux/platform/Kconfig
@@ -0,0 +1,115 @@
+config DRIVERS_HDF_PLATFORM
+ bool "Enable HDF platform driver"
+ default n
+ depends on DRIVERS_HDF
+ help
+ Answer Y to enable HDF platform driver.
+
+config DRIVERS_HDF_PLATFORM_MIPI_DSI
+ bool "Enable HDF platform mipi dsi driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform mipi dsi driver.
+
+config DRIVERS_HDF_PLATFORM_MIPI_CSI
+ bool "Enable HDF platform mipi csi driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform mipi csi driver.
+
+config DRIVERS_HDF_PLATFORM_GPIO
+ bool "Enable HDF platform gpio driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform gpio driver.
+
+config DRIVERS_HDF_PLATFORM_I2C
+ bool "Enable HDF platform i2c driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform i2c driver.
+
+config DRIVERS_HDF_PLATFORM_WATCHDOG
+ bool "Enable HDF platform watchdog driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform watchdog driver.
+
+config DRIVERS_HDF_PLATFORM_PWM
+ bool "Enable HDF platform pwm driver"
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform pwm driver.
+
+config DRIVERS_HDF_PLATFORM_UART
+ bool "Enable HDF platform uart driver"
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform uart driver.
+
+config DRIVERS_HDF_PLATFORM_SDIO
+ bool "Enable HDF platform sdio driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM && DRIVERS_HDF_PLATFORM_MMC
+ help
+ Answer Y to enable HDF platform sdio driver.
+
+config DRIVERS_HDF_PLATFORM_EMMC
+ bool "Enable HDF platform emmc driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform emmc driver.
+
+config DRIVERS_HDF_PLATFORM_MMC
+ bool "Enable HDF platform mmc driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform mmc driver.
+
+config DRIVERS_HDF_PLATFORM_SPI
+ bool "Enable HDF platform spi driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform spi driver.
+
+config DRIVERS_HDF_PLATFORM_RTC
+ bool "Enable HDF platform rtc driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform rtc driver.
+
+config PWM_HI35XX
+ bool "hi35xx pwm driver"
+ depends on PWM
+ help
+ Answer Y to enable hi35xx pwm driver
+
+config DRIVERS_HDF_PLATFORM_REGULATOR
+ bool "Enable HDF platform regulator driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform regulator driver.
+
+config DRIVERS_HDF_PLATFORM_ADC
+ bool "Enable HDF platform adc driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform adc driver.
+
+config DRIVERS_HDF_PLATFORM_TRACE
+ bool "Enable HDF platform trace driver"
+ default n
+ depends on DRIVERS_HDF_PLATFORM
+ help
+ Answer Y to enable HDF platform trace driver.
diff --git a/adapter/khdf/linux/platform/Makefile b/adapter/khdf/linux/platform/Makefile
new file mode 100644
index 00000000..793693e3
--- /dev/null
+++ b/adapter/khdf/linux/platform/Makefile
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM) += fwk/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_MIPI_DSI) += mipi_dsi/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_MIPI_CSI) += mipi_csi/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_GPIO) += gpio/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_I2C) += i2c/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_WATCHDOG) += watchdog/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_PWM) += pwm/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_UART) += uart/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_SPI) += spi/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_RTC) += rtc/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_ADC) += adc/
+obj-$(CONFIG_DRIVERS_HDF_PLATFORM_REGULATOR) += regulator/
diff --git a/adapter/khdf/linux/platform/adc/Makefile b/adapter/khdf/linux/platform/adc/Makefile
new file mode 100644
index 00000000..d982a8f5
--- /dev/null
+++ b/adapter/khdf/linux/platform/adc/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2022 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+include drivers/hdf/khdf/platform/platform.mk
+
+obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/adc/adc_core.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/adc/adc_if.o \
+ ./adc_iio_adapter.o
diff --git a/adapter/khdf/linux/platform/adc/adc_iio_adapter.c b/adapter/khdf/linux/platform/adc/adc_iio_adapter.c
new file mode 100644
index 00000000..c7eb5676
--- /dev/null
+++ b/adapter/khdf/linux/platform/adc/adc_iio_adapter.c
@@ -0,0 +1,226 @@
+/*
+ * adc driver adapter of linux
+ *
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include "device_resource_if.h"
+#include "hdf_base.h"
+#include "hdf_device_desc.h"
+#include "hdf_log.h"
+#include "osal_mem.h"
+#include "securec.h"
+#include "adc_core.h"
+
+#define ADC_STRING_VALUE_LEN 15
+#define ADC_DRIVER_PATHNAME_LEN 128
+#define INT_MAX_VALUE 2147483647
+#define FILE_MODE 0600
+#define DECIMAL_SHIFT_LEFT 10
+
+static char g_driverPathname[ADC_DRIVER_PATHNAME_LEN] = {0};
+struct AdcIioDevice {
+ struct AdcDevice device;
+ volatile unsigned char *regBase;
+ volatile unsigned char *pinCtrlBase;
+ uint32_t regBasePhy;
+ uint32_t regSize;
+ uint32_t deviceNum;
+ uint32_t dataWidth;
+ uint32_t validChannel;
+ uint32_t scanMode;
+ uint32_t delta;
+ uint32_t deglitch;
+ uint32_t glitchSample;
+ uint32_t rate;
+};
+
+static int32_t AdcIioRead(struct AdcDevice *device, uint32_t channel, uint32_t *val)
+{
+ int ret;
+ loff_t pos = 0;
+ struct file *fp = NULL;
+ unsigned char strValue[ADC_STRING_VALUE_LEN] = {0};
+
+ if (device == NULL || device->priv == NULL) {
+ HDF_LOGE("%s: Illegal object", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (val == NULL) {
+ HDF_LOGE("%s: Illegal parameter", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ fp = (struct file *)device->priv;
+ ret = kernel_read(fp, strValue, ADC_STRING_VALUE_LEN, &pos);
+ if (ret < 0) {
+ HDF_LOGE("%s: kernel_read fail %d", __func__, ret);
+ return HDF_PLT_ERR_OS_API;
+ }
+ *val = simple_strtoul(strValue, NULL, 0);
+
+ return HDF_SUCCESS;
+}
+
+static int32_t AdcIioStop(struct AdcDevice *device)
+{
+ int ret;
+ struct file *fp = NULL;
+
+ ret = HDF_FAILURE;
+ if (device == NULL || device->priv == NULL) {
+ HDF_LOGE("%s: Illegal object", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ fp = (struct file *)device->priv;
+ if (!IS_ERR(fp)) {
+ ret = filp_close(fp, NULL);
+ }
+
+ return ret;
+}
+
+static int32_t AdcIioStart(struct AdcDevice *device)
+{
+ struct file *fp = NULL;
+
+ if (device == NULL) {
+ HDF_LOGE("%s: device is NULL", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ fp = filp_open(g_driverPathname, O_RDWR | O_NOCTTY | O_NDELAY, FILE_MODE);
+ if (IS_ERR(fp)) {
+ HDF_LOGE("filp open fail");
+ return HDF_PLT_ERR_OS_API;
+ }
+ device->priv = fp;
+
+ return HDF_SUCCESS;
+}
+static const struct AdcMethod g_method = {
+ .read = AdcIioRead,
+ .stop = AdcIioStop,
+ .start = AdcIioStart,
+};
+
+static int32_t AdcIioReadDrs(struct AdcIioDevice *adcDevice, const struct DeviceResourceNode *node)
+{
+ int32_t ret;
+ const char *drName = NULL;
+ int32_t drNameLen;
+ struct DeviceResourceIface *drsOps = NULL;
+
+ drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
+ if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetString == NULL) {
+ HDF_LOGE("%s: invalid drs ops", __func__);
+ return HDF_ERR_NOT_SUPPORT;
+ }
+
+ ret = drsOps->GetString(node, "driver_name", &drName, "/sys/bus/iio/devices/iio:device0/in_voltage0-voltage0_raw");
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: read driver_name failed", __func__);
+ return ret;
+ }
+ drNameLen = strlen(drName);
+ if (drNameLen > (ADC_DRIVER_PATHNAME_LEN - 1)) {
+ HDF_LOGE("%s: Illegal length of drName", __func__);
+ return HDF_FAILURE;
+ }
+ ret = memcpy_s(g_driverPathname, ADC_DRIVER_PATHNAME_LEN, drName, drNameLen);
+ if (ret != 0) {
+ HDF_LOGE("%s: memcpy drName fail", __func__);
+ return HDF_FAILURE;
+ }
+
+ ret = drsOps->GetUint32(node, "deviceNum", &adcDevice->deviceNum, 0);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: read deviceNum failed", __func__);
+ return ret;
+ }
+
+ ret = drsOps->GetUint32(node, "scanMode", &adcDevice->scanMode, 0);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: read scanMode failed", __func__);
+ return ret;
+ }
+
+ ret = drsOps->GetUint32(node, "rate", &adcDevice->rate, 0);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: read rate failed", __func__);
+ return ret;
+ }
+
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxAdcInit(struct HdfDeviceObject *device)
+{
+ int32_t ret;
+ struct AdcIioDevice *adcDevice = NULL;
+
+ if (device == NULL) {
+ HDF_LOGE("%s: device is NULL", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (device->property == NULL) {
+ HDF_LOGE("%s: property of device is NULL", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ adcDevice = (struct AdcIioDevice *)OsalMemCalloc(sizeof(*adcDevice));
+ if (adcDevice == NULL) {
+ HDF_LOGE("%s: alloc adcDevice failed", __func__);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ device->priv = adcDevice;
+ ret = AdcIioReadDrs(adcDevice, device->property);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: read drs failed:%d", __func__, ret);
+ OsalMemFree(adcDevice);
+ return ret;
+ }
+
+ adcDevice->device.devNum = adcDevice->deviceNum;
+ adcDevice->device.ops = &g_method;
+ ret = AdcDeviceAdd(&adcDevice->device);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: add adc device:%u failed", __func__, adcDevice->deviceNum);
+ OsalMemFree(adcDevice);
+ return ret;
+ }
+
+ return HDF_SUCCESS;
+}
+
+static void LinuxAdcRelease(struct HdfDeviceObject *device)
+{
+ if (device == NULL || device->priv == NULL) {
+ HDF_LOGE("%s: Illegal parameter", __func__);
+ return;
+ }
+ AdcDeviceRemove(device->priv);
+ OsalMemFree(device->priv);
+}
+
+struct HdfDriverEntry g_adcLinuxDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = NULL,
+ .Init = LinuxAdcInit,
+ .Release = LinuxAdcRelease,
+ .moduleName = "linux_adc_adapter",
+};
+HDF_INIT(g_adcLinuxDriverEntry);
diff --git a/adapter/khdf/linux/platform/emmc/Makefile b/adapter/khdf/linux/platform/emmc/Makefile
new file mode 100644
index 00000000..13a23aab
--- /dev/null
+++ b/adapter/khdf/linux/platform/emmc/Makefile
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+include drivers/hdf/khdf/platform/platform.mk
+
+obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/mmc/emmc_if.o \
+ ./emmc_adapter.o
diff --git a/adapter/khdf/linux/platform/fwk/Makefile b/adapter/khdf/linux/platform/fwk/Makefile
new file mode 100644
index 00000000..281f87fc
--- /dev/null
+++ b/adapter/khdf/linux/platform/fwk/Makefile
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2020-2022 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+include drivers/hdf/khdf/platform/platform.mk
+
+obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/fwk/platform_common.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/fwk/platform_device.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/fwk/platform_event.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/fwk/platform_manager.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/fwk/platform_queue.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/fwk/platform_dumper.o
+
+ifeq ($(CONFIG_DRIVERS_HDF_PLATFORM_TRACE), y)
+obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/fwk/platform_trace_transfer.o \
+ ./platform_trace.o
+endif
+
+obj-y += ./plat_common.o
diff --git a/adapter/khdf/linux/platform/fwk/plat_common.c b/adapter/khdf/linux/platform/fwk/plat_common.c
new file mode 100644
index 00000000..7c1c0178
--- /dev/null
+++ b/adapter/khdf/linux/platform/fwk/plat_common.c
@@ -0,0 +1,26 @@
+/*
+ * plat_common.c
+ *
+ * platform common utils on linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "platform_core.h"
+
+#include
+
+bool PlatInIrqContext(void)
+{
+ return (in_irq() || in_nmi() || in_serving_softirq());
+}
diff --git a/adapter/khdf/linux/platform/fwk/platform_trace.c b/adapter/khdf/linux/platform/fwk/platform_trace.c
new file mode 100644
index 00000000..64a92435
--- /dev/null
+++ b/adapter/khdf/linux/platform/fwk/platform_trace.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "platform_trace.h"
+#include "hdf_base.h"
+#include "hdf_log.h"
+#include "osal_file.h"
+#include "osal_mem.h"
+#include "securec.h"
+#include "stdarg.h"
+#include
+#include
+
+#define CREATE_TRACE_POINTS
+#include
+
+#define PLATFORM_TRACE_MSG_MAX_LEN 512
+void PlatformTraceAddMsg(const char *module, const char *moduleFun, const char *fmt, ...)
+{
+ int length;
+ va_list argList;
+ char messages[PLATFORM_TRACE_MSG_MAX_LEN + 1] = {'\0'};
+ if ((module == NULL) || (moduleFun == NULL)) {
+ HDF_LOGE("PlatformTraceAddMsg params illegal", module, moduleFun);
+ return;
+ }
+
+ length = snprintf_s(messages, PLATFORM_TRACE_MSG_MAX_LEN + 1, PLATFORM_TRACE_MSG_MAX_LEN,
+ "module:%s function:%s params: ", module, moduleFun);
+ if (length < 0) {
+ HDF_LOGE("PlatformTraceAddMsg[%s][%s] generate messages fail[%d]!", module, moduleFun, length);
+ return;
+ }
+
+ va_start(argList, fmt);
+ length = vsprintf_s(messages + length - 1, PLATFORM_TRACE_MSG_MAX_LEN, fmt, argList);
+ va_end(argList);
+ if (length < 0) {
+ HDF_LOGE("PlatformTraceAddMsg[%s][%s] generate messages fail[%d]!", module, moduleFun, length);
+ return;
+ }
+
+ trace_platfrom_trace_record_messages(messages);
+}
+
+void PlatformTraceAddUintMsg(int module, int moduleFun, uint infos[], uint8_t size)
+{
+ int ret;
+ int i;
+ char messages[PLATFORM_TRACE_MSG_MAX_LEN + 1] = {0};
+ const char *moduleMean = PlatformTraceModuleExplainGet(module);
+ const char *moduleFunMean = PlatformTraceFunExplainGet(moduleFun);
+ if ((moduleMean == NULL) || (moduleFunMean == NULL)) {
+ HDF_LOGE("PlatformTraceAddUintMsg module[%d, %d] info illegal", module, moduleFun);
+ return;
+ }
+
+ if ((size <= 0) || (size > PLATFORM_TRACE_UINT_PARAM_SIZE_MAX)) {
+ HDF_LOGE("PlatformTraceAddUintMsg %hhu size illegal", size);
+ return;
+ }
+ if ((module < PLATFORM_TRACE_MODULE_I2S) || (module >= PLATFORM_TRACE_MODULE_MAX)) {
+ HDF_LOGE("PlatformTraceAddUintMsg %d module illegal", module);
+ return;
+ }
+ if ((moduleFun < PLATFORM_TRACE_MODULE_I2S_FUN) || (moduleFun >= PLATFORM_TRACE_MODULE_MAX_FUN)) {
+ HDF_LOGE("PlatformTraceAddUintMsg %d moduleFun illegal", moduleFun);
+ return;
+ }
+
+ ret = snprintf_s(messages, PLATFORM_TRACE_MSG_MAX_LEN + 1, PLATFORM_TRACE_MSG_MAX_LEN,
+ "module:%s function:%s params:", moduleMean, moduleFunMean);
+ if (ret < 0) {
+ HDF_LOGE("PlatformTraceAddUintMsg[%s][%s] generate messages fail[%d]!", moduleMean, moduleFunMean, ret);
+ return;
+ }
+ for (i = 0; i < size; i++) {
+ snprintf_s(messages + strlen(messages), PLATFORM_TRACE_MSG_MAX_LEN + 1 - strlen(messages),
+ PLATFORM_TRACE_MSG_MAX_LEN - strlen(messages),
+ "%d, ", infos[i]);
+ if ((ret < 0) || (strlen(messages) >= PLATFORM_TRACE_MSG_MAX_LEN)) {
+ HDF_LOGE("PlatformTraceAddUintMsg[%s][%s] generate messages fail[%d][%d]!", moduleMean, moduleFunMean, ret, strlen(messages));
+ return;
+ }
+ }
+
+ trace_platfrom_trace_record_messages(messages);
+ return;
+}
+
+static bool TraceIsOpen()
+{
+#ifndef CONFIG_TRACING
+ return false;
+#else
+ return true;
+#endif
+}
+
+static ssize_t TraceFileWrite(OsalFile *file, const void *string, uint32_t length)
+{
+ ssize_t ret;
+ loff_t pos;
+ mm_segment_t org_fs;
+ struct file *fp = NULL;
+
+ if (file == NULL || IS_ERR_OR_NULL(file->realFile) || string == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ fp = (struct file *)file->realFile;
+ pos = fp->f_pos;
+ org_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ ret = vfs_write(fp, string, length, &pos);
+ set_fs(org_fs);
+ if (ret < 0) {
+ HDF_LOGE("%s write file length %d fail %d", __func__, length, ret);
+ return HDF_FAILURE;
+ }
+
+ return ret;
+}
+
+static ssize_t TraceFileRead(OsalFile *file, void *buf, uint32_t length)
+{
+ ssize_t ret;
+ mm_segment_t org_fs;
+ loff_t pos;
+ struct file *fp = NULL;
+
+ if (file == NULL || IS_ERR_OR_NULL(file->realFile) || buf == NULL) {
+ HDF_LOGE("%s invalid param", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ fp = (struct file *)file->realFile;
+ org_fs = get_fs();
+ set_fs(KERNEL_DS);
+ pos = fp->f_pos;
+
+ ret = vfs_read(fp, buf, length, &pos);
+ set_fs(org_fs);
+ if (ret < 0) {
+ HDF_LOGE("%s read file length %d fail %d", __func__, length, ret);
+ return HDF_FAILURE;
+ }
+
+ return ret;
+}
+
+#define TRACE_EVENT_ENABLE_PATH "/sys/kernel/debug/tracing/events/platform_trace_event/enable"
+static int32_t TraceEventFileWrite(const char *enable)
+{
+ int32_t ret;
+ OsalFile file;
+ ret = OsalFileOpen(&file, TRACE_EVENT_ENABLE_PATH, OSAL_O_RDWR, OSAL_S_IWRITE);
+ if (ret < 0) {
+ HDF_LOGE("%s %d open err:%d %s", __func__, __LINE__, ret, TRACE_EVENT_ENABLE_PATH);
+ return ret;
+ }
+
+ ret = TraceFileWrite(&file, enable, 1);
+ if (ret < 0) {
+ HDF_LOGE("%s %d write err:%d %s", __func__, __LINE__, ret, TRACE_EVENT_ENABLE_PATH);
+ OsalFileClose(&file);
+ return ret;
+ }
+
+ OsalFileClose(&file);
+ return HDF_SUCCESS;
+}
+
+int32_t PlatformTraceStart(void)
+{
+ if (!TraceIsOpen()) {
+ return HDF_SUCCESS;
+ }
+ TraceEventFileWrite("1");
+ return HDF_SUCCESS;
+}
+
+int32_t PlatformTraceStop(void)
+{
+ if (!TraceIsOpen()) {
+ return HDF_SUCCESS;
+ }
+ TraceEventFileWrite("0");
+ return HDF_SUCCESS;
+}
+
+#define TRACE_EVENT_READ_PATH "/sys/kernel/debug/tracing/trace"
+#define TRACE_EVENT_READ_MATCH "platfrom_trace_record_messages"
+#define TRACE_INFO_DUMPER_LEN 512
+#define TRACE_INFO_DUMPER_FILE_MAX_LEN 102400
+void PlatformTraceInfoDump(void)
+{
+ int32_t ret;
+ char buf[TRACE_INFO_DUMPER_LEN];
+ OsalFile file;
+ int32_t len = 0;
+ off_t off;
+ if (!TraceIsOpen()) {
+ return;
+ }
+ ret = OsalFileOpen(&file, TRACE_EVENT_READ_PATH, OSAL_O_RDWR, OSAL_S_IREAD);
+ if (ret < 0) {
+ HDF_LOGE("PlatformTraceInfoDump open %s err:%d", TRACE_EVENT_READ_PATH, ret);
+ return;
+ }
+
+ do {
+ if (memset_s(buf, TRACE_INFO_DUMPER_LEN, 0, TRACE_INFO_DUMPER_LEN) != EOK) {
+ break;
+ }
+ ret = TraceFileRead(&file, buf, TRACE_INFO_DUMPER_LEN - 1);
+ if (ret > 0) {
+ len += ret;
+ off = OsalFileLseek(&file, len, 0);
+ printk("%s", buf);
+ }
+ if ((len >= TRACE_INFO_DUMPER_FILE_MAX_LEN) || (off < 0)) {
+ HDF_LOGE("PlatformTraceInfoDump trace info too big[%d] or lseek error[%ld]", len, off);
+ break;
+ }
+ } while (ret > 0);
+
+ OsalFileClose(&file);
+}
+
+void PlatformTraceReset(void)
+{
+ return;
+}
diff --git a/adapter/khdf/linux/platform/gpio/Makefile b/adapter/khdf/linux/platform/gpio/Makefile
new file mode 100644
index 00000000..f4ad6518
--- /dev/null
+++ b/adapter/khdf/linux/platform/gpio/Makefile
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+include drivers/hdf/khdf/platform/platform.mk
+
+obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/gpio/gpio_core.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/gpio/gpio_if.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/gpio/gpio_manager.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/gpio/gpio_service.o \
+ ./gpio_adapter.o
diff --git a/adapter/khdf/linux/platform/gpio/gpio_adapter.c b/adapter/khdf/linux/platform/gpio/gpio_adapter.c
new file mode 100644
index 00000000..37a44a5b
--- /dev/null
+++ b/adapter/khdf/linux/platform/gpio/gpio_adapter.c
@@ -0,0 +1,328 @@
+/*
+ * gpio_adapter.h
+ *
+ * gpio driver adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include "device_resource_if.h"
+#include "gpio/gpio_core.h"
+#include "hdf_base.h"
+#include "hdf_device_desc.h"
+#include "hdf_dlist.h"
+#include "hdf_log.h"
+#include "osal_mem.h"
+#include "osal_mutex.h"
+
+#define HDF_LOG_TAG linux_gpio_adapter
+
+#define LINUX_GPIO_NUM_MAX 0x7FFF
+
+static int32_t LinuxGpioWrite(struct GpioCntlr *cntlr, uint16_t local, uint16_t val)
+{
+ if (cntlr == NULL) {
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ gpio_set_value(cntlr->start + local, val);
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxGpioRead(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val)
+{
+ if (cntlr == NULL) {
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (val != NULL) {
+ *val = (gpio_get_value(cntlr->start + local) == 0) ?
+ GPIO_VAL_LOW : GPIO_VAL_HIGH;
+ return HDF_SUCCESS;
+ }
+ HDF_LOGE("%s: val is NULL!\n", __func__);
+ return HDF_ERR_BSP_PLT_API_ERR;
+}
+
+static int32_t LinuxGpioSetDir(struct GpioCntlr *cntlr, uint16_t local, uint16_t dir)
+{
+ int32_t ret;
+ int val;
+
+ if (cntlr == NULL) {
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ switch (dir) {
+ case GPIO_DIR_IN:
+ ret = gpio_direction_input(cntlr->start + local);
+ if (ret < 0) {
+ return HDF_ERR_BSP_PLT_API_ERR;
+ }
+ break;
+ case GPIO_DIR_OUT:
+ val = gpio_get_value(cntlr->start + local);
+ if (val < 0) {
+ return HDF_ERR_BSP_PLT_API_ERR;
+ }
+ ret = gpio_direction_output(cntlr->start + local, val);
+ if (ret < 0) {
+ return HDF_ERR_BSP_PLT_API_ERR;
+ }
+ break;
+ default:
+ HDF_LOGE("%s: invalid dir:%d\n", __func__, dir);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxGpioGetDir(struct GpioCntlr *cntlr, uint16_t local, uint16_t *dir)
+{
+ int dirGet;
+
+ if (cntlr == NULL) {
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ dirGet = gpiod_get_direction(gpio_to_desc(cntlr->start + local));
+ if (dirGet < 0) {
+ return HDF_ERR_BSP_PLT_API_ERR;
+ }
+ *dir = (dirGet == GPIOF_DIR_IN) ? GPIO_DIR_IN : GPIO_DIR_OUT;
+ return HDF_SUCCESS;
+}
+
+static irqreturn_t LinuxGpioIrqDummy(int irq, void *data)
+{
+ (void)irq;
+ (void)data;
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t LinuxGpioIrqBridge(int irq, void *data)
+{
+ int gpio = (int)(uintptr_t)data;
+ struct GpioCntlr *cntlr = NULL;
+
+ cntlr = GpioCntlrGetByGpio(gpio);
+ GpioCntlrIrqCallback(cntlr, GpioCntlrGetLocal(cntlr, gpio));
+ GpioCntlrPut(cntlr);
+ return IRQ_HANDLED;
+}
+
+static int32_t LinuxGpioSetIrq(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode)
+{
+ int ret, irq;
+ unsigned long flags = 0;
+ uint16_t gpio;
+
+ if (cntlr == NULL) {
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ gpio = cntlr->start + local;
+
+ irq = gpio_to_irq(gpio);
+ if (irq < 0) {
+ HDF_LOGE("%s: gpio(%u) to irq fail:%d", __func__, gpio, irq);
+ return HDF_ERR_BSP_PLT_API_ERR;
+ }
+ flags |= (mode & GPIO_IRQ_TRIGGER_RISING) == 0 ? 0 : IRQF_TRIGGER_RISING;
+ flags |= (mode & GPIO_IRQ_TRIGGER_FALLING) == 0 ? 0 : IRQF_TRIGGER_FALLING;
+ flags |= (mode & GPIO_IRQ_TRIGGER_HIGH) == 0 ? 0 : IRQF_TRIGGER_HIGH;
+ flags |= (mode & GPIO_IRQ_TRIGGER_LOW) == 0 ? 0 : IRQF_TRIGGER_LOW;
+ HDF_LOGI("%s: gona request normal irq:%d(%u)\n", __func__, irq, gpio);
+ ret = request_irq(irq, LinuxGpioIrqBridge, flags,
+ "LinuxIrqBridge", (void *)(uintptr_t)gpio);
+ if (ret != 0) {
+ HDF_LOGI("%s: gona request threaded irq:%d(%u)\n", __func__, irq, gpio);
+ flags |= IRQF_ONESHOT;
+ ret = request_threaded_irq(irq, LinuxGpioIrqBridge, LinuxGpioIrqDummy, flags,
+ "LinuxIrqBridge", (void *)(uintptr_t)gpio);
+ }
+ if (ret == 0) {
+ disable_irq_nosync(irq); // disable on set
+ }
+ return (ret == 0) ? HDF_SUCCESS : HDF_ERR_BSP_PLT_API_ERR;
+}
+
+static int32_t LinuxGpioUnsetIrq(struct GpioCntlr *cntlr, uint16_t local)
+{
+ int irq;
+ uint16_t gpio;
+
+ if (cntlr == NULL) {
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ gpio = cntlr->start + local;
+ irq = gpio_to_irq(gpio);
+ if (irq < 0) {
+ HDF_LOGE("%s: gpio(%u) to irq fail:%d", __func__, gpio, irq);
+ return HDF_ERR_BSP_PLT_API_ERR;
+ }
+ HDF_LOGI("%s: gona free irq:%d\n", __func__, irq);
+ free_irq(irq, (void *)(uintptr_t)gpio);
+ return HDF_SUCCESS;
+}
+
+static inline int32_t LinuxGpioEnableIrq(struct GpioCntlr *cntlr, uint16_t local)
+{
+ int irq;
+ uint16_t gpio;
+
+ if (cntlr == NULL) {
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ gpio = cntlr->start + local;
+ irq = gpio_to_irq(gpio);
+ if (irq < 0) {
+ HDF_LOGE("%s: gpio(%u) to irq fail:%d", __func__, gpio, irq);
+ return HDF_ERR_BSP_PLT_API_ERR;
+ }
+ enable_irq(irq);
+ return HDF_SUCCESS;
+}
+
+static inline int32_t LinuxGpioDisableIrq(struct GpioCntlr *cntlr, uint16_t local)
+{
+ int irq;
+ uint16_t gpio;
+
+ if (cntlr == NULL) {
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ gpio = cntlr->start + local;
+ irq = gpio_to_irq(gpio);
+ if (irq < 0) {
+ HDF_LOGE("%s: gpio(%u) to irq fail:%d", __func__, gpio, irq);
+ return HDF_ERR_BSP_PLT_API_ERR;
+ }
+ disable_irq_nosync(irq); // nosync default in case used in own irq
+ return HDF_SUCCESS;
+}
+
+static struct GpioMethod g_method = {
+ .write = LinuxGpioWrite,
+ .read = LinuxGpioRead,
+ .setDir = LinuxGpioSetDir,
+ .getDir = LinuxGpioGetDir,
+ .setIrq = LinuxGpioSetIrq,
+ .unsetIrq = LinuxGpioUnsetIrq,
+ .enableIrq = LinuxGpioEnableIrq,
+ .disableIrq = LinuxGpioDisableIrq,
+};
+
+static int32_t LinuxGpioBind(struct HdfDeviceObject *device)
+{
+ (void)device;
+ return HDF_SUCCESS;
+}
+
+static int LinuxGpioMatchProbe(struct gpio_chip *chip, void *data)
+{
+ int32_t ret;
+ struct GpioCntlr *cntlr = NULL;
+
+ (void)data;
+ if (chip == NULL) {
+ return 0;
+ }
+ HDF_LOGI("%s: find gpio chip(start:%d, count:%u)", __func__, chip->base, chip->ngpio);
+ if (chip->base >= LINUX_GPIO_NUM_MAX || (chip->base + chip->ngpio) > LINUX_GPIO_NUM_MAX) {
+ HDF_LOGW("%s: chip(base:%d-num:%u) exceed range", __func__, chip->base, chip->ngpio);
+ return 0;
+ }
+
+ cntlr = (struct GpioCntlr *)OsalMemCalloc(sizeof(*cntlr));
+ if (cntlr == NULL) {
+ HDF_LOGE("%s: malloc cntlr fail!", __func__);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+
+ cntlr->ops = &g_method;
+ cntlr->start = (uint16_t)chip->base;
+ cntlr->count = (uint16_t)chip->ngpio;
+ ret = GpioCntlrAdd(cntlr);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: add gpio controller(start:%d, count:%u) fail:%d!",
+ __func__, cntlr->start, cntlr->count, ret);
+ OsalMemFree(cntlr);
+ return ret;
+ }
+
+ HDF_LOGI("%s: add gpio controller(start:%d, count:%u) succeed",
+ __func__, cntlr->start, cntlr->count);
+ return 0; // return 0 to continue
+}
+
+static int32_t LinuxGpioInit(struct HdfDeviceObject *device)
+{
+ if (device == NULL) {
+ HDF_LOGE("%s: Fail, device is NULL.", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ (void)gpiochip_find(device, LinuxGpioMatchProbe);
+ HDF_LOGI("%s: dev service:%s init done!", __func__, HdfDeviceGetServiceName(device));
+ return HDF_SUCCESS;
+}
+
+static int LinuxGpioMatchRelease(struct gpio_chip *chip, void *data)
+{
+ int32_t ret;
+ struct GpioCntlr *cntlr = NULL;
+ struct PlatformManager *manager = GpioManagerGet();
+
+ if (chip == NULL) {
+ return 0;
+ }
+ HDF_LOGI("%s: find gpio chip(start:%d, count:%u)", __func__, chip->base, chip->ngpio);
+ if (chip->base >= LINUX_GPIO_NUM_MAX || (chip->base + chip->ngpio) > LINUX_GPIO_NUM_MAX) {
+ HDF_LOGW("%s: chip(base:%d-num:%u) exceed range", __func__, chip->base, chip->ngpio);
+ return 0;
+ }
+
+ cntlr = GpioCntlrGetByGpio((uint16_t)chip->base);
+ if (cntlr == NULL) {
+ HDF_LOGW("%s: get cntlr failed for base:%d!", __func__, chip->base);
+ return 0;
+ }
+ GpioCntlrPut(cntlr); // !!! be careful to keep the reference count balanced
+
+ HDF_LOGI("%s: gona remove gpio controller(start:%d, count:%u)",
+ __func__, cntlr->start, cntlr->count);
+ GpioCntlrRemove(cntlr);
+ OsalMemFree(cntlr);
+ return 0; // return 0 to continue
+}
+
+static void LinuxGpioRelease(struct HdfDeviceObject *device)
+{
+ struct GpioCntlr *cntlr = NULL;
+
+ if (device == NULL) {
+ HDF_LOGE("%s: device is null!", __func__);
+ return;
+ }
+
+ (void)gpiochip_find(device, LinuxGpioMatchRelease);
+}
+
+struct HdfDriverEntry g_gpioLinuxDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = LinuxGpioBind,
+ .Init = LinuxGpioInit,
+ .Release = LinuxGpioRelease,
+ .moduleName = "linux_gpio_adapter",
+};
+HDF_INIT(g_gpioLinuxDriverEntry);
diff --git a/adapter/khdf/linux/platform/i2c/Makefile b/adapter/khdf/linux/platform/i2c/Makefile
new file mode 100644
index 00000000..0a522c27
--- /dev/null
+++ b/adapter/khdf/linux/platform/i2c/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+include drivers/hdf/khdf/platform/platform.mk
+
+obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/i2c/i2c_core.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/i2c/i2c_if.o \
+ ./i2c_adapter.o
diff --git a/adapter/khdf/linux/platform/i2c/i2c_adapter.c b/adapter/khdf/linux/platform/i2c/i2c_adapter.c
new file mode 100644
index 00000000..86859ddd
--- /dev/null
+++ b/adapter/khdf/linux/platform/i2c/i2c_adapter.c
@@ -0,0 +1,189 @@
+/*
+ * i2c_adapter.h
+ *
+ * i2c driver adapter of linux
+ *
+ * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include "hdf_device_desc.h"
+#include "hdf_log.h"
+#include "i2c_core.h"
+#include "osal_mem.h"
+
+#define HDF_LOG_TAG i2c_linux_adapter
+
+static struct i2c_msg *CreateLinuxI2cMsgs(struct I2cMsg *msgs, int16_t count)
+{
+ int16_t i;
+ struct i2c_msg *linuxMsgs = NULL;
+
+ linuxMsgs = (struct i2c_msg *)OsalMemCalloc(sizeof(*linuxMsgs) * count);
+ if (linuxMsgs == NULL) {
+ HDF_LOGE("%s: malloc linux msgs fail!", __func__);
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++) {
+ linuxMsgs[i].addr = msgs[i].addr;
+ linuxMsgs[i].buf = msgs[i].buf;
+ linuxMsgs[i].len = msgs[i].len;
+ linuxMsgs[i].flags = msgs[i].flags;
+ }
+ return linuxMsgs;
+}
+
+static inline void FreeLinxI2cMsgs(struct i2c_msg *msgs, int16_t count)
+{
+ OsalMemFree(msgs);
+ (void)count;
+}
+
+static int32_t LinuxI2cTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count)
+{
+ int32_t ret;
+ struct i2c_msg *linuxMsgs = NULL;
+
+ if (cntlr == NULL || cntlr->priv == NULL) {
+ HDF_LOGE("%s: cntlr or priv is null!", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ if (msgs == NULL || count <= 0) {
+ HDF_LOGE("%s: err params! count:%d", __func__, count);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ linuxMsgs = CreateLinuxI2cMsgs(msgs, count);
+ if (linuxMsgs == NULL) {
+ return HDF_ERR_MALLOC_FAIL;
+ }
+
+ ret = i2c_transfer((struct i2c_adapter *)cntlr->priv, linuxMsgs, count);
+ FreeLinxI2cMsgs(linuxMsgs, count);
+ return ret;
+}
+
+static struct I2cMethod g_method = {
+ .transfer = LinuxI2cTransfer,
+};
+
+static int32_t LinuxI2cBind(struct HdfDeviceObject *device)
+{
+ (void)device;
+ return HDF_SUCCESS;
+}
+
+static int LinuxI2cRemove(struct device *dev, void *data)
+{
+ struct I2cCntlr *cntlr = NULL;
+ struct i2c_adapter *adapter = NULL;
+
+ HDF_LOGI("%s: Enter", __func__);
+ (void)data;
+
+ if (dev == NULL) {
+ HDF_LOGE("%s: dev is null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ if (dev->type != &i2c_adapter_type) {
+ return HDF_SUCCESS; // continue remove
+ }
+
+ adapter = to_i2c_adapter(dev);
+ cntlr = I2cCntlrGet(adapter->nr);
+ if (cntlr != NULL) {
+ I2cCntlrPut(cntlr);
+ I2cCntlrRemove(cntlr);
+ i2c_put_adapter(adapter);
+ OsalMemFree(cntlr);
+ }
+ return HDF_SUCCESS;
+}
+
+static int LinuxI2cProbe(struct device *dev, void *data)
+{
+ int32_t ret;
+ struct I2cCntlr *cntlr = NULL;
+ struct i2c_adapter *adapter = NULL;
+
+ (void)data;
+
+ if (dev == NULL) {
+ HDF_LOGE("%s: dev is null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ if (dev->type != &i2c_adapter_type) {
+ return HDF_SUCCESS; // continue probe
+ }
+
+ HDF_LOGI("%s: Enter", __func__);
+ adapter = to_i2c_adapter(dev);
+ cntlr = (struct I2cCntlr *)OsalMemCalloc(sizeof(*cntlr));
+ if (cntlr == NULL) {
+ HDF_LOGE("%s: malloc cntlr fail!", __func__);
+ i2c_put_adapter(adapter);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+
+ cntlr->busId = adapter->nr;
+ cntlr->priv = adapter;
+ cntlr->ops = &g_method;
+ ret = I2cCntlrAdd(cntlr);
+ if (ret != HDF_SUCCESS) {
+ i2c_put_adapter(adapter);
+ OsalMemFree(cntlr);
+ cntlr = NULL;
+ HDF_LOGE("%s: add controller fail:%d", __func__, ret);
+ return ret;
+ }
+ HDF_LOGI("%s: i2c adapter %d add success", __func__, cntlr->busId);
+ return HDF_SUCCESS;
+}
+
+static int32_t LinuxI2cInit(struct HdfDeviceObject *device)
+{
+ int32_t ret;
+
+ HDF_LOGI("%s: Enter", __func__);
+ if (device == NULL) {
+ HDF_LOGE("%s: device is NULL", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ ret = i2c_for_each_dev(NULL, LinuxI2cProbe);
+ HDF_LOGI("%s: done", __func__);
+ return ret;
+}
+
+static void LinuxI2cRelease(struct HdfDeviceObject *device)
+{
+ HDF_LOGI("%s: enter", __func__);
+ if (device == NULL) {
+ HDF_LOGE("%s: device is NULL", __func__);
+ return;
+ }
+
+ (void)i2c_for_each_dev(NULL, LinuxI2cRemove);
+}
+
+struct HdfDriverEntry g_i2cLinuxDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = LinuxI2cBind,
+ .Init = LinuxI2cInit,
+ .Release = LinuxI2cRelease,
+ .moduleName = "linux_i2c_adapter",
+};
+HDF_INIT(g_i2cLinuxDriverEntry);
diff --git a/adapter/khdf/linux/platform/mipi_csi/Makefile b/adapter/khdf/linux/platform/mipi_csi/Makefile
new file mode 100755
index 00000000..be5b690d
--- /dev/null
+++ b/adapter/khdf/linux/platform/mipi_csi/Makefile
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+include drivers/hdf/khdf/platform/platform.mk
+
+obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/mipi/mipi_csi_core.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/mipi/mipi_csi_if.o
+obj-$(CONFIG_VIDEO_V4L2) += mipi_v4l2_adapter.o
+
+obj-y += mipi_csi_dev.o \
+
+EXTRA_CFLAGS += -Wno-error=date-time
diff --git a/adapter/khdf/linux/platform/mipi_csi/mipi_csi_dev.c b/adapter/khdf/linux/platform/mipi_csi/mipi_csi_dev.c
new file mode 100644
index 00000000..6b0c985c
--- /dev/null
+++ b/adapter/khdf/linux/platform/mipi_csi/mipi_csi_dev.c
@@ -0,0 +1,1221 @@
+/*
+ * mipi_csi_dev.c
+ *
+ * create vfs node for mipi-csi
+ *
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "mipi_csi_dev.h"
+#include
+#include
+#include
+#include
+#include "hdf_log.h"
+#include "mipi_csi_core.h"
+#include "osal_mem.h"
+#include "securec.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* End of #ifdef __cplusplus */
+
+/* macro definition */
+#define HDF_LOG_TAG mipi_csi_dev
+#define MIPI_RX_DEV_NAME "mipi_csi_dev"
+#define MIPI_RX_PROC_NAME "mipi_rx"
+#define MAX_DEV_NAME_LEN 48
+#define HIMEDIA_DYNAMIC_MINOR 255
+
+#define COMBO_MAX_LANE_NUM 4
+
+#define COMBO_MIN_WIDTH 32
+#define COMBO_MIN_HEIGHT 32
+
+#define MIPI_HEIGHT_ALIGN 2
+#define MIPI_WIDTH_ALIGN 2
+#define MIPI_RX_MAX_PHY_NUM 1
+#define LANE_DATA_COUNT 12
+
+#define ENABLE_INT_MASK
+
+// SeqBuf and seq_file are used in different os.
+typedef struct seq_file SysProcEntryTag;
+struct MipiCsiVfsPara {
+ struct MipiCsiCntlr *cntlr;
+ struct miscdevice *miscDev;
+ // mutex and OsalMutex are used in different os.
+ struct OsalMutex lock;
+ void *priv;
+};
+
+static struct MipiCsiVfsPara g_vfsPara;
+void SysSeqPrintf(SysProcEntryTag *m, const char *f, ...)
+{
+ va_list args;
+
+ va_start(args, f);
+ // LosBufPrintf and seq_printf are used in different os.
+ seq_printf(m, f, args);
+ va_end(args);
+}
+
+static int32_t SysMutexLock(struct OsalMutex *mutex)
+{
+ // mutex_lock_interruptible and OsalMutexLock are used in different os.
+ return OsalMutexLock(mutex);
+}
+
+static int32_t RegisterDevice(const char *name, uint8_t id, unsigned short mode, struct file_operations *ops)
+{
+ int32_t error;
+ struct miscdevice *dev = NULL;
+
+ if ((name == NULL) || (ops == NULL) || (id >= MAX_CNTLR_CNT)) {
+ HDF_LOGE("%s: name, ops or id is error.", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ dev = OsalMemCalloc(sizeof(struct miscdevice));
+ if (dev == NULL) {
+ HDF_LOGE("%s: [OsalMemCalloc] failed.", __func__);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ dev->fops = ops;
+ dev->name = OsalMemCalloc(MAX_DEV_NAME_LEN + 1);
+ if (dev->name == NULL) {
+ OsalMemFree(dev);
+ HDF_LOGE("%s: [OsalMemCalloc] failed.", __func__);
+ return HDF_ERR_MALLOC_FAIL;
+ }
+ if (id != 0) { /* 0 : id */
+ if (snprintf_s((char *)dev->name, MAX_DEV_NAME_LEN + 1, MAX_DEV_NAME_LEN, "%s%u", name, id) < 0) {
+ OsalMemFree((char *)dev->name);
+ OsalMemFree(dev);
+ HDF_LOGE("%s: [snprintf_s] failed.", __func__);
+ return HDF_FAILURE;
+ }
+ } else {
+ if (memcpy_s((char *)dev->name, MAX_DEV_NAME_LEN, name, strlen(name)) != EOK) {
+ OsalMemFree((char *)dev->name);
+ OsalMemFree(dev);
+ HDF_LOGE("%s: [memcpy_s] failed.", __func__);
+ return HDF_ERR_IO;
+ }
+ }
+ ops->owner = THIS_MODULE;
+ dev->minor = MISC_DYNAMIC_MINOR;
+ dev->mode = mode;
+
+ // register_driver and misc_register are used in different os.
+ error = misc_register(dev);
+ if (error < 0) {
+ HDF_LOGE("%s: id %u cannot register miscDev on minor=%d (err=%d)",
+ __func__, id, MISC_DYNAMIC_MINOR, error);
+ OsalMemFree((char *)dev->name);
+ OsalMemFree(dev);
+ return error;
+ }
+
+ g_vfsPara.miscDev = dev;
+ HDF_LOGI("%s: create inode ok, name = %s, minor = %d", __func__, dev->name, dev->minor);
+
+ return HDF_SUCCESS;
+}
+
+static void UnregisterDevice(uint8_t id)
+{
+ struct miscdevice *dev = NULL;
+
+ if (id >= MAX_CNTLR_CNT) {
+ HDF_LOGE("%s: id error.", __func__);
+ return;
+ }
+ dev = g_vfsPara.miscDev;
+ if (dev == NULL) {
+ HDF_LOGE("%s: dev is NULL.", __func__);
+ return;
+ }
+
+ // unregister_driver <---> misc_deregister
+ misc_deregister(dev);
+ OsalMemFree((void *)dev->name);
+ dev->name = NULL;
+ OsalMemFree(dev);
+ dev = NULL;
+ HDF_LOGI("%s: success.", __func__);
+}
+
+static struct MipiCsiCntlr *GetCntlr(const SysProcEntryTag *s)
+{
+ if (s == NULL) {
+ HDF_LOGE("%s: s is NULL.", __func__);
+ return NULL;
+ }
+ return g_vfsPara.cntlr;
+}
+
+static int MipiSetComboDevAttr(struct MipiCsiVfsPara *vfsPara, ComboDevAttr *pAttr)
+{
+ int ret;
+
+ if (vfsPara == NULL) {
+ HDF_LOGE("%s: vfsPara is NULL.", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ if (SysMutexLock(&(vfsPara->lock))) {
+ HDF_LOGE("%s: [OsalMutexLock] failed.", __func__);
+ return HDF_FAILURE;
+ }
+ ret = MipiCsiCntlrSetComboDevAttr(vfsPara->cntlr, pAttr);
+ OsalMutexUnlock(&(vfsPara->lock));
+
+ return ret;
+}
+
+static int MipiSetExtDataType(struct MipiCsiVfsPara *vfsPara, ExtDataType *dataType)
+{
+ if (vfsPara == NULL) {
+ HDF_LOGE("%s: vfsPara is NULL.", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ if (dataType == NULL) {
+ HDF_LOGE("%s: dataType is NULL.", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ if (SysMutexLock(&(vfsPara->lock))) {
+ HDF_LOGE("%s: [OsalMutexLock] failed.", __func__);
+ return HDF_FAILURE;
+ }
+ MipiCsiCntlrSetExtDataType(vfsPara->cntlr, dataType);
+ OsalMutexUnlock(&(vfsPara->lock));
+
+ return HDF_SUCCESS;
+}
+
+static int MipiSetPhyCmvmode(struct MipiCsiVfsPara *vfsPara, uint8_t devno, PhyCmvMode cmvMode)
+{
+ if (vfsPara == NULL) {
+ HDF_LOGE("%s: vfsPara is NULL.", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+
+ if (SysMutexLock(&(vfsPara->lock))) {
+ HDF_LOGE("%s: [OsalMutexLock] failed.", __func__);
+ return HDF_FAILURE;
+ }
+ MipiCsiCntlrSetPhyCmvmode(vfsPara->cntlr, devno, cmvMode);
+ OsalMutexUnlock(&(vfsPara->lock));
+
+ return HDF_SUCCESS;
+}
+
+static long MipiRxIoctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ unsigned long *argp = (unsigned long *)(uintptr_t)arg;
+ struct MipiCsiCntlr *cntlr = g_vfsPara.cntlr;
+ int ret = HDF_FAILURE;
+ if ((argp == NULL) || (cntlr == NULL)) {
+ HDF_LOGE("%s: argp or cntlr is NULL.", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ (void)filep;
+ switch (cmd) {
+ case HI_MIPI_SET_DEV_ATTR:
+ ret = MipiSetComboDevAttr(&g_vfsPara, (ComboDevAttr *)argp);
+ break;
+ case HI_MIPI_SET_PHY_CMVMODE: {
+ PhyCmv *pPhyCmv = (PhyCmv *)argp;
+ ret = MipiSetPhyCmvmode(&g_vfsPara, pPhyCmv->devno, pPhyCmv->cmvMode);
+ break;
+ }
+ case HI_MIPI_RESET_SENSOR:
+ ret = MipiCsiCntlrResetSensor(cntlr, (uint8_t)argp);
+ break;
+ case HI_MIPI_UNRESET_SENSOR:
+ ret = MipiCsiCntlrUnresetSensor(cntlr, (uint8_t)argp);
+ break;
+ case HI_MIPI_RESET_MIPI:
+ ret = MipiCsiCntlrResetRx(cntlr, (uint8_t)argp);
+ break;
+ case HI_MIPI_UNRESET_MIPI:
+ ret = MipiCsiCntlrUnresetRx(cntlr, (uint8_t)argp);
+ break;
+ case HI_MIPI_RESET_SLVS:
+ break;
+ case HI_MIPI_UNRESET_SLVS:
+ break;
+ case HI_MIPI_SET_HS_MODE:
+ ret = MipiCsiCntlrSetHsMode(cntlr, (LaneDivideMode)argp);
+ break;
+ case HI_MIPI_ENABLE_MIPI_CLOCK:
+ ret = MipiCsiCntlrEnableClock(cntlr, (uint8_t)argp);
+ break;
+ case HI_MIPI_DISABLE_MIPI_CLOCK:
+ ret = MipiCsiCntlrDisableClock(cntlr, (uint8_t)argp);
+ break;
+ case HI_MIPI_ENABLE_SLVS_CLOCK:
+ break;
+ case HI_MIPI_DISABLE_SLVS_CLOCK:
+ break;
+ case HI_MIPI_ENABLE_SENSOR_CLOCK:
+ ret = MipiCsiCntlrEnableSensorClock(cntlr, (uint8_t)argp);
+ break;
+ case HI_MIPI_DISABLE_SENSOR_CLOCK:
+ ret = MipiCsiCntlrDisableSensorClock(cntlr, (uint8_t)argp);
+ break;
+ case HI_MIPI_SET_EXT_DATA_TYPE:
+ ret = MipiSetExtDataType(&g_vfsPara, (ExtDataType *)argp);
+ break;
+ default:
+ break;
+ }
+ HDF_LOGI("%s: cmd = %d %s.", __func__, cmd, (ret == HDF_SUCCESS) ? "success" : "failed");
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long MipiRxCompatIoctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ return MipiRxIoctl(filep, cmd, arg);
+}
+#endif
+
+#ifdef CONFIG_HI_PROC_SHOW_SUPPORT
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static int32_t ProcRegister(const char *name, uint8_t id, unsigned short mode, const struct proc_ops *ops)
+#else
+static int32_t ProcRegister(const char *name, uint8_t id, unsigned short mode, const struct file_operations *ops)
+#endif
+{
+ char procName[MAX_DEV_NAME_LEN + 1];
+ struct proc_dir_entry* entry = NULL;
+ int32_t ret;
+
+ if ((name == NULL) || (ops == NULL) || (id >= MAX_CNTLR_CNT)) {
+ HDF_LOGE("%s: name, ops or id is error.", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ if (memset_s(procName, MAX_DEV_NAME_LEN + 1, 0, MAX_DEV_NAME_LEN + 1) != EOK) {
+ HDF_LOGE("%s: [memcpy_s] failed.", __func__);
+ return HDF_ERR_IO;
+ }
+ if (id != 0) {
+ ret = snprintf_s(procName, MAX_DEV_NAME_LEN + 1, MAX_DEV_NAME_LEN, "%s%u", name, id);
+ } else {
+ ret = snprintf_s(procName, MAX_DEV_NAME_LEN + 1, MAX_DEV_NAME_LEN, "%s", name);
+ }
+ if (ret < 0) {
+ HDF_LOGE("%s: procName %s [snprintf_s] fail", __func__, procName);
+ return HDF_FAILURE;
+ }
+
+ // proc_create and CreateProcEntry are used in different os.
+ entry = proc_create(procName, mode, NULL, ops);
+ if (entry == NULL) {
+ HDF_LOGE("%s: [proc_create] name %s fail", __func__, procName);
+ return HDF_FAILURE;
+ }
+ HDF_LOGI("%s: success.", __func__);
+ return HDF_SUCCESS;
+}
+
+static void ProcUnregister(const char *name, uint8_t id)
+{
+ char procName[MAX_DEV_NAME_LEN + 1];
+ int32_t ret;
+
+ if (id >= MAX_CNTLR_CNT) {
+ HDF_LOGE("%s: id error.", __func__);
+ return;
+ }
+ if (memset_s(procName, MAX_DEV_NAME_LEN + 1, 0, MAX_DEV_NAME_LEN + 1) != EOK) {
+ HDF_LOGE("%s: [memcpy_s] failed.", __func__);
+ return;
+ }
+ if (id != 0) {
+ ret = snprintf_s(procName, MAX_DEV_NAME_LEN + 1, MAX_DEV_NAME_LEN, "%s%u", name, id);
+ } else {
+ ret = snprintf_s(procName, MAX_DEV_NAME_LEN + 1, MAX_DEV_NAME_LEN, "%s", name);
+ }
+ if (ret < 0) {
+ HDF_LOGE("%s: [snprintf_s] failed.", __func__);
+ return;
+ }
+
+ // remove_proc_entry and ProcFreeEntry are used in different os.
+ remove_proc_entry(procName, NULL);
+ HDF_LOGI("%s: success.", __func__);
+}
+
+static const char *MipiGetIntputModeName(InputMode inputMode)
+{
+ switch (inputMode) {
+ case INPUT_MODE_SUBLVDS:
+ case INPUT_MODE_LVDS:
+ case INPUT_MODE_HISPI:
+ return "LVDS";
+
+ case INPUT_MODE_MIPI:
+ return "MIPI";
+
+ case INPUT_MODE_CMOS:
+ case INPUT_MODE_BT1120:
+ case INPUT_MODE_BT656:
+ case INPUT_MODE_BYPASS:
+ return "CMOS";
+
+ default:
+ break;
+ }
+
+ return "N/A";
+}
+
+static const char *MipiGetRawDataTypeName(DataType type)
+{
+ switch (type) {
+ case DATA_TYPE_RAW_8BIT:
+ return "RAW8";
+
+ case DATA_TYPE_RAW_10BIT:
+ return "RAW10";
+
+ case DATA_TYPE_RAW_12BIT:
+ return "RAW12";
+
+ case DATA_TYPE_RAW_14BIT:
+ return "RAW14";
+
+ case DATA_TYPE_RAW_16BIT:
+ return "RAW16";
+
+ case DATA_TYPE_YUV420_8BIT_NORMAL:
+ return "yuv420_8bit_normal";
+
+ case DATA_TYPE_YUV420_8BIT_LEGACY:
+ return "yuv420_8bit_legacy";
+
+ case DATA_TYPE_YUV422_8BIT:
+ return "yuv422_8bit";
+
+ case DATA_TYPE_YUV422_PACKED:
+ return "yuv422_packed";
+
+ default:
+ break;
+ }
+
+ return "N/A";
+}
+
+static const char *MipiGetDataRateName(MipiDataRate dataRate)
+{
+ switch (dataRate) {
+ case MIPI_DATA_RATE_X1:
+ return "X1";
+
+ case MIPI_DATA_RATE_X2:
+ return "X2";
+
+ default:
+ break;
+ }
+
+ return "N/A";
+}
+
+static const char *MipiPrintMipiWdrMode(MipiWdrMode wdrMode)
+{
+ switch (wdrMode) {
+ case HI_MIPI_WDR_MODE_NONE:
+ return "None";
+
+ case HI_MIPI_WDR_MODE_VC:
+ return "VC";
+
+ case HI_MIPI_WDR_MODE_DT:
+ return "DT";
+
+ case HI_MIPI_WDR_MODE_DOL:
+ return "DOL";
+
+ default:
+ break;
+ }
+
+ return "N/A";
+}
+
+static const char *MipiPrintLvdsWdrMode(WdrMode wdrMode)
+{
+ switch (wdrMode) {
+ case HI_WDR_MODE_NONE:
+ return "None";
+
+ case HI_WDR_MODE_2F:
+ return "2F";
+
+ case HI_WDR_MODE_3F:
+ return "3F";
+
+ case HI_WDR_MODE_4F:
+ return "4F";
+
+ case HI_WDR_MODE_DOL_2F:
+ return "DOL_2F";
+
+ case HI_WDR_MODE_DOL_3F:
+ return "DOL_3F";
+
+ case HI_WDR_MODE_DOL_4F:
+ return "DOL_4F";
+
+ default:
+ break;
+ }
+
+ return "N/A";
+}
+
+static const char *MipiPrintLaneDivideMode(LaneDivideMode mode)
+{
+ if (mode == LANE_DIVIDE_MODE_0) {
+ return "4";
+ } else {
+ return "2+2";
+ }
+}
+
+static void ProcShowMipiDevice(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr)
+{
+ int32_t ret;
+ const char *wdrMode = NULL;
+ uint8_t devno;
+ InputMode inputMode;
+ DataType dataType;
+ MipiDevCtx tag;
+
+ ret = MipiCsiDebugGetMipiDevCtx(cntlr, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiDevCtx] failed.", __func__);
+ return;
+ }
+
+ SysSeqPrintf(s, "\nMIPI DEV ATTR\n");
+ SysSeqPrintf(s,
+ "%8s" "%10s" "%10s" "%20s" "%10s" "%8s" "%8s" "%8s" "%8s" "\n",
+ "Devno", "WorkMode", "DataRate", "DataType", "WDRMode", "ImgX", "ImgY", "ImgW", "ImgH");
+
+ for (devno = 0; devno < MIPI_RX_MAX_DEV_NUM; devno++) {
+ ComboDevAttr *pdevAttr = &tag.comboDevAttr[devno];
+ inputMode = pdevAttr->inputMode;
+ if (!tag.devCfged[devno]) {
+ continue;
+ }
+
+ if (inputMode == INPUT_MODE_MIPI) {
+ dataType = pdevAttr->mipiAttr.inputDataType;
+ wdrMode = MipiPrintMipiWdrMode(pdevAttr->mipiAttr.wdrMode);
+ } else {
+ dataType = pdevAttr->lvdsAttr.inputDataType;
+ wdrMode = MipiPrintLvdsWdrMode(pdevAttr->lvdsAttr.wdrMode);
+ }
+
+ SysSeqPrintf(s, "%8d" "%10s" "%10s" "%20s" "%10s" "%8d" "%8d" "%8d" "%8d" "\n",
+ devno,
+ MipiGetIntputModeName(inputMode),
+ MipiGetDataRateName(pdevAttr->dataRate),
+ MipiGetRawDataTypeName(dataType),
+ wdrMode,
+ pdevAttr->imgRect.x,
+ pdevAttr->imgRect.y,
+ pdevAttr->imgRect.width,
+ pdevAttr->imgRect.height);
+ }
+}
+
+static void ProcShowMipiLane(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr)
+{
+ int32_t ret;
+ uint8_t devno;
+ InputMode inputMode;
+ MipiDevCtx tag;
+
+ ret = MipiCsiDebugGetMipiDevCtx(cntlr, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiDevCtx] failed.", __func__);
+ return;
+ }
+
+ SysSeqPrintf(s, "\nMIPI LANE INFO\n");
+ SysSeqPrintf(s, "%8s" "%24s" "\n", "Devno", "LaneID");
+
+ for (devno = 0; devno < MIPI_RX_MAX_DEV_NUM; devno++) {
+ ComboDevAttr *pdevAttr = &tag.comboDevAttr[devno];
+
+ inputMode = pdevAttr->inputMode;
+ if (!tag.devCfged[devno]) {
+ continue;
+ }
+
+ if (inputMode == INPUT_MODE_MIPI) {
+ SysSeqPrintf(s, "%8d" "%10d,%3d,%3d,%3d" "\n",
+ devno,
+ pdevAttr->mipiAttr.laneId[0], /* 0 -- laneId 0 */
+ pdevAttr->mipiAttr.laneId[1], /* 1 -- laneId 1 */
+ pdevAttr->mipiAttr.laneId[2], /* 2 -- laneId 2 */
+ pdevAttr->mipiAttr.laneId[3]); /* 3 -- laneId 3 */
+ } else if (inputMode == INPUT_MODE_LVDS ||
+ inputMode == INPUT_MODE_SUBLVDS ||
+ inputMode == INPUT_MODE_HISPI) {
+ SysSeqPrintf(s, "%8d" "%10d,%3d,%3d,%3d" "\n",
+ devno,
+ pdevAttr->lvdsAttr.laneId[0],
+ pdevAttr->lvdsAttr.laneId[1],
+ pdevAttr->lvdsAttr.laneId[2], /* 2 -- laneId 2 */
+ pdevAttr->lvdsAttr.laneId[3]); /* 3 -- laneId 3 */
+ }
+ }
+}
+
+static unsigned int GetPhyData(struct MipiCsiCntlr *cntlr, int phyId, int laneId)
+{
+ int32_t ret;
+ unsigned int laneData;
+
+ ret = MipiCsiDebugGetPhyData(cntlr, phyId, laneId, &laneData);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetPhyData] failed.", __func__);
+ return 0;
+ }
+
+ return laneData;
+}
+
+static unsigned int GetPhyMipiLinkData(struct MipiCsiCntlr *cntlr, int phyId, int laneId)
+{
+ int32_t ret;
+ unsigned int laneData;
+
+ ret = MipiCsiDebugGetPhyMipiLinkData(cntlr, phyId, laneId, &laneData);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetPhyMipiLinkData] failed.", __func__);
+ return 0;
+ }
+
+ return laneData;
+}
+
+static unsigned int GetPhyLvdsLinkData(struct MipiCsiCntlr *cntlr, int phyId, int laneId)
+{
+ int32_t ret;
+ unsigned int laneData;
+
+ ret = MipiCsiDebugGetPhyLvdsLinkData(cntlr, phyId, laneId, &laneData);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetPhyLvdsLinkData] failed.", __func__);
+ return 0;
+ }
+
+ return laneData;
+}
+
+static void ProcShowMipiPhyData(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr)
+{
+ int i;
+
+ SysSeqPrintf(s, "\nMIPI PHY DATA INFO\n");
+ SysSeqPrintf(s, "%8s" "%15s" "%19s" "%24s" "%22s" "\n",
+ "PhyId", "LaneId", "PhyData", "MipiData", "LvdsData");
+
+ for (i = 0; i < MIPI_RX_MAX_PHY_NUM; i++) {
+ SysSeqPrintf(s,
+ "%8d%8d,%2d,%2d,%2d, 0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x"
+ " 0x%02x,0x%02x,0x%02x,0x%02x\n",
+ i,
+ 4 * i, /* 4 * i + 0 -- phyId laneId 0 */
+ 4 * i + 1, /* 4 * i + 1 -- phyId laneId 1 */
+ 4 * i + 2, /* 4 * i + 2 -- phyId laneId 2 */
+ 4 * i + 3, /* 4 * i + 3 -- phyId laneId 3 */
+ GetPhyData(cntlr, i, 0), /* 0 -- laneId 0 */
+ GetPhyData(cntlr, i, 1), /* 1 -- laneId 1 */
+ GetPhyData(cntlr, i, 2), /* 2 -- laneId 2 */
+ GetPhyData(cntlr, i, 3), /* 3 -- laneId 3 */
+ GetPhyMipiLinkData(cntlr, i, 0), /* 0 -- laneId 0 */
+ GetPhyMipiLinkData(cntlr, i, 1), /* 1 -- laneId 1 */
+ GetPhyMipiLinkData(cntlr, i, 2), /* 2 -- laneId 2 */
+ GetPhyMipiLinkData(cntlr, i, 3), /* 3 -- laneId 3 */
+ GetPhyLvdsLinkData(cntlr, i, 0), /* 0 -- laneId 0 */
+ GetPhyLvdsLinkData(cntlr, i, 1), /* 1 -- laneId 1 */
+ GetPhyLvdsLinkData(cntlr, i, 2), /* 2 -- laneId 2 */
+ GetPhyLvdsLinkData(cntlr, i, 3)); /* 3 -- laneId 3 */
+ }
+}
+
+static void ProcShowMipiDetectInfo(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr,
+ uint8_t devnoArray[], int mipiCnt)
+{
+ int32_t ret;
+ ImgSize imageSize;
+ short vcNum;
+ int devnoIdx;
+
+ SysSeqPrintf(s, "\nMIPI DETECT INFO\n");
+ SysSeqPrintf(s, "%6s%3s%8s%8s\n", "Devno", "VC", "width", "height");
+
+ for (devnoIdx = 0; devnoIdx < mipiCnt; devnoIdx++) {
+ for (vcNum = 0; vcNum < WDR_VC_NUM; vcNum++) {
+ ret = MipiCsiDebugGetMipiImgsizeStatis(cntlr, devnoArray[devnoIdx], vcNum, &imageSize);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiImgsizeStatis] failed.", __func__);
+ return;
+ }
+ SysSeqPrintf(s, "%6d%3d%8u%8u\n",
+ devnoArray[devnoIdx], vcNum, imageSize.width, imageSize.height);
+ }
+ }
+}
+
+static void ProcShowLvdsDetectInfo(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr,
+ uint8_t devnoArray[], int mipiCnt)
+{
+ int32_t ret;
+ ImgSize imageSize;
+ short vcNum;
+ int devnoIdx;
+
+ SysSeqPrintf(s, "\nLVDS DETECT INFO\n");
+ SysSeqPrintf(s, "%6s%3s%8s%8s\n", "Devno", "VC", "width", "height");
+
+ for (devnoIdx = 0; devnoIdx < mipiCnt; devnoIdx++) {
+ for (vcNum = 0; vcNum < WDR_VC_NUM; vcNum++) {
+ ret = MipiCsiDebugGetLvdsImgsizeStatis(cntlr, devnoArray[devnoIdx], vcNum, &imageSize);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetLvdsImgsizeStatis] failed.", __func__);
+ return;
+ }
+ SysSeqPrintf(s, "%6d%3d%8d%8d\n",
+ devnoArray[devnoIdx], vcNum, imageSize.width, imageSize.height);
+ }
+ }
+}
+
+static void ProcShowLvdsLaneDetectInfo(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr,
+ uint8_t devnoArray[], int mipiCnt)
+{
+ int32_t ret;
+ ImgSize imageSize;
+ short lane;
+ int devnoIdx;
+ ComboDevAttr *pstcomboDevAttr = NULL;
+ MipiDevCtx tag;
+
+ ret = MipiCsiDebugGetMipiDevCtx(cntlr, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiDevCtx] failed.", __func__);
+ return;
+ }
+
+ SysSeqPrintf(s, "\nLVDS LANE DETECT INFO\n");
+ SysSeqPrintf(s, "%6s%6s%8s%8s\n", "Devno", "Lane", "width", "height");
+
+ for (devnoIdx = 0; devnoIdx < mipiCnt; devnoIdx++) {
+ pstcomboDevAttr = &tag.comboDevAttr[devnoArray[devnoIdx]];
+ for (lane = 0; lane < LVDS_LANE_NUM; lane++) {
+ if (pstcomboDevAttr->lvdsAttr.laneId[lane] == -1) {
+ continue;
+ }
+ ret = MipiCsiDebugGetLvdsLaneImgsizeStatis(cntlr, devnoArray[devnoIdx], lane, &imageSize);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetLvdsLaneImgsizeStatis] failed.", __func__);
+ return;
+ }
+
+ SysSeqPrintf(s, "%6d%6d%8d%8d\n",
+ devnoArray[devnoIdx], pstcomboDevAttr->lvdsAttr.laneId[lane],
+ imageSize.width, imageSize.height);
+ }
+ }
+}
+
+static void ProcShowMipiHsMode(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr)
+{
+ int32_t ret;
+ MipiDevCtx tag;
+ LaneDivideMode laneDivideMode;
+
+ ret = MipiCsiDebugGetMipiDevCtx(cntlr, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiDevCtx] failed.", __func__);
+ return;
+ }
+
+ laneDivideMode = tag.laneDivideMode;
+ SysSeqPrintf(s, "\nMIPI LANE DIVIDE MODE\n");
+ SysSeqPrintf(s, "%6s" "%20s" "\n", "MODE", "LANE DIVIDE");
+ SysSeqPrintf(s, "%6d" "%20s" "\n", laneDivideMode, MipiPrintLaneDivideMode(laneDivideMode));
+}
+
+static void ProcShowPhyCilIntErrCnt(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr)
+{
+ int32_t ret;
+ PhyErrIntCnt tag;
+ int phyId;
+
+ SysSeqPrintf(s, "\nPHY CIL ERR INT INFO\n");
+ SysSeqPrintf(s, "%8s%11s%10s%12s%12s%12s%12s%9s%8s%10s%10s%10s%10s\n",
+ "PhyId", "Clk2TmOut", "ClkTmOut", "Lane0TmOut", "Lane1TmOut", "Lane2TmOut", "Lane3TmOut",
+ "Clk2Esc", "ClkEsc", "Lane0Esc", "Lane1Esc", "Lane2Esc", "Lane3Esc");
+
+ for (phyId = 0; phyId < MIPI_RX_MAX_PHY_NUM; phyId++) {
+ ret = MipiCsiDebugGetPhyErrIntCnt(cntlr, phyId, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetPhyErrIntCnt] failed.", __func__);
+ return;
+ }
+
+ SysSeqPrintf(s, "%8d%11d%10d%12d%12d%12d%12d%9d%8d%10d%10d%10d%10d\n",
+ phyId,
+ tag.clk1FsmTimeoutErrCnt,
+ tag.clk0FsmTimeoutErrCnt,
+ tag.d0FsmTimeoutErrCnt,
+ tag.d1FsmTimeoutErrCnt,
+ tag.d2FsmTimeoutErrCnt,
+ tag.d3FsmTimeoutErrCnt,
+ tag.clk1FsmEscapeErrCnt,
+ tag.clk0FsmEscapeErrCnt,
+ tag.d0FsmEscapeErrCnt,
+ tag.d1FsmEscapeErrCnt,
+ tag.d2FsmEscapeErrCnt,
+ tag.d3FsmEscapeErrCnt);
+ }
+}
+
+static void ProcShowMipirxCrcErr(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr,
+ const uint8_t devnoArray[], int mipiCnt)
+{
+ int32_t ret;
+ MipiErrIntCnt tag;
+ int devnoIdx;
+ uint8_t devno;
+
+ SysSeqPrintf(s, "\nMIPI ERROR INT INFO 1\n");
+ SysSeqPrintf(s, "%8s%6s%8s%8s%8s%8s%14s%14s%14s%14s\n",
+ "Devno", "Ecc2", "Vc0CRC", "Vc1CRC", "Vc2CRC", "Vc3CRC",
+ "Vc0EccCorrct", "Vc1EccCorrct", "Vc2EccCorrct", "Vc3EccCorrct");
+
+ for (devnoIdx = 0; devnoIdx < mipiCnt; devnoIdx++) {
+ devno = devnoArray[devnoIdx];
+ ret = MipiCsiDebugGetMipiErrInt(cntlr, devno, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiErrInt] failed.", __func__);
+ return;
+ }
+
+ SysSeqPrintf(s, "%8d%6d%8d%8d%8d%8d%14d%14d%14d%14d\n",
+ devno,
+ tag.errEccDoubleCnt,
+ tag.vc0ErrCrcCnt,
+ tag.vc1ErrCrcCnt,
+ tag.vc2ErrCrcCnt,
+ tag.vc3ErrCrcCnt,
+ tag.vc0ErrEccCorrectedCnt,
+ tag.vc1ErrEccCorrectedCnt,
+ tag.vc2ErrEccCorrectedCnt,
+ tag.vc3ErrEccCorrectedCnt);
+ }
+}
+
+static void ProcShowMipirxVcErr(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr,
+ const uint8_t devnoArray[], int mipiCnt)
+{
+ int32_t ret;
+ MipiErrIntCnt tag;
+ int devnoIdx;
+ uint8_t devno;
+
+ SysSeqPrintf(s, "\nMIPI ERROR INT INFO 2\n");
+ SysSeqPrintf(s, "%8s%7s%7s%7s%7s%11s%11s%11s%11s\n",
+ "Devno", "Vc0Dt", "Vc1Dt", "Vc2Dt", "Vc3Dt",
+ "Vc0FrmCrc", "Vc1FrmCrc", "Vc2FrmCrc", "Vc3FrmCrc");
+
+ for (devnoIdx = 0; devnoIdx < mipiCnt; devnoIdx++) {
+ devno = devnoArray[devnoIdx];
+ ret = MipiCsiDebugGetMipiErrInt(cntlr, devno, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiErrInt] failed.", __func__);
+ return;
+ }
+ SysSeqPrintf(s, "%8d%7d%7d%7d%7d%11d%11d%11d%11d\n",
+ devno,
+ tag.errIdVc0Cnt,
+ tag.errIdVc1Cnt,
+ tag.errIdVc2Cnt,
+ tag.errIdVc3Cnt,
+ tag.errFrameDataVc0Cnt,
+ tag.errFrameDataVc1Cnt,
+ tag.errFrameDataVc2Cnt,
+ tag.errFrameDataVc3Cnt);
+ }
+ SysSeqPrintf(s, "\nMIPI ERROR INT INFO 3\n");
+ SysSeqPrintf(s, "%8s%11s%11s%11s%11s%12s%12s%12s%12s\n",
+ "Devno", "Vc0FrmSeq", "Vc1FrmSeq", "Vc2FrmSeq", "Vc3FrmSeq",
+ "Vc0BndryMt", "Vc1BndryMt", "Vc2BndryMt", "Vc3BndryMt");
+ for (devnoIdx = 0; devnoIdx < mipiCnt; devnoIdx++) {
+ devno = devnoArray[devnoIdx];
+ ret = MipiCsiDebugGetMipiErrInt(cntlr, devno, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiErrInt] failed.", __func__);
+ return;
+ }
+ SysSeqPrintf(s, "%8d%11d%11d%11d%11d%12d%12d%12d%12d\n",
+ devno,
+ tag.errFSeqVc0Cnt,
+ tag.errFSeqVc1Cnt,
+ tag.errFSeqVc2Cnt,
+ tag.errFSeqVc3Cnt,
+ tag.errFBndryMatchVc0Cnt,
+ tag.errFBndryMatchVc1Cnt,
+ tag.errFBndryMatchVc2Cnt,
+ tag.errFBndryMatchVc3Cnt);
+ }
+}
+
+static void ProcShowMipirxFifoErr(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr,
+ const uint8_t devnoArray[], int mipiCnt)
+{
+ int32_t ret;
+ MipiErrIntCnt tag;
+ int devnoIdx;
+ uint8_t devno;
+
+ SysSeqPrintf(s, "\nMIPI ERROR INT INFO 4\n");
+ SysSeqPrintf(s, "%8s%15s%14s%14s%15s\n",
+ "Devno", "DataFifoRdErr", "CmdFifoRdErr", "CmdFifoWrErr", "DataFifoWrErr");
+
+ for (devnoIdx = 0; devnoIdx < mipiCnt; devnoIdx++) {
+ devno = devnoArray[devnoIdx];
+ ret = MipiCsiDebugGetMipiErrInt(cntlr, devno, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiErrInt] failed.", __func__);
+ return;
+ }
+
+ SysSeqPrintf(s, "%8d%15d%14d%14d%15d\n",
+ devno,
+ tag.dataFifoRderrCnt,
+ tag.cmdFifoRderrCnt,
+ tag.dataFifoWrerrCnt,
+ tag.cmdFifoWrerrCnt);
+ }
+}
+
+static void ProcShowMipiIntErr(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr, uint8_t devnoArray[], int mipiCnt)
+{
+ ProcShowMipirxCrcErr(s, cntlr, devnoArray, mipiCnt);
+ ProcShowMipirxVcErr(s, cntlr, devnoArray, mipiCnt);
+ ProcShowMipirxFifoErr(s, cntlr, devnoArray, mipiCnt);
+}
+
+static void ProcShowLvdsIntErr(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr,
+ const uint8_t devnoArray[], int lvdsCnt)
+{
+ int32_t ret;
+ LvdsErrIntCnt tag;
+ uint8_t devno;
+ int devnoIdx;
+
+ SysSeqPrintf(s, "\nLVDS ERROR INT INFO\n");
+ SysSeqPrintf(s, "%8s%10s%10s%8s%9s%12s%12s\n",
+ "Devno", "CmdRdErr", "CmdWrErr", "PopErr", "StatErr", "Link0WrErr", "Link0RdErr");
+
+ for (devnoIdx = 0; devnoIdx < lvdsCnt; devnoIdx++) {
+ devno = devnoArray[devnoIdx];
+ ret = MipiCsiDebugGetLvdsErrIntCnt(cntlr, devno, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetLvdsErrIntCnt] failed.", __func__);
+ return;
+ }
+
+ SysSeqPrintf(s, "%8d%10d%10d%8d%9d%12d%12d\n",
+ devno,
+ tag.cmdRdErrCnt,
+ tag.cmdWrErrCnt,
+ tag.popErrCnt,
+ tag.lvdsStateErrCnt,
+ tag.link0RdErrCnt,
+ tag.link0WrErrCnt);
+ }
+}
+
+static void ProcShowAlignIntErr(SysProcEntryTag *s, struct MipiCsiCntlr *cntlr)
+{
+ int32_t ret;
+ AlignErrIntCnt tag;
+ uint8_t devno;
+
+ SysSeqPrintf(s, "\nALIGN ERROR INT INFO\n");
+ for (devno = 0; devno < MIPI_RX_MAX_DEV_NUM; devno++) {
+ ret = MipiCsiDebugGetAlignErrIntCnt(cntlr, devno, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetAlignErrIntCnt] failed.", __func__);
+ continue;
+ }
+ SysSeqPrintf(s, "%8s%14s%10s%10s%10s%10s\n",
+ "Devno", "FIFO_FullErr", "Lane0Err", "Lane1Err", "Lane2Err", "Lane3Err");
+ SysSeqPrintf(s, "%8d%14d%10d%10d%10d%10d\n",
+ devno,
+ tag.fifoFullErrCnt,
+ tag.lane0AlignErrCnt,
+ tag.lane1AlignErrCnt,
+ tag.lane2AlignErrCnt,
+ tag.lane3AlignErrCnt);
+ }
+}
+
+static void MipiLvdsProcShow(int mipiCnt, int lvdsCnt, uint8_t devnoMipi[MIPI_RX_MAX_DEV_NUM],
+ uint8_t devnoLvds[MIPI_RX_MAX_DEV_NUM], SysProcEntryTag *s)
+{
+ struct MipiCsiCntlr *cntlr = GetCntlr(s);
+ if (cntlr == NULL) {
+ HDF_LOGE("%s: cntlr is NULL.", __func__);
+ return;
+ }
+
+ if (mipiCnt > 0 || lvdsCnt > 0) {
+ ProcShowMipiHsMode(s, cntlr);
+ ProcShowMipiDevice(s, cntlr);
+ ProcShowMipiLane(s, cntlr);
+ ProcShowMipiPhyData(s, cntlr);
+ }
+
+ if (mipiCnt > 0) {
+ ProcShowMipiDetectInfo(s, cntlr, devnoMipi, mipiCnt);
+ }
+
+ if (lvdsCnt > 0) {
+ ProcShowLvdsDetectInfo(s, cntlr, devnoLvds, lvdsCnt);
+ ProcShowLvdsLaneDetectInfo(s, cntlr, devnoLvds, lvdsCnt);
+ }
+
+ if (mipiCnt > 0 || lvdsCnt > 0) {
+ ProcShowPhyCilIntErrCnt(s, cntlr);
+ }
+
+ if (mipiCnt > 0) {
+ ProcShowMipiIntErr(s, cntlr, devnoMipi, mipiCnt);
+ }
+
+ if (lvdsCnt > 0) {
+ ProcShowLvdsIntErr(s, cntlr, devnoLvds, lvdsCnt);
+ }
+
+ if (mipiCnt > 0 || lvdsCnt > 0) {
+ ProcShowAlignIntErr(s, cntlr);
+ }
+}
+
+static int32_t GetMipiOrLvdsDeviceCount(SysProcEntryTag *s, int *pmipiCnt, int *plvdsCnt, uint8_t devnoMipi[],
+ uint8_t devnoLvds[])
+{
+ int32_t ret;
+ uint8_t devno;
+ int mipiCnt = 0;
+ int lvdsCnt = 0;
+ InputMode inputMode;
+ MipiDevCtx tag;
+ struct MipiCsiCntlr *cntlr = NULL;
+
+ if ((pmipiCnt == NULL) || (plvdsCnt == NULL) || (devnoMipi == NULL) || (devnoLvds == NULL)) {
+ HDF_LOGE("%s: pmipiCnt, plvdsCnt and other parameters are invalid.", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ cntlr = GetCntlr(s);
+ if (cntlr == NULL) {
+ HDF_LOGE("%s: cntlr is NULL.", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ ret = MipiCsiDebugGetMipiDevCtx(cntlr, &tag);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [MipiCsiDebugGetMipiDevCtx] failed.", __func__);
+ return ret;
+ }
+
+ for (devno = 0; devno < MIPI_RX_MAX_DEV_NUM; devno++) {
+ if (!tag.devCfged[devno]) {
+ continue;
+ }
+
+ inputMode = tag.comboDevAttr[devno].inputMode;
+ if (inputMode == INPUT_MODE_MIPI) {
+ devnoMipi[mipiCnt] = devno;
+ mipiCnt++;
+ } else if ((inputMode == INPUT_MODE_LVDS) || (inputMode == INPUT_MODE_SUBLVDS) ||
+ (inputMode == INPUT_MODE_HISPI)) {
+ devnoLvds[lvdsCnt] = devno;
+ lvdsCnt++;
+ }
+ }
+ *pmipiCnt = mipiCnt;
+ *plvdsCnt = lvdsCnt;
+
+ return ret;
+}
+
+static void MipiProcShow(SysProcEntryTag *s)
+{
+ int32_t ret;
+ int mipiCnt;
+ int lvdsCnt;
+ uint8_t devnoMipi[MIPI_RX_MAX_DEV_NUM] = {0};
+ uint8_t devnoLvds[MIPI_RX_MAX_DEV_NUM] = {0};
+
+ ret = GetMipiOrLvdsDeviceCount(s, &mipiCnt, &lvdsCnt, devnoMipi, devnoLvds);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [GetMipiOrLvdsDeviceCount] failed.", __func__);
+ return;
+ }
+ MipiLvdsProcShow(mipiCnt, lvdsCnt, devnoMipi, devnoLvds, s);
+}
+
+static int MipiRxProcShow(SysProcEntryTag *s, void *v)
+{
+ SysSeqPrintf(s, "\nModule: [MIPI_RX], Build Time["__DATE__", "__TIME__"]\n");
+ MipiProcShow(s);
+ HDF_LOGI("%s: v %p", __func__, v);
+ HDF_LOGI("%s: success.", __func__);
+ return HDF_SUCCESS;
+}
+
+static int MipiCsiDevProcOpen(struct inode *inode, struct file *file)
+{
+ (void)inode;
+ HDF_LOGI("%s: enter.", __func__);
+ return single_open(file, MipiRxProcShow, NULL);
+}
+
+// ProcFileOperations and file_operations are used in different os.
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
+static const struct proc_ops g_procMipiCsiDevOps = {
+ .proc_open = MipiCsiDevProcOpen,
+ .proc_read = seq_read,
+};
+#else
+static const struct file_operations g_procMipiCsiDevOps = {
+ .open = MipiCsiDevProcOpen,
+ .read = seq_read,
+};
+#endif
+#endif
+
+static int MipiRxInit(void)
+{
+ OsalMutexInit(&g_vfsPara.lock);
+
+ return HDF_SUCCESS;
+}
+
+static void MipiRxExit(void)
+{
+ OsalMutexDestroy(&g_vfsPara.lock);
+}
+
+static int MipiRxOpen(struct inode *inode, struct file *filep)
+{
+ (void)inode;
+ (void)filep;
+
+ g_vfsPara.cntlr = MipiCsiCntlrGet(0);
+ HDF_LOGI("%s: success.", __func__);
+
+ return HDF_SUCCESS;
+}
+
+static int MipiRxRelease(struct inode *inode, struct file *filep)
+{
+ (void)inode;
+ (void)filep;
+
+ if (g_vfsPara.cntlr != NULL) {
+ MipiCsiCntlrPut(g_vfsPara.cntlr);
+ }
+ HDF_LOGI("%s: success.", __func__);
+
+ return HDF_SUCCESS;
+}
+
+// file_operations_vfs and file_operations are used in different os.
+static const struct file_operations g_mipiRxFops = {
+ .open = MipiRxOpen,
+ .release = MipiRxRelease,
+ .unlocked_ioctl = MipiRxIoctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = MipiRxCompatIoctl,
+#endif
+};
+
+int MipiCsiDevModuleInit(uint8_t id)
+{
+ int32_t ret;
+
+ /* 0660 : node mode */
+ ret = RegisterDevice(MIPI_RX_DEV_NAME, id, 0660, (struct file_operations *)&g_mipiRxFops);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: [RegisterDevice] fail: %d.", __func__, ret);
+ return ret;
+ }
+#ifdef CONFIG_HI_PROC_SHOW_SUPPORT
+ ret = ProcRegister(MIPI_RX_PROC_NAME, id, 0440, &g_procMipiCsiDevOps); /* 0440 : proc file mode */
+ if (ret != HDF_SUCCESS) {
+ UnregisterDevice(id);
+ HDF_LOGE("%s: [ProcRegister] fail: %d.", __func__, ret);
+ return ret;
+ }
+#endif
+
+ ret = MipiRxInit();
+ if (ret != HDF_SUCCESS) {
+ UnregisterDevice(id);
+#ifdef CONFIG_HI_PROC_SHOW_SUPPORT
+ ProcUnregister(MIPI_RX_PROC_NAME, id);
+#endif
+ HDF_LOGE("%s: [MipiRxInit] failed.", __func__);
+ return ret;
+ }
+
+ HDF_LOGI("%s: success!", __func__);
+ return ret;
+}
+
+void MipiCsiDevModuleExit(uint8_t id)
+{
+ MipiRxExit();
+#ifdef CONFIG_HI_PROC_SHOW_SUPPORT
+ ProcUnregister(MIPI_RX_PROC_NAME, id);
+#endif
+ UnregisterDevice(id);
+
+ HDF_LOGI("%s: success!", __func__);
+}
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+
+#endif
+#endif /* End of #ifdef __cplusplus */
diff --git a/adapter/khdf/linux/platform/mipi_csi/mipi_v4l2_adapter.c b/adapter/khdf/linux/platform/mipi_csi/mipi_v4l2_adapter.c
new file mode 100644
index 00000000..d3eb584e
--- /dev/null
+++ b/adapter/khdf/linux/platform/mipi_csi/mipi_v4l2_adapter.c
@@ -0,0 +1,515 @@
+/*
+ * mipi_v4l2_adapter.c
+ *
+ * Mipi v4l2 adapter driver.
+ *
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "hdf_log.h"
+#include "mipi_csi_core.h"
+
+#define HDF_LOG_TAG mipi_v4l2_adapter
+#define SENSOR_FLL_MAX 0xffff
+#define PIXEL_RATE_DIVISOR 10
+#define LINKS_COUNT 2
+#define LANES_COUNT 4
+#define CTRLS_COUNT 10
+
+/* Mode : resolution and related config&values */
+struct CameraSensorMode {
+ /* V-timing */
+ u32 fll_def;
+ u32 fll_min;
+
+ /* H-timing */
+ u32 llp;
+};
+
+struct CameraDrvData {
+ struct v4l2_subdev *sd;
+ struct media_pad *pad;
+
+ /* V4L2 Controls */
+ struct v4l2_ctrl_handler *ctrl_handler;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+
+ /* Current mode */
+ const struct CameraSensorMode *cur_mode;
+ s64 link_freqs; /* CSI-2 link frequencies, Application under v4l2 framework */
+
+ /* Streaming on/off */
+ bool streaming;
+};
+
+struct AdapterDrvData {
+ struct CameraDrvData *camera;
+ ComboDevAttr *attr;
+
+ struct v4l2_subdev_format fmt;
+ /*
+ * Mutex for serialized access:
+ * Protect sensor set pad format and start/stop streaming safely.
+ * Protect access to sensor v4l2 controls.
+ */
+ struct mutex mutex;
+};
+
+static struct AdapterDrvData g_adapterDrvData;
+
+/**
+ * Get bayer order based on flip setting.
+ * ref. linuxtv.org/downloads/v4l-dvb-apis/userspace-api/v4l/subdev-formats.html?highlight=media_bus_fmt_uv8_1x8
+ */
+static u32 LinuxGetFormatCode(DataType dataType)
+{
+ u32 code = MEDIA_BUS_FMT_SGBRG12_1X12;
+
+ switch (dataType) {
+ case DATA_TYPE_RAW_8BIT:
+ code = MEDIA_BUS_FMT_SBGGR8_1X8;
+ break;
+ case DATA_TYPE_RAW_10BIT:
+ code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ break;
+ case DATA_TYPE_RAW_12BIT:
+ code = MEDIA_BUS_FMT_SBGGR12_1X12;
+ break;
+ case DATA_TYPE_RAW_14BIT:
+ code = MEDIA_BUS_FMT_SBGGR14_1X14;
+ break;
+ case DATA_TYPE_RAW_16BIT:
+ code = MEDIA_BUS_FMT_SBGGR16_1X16;
+ break;
+ case DATA_TYPE_YUV420_8BIT_NORMAL:
+ code = MEDIA_BUS_FMT_Y8_1X8;
+ break;
+ case DATA_TYPE_YUV420_8BIT_LEGACY:
+ code = MEDIA_BUS_FMT_Y8_1X8;
+ break;
+ case DATA_TYPE_YUV422_8BIT:
+ code = MEDIA_BUS_FMT_YUYV8_1X16;
+ break;
+ case DATA_TYPE_YUV422_PACKED:
+ code = MEDIA_BUS_FMT_YVYU8_1X16;
+ break;
+ default:
+ break;
+ }
+
+ return code;
+}
+
+static int LinuxEnumMbusCode(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct AdapterDrvData *drvData = &g_adapterDrvData;
+ (void)sd;
+ (void)cfg;
+
+ if (code == NULL) {
+ HDF_LOGE("%s: code is NULL.", __func__);
+ return -EINVAL;
+ }
+ if (code->index > 0) {
+ HDF_LOGE("%s: code->index is invalid.", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&drvData->mutex);
+ code->code = drvData->fmt.format.code;
+ mutex_unlock(&drvData->mutex);
+
+ return 0;
+}
+
+static void LinuxUpdatePadFormat(struct AdapterDrvData *drvData,
+ const struct CameraSensorMode *mode, struct v4l2_subdev_format *fmt)
+{
+ (void)mode;
+
+ if ((drvData == NULL) || (fmt == NULL)) {
+ HDF_LOGE("%s: drvData or fmt is NULL.", __func__);
+ return;
+ }
+ fmt->format = drvData->fmt.format;
+}
+
+static int LinuxSetPadFormat(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ s32 vblank_def;
+ s32 vblank_min;
+ s64 h_blank;
+ u64 pixel_rate;
+ u32 height;
+ struct AdapterDrvData *drvData = &g_adapterDrvData;
+ struct CameraDrvData *camera = drvData->camera;
+ const struct CameraSensorMode *mode = camera->cur_mode;
+ ImgRect *rect = &drvData->attr->imgRect;
+
+ (void)sd;
+ (void)cfg;
+ mutex_lock(&drvData->mutex);
+ /*
+ * Only one bayer order is supported.
+ * It depends on the flip settings.
+ */
+ fmt->format.code = drvData->fmt.format.code;
+ LinuxUpdatePadFormat(drvData, mode, fmt);
+
+ pixel_rate = camera->link_freqs * LINKS_COUNT * LANES_COUNT;
+ do_div(pixel_rate, PIXEL_RATE_DIVISOR);
+ __v4l2_ctrl_s_ctrl_int64(camera->pixel_rate, pixel_rate);
+ /* Update limits and set FPS to default */
+ height = rect->height;
+ vblank_def = camera->cur_mode->fll_def - height;
+ vblank_min = camera->cur_mode->fll_min - height;
+ height = SENSOR_FLL_MAX - height;
+ __v4l2_ctrl_modify_range(camera->vblank, vblank_min, height, 1, vblank_def);
+ __v4l2_ctrl_s_ctrl(camera->vblank, vblank_def);
+ h_blank = mode->llp - rect->width;
+ /*
+ * Currently hblank is not changeable.
+ * So FPS control is done only by vblank.
+ */
+ __v4l2_ctrl_modify_range(camera->hblank, h_blank, h_blank, 1, h_blank);
+ mutex_unlock(&drvData->mutex);
+
+ return 0;
+}
+
+static int SetStream(int enable)
+{
+ struct AdapterDrvData *drvData = &g_adapterDrvData;
+ struct CameraDrvData *camera = drvData->camera;
+
+ mutex_lock(&drvData->mutex);
+ if (camera->streaming == enable) {
+ mutex_unlock(&drvData->mutex);
+ HDF_LOGE("%s: streaming-flag is not change.", __func__);
+ return 0;
+ }
+
+ camera->streaming = enable;
+
+ /* vflip and hflip cannot change during streaming */
+ __v4l2_ctrl_grab(camera->vflip, enable);
+ __v4l2_ctrl_grab(camera->hflip, enable);
+ mutex_unlock(&drvData->mutex);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops g_cameraVideoOps = {
+ .s_stream = NULL,
+};
+
+static const struct v4l2_subdev_pad_ops g_cameraPadOps = {
+ .enum_mbus_code = LinuxEnumMbusCode,
+ .set_fmt = LinuxSetPadFormat,
+};
+
+static const struct v4l2_subdev_ops g_cameraSubdevOps = {
+ .video = &g_cameraVideoOps,
+ .pad = &g_cameraPadOps,
+};
+
+/* Initialize control handlers */
+static int LinuxInitControls(struct AdapterDrvData *drvData)
+{
+ s64 vblank_def;
+ s64 vblank_min;
+ s64 hblank;
+ u64 pixel_rate;
+ int ret;
+
+ struct CameraDrvData *camera = drvData->camera;
+ struct v4l2_ctrl_handler *ctrl_hdlr = camera->ctrl_handler;
+ const struct CameraSensorMode *mode = camera->cur_mode;
+ ImgRect *rect = &(drvData->attr->imgRect);
+
+ if (ctrl_hdlr == NULL) {
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, CTRLS_COUNT);
+ if (ret) {
+ HDF_LOGE("%s: [v4l2_ctrl_handler_init] failed.", __func__);
+ return ret;
+ }
+ }
+ ctrl_hdlr->lock = &drvData->mutex;
+ if (camera->link_freq == NULL) {
+ camera->link_freq = v4l2_ctrl_new_std(ctrl_hdlr, NULL,
+ V4L2_CID_LINK_FREQ, camera->link_freqs, camera->link_freqs, 1, camera->link_freqs);
+ if (camera->link_freq) {
+ camera->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ }
+ }
+
+ if (camera->pixel_rate == NULL) {
+ /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
+ pixel_rate = camera->link_freqs * LINKS_COUNT * LANES_COUNT;
+ do_div(pixel_rate, PIXEL_RATE_DIVISOR);
+ /* By default, PIXEL_RATE is read only */
+ camera->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, NULL,
+ V4L2_CID_PIXEL_RATE, pixel_rate, pixel_rate, 1, pixel_rate);
+ }
+
+ /* Initialize vblank/hblank/exposure parameters based on current mode */
+ if (camera->vblank == NULL) {
+ vblank_def = mode->fll_def - rect->height;
+ vblank_min = mode->fll_min - rect->height;
+ camera->vblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL,
+ V4L2_CID_VBLANK, vblank_min, SENSOR_FLL_MAX - rect->height, 1, vblank_def);
+ }
+
+ if (camera->hblank == NULL) {
+ hblank = mode->llp - rect->width;
+ camera->hblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL,
+ V4L2_CID_HBLANK, hblank, hblank, 1, hblank);
+ if (camera->hblank) {
+ camera->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ }
+ }
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ HDF_LOGE("%s: control init failed: %d", __func__, ret);
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ return ret;
+ }
+ camera->sd->ctrl_handler = ctrl_hdlr;
+
+ return 0;
+}
+
+static int32_t MipiCsiAdapterTraceMipiCfg(ComboDevAttr *attr)
+{
+ unsigned int i;
+ MipiDevAttr *cfg = NULL;
+
+ if (attr == NULL) {
+ HDF_LOGE("%s: attr is NULL!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ cfg = &(attr->mipiAttr);
+ HDF_LOGD("%s: inputDataType = %d, wdrMode = %d", __func__, cfg->inputDataType, cfg->wdrMode);
+ for (i = 0; i < MIPI_LANE_NUM; i++) {
+ HDF_LOGD("laneId[%d] = %d", i, cfg->laneId[i]);
+ }
+
+ HDF_LOGD("%s: inputMode = %d, dataRate = %d, imgRect(x = %d, y = %d, width = %d, height = %d).",
+ __func__, attr->inputMode, attr->dataRate, attr->imgRect.x, attr->imgRect.y,
+ attr->imgRect.width, attr->imgRect.height);
+
+ return HDF_SUCCESS;
+}
+
+static int32_t MipiCsiAdapterTraceCameraCfg(struct CameraDrvData *camera)
+{
+ const struct CameraSensorMode *mode = NULL;
+ if (camera == NULL) {
+ HDF_LOGE("%s: camera is NULL!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ mode = camera->cur_mode;
+ HDF_LOGD("%s: link_freq = %lld", __func__, camera->link_freqs);
+ HDF_LOGD("%s: fll_def = %d, fll_min = %d, llp = %d.", __func__, mode->fll_def, mode->fll_min, mode->llp);
+
+ return HDF_SUCCESS;
+}
+
+static int32_t MipiCsiAdapterSetComboDevAttr(struct MipiCsiCntlr *cntlr, ComboDevAttr *pAttr)
+{
+ int32_t ret;
+ struct AdapterDrvData *drvData = (struct AdapterDrvData *)cntlr->priv;
+ struct v4l2_mbus_framefmt *fmt = NULL;
+
+ if ((drvData == NULL) || (pAttr == NULL)) {
+ HDF_LOGE("%s: drvData or pAttr is NULL!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ drvData->attr = pAttr;
+ fmt = &drvData->fmt.format;
+ fmt->width = pAttr->imgRect.width;
+ fmt->height = pAttr->imgRect.height;
+ fmt->code = LinuxGetFormatCode(pAttr->mipiAttr.inputDataType);
+ fmt->field = V4L2_FIELD_NONE;
+
+ ret = MipiCsiAdapterTraceMipiCfg(pAttr);
+
+ return ret;
+}
+
+static int32_t MipiCsiAdapterResetRx(struct MipiCsiCntlr *cntlr, uint8_t comboDev)
+{
+ int32_t ret;
+
+ (void)cntlr;
+ ret = SetStream(1);
+ return (ret == 0) ? HDF_SUCCESS : HDF_FAILURE;
+}
+
+static int32_t MipiCsiAdapterUnresetRx(struct MipiCsiCntlr *cntlr, uint8_t comboDev)
+{
+ int32_t ret;
+
+ (void)cntlr;
+ ret = SetStream(0);
+ return (ret == 0) ? HDF_SUCCESS : HDF_FAILURE;
+}
+
+static int32_t MipiCsiAdapterProbeV4l2(struct MipiCsiCntlr *cntlr)
+{
+ int32_t ret;
+ struct AdapterDrvData *drvData = (struct AdapterDrvData *)cntlr->priv;
+ struct CameraDrvData *camera = NULL;
+
+ if ((drvData == NULL) || (drvData->camera == NULL)) {
+ HDF_LOGE("%s: drvData or drvData->camera is NULL.", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+
+ camera = drvData->camera;
+ /* Initialize subdev */
+ v4l2_subdev_init(camera->sd, &g_cameraSubdevOps);
+ ret = LinuxInitControls(drvData);
+ if (ret) {
+ HDF_LOGE("%s: failed to init controls: %d", __func__, ret);
+ v4l2_ctrl_handler_free(camera->sd->ctrl_handler);
+ return HDF_FAILURE;
+ }
+
+ mutex_init(&drvData->mutex);
+ return HDF_SUCCESS;
+}
+
+static int32_t MipiCsiAdapterSetDrvData(struct MipiCsiCntlr *cntlr, void *cameraData)
+{
+ int32_t ret;
+ struct AdapterDrvData *drvData = (struct AdapterDrvData *)cntlr->priv;
+
+ if ((drvData == NULL) || (cameraData == NULL)) {
+ HDF_LOGE("%s: drvData or cameraData is NULL!", __func__);
+ return HDF_ERR_INVALID_PARAM;
+ }
+ drvData->camera = (struct CameraDrvData *)cameraData;
+ ret = MipiCsiAdapterTraceCameraCfg(drvData->camera);
+ if (ret != HDF_SUCCESS) {
+ HDF_LOGE("%s: trace Camera Cfg failed!", __func__);
+ return HDF_FAILURE;
+ }
+ ret = MipiCsiAdapterProbeV4l2(cntlr);
+
+ return ret;
+}
+
+static struct MipiCsiCntlr g_mipiRx = {
+ .devNo = 0
+};
+
+static struct MipiCsiCntlrMethod g_method = {
+ .setComboDevAttr = MipiCsiAdapterSetComboDevAttr,
+ .resetRx = MipiCsiAdapterResetRx,
+ .unresetRx = MipiCsiAdapterUnresetRx,
+ .setDrvData = MipiCsiAdapterSetDrvData,
+};
+
+static void MipiCsiAdapterRemoveV4l2(struct MipiCsiCntlr *cntlr)
+{
+ struct AdapterDrvData *drvData = (struct AdapterDrvData *)cntlr->priv;
+ struct CameraDrvData *camera = NULL;
+
+ if ((drvData == NULL) || (drvData->camera == NULL)) {
+ HDF_LOGE("%s: drvData or drvData->camera is NULL!", __func__);
+ return;
+ }
+
+ camera = drvData->camera;
+ if ((camera->sd != NULL) && (camera->sd->ctrl_handler != NULL)) {
+ v4l2_ctrl_handler_free(camera->sd->ctrl_handler);
+ camera->sd->ctrl_handler = NULL;
+ }
+ mutex_destroy(&drvData->mutex);
+ drvData->attr = NULL;
+ drvData->camera = NULL;
+}
+
+static int32_t MipiCsiAdapterBind(struct HdfDeviceObject *device)
+{
+ int32_t ret;
+
+ HDF_LOGI("%s: enter.", __func__);
+ g_mipiRx.priv = &g_adapterDrvData;
+ g_mipiRx.ops = &g_method;
+ ret = MipiCsiRegisterCntlr(&g_mipiRx, device);
+ if (ret != HDF_SUCCESS) {
+ return ret;
+ }
+ HDF_LOGI("%s: success.", __func__);
+
+ return HDF_SUCCESS;
+}
+
+static int32_t MipiCsiAdapterInit(struct HdfDeviceObject *device)
+{
+ (void)device;
+
+ HDF_LOGI("%s: success.", __func__);
+ return HDF_SUCCESS;
+}
+
+static void MipiCsiAdapterRelease(struct HdfDeviceObject *device)
+{
+ struct MipiCsiCntlr *cntlr = NULL;
+
+ if (device == NULL) {
+ HDF_LOGE("%s: device is NULL.", __func__);
+ return;
+ }
+ cntlr = MipiCsiCntlrFromDevice(device);
+ if (cntlr == NULL) {
+ HDF_LOGE("%s: cntlr is NULL.", __func__);
+ return;
+ }
+ MipiCsiAdapterRemoveV4l2(cntlr);
+ MipiCsiUnregisterCntlr(cntlr);
+ cntlr->priv = NULL;
+
+ HDF_LOGI("%s: success.", __func__);
+}
+
+struct HdfDriverEntry g_mipiCsiLinuxDriverEntry = {
+ .moduleVersion = 1,
+ .Bind = MipiCsiAdapterBind,
+ .Init = MipiCsiAdapterInit,
+ .Release = MipiCsiAdapterRelease,
+ .moduleName = "linux_mipi_csi_adapter",
+};
+HDF_INIT(g_mipiCsiLinuxDriverEntry);
+
diff --git a/adapter/khdf/linux/platform/mipi_dsi/Makefile b/adapter/khdf/linux/platform/mipi_dsi/Makefile
new file mode 100644
index 00000000..337a1b32
--- /dev/null
+++ b/adapter/khdf/linux/platform/mipi_dsi/Makefile
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
+#
+# This software is licensed under the terms of the GNU General Public
+# License version 2, as published by the Free Software Foundation, and
+# may be copied, distributed, and modified under those terms.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+#
+
+include drivers/hdf/khdf/platform/platform.mk
+
+obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/mipi/mipi_dsi_core.o \
+ $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/mipi/mipi_dsi_if.o
+obj-$(CONFIG_DRM_MIPI_DSI) += mipi_drm_adapter.o
+
+obj-y += mipi_tx_dev.o \
+ mipi_tx_hi35xx.o
+
+EXTRA_CFLAGS += -Wno-error=date-time
diff --git a/adapter/khdf/linux/platform/mipi_dsi/mipi_drm_adapter.c b/adapter/khdf/linux/platform/mipi_dsi/mipi_drm_adapter.c
new file mode 100644
index 00000000..58dd1fda
--- /dev/null
+++ b/adapter/khdf/linux/platform/mipi_dsi/mipi_drm_adapter.c
@@ -0,0 +1,266 @@
+/*
+ * mipi_drm_adapter.c
+ *
+ * Mipi drm adapter driver.
+ *
+ * Copyright (c) 2021 Huawei Device Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include
+#include "hdf_base.h"
+#include
+#include