diff options
author | Xin Li <delphij@google.com> | 2017-12-06 23:18:30 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-12-06 23:18:30 +0000 |
commit | c8fdc0c1310af6aa6c2f3ffc081d81e90dcc3768 (patch) | |
tree | 59fdfdf8f2f4b63726eddf061e57f6e6ed4ffe9c | |
parent | 3c54d85c5b99a3dc9efecaf1856bbdbbff439923 (diff) | |
parent | 9490ad1f699812d07a429bd002070dc4e05f18c3 (diff) | |
download | bt-c8fdc0c1310af6aa6c2f3ffc081d81e90dcc3768.tar.gz |
Merge "DO NOT MERGE: Merge Oreo MR1 into master"
30 files changed, 7289 insertions, 78 deletions
@@ -1,23 +1,11 @@ +LOCAL_PATH := $(call my-dir) # TODO: Find a better way to separate build configs for ADP vs non-ADP devices ifneq ($(BOARD_IS_AUTOMOTIVE),true) - ifneq ($(filter msm8960 msm8x27 msm8226,$(TARGET_BOARD_PLATFORM)),) + ifneq ($(filter msm8x27 msm8226,$(TARGET_BOARD_PLATFORM)),) include $(call all-named-subdir-makefiles,msm8960) - else - ifneq ($(filter msm8994 msm8992,$(TARGET_BOARD_PLATFORM)),) - include $(call all-named-subdir-makefiles,msm8992) - else - ifneq ($(filter msm8996,$(TARGET_BOARD_PLATFORM)),) - include $(call all-named-subdir-makefiles,msm8996) - else - ifneq ($(filter msm8909 ,$(TARGET_BOARD_PLATFORM)),) - #For msm8909 target - include $(call all-named-subdir-makefiles,msm8909) - else - ifneq ($(filter msm8998,$(TARGET_BOARD_PLATFORM)),) - include $(call all-named-subdir-makefiles,msm8998) - endif - endif - endif - endif + else ifneq ($(filter msm8994,$(TARGET_BOARD_PLATFORM)),) + include $(call all-named-subdir-makefiles,msm8992) + else ifneq ($(wildcard $(LOCAL_PATH)/$(TARGET_BOARD_PLATFORM)),) + include $(call all-named-subdir-makefiles,$(TARGET_BOARD_PLATFORM)) endif endif diff --git a/msm8998/libbt-vendor/Android.mk b/msm8998/libbt-vendor/Android.mk index 841c3c4..2bb2283 100644 --- a/msm8998/libbt-vendor/Android.mk +++ b/msm8998/libbt-vendor/Android.mk @@ -66,6 +66,9 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ liblog +LOCAL_HEADER_LIBRARIES := \ + libutils_headers + LOCAL_MODULE := libbt-vendor LOCAL_MODULE_TAGS := optional LOCAL_MODULE_CLASS := SHARED_LIBRARIES diff --git a/msm8998/libbt-vendor/include/hci_uart.h b/msm8998/libbt-vendor/include/hci_uart.h index 21e9689..50740d7 100644 --- a/msm8998/libbt-vendor/include/hci_uart.h +++ b/msm8998/libbt-vendor/include/hci_uart.h @@ -20,6 +20,7 @@ #define HCI_UART_H #include <asm-generic/ioctls.h> +#include <termios.h> /* Variables to identify the platform */ /*BT HS UART TTY DEVICE */ diff --git a/msm8998/libbt-vendor/include/hw_ar3k.h b/msm8998/libbt-vendor/include/hw_ar3k.h index 2129548..1b22f4f 100644 --- a/msm8998/libbt-vendor/include/hw_ar3k.h +++ b/msm8998/libbt-vendor/include/hw_ar3k.h @@ -18,6 +18,8 @@ #ifndef HW_AR3K_H #define HW_AR3K_H +#include <sys/socket.h> + /****************************************************************************** ** Constants & Macros ******************************************************************************/ diff --git a/msm8998/libbt-vendor/src/bt_vendor_qcom.c b/msm8998/libbt-vendor/src/bt_vendor_qcom.c index a1f88fe..432534a 100644 --- a/msm8998/libbt-vendor/src/bt_vendor_qcom.c +++ b/msm8998/libbt-vendor/src/bt_vendor_qcom.c @@ -26,20 +26,24 @@ #define LOG_TAG "bt_vendor" #define BLUETOOTH_MAC_ADDR_BOOT_PROPERTY "ro.boot.btmacaddr" -#include <utils/Log.h> -#include <cutils/properties.h> -#include <fcntl.h> -#include <termios.h> +#include "bt_vendor_lib.h" +#include "bt_vendor_persist.h" #include "bt_vendor_qcom.h" -#include "hci_uart.h" #include "hci_smd.h" +#include "hci_uart.h" +#include "hw_rome.h" + +#include <fcntl.h> +#include <linux/un.h> +#include <pthread.h> #include <sys/ioctl.h> #include <sys/socket.h> +#include <termios.h> +#include <unistd.h> + +#include <cutils/properties.h> #include <cutils/sockets.h> -#include <linux/un.h> -#include "bt_vendor_persist.h" -#include "hw_rome.h" -#include "bt_vendor_lib.h" +#include <utils/Log.h> #define WAIT_TIMEOUT 200000 #define BT_VND_OP_GET_LINESPEED 30 @@ -604,7 +608,7 @@ static int init(const bt_vendor_callbacks_t *cb, unsigned char *bdaddr) q.rfkill_id = -1; q.enable_extldo = FALSE; - q.cb = cb; + q.cb = (bt_vendor_callbacks_t*)cb; q.ant_fd = -1; q.soc_type = get_bt_soc_type(); soc_init(q.soc_type); diff --git a/msm8998/libbt-vendor/src/hardware.c b/msm8998/libbt-vendor/src/hardware.c index 6984ff0..cd6790b 100644 --- a/msm8998/libbt-vendor/src/hardware.c +++ b/msm8998/libbt-vendor/src/hardware.c @@ -26,20 +26,22 @@ #define LOG_TAG "bt_vendor" -#include <utils/Log.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <signal.h> -#include <time.h> +#include "bt_hci_bdroid.h" +#include "bt_vendor_qcom.h" +#include <ctype.h> +#include <dirent.h> #include <errno.h> #include <fcntl.h> -#include <dirent.h> -#include <ctype.h> -#include <cutils/properties.h> +#include <signal.h> #include <stdlib.h> -#include "bt_hci_bdroid.h" -#include "bt_vendor_qcom.h" #include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include <cutils/properties.h> +#include <utils/Log.h> #define MAX_CNT_RETRY 100 int hw_config(int nState) diff --git a/msm8998/libbt-vendor/src/hci_smd.c b/msm8998/libbt-vendor/src/hci_smd.c index 7e5b16d..9833281 100644 --- a/msm8998/libbt-vendor/src/hci_smd.c +++ b/msm8998/libbt-vendor/src/hci_smd.c @@ -24,15 +24,18 @@ #define LOG_TAG "bt_vendor" -#include <utils/Log.h> -#include <termios.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> #include "bt_vendor_qcom.h" #include "hci_smd.h" + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> #include <string.h> +#include <termios.h> +#include <unistd.h> + #include <cutils/properties.h> +#include <utils/Log.h> /***************************************************************************** ** Macros & Constants diff --git a/msm8998/libbt-vendor/src/hci_uart.c b/msm8998/libbt-vendor/src/hci_uart.c index 2aeace8..fa0fc0f 100644 --- a/msm8998/libbt-vendor/src/hci_uart.c +++ b/msm8998/libbt-vendor/src/hci_uart.c @@ -26,14 +26,18 @@ #define LOG_TAG "bt_vendor" -#include <utils/Log.h> -#include <termios.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> #include "bt_vendor_qcom.h" #include "hci_uart.h" + +#include <asm-generic/ioctls.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> #include <string.h> +#include <termios.h> +#include <unistd.h> + +#include <utils/Log.h> /****************************************************************************** ** Constants & Macros diff --git a/msm8998/libbt-vendor/src/hw_ar3k.c b/msm8998/libbt-vendor/src/hw_ar3k.c index 1a68aab..b484d0b 100644 --- a/msm8998/libbt-vendor/src/hw_ar3k.c +++ b/msm8998/libbt-vendor/src/hw_ar3k.c @@ -34,26 +34,29 @@ extern "C" { #define LOG_TAG "bt_vendor" -#include <sys/socket.h> -#include <utils/Log.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <signal.h> -#include <time.h> +#include "bt_hci_bdroid.h" +#include "bt_vendor_qcom.h" +#include "bt_vendor_qcom.h" +#include "hci_uart.h" +#include "hw_ar3k.h" + +#include <ctype.h> +#include <dirent.h> #include <errno.h> #include <fcntl.h> -#include <dirent.h> -#include <ctype.h> -#include <cutils/properties.h> +#include <signal.h> #include <stdlib.h> -#include <termios.h> #include <string.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <termios.h> +#include <time.h> +#include <unistd.h> -#include "bt_hci_bdroid.h" -#include "bt_vendor_qcom.h" -#include "hci_uart.h" -#include "hw_ar3k.h" -#include "bt_vendor_qcom.h" +#include <cutils/properties.h> +#include <utils/Log.h> /****************************************************************************** ** Variables diff --git a/msm8998/libbt-vendor/src/hw_rome.c b/msm8998/libbt-vendor/src/hw_rome.c index 58c0159..cf34006 100644 --- a/msm8998/libbt-vendor/src/hw_rome.c +++ b/msm8998/libbt-vendor/src/hw_rome.c @@ -34,26 +34,29 @@ extern "C" { #define LOG_TAG "bt_vendor" -#include <sys/socket.h> -#include <utils/Log.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <signal.h> -#include <time.h> -#include <errno.h> -#include <fcntl.h> -#include <dirent.h> -#include <ctype.h> -#include <cutils/properties.h> -#include <stdlib.h> -#include <termios.h> -#include <string.h> -#include <stdbool.h> #include "bt_hci_bdroid.h" #include "bt_vendor_qcom.h" #include "hci_uart.h" #include "hw_rome.h" +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <termios.h> +#include <time.h> +#include <unistd.h> + +#include <cutils/properties.h> +#include <utils/Log.h> + #ifdef __cplusplus } #endif diff --git a/sdm845/Android.mk b/sdm845/Android.mk new file mode 100644 index 0000000..cd2c3ae --- /dev/null +++ b/sdm845/Android.mk @@ -0,0 +1,3 @@ +ifeq ($(call is-vendor-board-platform,QCOM),true) +include $(call all-named-subdir-makefiles,libbt-vendor) +endif # is-vendor-board-platform diff --git a/sdm845/CleanSpec.mk b/sdm845/CleanSpec.mk new file mode 100755 index 0000000..8ab6f23 --- /dev/null +++ b/sdm845/CleanSpec.mk @@ -0,0 +1,54 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbt-vendor_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/NOTICE_FILES/src/system/vendor/lib/libbt-vendor.so.txt) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libbt-vendor.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/vendor/lib/libbt-vendor.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/vendor/lib/libbt-vendor.so) diff --git a/sdm845/libbt-vendor/Android.mk b/sdm845/libbt-vendor/Android.mk new file mode 100644 index 0000000..8d3f9d4 --- /dev/null +++ b/sdm845/libbt-vendor/Android.mk @@ -0,0 +1,88 @@ +# +# Copyright 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +ifeq ($(BOARD_HAVE_BLUETOOTH_QCOM),true) + +include $(CLEAR_VARS) + + +LOCAL_SRC_FILES := \ + src/bt_vendor_qcom.c \ + src/hardware.c \ + src/hci_uart.c \ + src/hci_smd.c \ + src/hw_rome.c \ + src/hw_ar3k.c \ + src/bt_vendor_persist.cpp + +#Disable this flag in case if FM over UART support not needed +LOCAL_CFLAGS := -DFM_OVER_UART + +ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) +LOCAL_CFLAGS += -DPANIC_ON_SOC_CRASH +LOCAL_CFLAGS += -DENABLE_DBG_FLAGS +endif + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + external/bluetooth/bluedroid/hci/include \ + system/bt/hci/include \ + $(TARGET_OUT_HEADERS)/bt/hci_qcomm_init \ + $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + +LOCAL_ADDITIONAL_DEPENDENCIES += \ +$(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr + +ifeq ($(BOARD_HAS_QCA_BT_AR3002), true) +LOCAL_C_FLAGS := \ + -DBT_WAKE_VIA_PROC +endif #BOARD_HAS_QCA_BT_AR3002 + +ifeq ($(WIFI_BT_STATUS_SYNC), true) +LOCAL_CFLAGS += -DWIFI_BT_STATUS_SYNC +endif #WIFI_BT_STATUS_SYNC + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libbtnv + +LOCAL_MODULE := libbt-vendor +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := SHARED_LIBRARIES +LOCAL_MODULE_OWNER := qcom + +ifdef TARGET_2ND_ARCH +LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib +LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64 +else +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES) +endif + +LOCAL_CFLAGS += -DBT_NV_SUPPORT + +ifneq ($(BOARD_ANT_WIRELESS_DEVICE),) +LOCAL_CFLAGS += -DENABLE_ANT +endif +#LOCAL_CFLAGS += -DREAD_BT_ADDR_FROM_PROP + +#include $(LOCAL_PATH)/vnd_buildcfg.mk + +include $(BUILD_SHARED_LIBRARY) + +endif # BOARD_HAVE_BLUETOOTH_QCOM diff --git a/sdm845/libbt-vendor/NOTICE b/sdm845/libbt-vendor/NOTICE new file mode 100644 index 0000000..33ff961 --- /dev/null +++ b/sdm845/libbt-vendor/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2012, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/sdm845/libbt-vendor/include/bt_vendor_persist.h b/sdm845/libbt-vendor/include/bt_vendor_persist.h new file mode 100644 index 0000000..4f2e8ee --- /dev/null +++ b/sdm845/libbt-vendor/include/bt_vendor_persist.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef BT_VENDOR_PERSIST_H_ +#define BT_VENDOR_PERSIST_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdio.h> + +#ifdef BT_NV_SUPPORT + +#endif /* BT_NV_SUPPORT */ +typedef unsigned char boolean; +/*=========================================================================== +FUNCTION bt_vendor_nv_read + +DESCRIPTION + Helper Routine to process the nv read command + +DEPENDENCIES + NIL + +RETURN VALUE + RETURN VALUE + FALSE = failure, else TRUE + +SIDE EFFECTS + None + +===========================================================================*/ +extern uint8_t bt_vendor_nv_read +( + uint8_t nv_item, + uint8_t * rsp_buf +); + +#ifdef __cplusplus +} +#endif + +#endif /* BT_VENDOR_PERSIST_H_ */ + diff --git a/sdm845/libbt-vendor/include/bt_vendor_qcom.h b/sdm845/libbt-vendor/include/bt_vendor_qcom.h new file mode 100644 index 0000000..8565b6c --- /dev/null +++ b/sdm845/libbt-vendor/include/bt_vendor_qcom.h @@ -0,0 +1,97 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BT_VENDOR_QCOM_H +#define BT_VENDOR_QCOM_H + +#include <stdbool.h> +#include "bt_vendor_lib.h" + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;} +#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);} +#define UINT32_TO_STREAM(p, u32) {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);} + +typedef enum { + BT_SOC_DEFAULT = 0, + BT_SOC_SMD = BT_SOC_DEFAULT, + BT_SOC_AR3K, + BT_SOC_ROME, + BT_SOC_CHEROKEE, + /* Add chipset type here */ + BT_SOC_RESERVED +}bt_soc_type; + +typedef enum { + FM_VND_OP_POWER_CTRL = (unsigned int)BT_VND_OP_A2DP_OFFLOAD_STOP + 1, + BT_VND_OP_FM_USERIAL_OPEN, + BT_VND_OP_FM_USERIAL_CLOSE, +}bt_fm_serial; + +typedef enum { + BT_VND_OP_ANT_USERIAL_OPEN = 254, + BT_VND_OP_ANT_USERIAL_CLOSE +}ant_serial; + +/* HW_NEED_END_WITH_HCI_RESET + + code implementation of sending a HCI_RESET command during the epilog + process. It calls back to the callers after command complete of HCI_RESET + is received. + + Default TRUE . +*/ +#ifndef HW_NEED_END_WITH_HCI_RESET +#define HW_NEED_END_WITH_HCI_RESET TRUE +#endif + +#define HCI_RESET 0x0C03 +#define HCI_CMD_PREAMBLE_SIZE 3 +#define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE 5 +#define HCI_EVT_CMD_CMPL_OPCODE 3 +#define BT_PWR_CNTRL_DEVICE "/dev/btpower" + +enum { + BT_STATUS_SUCCESS = 0, + BT_STATUS_FAIL, + BT_STATUS_INVAL, + BT_STATUS_NOMEM, + BT_STATUS_PROP_FAILURE, +}; +#define BT_CMD_PWR_CTRL 0xbfad +struct bt_qcom_struct { + int fd[2]; + int ant_fd; + int fm_fd; + bt_vendor_callbacks_t *cb; + uint8_t bdaddr[6]; + int soc_type; + int rfkill_id; + char *rfkill_state; + bool enable_extldo; +}; +extern struct bt_qcom_struct *q; +extern pthread_mutex_t q_lock; + +#endif /* BT_VENDOR_QCOM_H */ + diff --git a/sdm845/libbt-vendor/include/hci_smd.h b/sdm845/libbt-vendor/include/hci_smd.h new file mode 100644 index 0000000..055b779 --- /dev/null +++ b/sdm845/libbt-vendor/include/hci_smd.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012 The Android Open Source Project + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * 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. + */ + +/****************************************************************************** + * + * Filename: hci_smd.h + * + * Description: Contains vendor-specific definitions used in smd controls + * + ******************************************************************************/ + +#ifndef HCI_SMD_H +#define HCI_SMD_H + +#define APPS_RIVA_BT_ACL_CH "/dev/smd2" +#define APPS_RIVA_BT_CMD_CH "/dev/smd3" + +int bt_hci_init_transport ( int *pFd ); + +int bt_hci_deinit_transport(int *pFd); + +#endif /* HCI_SMD_H */ diff --git a/sdm845/libbt-vendor/include/hci_uart.h b/sdm845/libbt-vendor/include/hci_uart.h new file mode 100644 index 0000000..21e9689 --- /dev/null +++ b/sdm845/libbt-vendor/include/hci_uart.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HCI_UART_H +#define HCI_UART_H + +#include <asm-generic/ioctls.h> + +/* Variables to identify the platform */ +/*BT HS UART TTY DEVICE */ +#define BT_HS_UART_DEVICE "/dev/ttyHS0" + +/**** baud rates ****/ +#define USERIAL_BAUD_300 0 +#define USERIAL_BAUD_600 1 +#define USERIAL_BAUD_1200 2 +#define USERIAL_BAUD_2400 3 +#define USERIAL_BAUD_9600 4 +#define USERIAL_BAUD_19200 5 +#define USERIAL_BAUD_57600 6 +#define USERIAL_BAUD_115200 7 +#define USERIAL_BAUD_230400 8 +#define USERIAL_BAUD_460800 9 +#define USERIAL_BAUD_921600 10 +#define USERIAL_BAUD_1M 11 +#define USERIAL_BAUD_1_5M 12 +#define USERIAL_BAUD_2M 13 +#define USERIAL_BAUD_3M 14 +#define USERIAL_BAUD_4M 15 +#define USERIAL_BAUD_AUTO 16 + +/**** Data Format ****/ +/* Stop Bits */ +#define USERIAL_STOPBITS_1 1 +#define USERIAL_STOPBITS_1_5 (1<<1) +#define USERIAL_STOPBITS_2 (1<<2) + +/* Parity Bits */ +#define USERIAL_PARITY_NONE (1<<3) +#define USERIAL_PARITY_EVEN (1<<4) +#define USERIAL_PARITY_ODD (1<<5) + +/* Data Bits */ +#define USERIAL_DATABITS_5 (1<<6) +#define USERIAL_DATABITS_6 (1<<7) +#define USERIAL_DATABITS_7 (1<<8) +#define USERIAL_DATABITS_8 (1<<9) + +/* HCI Packet types */ +#define HCI_COMMAND_PKT 0x01 +#define HCI_ACLDATA_PKT 0x02 +#define HCI_SCODATA_PKT 0x03 +#define HCI_EVENT_PKT 0x04 +#define HCI_VENDOR_PKT 0xff + +/* HCI Command/Event Opcode */ +#define HCI_RESET 0x0C03 +#define EVT_CMD_COMPLETE 0x0E + +/* Command opcode pack/unpack */ +#define cmd_opcode_pack(ogf, ocf) (uint16_t)((ocf & 0x03ff)|(ogf << 10)) + +#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) +/* These are the ioctl values used for bt_wake ioctl via UART driver. you may + * need to redefine them on you platform! + * Logically they need to be unique and not colide with existing uart ioctl's. + */ +#ifndef USERIAL_IOCTL_BT_WAKE_ASSERT +#define USERIAL_IOCTL_BT_WAKE_ASSERT 0x8003 +#endif +#ifndef USERIAL_IOCTL_BT_WAKE_DEASSERT +#define USERIAL_IOCTL_BT_WAKE_DEASSERT 0x8004 +#endif +#ifndef USERIAL_IOCTL_BT_WAKE_GET_ST +#define USERIAL_IOCTL_BT_WAKE_GET_ST 0x8005 +#endif +#endif // (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) + +/* UART CLOCK IOCTLS*/ +/* UART CLOCK IOCTLS*/ +#define USERIAL_OP_CLK_ON TIOCPMGET /* PM get */ +#define USERIAL_OP_CLK_OFF TIOCPMPUT /* PM put */ +#define USERIAL_OP_CLK_STATE TIOCPMACT /* PM is active */ + +/****************************************************************************** +** Type definitions +******************************************************************************/ + +/* Structure used to configure serial port during open */ +typedef struct +{ + uint16_t fmt; /* Data format */ + uint8_t baud; /* Baud rate */ +} tUSERIAL_CFG; + +typedef enum { +#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) + USERIAL_OP_ASSERT_BT_WAKE, + USERIAL_OP_DEASSERT_BT_WAKE, + USERIAL_OP_GET_BT_WAKE_STATE, +#endif + USERIAL_OP_FLOW_ON, + USERIAL_OP_FLOW_OFF, + USERIAL_OP_NOP, +} userial_vendor_ioctl_op_t; + +/* UPIO signals */ +enum { + UPIO_BT_WAKE = 0, + UPIO_HOST_WAKE, + UPIO_LPM_MODE, + UPIO_MAX_COUNT +}; + +/* UPIO assertion/deassertion */ +enum { + UPIO_UNKNOWN = 0, + UPIO_DEASSERT, + UPIO_ASSERT +}; + +#define VND_PORT_NAME_MAXLEN 256 + +/* vendor serial control block */ +typedef struct +{ + int fd; /* fd to Bluetooth device */ + struct termios termios; /* serial terminal of BT port */ + char port_name[VND_PORT_NAME_MAXLEN]; +} vnd_userial_cb_t; + +typedef struct { + uint8_t ncmd; + uint16_t opcode; +} __attribute__ ((packed)) evt_cmd_complete; + +typedef struct { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; +} __attribute__ ((packed)) evt_cmd_status; + +typedef struct { + uint16_t opcode; + uint8_t plen; +} __attribute__ ((packed)) hci_command_hdr; + +typedef struct { + uint8_t evt; + uint8_t plen; +} __attribute__ ((packed)) hci_event_hdr; + +/****************************************************************************** +** Extern +******************************************************************************/ +extern vnd_userial_cb_t vnd_userial; + + +/******************************************************************************* +** +** Function userial_vendor_init +** +** Description Initialize userial vendor-specific control block +** +** Returns None +** +*******************************************************************************/ +void userial_vendor_init(void); + +/******************************************************************************* +** +** Function userial_vendor_open +** +** Description Open the serial port with the given configuration +** +** Returns device fd +** +*******************************************************************************/ +int userial_vendor_open(tUSERIAL_CFG *p_cfg); + +/******************************************************************************* +** +** Function userial_vendor_close +** +** Description Conduct vendor-specific close work +** +** Returns None +** +*******************************************************************************/ +void userial_vendor_close(void); + +/******************************************************************************* +** +** Function userial_vendor_set_baud +** +** Description Set new baud rate +** +** Returns None +** +*******************************************************************************/ +void userial_vendor_set_baud(uint8_t userial_baud); + +/******************************************************************************* +** +** Function userial_vendor_ioctl +** +** Description ioctl inteface +** +** Returns int error +** +*******************************************************************************/ +int userial_vendor_ioctl(userial_vendor_ioctl_op_t op, int *p_data); + +/******************************************************************************* +** +** Function userial_to_tcio_baud +** +** Description helper function converts USERIAL baud rates into TCIO +** conforming baud rates +** +** Returns TRUE/FALSE +** +*******************************************************************************/ +uint8_t userial_to_tcio_baud(uint8_t cfg_baud, uint32_t *baud); + +/******************************************************************************* +** +** Function userial_to_baud_tcio +** +** Description helper function converts TCIO baud rate into integer +** +** Returns uint32_t +** +*******************************************************************************/ +int userial_tcio_baud_to_int(uint32_t baud); + +/******************************************************************************* +** +** Function read_hci_event +** +** Description Read HCI event during vendor initialization +** +** Returns int: size to read +** +*******************************************************************************/ +int read_hci_event(int fd, unsigned char* buf, int size); + +#endif /* HCI_UART_H */ diff --git a/sdm845/libbt-vendor/include/hw_ar3k.h b/sdm845/libbt-vendor/include/hw_ar3k.h new file mode 100644 index 0000000..2129548 --- /dev/null +++ b/sdm845/libbt-vendor/include/hw_ar3k.h @@ -0,0 +1,164 @@ +/* + * Copyright 2012 The Android Open Source Project + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HW_AR3K_H +#define HW_AR3K_H + +/****************************************************************************** +** Constants & Macros +******************************************************************************/ +#define MAX_CNT_RETRY 100 + +#define HCI_MAX_CMD_SIZE 260 +#define HCI_MAX_EVENT_SIZE 260 +#define HCI_CHG_BAUD_CMD_OCF 0x0C +#define HCI_VENDOR_CMD_OGF 0x3F +#define WRITE_BDADDR_CMD_LEN 14 +#define WRITE_BAUD_CMD_LEN 6 +#define MAX_CMD_LEN WRITE_BDADDR_CMD_LEN +#define GET_VERSION_OCF 0x1E +/* Byte order conversions */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htobs(d) (d) +#define htobl(d) (d) +#define btohs(d) (d) +#define btohl(d) (d) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define htobs(d) bswap_16(d) +#define htobl(d) bswap_32(d) +#define btohs(d) bswap_16(d) +#define btohl(d) bswap_32(d) +#else +#error "Unknown byte order" +#endif + +#define FW_PATH "/system/etc/firmware/ar3k/" + +#define STREAM_TO_UINT16(u16, p) \ + {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;} +#define UINT16_TO_STREAM(p, u16) \ + {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);} +#define UINT32_TO_STREAM(p, u32) \ + {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8);\ + *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);} + +#define MAX_TAGS 50 +#define PS_HDR_LEN 4 +#define HCI_VENDOR_CMD_OGF 0x3F +#define HCI_PS_CMD_OCF 0x0B + +#define VERIFY_CRC 9 +#define PS_REGION 1 +#define PATCH_REGION 2 +#define BDADDR_FILE "ar3kbdaddr.pst" + + +#define MAX_PATCH_CMD 244 +struct patch_entry { + int16_t len; + uint8_t data[MAX_PATCH_CMD]; +}; +#define HCI_UART_RAW_DEVICE 0 +#define HCI_COMMAND_HDR_SIZE 3 +#define PS_WRITE 1 +#define PS_RESET 2 +#define WRITE_PATCH 8 +#define ENABLE_PATCH 11 + +#define HCI_PS_CMD_HDR_LEN 7 +#define HCI_CMD_MAX_LEN 258 +#define PS_RESET_PARAM_LEN 6 +#define PS_RESET_CMD_LEN (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN) + +#define PS_ID_MASK 0xFF + + +#define LOCAL_NAME_BUFFER_LEN 32 +#define DEV_REGISTER 0x4FFC +#define GET_DEV_TYPE_OCF 0x05 + +#define HCIDEVUP _IOW('H', 201, int) +#define OGF_VENDOR_CMD 0x3f +#define EVT_CMD_COMPLETE_SIZE 3 +#define EVT_CMD_STATUS 0x0F +#define EVT_CMD_STATUS_SIZE 4 +#define HCI_COMMAND_HDR_SIZE 3 +#define HCI_EVENT_HDR_SIZE 2 +#define HCI_EV_SUCCESS 0x00 +/* HCI Socket options */ +#define HCI_DATA_DIR 1 +#define HCI_FILTER 2 +#define HCI_TIME_STAMP 3 + +/* HCI CMSG flags */ +#define HCI_CMSG_DIR 0x0001 +#define HCI_CMSG_TSTAMP 0x0002 + +#ifndef VENDOR_LPM_PROC_NODE +#define VENDOR_LPM_PROC_NODE "/sys/module/hci_uart/parameters/ath_lpm" +#endif + +/* proc fs node for notifying write request */ +#ifndef VENDOR_BTWRITE_PROC_NODE +#define VENDOR_BTWRITE_PROC_NODE "/sys/module/hci_uart/parameters/ath_btwrite" +#endif + +/****************************************************************************** +** Local type definitions +******************************************************************************/ +typedef struct { + uint8_t b[6]; +} __attribute__((packed)) bdaddr_t; + +struct sockaddr_hci { + sa_family_t hci_family; + unsigned short hci_dev; + unsigned short hci_channel; +}; + +struct tag_info { + unsigned section; + unsigned line_count; + unsigned char_cnt; + unsigned byte_count; +}; + +struct ps_cfg_entry { + uint32_t id; + uint32_t len; + uint8_t *data; +}; + +struct ps_entry_type { + unsigned char type; + unsigned char array; +}; + +struct uart_t { + char *type; + int m_id; + int p_id; + int proto; + int init_speed; + int speed; + int flags; + int pm; + char *bdaddr; + int (*init) (int fd, struct uart_t *u, struct termios *ti); + int (*post) (int fd, struct uart_t *u, struct termios *ti); +}; +#endif /* HW_AR3K_H */ diff --git a/sdm845/libbt-vendor/include/hw_rome.h b/sdm845/libbt-vendor/include/hw_rome.h new file mode 100644 index 0000000..08efb39 --- /dev/null +++ b/sdm845/libbt-vendor/include/hw_rome.h @@ -0,0 +1,290 @@ +/* + * Copyright 2012 The Android Open Source Project + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HW_ROME_H +#define HW_ROME_H + + +/****************************************************************************** +** Constants & Macros +******************************************************************************/ +#define HCI_MAX_CMD_SIZE 260 +#define HCI_MAX_EVENT_SIZE 260 +#define PRINT_BUF_SIZE ((HCI_MAX_CMD_SIZE * 3) + 2) + +#define HCI_CHG_BAUD_CMD_OCF 0x0C +#define HCI_VENDOR_CMD_OGF 0x3F +#define WRITE_BDADDR_CMD_LEN 14 +#define WRITE_BAUD_CMD_LEN 6 +#define MAX_CMD_LEN WRITE_BDADDR_CMD_LEN +#define GET_VERSION_OCF 0x1E + +#define PS_HDR_LEN 4 +#define HCI_VENDOR_CMD_OGF 0x3F +#define HCI_PS_CMD_OCF 0x0B + +#define HCI_COMMAND_HDR_SIZE 3 +#define EVT_CMD_COMPLETE_SIZE 3 +#define EVT_CMD_STATUS 0x0F +#define EVT_CMD_STATUS_SIZE 4 +#define HCI_EVENT_HDR_SIZE 2 +#define HCI_EV_SUCCESS 0x00 +/* HCI Socket options */ +#define HCI_DATA_DIR 1 +#define HCI_FILTER 2 +#define HCI_TIME_STAMP 3 + +#define P_ID_OFFSET (0) +#define HCI_CMD_IND (1) +#define EVENTCODE_OFFSET (1) +#define EVT_PLEN (2) +#define PLEN (3) +#define CMD_RSP_OFFSET (3) +#define RSP_TYPE_OFFSET (4) +#define BAUDRATE_RSP_STATUS_OFFSET (4) +#define CMD_STATUS_OFFSET (5) +#define P_ROME_VER_OFFSET (4) +#define P_BUILD_VER_OFFSET (6) +#define P_BASE_ADDR_OFFSET (8) +#define P_ENTRY_ADDR_OFFSET (12) +#define P_LEN_OFFSET (16) +#define P_CRC_OFFSET (20) +#define P_CONTROL_OFFSET (24) +#define PATCH_HDR_LEN (28) +#define MAX_DATA_PER_SEGMENT (239) +#define VSEVENT_CODE (0xFF) +#define HC_VS_MAX_CMD_EVENT (0xFF) +#define PATCH_PROD_ID_OFFSET (5) +#define PATCH_PATCH_VER_OFFSET (9) +#define PATCH_ROM_BUILD_VER_OFFSET (11) +#define PATCH_SOC_VER_OFFSET (13) +#define MAX_SIZE_PER_TLV_SEGMENT (243) + +/* VS Opcode */ +#define HCI_PATCH_CMD_OCF (0) +#define EDL_SET_BAUDRATE_CMD_OCF (0x48) +#define EDL_WIPOWER_VS_CMD_OCF (0x1f) +#define HCI_VS_GET_ADDON_FEATURES_SUPPORT (0x1d) + +/* VS Commands */ +#define VSC_SET_BAUDRATE_REQ_LEN (1) +#define EDL_PATCH_CMD_LEN (1) +#define EDL_PATCH_CMD_REQ_LEN (1) +#define EDL_WIP_QUERY_CHARGING_STATUS_LEN (0x01) +#define EDL_WIP_START_HANDOFF_TO_HOST_LEN (0x01) +#define EDL_PATCH_DLD_REQ_CMD (0x01) +#define EDL_PATCH_RST_REQ_CMD (0x05) +#define EDL_PATCH_SET_REQ_CMD (0x16) +#define EDL_PATCH_ATCH_REQ_CMD (0x17) +#define EDL_PATCH_VER_REQ_CMD (0x19) +#define EDL_GET_BUILD_INFO (0x20) +#define EDL_PATCH_TLV_REQ_CMD (0x1E) +#define EDL_WIP_QUERY_CHARGING_STATUS_CMD (0x1D) +#define EDL_WIP_START_HANDOFF_TO_HOST_CMD (0x1E) + +/* VS Event */ +#define EDL_CMD_REQ_RES_EVT (0x00) +#define EDL_CMD_EXE_STATUS_EVT (0x00) +#define EDL_SET_BAUDRATE_RSP_EVT (0x92) +#define EDL_PATCH_VER_RES_EVT (0x19) +#define EDL_TVL_DNLD_RES_EVT (0x04) +#define EDL_APP_VER_RES_EVT (0x02) +#define EDL_WIP_QUERY_CHARGING_STATUS_EVT (0x18) +#define EDL_WIP_START_HANDOFF_TO_HOST_EVENT (0x19) +#define HCI_VS_GET_ADDON_FEATURES_EVENT (0x1B) +#define HCI_VS_GET_BUILD_VER_EVT (0x05) +#define HCI_VS_STRAY_EVT (0x17) + +/* Status Codes of HCI CMD execution*/ +#define HCI_CMD_SUCCESS (0x0) +#define PATCH_LEN_ERROR (0x1) +#define PATCH_VER_ERROR (0x2) +#define PATCH_CRC_ERROR (0x3) +#define PATCH_NOT_FOUND (0x4) +#define TLV_TYPE_ERROR (0x10) +#define NVM_ACCESS_CODE (0x0B) +#define BAUDRATE_CHANGE_SUCCESS (1) + +/* Wipower status codes */ +#define WIPOWER_IN_EMBEDDED_MODE 0x01 +#define NON_WIPOWER_MODE 0x02 + +/* mask to validate support for wipower */ +#define ADDON_FEATURES_EVT_WIPOWER_MASK (0x01) + +/* TLV_TYPE */ +#define TLV_TYPE_PATCH (1) +#define TLV_TYPE_NVM (2) + +/* NVM */ +#define MAX_TAG_CMD 30 +#define TAG_END 0xFF +#define NVM_ACCESS_SET 0x01 +#define TAG_NUM_OFFSET 5 +#define TAG_NUM_2 2 +#define TAG_BDADDR_OFFSET 7 + +/* NVM Tags specifically used for ROME 1.0 */ +#define ROME_1_0_100022_1 0x101000221 +#define ROME_1_0_100019 0x101000190 +#define ROME_1_0_6002 0x100600200 + +/* Default NVM Version setting for ROME 1.0 */ +#define NVM_VERSION ROME_1_0_100022_1 + + +#define LSH(val, n) ((uint32_t)(val) << (n)) +#define EXTRACT_BYTE(val, pos) (char) (((val) >> (8 * (pos))) & 0xFF) +#define CALC_SEG_SIZE(len, max) ((plen) % (max))?((plen/max)+1) : ((plen) / (max)) + +#define ROME_FW_PATH "/system/etc/firmware/rampatch.img" +#define ROME_RAMPATCH_TLV_PATH "/system/etc/firmware/rampatch_tlv.img" +#define ROME_NVM_TLV_PATH "/system/etc/firmware/nvm_tlv.bin" +#define ROME_RAMPATCH_TLV_1_0_3_PATH "/system/etc/firmware/rampatch_tlv_1.3.tlv" +#define ROME_NVM_TLV_1_0_3_PATH "/system/etc/firmware/nvm_tlv_1.3.bin" +#define ROME_RAMPATCH_TLV_2_0_1_PATH "/system/etc/firmware/rampatch_tlv_2.1.tlv" +#define ROME_NVM_TLV_2_0_1_PATH "/system/etc/firmware/nvm_tlv_2.1.bin" +#define ROME_RAMPATCH_TLV_3_0_0_PATH "/bt_firmware/image/btfw30.tlv" +#define ROME_NVM_TLV_3_0_0_PATH "/bt_firmware/image/btnv30.bin" +#define ROME_RAMPATCH_TLV_3_0_2_PATH "/bt_firmware/image/btfw32.tlv" +#define ROME_NVM_TLV_3_0_2_PATH "/bt_firmware/image/btnv32.bin" + +#define ROME_3_1_FW_SU "bprm.cnss.3.1" +#define ROME_3_2_FW_SU "btfwp.cnss.3.2" + +/* Rome 3.1 FW SU release has been branched from rome 3.0 SU 224 + So, rome 3.1 formula is SU = patch version -(0xE0 = 224) - 0x111 -1 +*/ +#define ROME_3_1_FW_SW_OFFSET 0x01F2 + +/* Rome 3.2 FW SU formula is SU = patch version - 0x111 -1 */ +#define ROME_3_2_FW_SW_OFFSET 0x0112 + +/* This header value in rampatch file decides event handling mechanism in the HOST */ +#define ROME_SKIP_EVT_NONE 0x00 +#define ROME_SKIP_EVT_VSE 0x01 +#define ROME_SKIP_EVT_CC 0x02 +#define ROME_SKIP_EVT_VSE_CC 0x03 + +/****************************************************************************** +** Local type definitions +******************************************************************************/ +typedef struct { + unsigned short rom_version; + unsigned short build_version; +} __attribute__ ((packed)) patch_version; + +typedef struct { + unsigned int patch_id; + patch_version patch_ver; + unsigned int patch_base_addr; + unsigned int patch_entry_addr; + unsigned short patch_length; + int patch_crc; + unsigned short patch_ctrl; +} __attribute__ ((packed)) patch_info; + +typedef struct { + unsigned int tlv_data_len; + unsigned int tlv_patch_data_len; + unsigned char sign_ver; + unsigned char sign_algorithm; + unsigned char dwnd_cfg; + unsigned char reserved1; + unsigned short prod_id; + unsigned short build_ver; + unsigned short patch_ver; + unsigned short reserved2; + unsigned int patch_entry_addr; +} __attribute__ ((packed)) tlv_patch_hdr; + +typedef struct { + unsigned short tag_id; + unsigned short tag_len; + unsigned int tag_ptr; + unsigned int tag_ex_flag; +} __attribute__ ((packed)) tlv_nvm_hdr; + +typedef struct { + unsigned char tlv_type; + unsigned char tlv_length1; + unsigned char tlv_length2; + unsigned char tlv_length3; + + union{ + tlv_patch_hdr patch; + tlv_nvm_hdr nvm; + }tlv; +} __attribute__ ((packed)) tlv_patch_info; + + +enum{ + BAUDRATE_115200 = 0x00, + BAUDRATE_57600 = 0x01, + BAUDRATE_38400 = 0x02, + BAUDRATE_19200 = 0x03, + BAUDRATE_9600 = 0x04, + BAUDRATE_230400 = 0x05, + BAUDRATE_250000 = 0x06, + BAUDRATE_460800 = 0x07, + BAUDRATE_500000 = 0x08, + BAUDRATE_720000 = 0x09, + BAUDRATE_921600 = 0x0A, + BAUDRATE_1000000 = 0x0B, + BAUDRATE_1250000 = 0x0C, + BAUDRATE_2000000 = 0x0D, + BAUDRATE_3000000 = 0x0E, + BAUDRATE_4000000 = 0x0F, + BAUDRATE_1600000 = 0x10, + BAUDRATE_3200000 = 0x11, + BAUDRATE_3500000 = 0x12, + BAUDRATE_AUTO = 0xFE, + BAUDRATE_Reserved = 0xFF +}; + +enum{ + ROME_PATCH_VER_0100 = 0x0100, + ROME_PATCH_VER_0101 = 0x0101, + ROME_PATCH_VER_0200 = 0x0200, + ROME_PATCH_VER_0300 = 0x0300, + ROME_PATCH_VER_0302 = 0x0302 + }; + +enum{ + ROME_SOC_ID_00 = 0x00000000, + ROME_SOC_ID_11 = 0x00000011, + ROME_SOC_ID_22 = 0x00000022, + ROME_SOC_ID_44 = 0x00000044 +}; + +enum{ + ROME_VER_UNKNOWN = 0, + ROME_VER_1_0 = ((ROME_PATCH_VER_0100 << 16 ) | ROME_SOC_ID_00 ), + ROME_VER_1_1 = ((ROME_PATCH_VER_0101 << 16 ) | ROME_SOC_ID_00 ), + ROME_VER_1_3 = ((ROME_PATCH_VER_0200 << 16 ) | ROME_SOC_ID_00 ), + ROME_VER_2_1 = ((ROME_PATCH_VER_0200 << 16 ) | ROME_SOC_ID_11 ), + ROME_VER_3_0 = ((ROME_PATCH_VER_0300 << 16 ) | ROME_SOC_ID_22 ), + ROME_VER_3_2 = ((ROME_PATCH_VER_0302 << 16 ) | ROME_SOC_ID_44 ) +}; + +//declarations +int rome_soc_init(int fd, char *bdaddr); +int check_embedded_mode(int fd); +int rome_get_addon_feature_list(int fd); +void enable_controller_log(int fd, unsigned char req); +void cherokee_shutdown_vs_cmd(int fd); +#endif /* HW_ROME_H */ diff --git a/sdm845/libbt-vendor/include/vnd_generic.txt b/sdm845/libbt-vendor/include/vnd_generic.txt new file mode 100644 index 0000000..43e790c --- /dev/null +++ b/sdm845/libbt-vendor/include/vnd_generic.txt @@ -0,0 +1,9 @@ +BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyO1" +FW_PATCHFILE_LOCATION = "/vendor/firmware/" +BT_WAKE_VIA_USERIAL_IOCTL = TRUE +LPM_IDLE_TIMEOUT_MULTIPLE = 5 +SCO_USE_I2S_INTERFACE = TRUE +BTVND_DBG = FALSE +BTHW_DBG = TRUE +VNDUSERIAL_DBG = FALSE +UPIO_DBG = FALSE diff --git a/sdm845/libbt-vendor/include/vnd_mako.txt b/sdm845/libbt-vendor/include/vnd_mako.txt new file mode 100644 index 0000000..5408c92 --- /dev/null +++ b/sdm845/libbt-vendor/include/vnd_mako.txt @@ -0,0 +1,9 @@ +BLUETOOTH_UART_DEVICE_PORT = "/dev/smd3" +FW_PATCHFILE_LOCATION = "/vendor/firmware/" +BT_WAKE_VIA_USERIAL_IOCTL = TRUE +LPM_IDLE_TIMEOUT_MULTIPLE = 5 +SCO_USE_I2S_INTERFACE = TRUE +BTVND_DBG = FALSE +BTHW_DBG = TRUE +VNDUSERIAL_DBG = FALSE +UPIO_DBG = FALSE diff --git a/sdm845/libbt-vendor/src/bt_vendor_persist.cpp b/sdm845/libbt-vendor/src/bt_vendor_persist.cpp new file mode 100644 index 0000000..519e826 --- /dev/null +++ b/sdm845/libbt-vendor/src/bt_vendor_persist.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include "bt_vendor_persist.h" + +#ifdef BT_NV_SUPPORT +#include "bt_nv.h" +#include <utils/Log.h> + +/*=========================================================================== +FUNCTION bt_vendor_nv_read + +DESCRIPTION + Helper Routine to process the nv read command + +DEPENDENCIES + NIL + +RETURN VALUE + RETURN VALUE + FALSE = failure, else TRUE + +SIDE EFFECTS + None + +===========================================================================*/ +uint8_t bt_vendor_nv_read +( + uint8_t nv_item, + uint8_t * rsp_buf +) +{ + nv_persist_item_type my_nv_item; + nv_persist_stat_enum_type cmd_result; + boolean result = FALSE; + + switch(nv_item) + { + case NV_BD_ADDR_I: + cmd_result = (nv_persist_stat_enum_type)bt_nv_cmd(NV_READ_F, NV_BD_ADDR_I, &my_nv_item); + ALOGI("CMD result: %d", cmd_result); + if (NV_SUCCESS != cmd_result) + { + ALOGE("Failed to read BD_ADDR from NV"); + /* Send fail response */ + result = FALSE; + } + else + { + /* copy bytes */ + rsp_buf[0] = my_nv_item.bd_addr[0]; + rsp_buf[1] = my_nv_item.bd_addr[1]; + rsp_buf[2] = my_nv_item.bd_addr[2]; + rsp_buf[3] = my_nv_item.bd_addr[3]; + rsp_buf[4] = my_nv_item.bd_addr[4]; + rsp_buf[5] = my_nv_item.bd_addr[5]; + + ALOGI("BD address read for NV_BD_ADDR_I: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + (unsigned int) my_nv_item.bd_addr[0],(unsigned int) my_nv_item.bd_addr[1], + (unsigned int) my_nv_item.bd_addr[2],(unsigned int) my_nv_item.bd_addr[3], + (unsigned int) my_nv_item.bd_addr[4],(unsigned int) my_nv_item.bd_addr[5]); + result = TRUE; + } + break; + } + return result; +} +#endif /* End of BT_NV_SUPPORT */ diff --git a/sdm845/libbt-vendor/src/bt_vendor_qcom.c b/sdm845/libbt-vendor/src/bt_vendor_qcom.c new file mode 100755 index 0000000..8cbf5d1 --- /dev/null +++ b/sdm845/libbt-vendor/src/bt_vendor_qcom.c @@ -0,0 +1,1483 @@ +/* + * Copyright 2012 The Android Open Source Project + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * 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. + */ + +/****************************************************************************** + * + * Filename: bt_vendor_qcom.c + * + * Description: vendor specific library implementation + * + ******************************************************************************/ +#define LOG_TAG "bt_vendor" +#define BLUETOOTH_MAC_ADDR_BOOT_PROPERTY "ro.boot.btmacaddr" + +#include <utils/Log.h> +#include <cutils/properties.h> +#include <fcntl.h> +#include <termios.h> +#include "bt_vendor_qcom.h" +#include "hci_uart.h" +#include "hci_smd.h" +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <cutils/sockets.h> +#include <linux/un.h> +#include "bt_vendor_persist.h" +#include "hw_rome.h" +#include "bt_vendor_lib.h" +#define WAIT_TIMEOUT 200000 +#define BT_VND_OP_GET_LINESPEED 30 + +#define STOP_WCNSS_FILTER 0xDD +#define STOP_WAIT_TIMEOUT 1000 + +#define SOC_INIT_PROPERTY "wc_transport.soc_initialized" + +#define BT_VND_FILTER_START "wc_transport.start_hci" + +#define CMD_TIMEOUT 0x22 + +static void wait_for_patch_download(bool is_ant_req); +static bool is_debug_force_special_bytes(void); +int connect_to_local_socket(char* name); +/****************************************************************************** +** Externs +******************************************************************************/ +extern int hw_config(int nState); +extern int is_hw_ready(); +extern int chipset_ver; + +/****************************************************************************** +** Variables +******************************************************************************/ +struct bt_qcom_struct *q = NULL; +pthread_mutex_t q_lock = PTHREAD_MUTEX_INITIALIZER; + +int userial_clock_operation(int fd, int cmd); +int ath3k_init(int fd, int speed, int init_speed, char *bdaddr, struct termios *ti); +int userial_vendor_get_baud(void); +int readTrpState(); +void lpm_set_ar3k(uint8_t pio, uint8_t action, uint8_t polarity); +bool is_download_progress(); + +static const tUSERIAL_CFG userial_init_cfg = +{ + (USERIAL_DATABITS_8 | USERIAL_PARITY_NONE | USERIAL_STOPBITS_1), + USERIAL_BAUD_115200 +}; + +#if (HW_NEED_END_WITH_HCI_RESET == TRUE) +void __hw_epilog_process(void); +#endif + +#ifdef WIFI_BT_STATUS_SYNC +#include <string.h> +#include <errno.h> +#include <dlfcn.h> +#include "cutils/properties.h" + +static const char WIFI_PROP_NAME[] = "wlan.driver.status"; +static const char SERVICE_PROP_NAME[] = "bluetooth.hsic_ctrl"; +static const char BT_STATUS_NAME[] = "bluetooth.enabled"; +static const char WIFI_SERVICE_PROP[] = "wlan.hsic_ctrl"; + +#define WIFI_BT_STATUS_LOCK "/data/connectivity/wifi_bt_lock" +int isInit=0; +#endif /* WIFI_BT_STATUS_SYNC */ +bool is_soc_initialized(void); + +/****************************************************************************** +** Local type definitions +******************************************************************************/ + +/****************************************************************************** +** Functions +******************************************************************************/ +#ifdef WIFI_BT_STATUS_SYNC +int bt_semaphore_create(void) +{ + int fd; + + fd = open(WIFI_BT_STATUS_LOCK, O_RDONLY); + + if (fd < 0) + ALOGE("can't create file\n"); + + return fd; +} + +int bt_semaphore_get(int fd) +{ + int ret; + + if (fd < 0) + return -1; + + ret = flock(fd, LOCK_EX); + if (ret != 0) { + ALOGE("can't hold lock: %s\n", strerror(errno)); + return -1; + } + + return ret; +} + +int bt_semaphore_release(int fd) +{ + int ret; + + if (fd < 0) + return -1; + + ret = flock(fd, LOCK_UN); + if (ret != 0) { + ALOGE("can't release lock: %s\n", strerror(errno)); + return -1; + } + + return ret; +} + +int bt_semaphore_destroy(int fd) +{ + if (fd < 0) + return -1; + + return close (fd); +} + +int bt_wait_for_service_done(void) +{ + char service_status[PROPERTY_VALUE_MAX]; + int count = 30; + + ALOGE("%s: check\n", __func__); + + /* wait for service done */ + while (count-- > 0) { + property_get(WIFI_SERVICE_PROP, service_status, NULL); + + if (strcmp(service_status, "") != 0) { + usleep(200000); + } else { + break; + } + } + + return 0; +} + +#endif /* WIFI_BT_STATUS_SYNC */ + +/** Get Bluetooth SoC type from system setting */ +static int get_bt_soc_type() +{ + int ret = 0; + char bt_soc_type[PROPERTY_VALUE_MAX]; + + ALOGI("bt-vendor : get_bt_soc_type"); + + ret = property_get("qcom.bluetooth.soc", bt_soc_type, NULL); + if (ret != 0) { + ALOGI("qcom.bluetooth.soc set to %s\n", bt_soc_type); + if (!strncasecmp(bt_soc_type, "rome", sizeof("rome"))) { + return BT_SOC_ROME; + } + else if (!strncasecmp(bt_soc_type, "cherokee", sizeof("cherokee"))) { + return BT_SOC_CHEROKEE; + } + else if (!strncasecmp(bt_soc_type, "ath3k", sizeof("ath3k"))) { + return BT_SOC_AR3K; + } + else if (!strncasecmp(bt_soc_type, "cherokee", sizeof("cherokee"))) { + return BT_SOC_CHEROKEE; + } + else { + ALOGI("qcom.bluetooth.soc not set, so using default.\n"); + return BT_SOC_DEFAULT; + } + } + else { + ALOGE("%s: Failed to get soc type", __FUNCTION__); + ret = BT_SOC_DEFAULT; + } + + return ret; +} + +bool can_perform_action(char action) { + bool can_perform = false; + char ref_count[PROPERTY_VALUE_MAX]; + char inProgress[PROPERTY_VALUE_MAX] = {'\0'}; + int value, ret; + + property_get("wc_transport.ref_count", ref_count, "0"); + + value = atoi(ref_count); + ALOGV("%s: ref_count: %s\n",__func__, ref_count); + + if(action == '1') { + ALOGV("%s: on : value is: %d", __func__, value); + if(value == 1) + { + if ((is_soc_initialized() == true) + || is_download_progress() || get_bt_soc_type() == BT_SOC_CHEROKEE) + { + value++; + ALOGV("%s: on : value is incremented to : %d", __func__, value); + } + } + else + { + value++; + } + + if (value == 1) + can_perform = true; + else if (value > 3) + return false; + } + else { + ALOGV("%s: off : value is: %d", __func__, value); + if (--value <= 0) { + ALOGE("%s: BT turn off twice before BT On(ref_count=%d)\n", + __func__, value); + value = 0; + can_perform = true; + } + } + + snprintf(ref_count, 3, "%d", value); + ALOGV("%s: updated ref_count is: %s", __func__, ref_count); + + ret = property_set("wc_transport.ref_count", ref_count); + if (ret < 0) { + ALOGE("%s: Error while updating property: %d\n", __func__, ret); + return false; + } + ALOGV("%s returning %d", __func__, can_perform); + return can_perform; +} + +void stop_hci_filter() { + char value[PROPERTY_VALUE_MAX] = {'\0'}; + int retval, filter_ctrl, i; + char stop_val = STOP_WCNSS_FILTER; + int soc_type = BT_SOC_DEFAULT; + + ALOGV("%s: Entry ", __func__); + + if ((soc_type = get_bt_soc_type()) == BT_SOC_CHEROKEE) { + property_get("wc_transport.hci_filter_status", value, "0"); + if (strcmp(value, "0") == 0) { + ALOGI("%s: hci_filter has been stopped already", __func__); + } + else { + filter_ctrl = connect_to_local_socket("wcnssfilter_ctrl"); + if (filter_ctrl < 0) { + ALOGI("%s: Error while connecting to CTRL_SOCK, filter should stopped: %d", + __func__, filter_ctrl); + } + else { + retval = write(filter_ctrl, &stop_val, 1); + if (retval != 1) { + ALOGI("%s: problem writing to CTRL_SOCK, ignore: %d", __func__, retval); + //Ignore and fallback + } + + close(filter_ctrl); + } + } + + /* Ensure Filter is closed by checking the status before + RFKILL 0 operation. this should ideally comeout very + quick */ + for(i=0; i<500; i++) { + property_get(BT_VND_FILTER_START, value, "false"); + if (strcmp(value, "false") == 0) { + ALOGI("%s: WCNSS_FILTER stopped", __func__); + usleep(STOP_WAIT_TIMEOUT * 10); + break; + } else { + /*sleep of 1ms, This should give enough time for FILTER to + exit with all necessary cleanup*/ + usleep(STOP_WAIT_TIMEOUT); + } + } + + /*Never use SIGKILL to stop the filter*/ + /* Filter will be stopped by below two conditions + - by Itself, When it realizes there are no CONNECTED clients + - Or through STOP_WCNSS_FILTER byte on Control socket + both of these ensure clean shutdown of chip + */ + //property_set(BT_VND_FILTER_START, "false"); + } else if (soc_type == BT_SOC_ROME) { + property_set(BT_VND_FILTER_START, "false"); + } else { + ALOGI("%s: Unknown soc type %d, Unexpected!", __func__, soc_type); + } + + ALOGV("%s: Exit ", __func__); +} + +int start_hci_filter() { + ALOGV("%s: Entry ", __func__); + int i, init_success = -1; + char value[PROPERTY_VALUE_MAX] = {'\0'}; + + property_get(BT_VND_FILTER_START, value, false); + + if (strcmp(value, "true") == 0) { + ALOGI("%s: hci_filter has been started already", __func__); + //Filter should have been started OR in the process of initializing + //Make sure of hci_filter_status and return the state based on it + } else { + + property_set("wc_transport.hci_filter_status", "0"); + property_set(BT_VND_FILTER_START, "true"); + ALOGV("%s: %s set to true ", __func__, BT_VND_FILTER_START ); + } + + /*If there are back to back ON requests from different clients, + All client should come and stuck in this while loop till FILTER + comesup and ready to accept the connections */ + //sched_yield(); + for(i=0; i<45; i++) { + property_get("wc_transport.hci_filter_status", value, "0"); + if (strcmp(value, "1") == 0) { + init_success = 1; + break; + } else { + usleep(WAIT_TIMEOUT); + } + } + ALOGV("start_hcifilter status:%d after %f seconds \n", init_success, 0.2*i); + + ALOGV("%s: Exit ", __func__); + return init_success; +} + +/* + * Bluetooth Controller power up or shutdown, this function is called with + * q_lock held and q is non-NULL + */ +static int bt_powerup(int en ) +{ + char rfkill_type[64], *enable_ldo_path = NULL; + char type[16], enable_ldo[6]; + int fd = 0, size, i, ret, fd_ldo, fd_btpower; + + char disable[PROPERTY_VALUE_MAX]; + char state; + char on = (en)?'1':'0'; + +#ifdef WIFI_BT_STATUS_SYNC + char wifi_status[PROPERTY_VALUE_MAX]; + int lock_fd; +#endif /*WIFI_BT_STATUS_SYNC*/ + + ALOGI("bt_powerup: %c", on); + + /* Check if rfkill has been disabled */ + ret = property_get("ro.rfkilldisabled", disable, "0"); + if (!ret ){ + ALOGE("Couldn't get ro.rfkilldisabled (%d)", ret); + return -1; + } + /* In case rfkill disabled, then no control power*/ + if (strcmp(disable, "1") == 0) { + ALOGI("ro.rfkilldisabled : %s", disable); + return -1; + } + +#ifdef WIFI_BT_STATUS_SYNC + lock_fd = bt_semaphore_create(); + bt_semaphore_get(lock_fd); + bt_wait_for_service_done(); +#endif + + /* Assign rfkill_id and find bluetooth rfkill state path*/ + for(i = 0; (q->rfkill_id == -1) && (q->rfkill_state == NULL); i++) + { + snprintf(rfkill_type, sizeof(rfkill_type), "/sys/class/rfkill/rfkill%d/type", i); + if ((fd = open(rfkill_type, O_RDONLY)) < 0) + { + ALOGE("open(%s) failed: %s (%d)\n", rfkill_type, strerror(errno), errno); + +#ifdef WIFI_BT_STATUS_SYNC + bt_semaphore_release(lock_fd); + bt_semaphore_destroy(lock_fd); +#endif + return -1; + } + + size = read(fd, &type, sizeof(type)); + close(fd); + + if ((size >= 9) && !memcmp(type, "bluetooth", 9)) + { + asprintf(&q->rfkill_state, "/sys/class/rfkill/rfkill%d/state", q->rfkill_id = i); + break; + } + } + + /* Get rfkill State to control */ + if (q->rfkill_state != NULL) + { + if ((fd = open(q->rfkill_state, O_RDWR)) < 0) + { + ALOGE("open(%s) for write failed: %s (%d)", q->rfkill_state, strerror(errno), errno); +#ifdef WIFI_BT_STATUS_SYNC + bt_semaphore_release(lock_fd); + bt_semaphore_destroy(lock_fd); +#endif + + return -1; + } + } + /* Always perform BT power action so as to have the chance to + recover BT power properly from un-expected error. */ +#ifdef CHECK_BT_POWER_PERFORM_ACTION + if(can_perform_action(on) == false) { + ALOGE("%s:can't perform action as it is being used by other clients", __func__); +#ifdef WIFI_BT_STATUS_SYNC + bt_semaphore_release(lock_fd); + bt_semaphore_destroy(lock_fd); +#endif + goto done; + } +#else + ALOGI("%s: always perform action", __func__); +#endif + ret = asprintf(&enable_ldo_path, "/sys/class/rfkill/rfkill%d/device/extldo", q->rfkill_id); + if( (ret < 0 ) || (enable_ldo_path == NULL) ) + { + ALOGE("Memory Allocation failure"); + return -1; + } + if ((fd_ldo = open(enable_ldo_path, O_RDWR)) < 0) { + ALOGE("open(%s) failed: %s (%d)", enable_ldo_path, strerror(errno), errno); + return -1; + } + size = read(fd_ldo, &enable_ldo, sizeof(enable_ldo)); + close(fd_ldo); + if (size <= 0) { + ALOGE("read(%s) failed: %s (%d)", enable_ldo_path, strerror(errno), errno); + return -1; + } + if (!memcmp(enable_ldo, "true", 4)) { + ALOGI("External LDO has been configured"); + ret = property_set("wc_transport.extldo", "enabled"); + if (ret < 0) { + ALOGI("%s: Not able to set property wc_transport.extldo\n", __func__); + } + q->enable_extldo = TRUE; + } + + if(on == '0'){ + ALOGE("Stopping HCI filter as part of CTRL:OFF"); + stop_hci_filter(); + property_set("wc_transport.soc_initialized", "0"); + } + + if (q->soc_type >= BT_SOC_CHEROKEE && q->soc_type < BT_SOC_RESERVED) { + ALOGI("open bt power devnode,send ioctl power op :%d ",en); + fd_btpower = open(BT_PWR_CNTRL_DEVICE, O_RDWR, O_NONBLOCK); + if (fd_btpower < 0) { + ALOGE("\nfailed to open bt device error = (%s)\n",strerror(errno)); +#ifdef WIFI_BT_STATUS_SYNC + bt_semaphore_release(lock_fd); + bt_semaphore_destroy(lock_fd); +#endif + return -1; + } + ret = ioctl(fd_btpower, BT_CMD_PWR_CTRL, (unsigned long)en); + if (ret < 0) { + ALOGE(" ioctl failed to power control:%d error =(%s)",ret,strerror(errno)); + } + close(fd_btpower); + } else { + ALOGI("Write %c to rfkill\n", on); + /* Write value to control rfkill */ + if(fd >= 0) { + if ((size = write(fd, &on, 1)) < 0) { + ALOGE("write(%s) failed: %s (%d)", q->rfkill_state, strerror(errno), errno); +#ifdef WIFI_BT_STATUS_SYNC + bt_semaphore_release(lock_fd); + bt_semaphore_destroy(lock_fd); +#endif + return -1; + } + } + } +#ifdef WIFI_BT_STATUS_SYNC + /* query wifi status */ + property_get(WIFI_PROP_NAME, wifi_status, ""); + + ALOGE("bt get wifi status: %s, isInit: %d\n", wifi_status, isInit); + + /* If wlan driver is not loaded, and bt is changed from off => on */ + if (strncmp(wifi_status, "unloaded", strlen("unloaded")) == 0 || strlen(wifi_status) == 0) { + if (on == '1') { + ALOGI("%s: BT_VND_PWR_ON\n", __func__); + if(property_set(SERVICE_PROP_NAME, "load_wlan") < 0) { + ALOGE("%s Property setting failed", SERVICE_PROP_NAME); + close(fd); + bt_semaphore_release(lock_fd); + bt_semaphore_destroy(lock_fd); + return -1; + } + } + else if (isInit == 0 && on == '0') { + ALOGI("%s: BT_VND_PWR_OFF\n", __func__); + if(property_set(SERVICE_PROP_NAME, "unbind_hsic") < 0) { + ALOGE("%s Property setting failed", SERVICE_PROP_NAME); + close(fd); + bt_semaphore_release(lock_fd); + bt_semaphore_destroy(lock_fd); + return -1; + } + } + } + + if (isInit == 0 && on == '0') + property_set(BT_STATUS_NAME, "false"); + else if (on == '1') + property_set(BT_STATUS_NAME, "true"); + + bt_semaphore_release(lock_fd); + bt_semaphore_destroy(lock_fd); +#endif /* WIFI_BT_STATUS_SYNC */ + +done: + if (fd >= 0) + close(fd); + return 0; +} + +static inline void soc_init(int soc_type) +{ + switch (soc_type) + { + case BT_SOC_CHEROKEE: + case BT_SOC_ROME: + case BT_SOC_AR3K: + ALOGI("bt-vendor : Initializing UART transport layer"); + userial_vendor_init(); + break; + case BT_SOC_DEFAULT: + break; + default: + ALOGE("Unknown soc yype: %d", soc_type); + break; + } +} + +/* Copy BD Address as little-endian byte order */ +static inline void le2bd(unsigned char *src, unsigned char *dst) +{ + int i; + for (i = 0; i < 6; i++) + dst[i] = src[5-i]; +} + +static inline void print_bdaddr(unsigned char *addr) +{ + ALOGI("BD Address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr[0], addr[1], + addr[2], addr[3], addr[4], addr[5]); +} + +/***************************************************************************** +** +** BLUETOOTH VENDOR INTERFACE LIBRARY FUNCTIONS +** +*****************************************************************************/ + +static int init(const bt_vendor_callbacks_t *cb, unsigned char *bdaddr) +{ + char prop[PROPERTY_VALUE_MAX] = {0}; + struct bt_qcom_struct *temp = NULL; + int ret = BT_STATUS_SUCCESS, i; + + ALOGI("++%s", __FUNCTION__); + + if (!cb || !bdaddr) { + ALOGE("Invalid input args cb %p bdaddr %p", cb, bdaddr); + ret = -BT_STATUS_INVAL; + goto out; + } + + temp = (struct bt_qcom_struct *) malloc(sizeof(*q)); + if (!temp) { + ALOGE("Failed to allocate memory. err %s(%d)", strerror(errno), errno); + ret = -BT_STATUS_NOMEM; + goto out; + } + memset(temp, 0, sizeof(*temp)); + + temp->rfkill_id = -1; + temp->enable_extldo = FALSE; + temp->cb = cb; + temp->ant_fd = -1; + temp->soc_type = get_bt_soc_type(); + soc_init(temp->soc_type); + + le2bd(bdaddr, temp->bdaddr); + print_bdaddr(temp->bdaddr); + snprintf(prop, sizeof(prop), "%02x:%02x:%02x:%02x:%02x:%02x", + temp->bdaddr[0], temp->bdaddr[1], temp->bdaddr[2], + temp->bdaddr[3], temp->bdaddr[4], temp->bdaddr[5]); + ret = property_set("wc_transport.stack_bdaddr", prop); + if (ret < 0) { + ALOGE("Failed to set wc_transport.stack_bdaddr prop, ret = %d", ret); + ret = -BT_STATUS_PROP_FAILURE; + goto out; + } + +/* TODO: Move these fields inside bt_qcom context */ +#ifdef WIFI_BT_STATUS_SYNC + isInit = 1; +#endif /* WIFI_BT_STATUS_SYNC */ + + /* Everything successful */ + q = temp; + return ret; + +out: + if (temp) + free(temp); + ALOGI("--%s ret %d", __FUNCTION__, ret); + return ret; +} + +#ifdef READ_BT_ADDR_FROM_PROP +static bool validate_tok(char* bdaddr_tok) { + int i = 0; + bool ret; + + if (strlen(bdaddr_tok) != 2) { + ret = FALSE; + ALOGE("Invalid token length"); + } else { + ret = TRUE; + for (i=0; i<2; i++) { + if ((bdaddr_tok[i] >= '0' && bdaddr_tok[i] <= '9') || + (bdaddr_tok[i] >= 'A' && bdaddr_tok[i] <= 'F') || + (bdaddr_tok[i] >= 'a' && bdaddr_tok[i] <= 'f')) { + ret = TRUE; + ALOGV("%s: tok %s @ %d is good", __func__, bdaddr_tok, i); + } else { + ret = FALSE; + ALOGE("invalid character in tok: %s at ind: %d", bdaddr_tok, i); + break; + } + } + } + return ret; +} +#endif /*READ_BT_ADDR_FROM_PROP*/ + +int connect_to_local_socket(char* name) { + socklen_t len; int sk = -1; + + ALOGE("%s: ACCEPT ", __func__); + sk = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sk < 0) { + ALOGE("Socket creation failure"); + return -1; + } + + if(socket_local_client_connect(sk, name, + ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0) + { + ALOGE("failed to connect (%s)", strerror(errno)); + close(sk); + sk = -1; + } else { + ALOGE("%s: Connection succeeded\n", __func__); + } + return sk; +} + +bool is_soc_initialized() { + bool init = false; + char init_value[PROPERTY_VALUE_MAX]; + int ret; + + ALOGI("bt-vendor : is_soc_initialized"); + + ret = property_get(SOC_INIT_PROPERTY, init_value, NULL); + if (ret != 0) { + ALOGI("%s set to %s\n", SOC_INIT_PROPERTY, init_value); + if (!strncasecmp(init_value, "1", sizeof("1"))) { + init = true; + } + } + else { + ALOGE("%s: Failed to get %s", __FUNCTION__, SOC_INIT_PROPERTY); + } + + return init; +} + +/* flavor of op without locks */ +static int __op(bt_vendor_opcode_t opcode, void *param) +{ + int retval = BT_STATUS_SUCCESS; + int nCnt = 0; + int nState = -1; + bool is_ant_req = false; + bool is_fm_req = false; + char wipower_status[PROPERTY_VALUE_MAX]; + char emb_wp_mode[PROPERTY_VALUE_MAX]; + char bt_version[PROPERTY_VALUE_MAX]; + char lpm_config[PROPERTY_VALUE_MAX]; + bool ignore_boot_prop = TRUE; +#ifdef READ_BT_ADDR_FROM_PROP + int i = 0; + static char bd_addr[PROPERTY_VALUE_MAX]; + uint8_t local_bd_addr_from_prop[6]; + char* tok; +#endif + bool skip_init = true; + int opcode_init = opcode; + ALOGV("++%s opcode %d", __FUNCTION__, opcode); + + switch(opcode_init) + { +#ifdef FM_OVER_UART + case FM_VND_OP_POWER_CTRL: + { + is_fm_req = true; + if (is_soc_initialized()) { + // add any FM specific actions if needed in future + break; + } + } +#endif + case BT_VND_OP_POWER_CTRL: + { + if (!param) { + ALOGE("opcode = %d: param is null", opcode_init); + break; + } + nState = *(int *) param; + ALOGI("bt-vendor : BT_VND_OP_POWER_CTRL: %s", + (nState == BT_VND_PWR_ON)? "On" : "Off" ); + + switch(q->soc_type) + { + case BT_SOC_DEFAULT: + if (readTrpState()) + { + ALOGI("bt-vendor : resetting BT status"); + hw_config(BT_VND_PWR_OFF); + } + retval = hw_config(nState); + if(nState == BT_VND_PWR_ON + && retval == 0 + && is_hw_ready() == TRUE){ + retval = 0; + } + else { + retval = -1; + } + break; + case BT_SOC_ROME: + case BT_SOC_AR3K: + case BT_SOC_CHEROKEE: + if (q->soc_type == BT_SOC_ROME) + { + if (nState == BT_VND_PWR_ON) + { + /* Always power BT off before power on. */ + ALOGI("bt-vendor: always power off before power on"); + bt_powerup(BT_VND_PWR_OFF); + } + } + + /* BT Chipset Power Control through Device Tree Node */ + retval = bt_powerup(nState); + default: + break; + } + } + break; + + case BT_VND_OP_FW_CFG: { + /* call hciattach to initalize the stack */ + if (q->soc_type == BT_SOC_ROME) { + if (is_soc_initialized()) { + ALOGI("Bluetooth FW and transport layer are initialized"); + q->cb->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS); + } else { + ALOGE("bt_vendor_cbacks is null or SoC not initialized"); + ALOGE("Error : hci, smd initialization Error"); + retval = -1; + } + } else { + ALOGI("Bluetooth FW and transport layer are initialized"); + q->cb->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS); + } + } + break; + + case BT_VND_OP_SCO_CFG: + q->cb->scocfg_cb(BT_VND_OP_RESULT_SUCCESS); //dummy + break; +#ifdef ENABLE_ANT + case BT_VND_OP_ANT_USERIAL_OPEN: + ALOGI("bt-vendor : BT_VND_OP_ANT_USERIAL_OPEN"); + is_ant_req = true; + goto userial_open; +#endif +#ifdef FM_OVER_UART + case BT_VND_OP_FM_USERIAL_OPEN: + ALOGI("bt-vendor : BT_VND_OP_FM_USERIAL_OPEN"); + is_fm_req = true; + goto userial_open; +#endif +userial_open: + case BT_VND_OP_USERIAL_OPEN: + { + if (!param) { + ALOGE("opcode = %d: param is null", opcode_init); + break; + } + int (*fd_array)[] = (int (*)[]) param; + int idx, fd = -1, fd_filter = -1; + ALOGI("bt-vendor : BT_VND_OP_USERIAL_OPEN"); + switch(q->soc_type) + { + case BT_SOC_DEFAULT: + { + if(bt_hci_init_transport(q->fd) != -1){ + int (*fd_array)[] = (int (*) []) param; + + (*fd_array)[CH_CMD] = q->fd[0]; + (*fd_array)[CH_EVT] = q->fd[0]; + (*fd_array)[CH_ACL_OUT] = q->fd[1]; + (*fd_array)[CH_ACL_IN] = q->fd[1]; + } + else { + retval = -1; + break; + } + retval = 2; + } + break; + case BT_SOC_AR3K: + { + fd = userial_vendor_open((tUSERIAL_CFG *) &userial_init_cfg); + if (fd != -1) { + for (idx=0; idx < CH_MAX; idx++) + (*fd_array)[idx] = fd; + retval = 1; + } + else { + retval = -1; + break; + } + + /* Vendor Specific Process should happened during userial_open process + After userial_open, rx read thread is running immediately, + so it will affect VS event read process. + */ + if(ath3k_init(fd,3000000,115200,NULL,&vnd_userial.termios)<0) + retval = -1; + } + break; + case BT_SOC_ROME: + { + wait_for_patch_download(is_ant_req); + property_get("ro.bluetooth.emb_wp_mode", emb_wp_mode, false); + if (!is_soc_initialized()) { + char* dlnd_inprog = is_ant_req ? "ant" : "bt"; + if (property_set("wc_transport.patch_dnld_inprog", dlnd_inprog) < 0) { + ALOGE("%s: Failed to set dnld_inprog %s", __FUNCTION__, dlnd_inprog); + } + + fd = userial_vendor_open((tUSERIAL_CFG *) &userial_init_cfg); + if (fd < 0) { + ALOGE("userial_vendor_open returns err"); + retval = -1; + break; + } + + /* Clock on */ + userial_clock_operation(fd, USERIAL_OP_CLK_ON); + + if(strcmp(emb_wp_mode, "true") == 0) { + property_get("ro.bluetooth.wipower", wipower_status, false); + if(strcmp(wipower_status, "true") == 0) { + check_embedded_mode(fd); + } else { + ALOGI("Wipower not enabled"); + } + } + ALOGV("rome_soc_init is started"); + property_set("wc_transport.soc_initialized", "0"); +#ifdef READ_BT_ADDR_FROM_PROP + /*Give priority to read BD address from boot property*/ + ignore_boot_prop = FALSE; + if (property_get(BLUETOOTH_MAC_ADDR_BOOT_PROPERTY, bd_addr, NULL)) { + ALOGV("BD address read from Boot property: %s\n", bd_addr); + tok = strtok(bd_addr, ":"); + while (tok != NULL) { + ALOGV("bd add [%d]: %d ", i, strtol(tok, NULL, 16)); + if (i>=6) { + ALOGE("bd property of invalid length"); + ignore_boot_prop = TRUE; + break; + } + if (i == 6 && !ignore_boot_prop) { + ALOGV("Valid BD address read from prop"); + memcpy(q->bdaddr, local_bd_addr_from_prop, sizeof(vnd_local_bd_addr)); + ignore_boot_prop = FALSE; + } else { + ALOGE("There are not enough tokens in BD addr"); + ignore_boot_prop = TRUE; + break; + } + local_bd_addr_from_prop[5-i] = strtol(tok, NULL, 16); + tok = strtok(NULL, ":"); + i++; + } + if (i == 6 && !ignore_boot_prop) { + ALOGV("Valid BD address read from prop"); + memcpy(vnd_local_bd_addr, local_bd_addr_from_prop, sizeof(vnd_local_bd_addr)); + ignore_boot_prop = FALSE; + } else { + ALOGE("There are not enough tokens in BD addr"); + ignore_boot_prop = TRUE; + } + } + else { + ALOGE("BD address boot property not set"); + ignore_boot_prop = TRUE; + } +#endif //READ_BT_ADDR_FROM_PROP + /* Always read BD address from NV file */ + if(ignore_boot_prop && !bt_vendor_nv_read(1, q->bdaddr)) + { + /* Since the BD address is configured in boot time We should not be here */ + ALOGI("Failed to read BD address. Use the one from bluedroid stack/ftm"); + } + if(rome_soc_init(fd, (char*)q->bdaddr)<0) { + retval = -1; + } else { + ALOGV("rome_soc_init is completed"); + property_set("wc_transport.soc_initialized", "1"); + skip_init = false; + } + } + if (property_set("wc_transport.patch_dnld_inprog", "null") < 0) { + ALOGE("%s: Failed to set property", __FUNCTION__); + } + + property_set("wc_transport.clean_up","0"); + if (retval != -1) { + + retval = start_hci_filter(); + if (retval < 0) { + ALOGE("%s: WCNSS_FILTER wouldn't have started in time\n", __func__); + } else { +#ifdef ENABLE_ANT + if (is_ant_req) { + ALOGI("%s: connect to ant channel", __func__); + q->ant_fd = fd_filter = connect_to_local_socket("ant_sock"); + } + else +#endif + { + ALOGI("%s: connect to bt channel", __func__); + vnd_userial.fd = fd_filter = connect_to_local_socket("bt_sock"); + } + + if (fd_filter != -1) { + ALOGI("%s: received the socket fd: %d is_ant_req: %d is_fm_req: %d\n", + __func__, fd_filter, is_ant_req,is_fm_req); + if((strcmp(emb_wp_mode, "true") == 0) && !is_ant_req && !is_fm_req) { + if (chipset_ver >= ROME_VER_3_0) { + /* get rome supported feature request */ + ALOGE("%s: %x08 %0x", __FUNCTION__,chipset_ver, ROME_VER_3_0); + rome_get_addon_feature_list(fd_filter); + } + } + if (!skip_init) { + /*Skip if already sent*/ + enable_controller_log(fd_filter, (is_ant_req || is_fm_req) ); + skip_init = true; + } + for (idx=0; idx < CH_MAX; idx++) + (*fd_array)[idx] = fd_filter; + retval = 1; + } + else { + if (is_ant_req) + ALOGE("Unable to connect to ANT Server Socket!!!"); + else + ALOGE("Unable to connect to BT Server Socket!!!"); + retval = -1; + } + } + } else { + if (q->soc_type == BT_SOC_ROME) + ALOGE("Failed to initialize ROME Controller!!!"); + } + + if (fd >= 0) { + userial_clock_operation(fd, USERIAL_OP_CLK_OFF); + /*Close the UART port*/ + close(fd); + } + } + break; + case BT_SOC_CHEROKEE: + { + property_get("ro.bluetooth.emb_wp_mode", emb_wp_mode, false); + retval = start_hci_filter(); + if (retval < 0) { + ALOGE("WCNSS_FILTER wouldn't have started in time\n"); + + } else { +#ifdef ENABLE_ANT + if (is_ant_req) { + ALOGI("%s: connect to ant channel", __func__); + q->ant_fd = fd_filter = connect_to_local_socket("ant_sock"); + } + else +#endif +#ifdef FM_OVER_UART + if (is_fm_req && (q->soc_type >=BT_SOC_ROME && q->soc_type < BT_SOC_RESERVED)) { + ALOGI("%s: connect to fm channel", __func__); + q->fm_fd = fd_filter = connect_to_local_socket("fm_sock"); + } + else +#endif + { + ALOGI("%s: connect to bt channel", __func__); + vnd_userial.fd = fd_filter = connect_to_local_socket("bt_sock"); + + } + if (fd_filter != -1) { + ALOGV("%s: received the socket fd: %d \n", + __func__, fd_filter); + + for (idx=0; idx < CH_MAX; idx++) { + (*fd_array)[idx] = fd_filter; + } + retval = 1; + } + else { +#ifdef ENABLE_ANT + if (is_ant_req) + ALOGE("Unable to connect to ANT Server Socket!!!"); + else +#endif +#ifdef FM_OVER_UART + if (is_fm_req) + ALOGE("Unable to connect to FM Server Socket!!!"); + else +#endif + ALOGE("Unable to connect to BT Server Socket!!!"); + retval = -1; + } + } + } + break; + default: + ALOGE("Unknown soc_type: 0x%x", q->soc_type); + break; + } + } break; +#ifdef ENABLE_ANT + case BT_VND_OP_ANT_USERIAL_CLOSE: + { + ALOGI("bt-vendor : BT_VND_OP_ANT_USERIAL_CLOSE"); + property_set("wc_transport.clean_up","1"); + if (q->ant_fd != -1) { + ALOGE("closing ant_fd"); + close(q->ant_fd); + q->ant_fd = -1; + } + } + break; +#endif +#ifdef FM_OVER_UART + case BT_VND_OP_FM_USERIAL_CLOSE: + { + ALOGI("bt-vendor : BT_VND_OP_FM_USERIAL_CLOSE"); + property_set("wc_transport.clean_up","1"); + if (q->fm_fd != -1) { + ALOGE("closing fm_fd"); + close(q->fm_fd); + q->fm_fd = -1; + } + break; + } +#endif + case BT_VND_OP_USERIAL_CLOSE: + { + ALOGI("bt-vendor : BT_VND_OP_USERIAL_CLOSE soc_type: %d", q->soc_type); + switch(q->soc_type) + { + case BT_SOC_DEFAULT: + bt_hci_deinit_transport(q->fd); + break; + case BT_SOC_ROME: + case BT_SOC_AR3K: + case BT_SOC_CHEROKEE: + { + property_set("wc_transport.clean_up","1"); + userial_vendor_close(); + break; + } + default: + ALOGE("Unknown soc_type: 0x%x", q->soc_type); + break; + } + } + break; + + case BT_VND_OP_GET_LPM_IDLE_TIMEOUT: + { + if (!param) { + ALOGE("opcode = %d: param is null", opcode_init); + break; + } + uint32_t *timeout_ms = (uint32_t *) param; + *timeout_ms = 1000; + } + + break; + + case BT_VND_OP_LPM_SET_MODE: + if (q->soc_type == BT_SOC_AR3K) { + if (!param) { + ALOGE("opcode = %d: param is null", opcode_init); + break; + } + uint8_t *mode = (uint8_t *) param; + + if (*mode) { + lpm_set_ar3k(UPIO_LPM_MODE, UPIO_ASSERT, 0); + } + else { + lpm_set_ar3k(UPIO_LPM_MODE, UPIO_DEASSERT, 0); + } + q->cb->lpm_cb(BT_VND_OP_RESULT_SUCCESS); + } else { + int lpm_result = BT_VND_OP_RESULT_SUCCESS; + + property_get("persist.service.bdroid.lpmcfg", lpm_config, "all"); + ALOGI("%s: property_get: persist.service.bdroid.lpmcfg: %s", + __func__, lpm_config); + + if (!strcmp(lpm_config, "all")) { + // respond with success since we want to hold wake lock through LPM + lpm_result = BT_VND_OP_RESULT_SUCCESS; + } + else { + lpm_result = BT_VND_OP_RESULT_FAIL; + } + + q->cb->lpm_cb(lpm_result); + } + break; + + case BT_VND_OP_LPM_WAKE_SET_STATE: { + switch(q->soc_type) { + case BT_SOC_CHEROKEE: + case BT_SOC_ROME: { + if (!param) { + ALOGE("opcode = %d: param is null", opcode_init); + break; + } + uint8_t *state = (uint8_t *) param; + uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \ + BT_VND_LPM_WAKE_ASSERT : BT_VND_LPM_WAKE_DEASSERT; + + if (wake_assert == 0) + ALOGV("ASSERT: Waking up BT-Device"); + else if (wake_assert == 1) + ALOGV("DEASSERT: Allowing BT-Device to Sleep"); + +#ifdef QCOM_BT_SIBS_ENABLE + ALOGI("Invoking HCI H4 callback function"); + q->cb->lpm_set_state_cb(wake_assert); +#endif + } + break; + case BT_SOC_AR3K: { + if (!param) { + ALOGE("opcode = %d: param is null", opcode_init); + break; + } + uint8_t *state = (uint8_t *) param; + uint8_t wake_assert = (*state == BT_VND_LPM_WAKE_ASSERT) ? \ + UPIO_ASSERT : UPIO_DEASSERT; + lpm_set_ar3k(UPIO_BT_WAKE, wake_assert, 0); + } + case BT_SOC_DEFAULT: + break; + default: + ALOGE("Unknown soc_type: 0x%x", q->soc_type); + break; + } + } + break; + case BT_VND_OP_EPILOG: { +#if (HW_NEED_END_WITH_HCI_RESET == FALSE) + q->cb->epilog_cb(BT_VND_OP_RESULT_SUCCESS); +#else + switch(q->soc_type) + { + case BT_SOC_CHEROKEE: + case BT_SOC_ROME: + { + char value[PROPERTY_VALUE_MAX] = {'\0'}; + property_get("wc_transport.hci_filter_status", value, "0"); + if(is_soc_initialized()&& (strcmp(value,"1") == 0)) + { + __hw_epilog_process(); + } + else + { + q->cb->epilog_cb(BT_VND_OP_RESULT_SUCCESS); + } + } + break; + default: + __hw_epilog_process(); + break; + } +#endif + } + break; + case BT_VND_OP_GET_LINESPEED: + { + retval = -1; + if(!is_soc_initialized()) { + ALOGE("BT_VND_OP_GET_LINESPEED: error" + " - transport driver not initialized!"); + break; + } + + switch(q->soc_type) + { + case BT_SOC_CHEROKEE: + retval = 3200000; + break; + case BT_SOC_ROME: + retval = 3000000; + break; + default: + retval = userial_vendor_get_baud(); + break; + } + break; + } + } + +out: + ALOGV("--%s", __FUNCTION__); + return retval; +} + +static int op(bt_vendor_opcode_t opcode, void *param) +{ + int ret; + ALOGV("++%s", __FUNCTION__); +#ifdef BT_THREADLOCK_SAFE + pthread_mutex_lock(&q_lock); +#endif + if (!q) { + ALOGE("op called with NULL context"); + ret = -BT_STATUS_INVAL; + goto out; + } + ret = __op(opcode, param); +out: +#ifdef BT_THREADLOCK_SAFE + pthread_mutex_unlock(&q_lock); +#endif + ALOGV("--%s ret = 0x%x", __FUNCTION__, ret); + return ret; +} + +static void ssr_cleanup(int reason) +{ + int pwr_state = BT_VND_PWR_OFF; + int ret; + unsigned char trig_ssr = 0xEE; + + ALOGI("++%s", __FUNCTION__); + + pthread_mutex_lock(&q_lock); + if (!q) { + ALOGE("ssr_cleanup called with NULL context"); + goto out; + } + if (property_set("wc_transport.patch_dnld_inprog", "null") < 0) { + ALOGE("Failed to set property"); + } + + if (q->soc_type >= BT_SOC_ROME && q->soc_type < BT_SOC_RESERVED) { +#ifdef ENABLE_ANT + /*Indicate to filter by sending special byte */ + if (reason == CMD_TIMEOUT) { + trig_ssr = 0xEE; + ret = write (vnd_userial.fd, &trig_ssr, 1); + ALOGI("Trig_ssr is being sent to BT socket, ret %d err %s", + ret, strerror(errno)); + + if (is_debug_force_special_bytes()) { + /* + * Then we should send special byte to crash SOC in + * WCNSS_Filter, so we do not need to power off UART here. + */ + goto out; + } + } + + /* Close both ANT channel */ + __op(BT_VND_OP_ANT_USERIAL_CLOSE, NULL); +#endif + /* Close both BT channel */ + __op(BT_VND_OP_USERIAL_CLOSE, NULL); + +#ifdef FM_OVER_UART + __op(BT_VND_OP_FM_USERIAL_CLOSE, NULL); +#endif + /*CTRL OFF twice to make sure hw + * turns off*/ +#ifdef ENABLE_ANT + __op(BT_VND_OP_POWER_CTRL, &pwr_state); +#endif + } + /*Generally switching of chip should be enough*/ + __op(BT_VND_OP_POWER_CTRL, &pwr_state); + +out: + pthread_mutex_unlock(&q_lock); + ALOGI("--%s", __FUNCTION__); +} + +/** Closes the interface */ +static void cleanup(void) +{ + ALOGI("cleanup"); + + pthread_mutex_lock(&q_lock); + q->cb = NULL; + free(q); + q = NULL; + pthread_mutex_unlock(&q_lock); + +#ifdef WIFI_BT_STATUS_SYNC + isInit = 0; +#endif /* WIFI_BT_STATUS_SYNC */ +} + +/* Check for one of the cients ANT/BT patch download is already in +** progress if yes wait till complete +*/ +void wait_for_patch_download(bool is_ant_req) { + ALOGV("%s:", __FUNCTION__); + char inProgress[PROPERTY_VALUE_MAX] = {'\0'}; + while (1) { + property_get("wc_transport.patch_dnld_inprog", inProgress, "null"); + + if(is_ant_req && !(strcmp(inProgress,"bt"))) { + //ANT request, wait for BT to finish + usleep(50000); + } + else if(!is_ant_req && !(strcmp(inProgress,"ant"))) { + //BT request, wait for ANT to finish + usleep(50000); + } + else { + ALOGI("%s: patch download completed", __FUNCTION__); + break; + } + } +} + +bool is_download_progress () { + char inProgress[PROPERTY_VALUE_MAX] = {'\0'}; + bool retval = false; + + ALOGV("%s:", __FUNCTION__); + + if ((q->soc_type = get_bt_soc_type()) < 0) { + ALOGE("%s: Failed to detect BT SOC Type", __FUNCTION__); + return -1; + } + + switch(q->soc_type) + { + case BT_SOC_ROME: + ALOGI("%s: ROME case", __func__); + property_get("wc_transport.patch_dnld_inprog", inProgress, "null"); + if(strcmp(inProgress,"null") == 0) { + retval = false; + } else { + retval = true; + } + break; + case BT_SOC_CHEROKEE: + ALOGI("%s: CHEROKEE case", __func__); + break; + case BT_SOC_DEFAULT: + break; + default: + ALOGE("Unknown btSocType: 0x%x", q->soc_type); + break; + } + return retval; +} + +static bool is_debug_force_special_bytes() { + int ret = 0; + char value[PROPERTY_VALUE_MAX] = {'\0'}; + bool enabled = false; +#ifdef ENABLE_DBG_FLAGS + enabled = true; +#endif + + ret = property_get("wc_transport.force_special_byte", value, NULL); + + if (ret) { + enabled = (strcmp(value, "false") ==0) ? false : true; + ALOGV("%s: wc_transport.force_special_byte: %s, enabled: %d ", + __func__, value, enabled); + } + + return enabled; +} + +// Entry point of DLib +/* Remove 'ssr_cleanup' because it's not defined in 'bt_vendor_interface_t'. */ +const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = { + sizeof(bt_vendor_interface_t), + init, + op, + cleanup +}; diff --git a/sdm845/libbt-vendor/src/hardware.c b/sdm845/libbt-vendor/src/hardware.c new file mode 100644 index 0000000..90db801 --- /dev/null +++ b/sdm845/libbt-vendor/src/hardware.c @@ -0,0 +1,194 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * + * Filename: hardware.c + * + * Description: Contains controller-specific functions, like + * firmware patch download + * low power mode operations + * + ******************************************************************************/ + +#define LOG_TAG "bt_vendor" + +#include <utils/Log.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <time.h> +#include <errno.h> +#include <fcntl.h> +#include <dirent.h> +#include <ctype.h> +#include <cutils/properties.h> +#include <stdlib.h> +#include "bt_hci_bdroid.h" +#include "bt_vendor_qcom.h" +#include <string.h> +#define MAX_CNT_RETRY 100 + +int hw_config(int nState) +{ + char *szState[] = {"true", "false"}; + char *szReqSt = NULL; + char szBtSocStatus[PROPERTY_VALUE_MAX] = {'\0', }; + + if(nState == BT_VND_PWR_OFF) + szReqSt = szState[1]; + else + szReqSt = szState[0]; + + if((property_get("bluetooth.status", szBtSocStatus, "") <= 0)) + { + if(nState == BT_VND_PWR_ON ) { + ALOGW("Hw_config: First Time BT on after boot.Starting hciattach daemon BTStatus=%s",szBtSocStatus); + if (property_set("bluetooth.hciattach", szReqSt) < 0) + { + ALOGE("Hw_config: Property Setting fail"); + return -1; + } + } + } else if( !(strncmp(szBtSocStatus, "on", strlen("on")))) { + //BTSOC is already on + ALOGW("Hw_config: nState = %d", nState); + } else { + ALOGW("Hw_config: trigerring hciattach"); + if (property_set("bluetooth.hciattach", szReqSt) < 0) + { + ALOGE("Hw_config: Property Setting fail"); + return -1; + } + } + + return 0; +} + +int readTrpState() +{ + char szBtStatus[PROPERTY_VALUE_MAX] = {0, }; + if(property_get("bluetooth.status", szBtStatus, "") < 0){ + ALOGE("Fail to get bluetooth status"); + return FALSE; + } + + if(!strncmp(szBtStatus, "on", strlen("on"))){ + ALOGI("bluetooth status is on"); + return TRUE; + } + return FALSE; +} + +int is_hw_ready() +{ + int i=0; + char szStatus[10] = {0,}; + + for(i=MAX_CNT_RETRY; i>0; i--){ + //TODO :: checking routine + if(readTrpState()==TRUE){ + break; + } + usleep(50*1000); + } + return (i==0)? FALSE:TRUE; +} + +#if (HW_NEED_END_WITH_HCI_RESET == TRUE) +/******************************************************************************* +** +** Function hw_epilog_cback +** +** Description Callback function for Command Complete Events from HCI +** commands sent in epilog process. +** +** Returns None +** +*******************************************************************************/ +void hw_epilog_cback(void *p_mem) +{ + HC_BT_HDR *p_evt_buf = (HC_BT_HDR *) p_mem; + char *p_name, *p_tmp; + uint8_t *p, status; + uint16_t opcode; + + status = *((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_STATUS_RET_BYTE); + p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE; + STREAM_TO_UINT16(opcode,p); + + ALOGI("%s Opcode:0x%04X Status: %d", __FUNCTION__, opcode, status); + +#ifdef BT_THREADLOCK_SAFE + pthread_mutex_lock(&q_lock); +#endif + if (!q) { + ALOGE("hw_epilog_cback called with NULL context"); + goto out; + } + /* Must free the RX event buffer */ + q->cb->dealloc(p_evt_buf); + + /* Once epilog process is done, must call callback to notify caller */ + q->cb->epilog_cb(BT_VND_OP_RESULT_SUCCESS); +out: +#ifdef BT_THREADLOCK_SAFE + pthread_mutex_unlock(&q_lock); +#endif + return; +} + +/******************************************************************************* +** +** Function hw_epilog_process +** +** Description Sample implementation of epilog process. This process is +** called with q_lock held and q->cb is assumed to be valid. +** +** Returns None +** +*******************************************************************************/ +void __hw_epilog_process(void) +{ + HC_BT_HDR *p_buf = NULL; + uint8_t *p; + + ALOGI("hw_epilog_process"); + + /* Sending a HCI_RESET */ + /* Must allocate command buffer via HC's alloc API */ + p_buf = (HC_BT_HDR *) q->cb->alloc(BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE); + if (p_buf) + { + p_buf->event = MSG_STACK_TO_HC_HCI_CMD; + p_buf->offset = 0; + p_buf->layer_specific = 0; + p_buf->len = HCI_CMD_PREAMBLE_SIZE; + + p = (uint8_t *) (p_buf + 1); + UINT16_TO_STREAM(p, HCI_RESET); + *p = 0; /* parameter length */ + + /* Send command via HC's xmit_cb API */ + q->cb->xmit_cb(HCI_RESET, p_buf, hw_epilog_cback); + } + else + { + ALOGE("vendor lib epilog process aborted [no buffer]"); + q->cb->epilog_cb(BT_VND_OP_RESULT_FAIL); + } +} +#endif // (HW_NEED_END_WITH_HCI_RESET == TRUE) diff --git a/sdm845/libbt-vendor/src/hci_smd.c b/sdm845/libbt-vendor/src/hci_smd.c new file mode 100644 index 0000000..7e5b16d --- /dev/null +++ b/sdm845/libbt-vendor/src/hci_smd.c @@ -0,0 +1,161 @@ +/* + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * + * Filename: hci_smd.c + * + * Description: Contains vendor-specific userial functions + * + ******************************************************************************/ + +#define LOG_TAG "bt_vendor" + +#include <utils/Log.h> +#include <termios.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include "bt_vendor_qcom.h" +#include "hci_smd.h" +#include <string.h> +#include <cutils/properties.h> + +/***************************************************************************** +** Macros & Constants +*****************************************************************************/ +#define NUM_OF_DEVS 2 +static char *s_pszDevSmd[] = { + "/dev/smd3", + "/dev/smd2" +}; + +/****************************************************************************** +** Externs +******************************************************************************/ +extern int is_bt_ssr_hci; + + +/***************************************************************************** +** Functions +*****************************************************************************/ + +int bt_hci_init_transport_id (int chId ) +{ + struct termios term; + int fd = -1; + int retry = 0; + char ssrvalue[92]= {'\0'}; + + ssrvalue[0] = '0'; + if(chId >= 2 || chId <0) + return -1; + + fd = open(s_pszDevSmd[chId], (O_RDWR | O_NOCTTY)); + + while ((-1 == fd) && (retry < 7)) { + ALOGE("init_transport: Cannot open %s: %s\n. Retry after 2 seconds", + s_pszDevSmd[chId], strerror(errno)); + usleep(2000000); + fd = open(s_pszDevSmd[chId], (O_RDWR | O_NOCTTY)); + retry++; + } + + if (-1 == fd) + { + ALOGE("init_transport: Cannot open %s: %s\n", + s_pszDevSmd[chId], strerror(errno)); + return -1; + } + + /* Sleep (0.5sec) added giving time for the smd port to be successfully + opened internally. Currently successful return from open doesn't + ensure the smd port is successfully opened. + TODO: Following sleep to be removed once SMD port is successfully + opened immediately on return from the aforementioned open call */ + + property_get("bluetooth.isSSR", ssrvalue, ""); + + if(ssrvalue[0] == '1') + { + /*reset the SSR flag */ + if(chId == 1) + { + if(property_set("bluetooth.isSSR", "0") < 0) + { + ALOGE("SSR: hci_smd.c:SSR case : error in setting up property new\n "); + } + else + { + ALOGE("SSR: hci_smd.c:SSR case : Reset the SSr Flag new\n "); + } + } + ALOGE("hci_smd.c:IN SSR sleep for 500 msec New \n"); + usleep(500000); + } + + if (tcflush(fd, TCIOFLUSH) < 0) + { + ALOGE("init_uart: Cannot flush %s\n", s_pszDevSmd[chId]); + close(fd); + return -1; + } + + if (tcgetattr(fd, &term) < 0) + { + ALOGE("init_uart: Error while getting attributes\n"); + close(fd); + return -1; + } + + cfmakeraw(&term); + + /* JN: Do I need to make flow control configurable, since 4020 cannot + * disable it? + */ + term.c_cflag |= (CRTSCTS | CLOCAL); + + if (tcsetattr(fd, TCSANOW, &term) < 0) + { + ALOGE("init_uart: Error while getting attributes\n"); + close(fd); + return -1; + } + + ALOGI("Done intiailizing UART\n"); + return fd; +} + +int bt_hci_init_transport(int *pFd) +{ + int i = 0; + int fd; + for(i=0; i < NUM_OF_DEVS; i++){ + fd = bt_hci_init_transport_id(i); + if(fd < 0 ){ + return -1; + } + pFd[i] = fd; + } + return 0; +} + +int bt_hci_deinit_transport(int *pFd) +{ + close(pFd[0]); + close(pFd[1]); + return TRUE; +} diff --git a/sdm845/libbt-vendor/src/hci_uart.c b/sdm845/libbt-vendor/src/hci_uart.c new file mode 100644 index 0000000..2aeace8 --- /dev/null +++ b/sdm845/libbt-vendor/src/hci_uart.c @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * + * Filename: userial_vendor.c + * + * Description: Contains vendor-specific userial functions + * + ******************************************************************************/ + +#define LOG_TAG "bt_vendor" + +#include <utils/Log.h> +#include <termios.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include "bt_vendor_qcom.h" +#include "hci_uart.h" +#include <string.h> + +/****************************************************************************** +** Constants & Macros +******************************************************************************/ + +#ifndef VNDUSERIAL_DBG +#define VNDUSERIAL_DBG TRUE +#endif + +#if (VNDUSERIAL_DBG == TRUE) +#define VNDUSERIALDBG(param, ...) {ALOGI(param, ## __VA_ARGS__);} +#else +#define VNDUSERIALDBG(param, ...) {} +#endif + +#define RESERVED(p) if(p) ALOGI( "%s: reserved param", __FUNCTION__); + +/****************************************************************************** +** Global variables +******************************************************************************/ +vnd_userial_cb_t vnd_userial; + +/***************************************************************************** +** Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function userial_to_tcio_baud +** +** Description helper function converts USERIAL baud rates into TCIO +** conforming baud rates +** +** Returns TRUE/FALSE +** +*******************************************************************************/ +uint8_t userial_to_tcio_baud(uint8_t cfg_baud, uint32_t *baud) +{ + if (cfg_baud == USERIAL_BAUD_115200) + *baud = B115200; + else if (cfg_baud == USERIAL_BAUD_4M) + *baud = B4000000; + else if (cfg_baud == USERIAL_BAUD_3M) + *baud = B3000000; + else if (cfg_baud == USERIAL_BAUD_2M) + *baud = B2000000; + else if (cfg_baud == USERIAL_BAUD_1M) + *baud = B1000000; + else if (cfg_baud == USERIAL_BAUD_921600) + *baud = B921600; + else if (cfg_baud == USERIAL_BAUD_460800) + *baud = B460800; + else if (cfg_baud == USERIAL_BAUD_230400) + *baud = B230400; + else if (cfg_baud == USERIAL_BAUD_57600) + *baud = B57600; + else if (cfg_baud == USERIAL_BAUD_19200) + *baud = B19200; + else if (cfg_baud == USERIAL_BAUD_9600) + *baud = B9600; + else if (cfg_baud == USERIAL_BAUD_1200) + *baud = B1200; + else if (cfg_baud == USERIAL_BAUD_600) + *baud = B600; + else + { + ALOGE( "userial vendor open: unsupported baud idx %i", cfg_baud); + *baud = B115200; + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function userial_to_baud_tcio +** +** Description helper function converts TCIO baud rate into integer +** +** Returns uint32_t +** +*******************************************************************************/ +int userial_tcio_baud_to_int(uint32_t baud) +{ + int baud_rate =0; + + switch (baud) + { + case B600: + baud_rate = 600; + break; + case B1200: + baud_rate = 1200; + break; + case B9600: + baud_rate = 9600; + break; + case B19200: + baud_rate = 19200; + break; + case B57600: + baud_rate = 57600; + break; + case B115200: + baud_rate = 115200; + break; + case B230400: + baud_rate = 230400; + break; + case B460800: + baud_rate = 460800; + break; + case B921600: + baud_rate = 921600; + break; + case B1000000: + baud_rate = 1000000; + break; + case B2000000: + baud_rate = 2000000; + break; + case B3000000: + baud_rate = 3000000; + break; + case B4000000: + baud_rate = 4000000; + break; + default: + ALOGE( "%s: unsupported baud %d", __FUNCTION__, baud); + break; + } + + ALOGI( "%s: Current Baudrate = %d bps", __FUNCTION__, baud_rate); + return baud_rate; +} + + +#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) +/******************************************************************************* +** +** Function userial_ioctl_init_bt_wake +** +** Description helper function to set the open state of the bt_wake if ioctl +** is used. it should not hurt in the rfkill case but it might +** be better to compile it out. +** +** Returns none +** +*******************************************************************************/ +void userial_ioctl_init_bt_wake(int fd) +{ + uint32_t bt_wake_state; + + /* assert BT_WAKE through ioctl */ + ioctl(fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL); + ioctl(fd, USERIAL_IOCTL_BT_WAKE_GET_ST, &bt_wake_state); + VNDUSERIALDBG("userial_ioctl_init_bt_wake read back BT_WAKE state=%i", \ + bt_wake_state); +} +#endif // (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) + + +/***************************************************************************** +** Userial Vendor API Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function userial_vendor_init +** +** Description Initialize userial vendor-specific control block +** +** Returns None +** +*******************************************************************************/ +void userial_vendor_init(void) +{ + vnd_userial.fd = -1; + snprintf(vnd_userial.port_name, VND_PORT_NAME_MAXLEN, "%s", BT_HS_UART_DEVICE); +} + +/******************************************************************************* +** +** Function userial_vendor_open +** +** Description Open the serial port with the given configuration +** +** Returns device fd +** +*******************************************************************************/ +int userial_vendor_open(tUSERIAL_CFG *p_cfg) +{ + uint32_t baud; + uint8_t data_bits; + uint16_t parity; + uint8_t stop_bits; + + vnd_userial.fd = -1; + + if (!userial_to_tcio_baud(p_cfg->baud, &baud)) + { + return -1; + } + + if(p_cfg->fmt & USERIAL_DATABITS_8) + data_bits = CS8; + else if(p_cfg->fmt & USERIAL_DATABITS_7) + data_bits = CS7; + else if(p_cfg->fmt & USERIAL_DATABITS_6) + data_bits = CS6; + else if(p_cfg->fmt & USERIAL_DATABITS_5) + data_bits = CS5; + else + { + ALOGE("userial vendor open: unsupported data bits"); + return -1; + } + + if(p_cfg->fmt & USERIAL_PARITY_NONE) + parity = 0; + else if(p_cfg->fmt & USERIAL_PARITY_EVEN) + parity = PARENB; + else if(p_cfg->fmt & USERIAL_PARITY_ODD) + parity = (PARENB | PARODD); + else + { + ALOGE("userial vendor open: unsupported parity bit mode"); + return -1; + } + + if(p_cfg->fmt & USERIAL_STOPBITS_1) + stop_bits = 0; + else if(p_cfg->fmt & USERIAL_STOPBITS_2) + stop_bits = CSTOPB; + else + { + ALOGE("userial vendor open: unsupported stop bits"); + return -1; + } + + ALOGI("userial vendor open: opening %s", vnd_userial.port_name); + + if ((vnd_userial.fd = open(vnd_userial.port_name, O_RDWR|O_NOCTTY)) == -1) + { + ALOGE("userial vendor open: unable to open %s: %s(%d)", vnd_userial.port_name, + strerror(errno), errno); + return -1; + } + + tcflush(vnd_userial.fd, TCIOFLUSH); + + tcgetattr(vnd_userial.fd, &vnd_userial.termios); + cfmakeraw(&vnd_userial.termios); + + /* Set UART Control Modes */ + vnd_userial.termios.c_cflag |= CLOCAL; + vnd_userial.termios.c_cflag |= (CRTSCTS | stop_bits); + + tcsetattr(vnd_userial.fd, TCSANOW, &vnd_userial.termios); + + /* set input/output baudrate */ + cfsetospeed(&vnd_userial.termios, baud); + cfsetispeed(&vnd_userial.termios, baud); + tcsetattr(vnd_userial.fd, TCSANOW, &vnd_userial.termios); + + tcflush(vnd_userial.fd, TCIOFLUSH); + +#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) + userial_ioctl_init_bt_wake(vnd_userial.fd); +#endif + + ALOGI("device fd = %d open", vnd_userial.fd); + + return vnd_userial.fd; +} + +/******************************************************************************* +** +** Function userial_vendor_close +** +** Description Conduct vendor-specific close work +** +** Returns None +** +*******************************************************************************/ +void userial_vendor_close(void) +{ + int result; + + if (vnd_userial.fd == -1) + return; + +#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) + /* de-assert bt_wake BEFORE closing port */ + ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL); +#endif + + ALOGI("device fd = %d close", vnd_userial.fd); + + if ((result = close(vnd_userial.fd)) < 0) + ALOGE( "close(fd:%d) FAILED result:%d", vnd_userial.fd, result); + + vnd_userial.fd = -1; +} + +/******************************************************************************* +** +** Function userial_vendor_set_baud +** +** Description Set new baud rate +** +** Returns None +** +*******************************************************************************/ +void userial_vendor_set_baud(uint8_t userial_baud) +{ + uint32_t tcio_baud; + + VNDUSERIALDBG("## userial_vendor_set_baud: %d", userial_baud); + + userial_to_tcio_baud(userial_baud, &tcio_baud); + + cfsetospeed(&vnd_userial.termios, tcio_baud); + cfsetispeed(&vnd_userial.termios, tcio_baud); + tcsetattr(vnd_userial.fd, TCSADRAIN, &vnd_userial.termios); /* don't change speed until last write done */ +// tcflush(vnd_userial.fd, TCIOFLUSH); +} + +/******************************************************************************* +** +** Function userial_vendor_get_baud +** +** Description Get current baud rate +** +** Returns int +** +*******************************************************************************/ +int userial_vendor_get_baud(void) +{ + if (vnd_userial.fd == -1) + { + ALOGE( "%s: uart port(%s) has not been opened", __FUNCTION__, BT_HS_UART_DEVICE ); + return -1; + } + + return userial_tcio_baud_to_int(cfgetispeed(&vnd_userial.termios)); +} + +/******************************************************************************* +** +** Function userial_vendor_ioctl +** +** Description ioctl inteface +** +** Returns None +** +*******************************************************************************/ +int userial_vendor_ioctl(userial_vendor_ioctl_op_t op, int *p_data) +{ + int err = -1; + + switch(op) + { +#if (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) + case USERIAL_OP_ASSERT_BT_WAKE: + VNDUSERIALDBG("## userial_vendor_ioctl: Asserting BT_Wake ##"); + err = ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_ASSERT, NULL); + break; + + case USERIAL_OP_DEASSERT_BT_WAKE: + VNDUSERIALDBG("## userial_vendor_ioctl: De-asserting BT_Wake ##"); + err = ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_DEASSERT, NULL); + break; + + case USERIAL_OP_GET_BT_WAKE_STATE: + err = ioctl(vnd_userial.fd, USERIAL_IOCTL_BT_WAKE_GET_ST, p_data); + break; +#endif // (BT_WAKE_VIA_USERIAL_IOCTL==TRUE) + case USERIAL_OP_FLOW_ON: + ALOGI("## userial_vendor_ioctl: UART Flow On "); + *p_data |=TIOCM_RTS; + err = ioctl(vnd_userial.fd, TIOCMSET, p_data); + break; + + case USERIAL_OP_FLOW_OFF: + ALOGI("## userial_vendor_ioctl: UART Flow Off "); + ioctl(vnd_userial.fd, TIOCMGET, p_data); + *p_data &= ~TIOCM_RTS; + err = ioctl(vnd_userial.fd, TIOCMSET, p_data); + break; + + default: + break; + } + + return err; +} + +/******************************************************************************* +** +** Function userial_set_port +** +** Description Configure UART port name +** +** Returns 0 : Success +** Otherwise : Fail +** +*******************************************************************************/ +int userial_set_port(char *p_conf_name, char *p_conf_value, int param) +{ + RESERVED(p_conf_name); + RESERVED(param); + strlcpy(vnd_userial.port_name, p_conf_value, VND_PORT_NAME_MAXLEN); + + return 0; +} + +/******************************************************************************* +** +** Function read_hci_event +** +** Description Read HCI event during vendor initialization +** +** Returns int: size to read +** +*******************************************************************************/ +int read_hci_event(int fd, unsigned char* buf, int size) +{ + int remain, r; + int count = 0; + + if (size <= 0) { + ALOGE("Invalid size arguement!"); + return -1; + } + + ALOGI("%s: Wait for Command Compete Event from SOC", __FUNCTION__); + + /* The first byte identifies the packet type. For HCI event packets, it + * should be 0x04, so we read until we get to the 0x04. */ + while (1) { + r = read(fd, buf, 1); + if (r <= 0) + return -1; + if (buf[0] == 0x04) + break; + } + count++; + + /* The next two bytes are the event code and parameter total length. */ + while (count < 3) { + r = read(fd, buf + count, 3 - count); + if (r <= 0) + return -1; + count += r; + } + + /* Now we read the parameters. */ + if (buf[2] < (size - 3)) + remain = buf[2]; + else + remain = size - 3; + + while ((count - 3) < remain) { + r = read(fd, buf + count, remain - (count - 3)); + if (r <= 0) + return -1; + count += r; + } + return count; +} + +int userial_clock_operation(int fd, int cmd) +{ + int ret = 0; + + switch (cmd) + { + case USERIAL_OP_CLK_ON: + case USERIAL_OP_CLK_OFF: + ioctl(fd, cmd); + break; + case USERIAL_OP_CLK_STATE: + ret = ioctl(fd, cmd); + break; + } + + return ret; +} diff --git a/sdm845/libbt-vendor/src/hw_ar3k.c b/sdm845/libbt-vendor/src/hw_ar3k.c new file mode 100644 index 0000000..cc54db8 --- /dev/null +++ b/sdm845/libbt-vendor/src/hw_ar3k.c @@ -0,0 +1,1488 @@ +/* + * + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you + * may not use this file except in compliance with the License. You may + * obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +/****************************************************************************** + * + * Filename: hw_ar3k.c + * + * Description: Contains controller-specific functions, like + * firmware patch download + * low power mode operations + * + ******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +#define LOG_TAG "bt_vendor" + +#include <sys/socket.h> +#include <utils/Log.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <time.h> +#include <errno.h> +#include <fcntl.h> +#include <dirent.h> +#include <ctype.h> +#include <cutils/properties.h> +#include <stdlib.h> +#include <termios.h> +#include <string.h> + +#include "bt_hci_bdroid.h" +#include "bt_vendor_qcom.h" +#include "hci_uart.h" +#include "hw_ar3k.h" + +/****************************************************************************** +** Variables +******************************************************************************/ +int cbstat = 0; +#define PATCH_LOC_STRING_LEN 8 +char ARbyte[3]; +char ARptr[MAX_PATCH_CMD + 1]; +int byte_cnt; +int patch_count = 0; +char patch_loc[PATCH_LOC_STRING_LEN + 1]; +int PSCounter=0; + +uint32_t dev_type = 0; +uint32_t rom_version = 0; +uint32_t build_version = 0; + +char patch_file[PATH_MAX]; +char ps_file[PATH_MAX]; +FILE *stream; +int tag_count=0; + +/* for friendly debugging outpout string */ +static char *lpm_mode[] = { + "UNKNOWN", + "disabled", + "enabled" +}; + +static char *lpm_state[] = { + "UNKNOWN", + "de-asserted", + "asserted" +}; + +static uint8_t upio_state[UPIO_MAX_COUNT]; +struct ps_cfg_entry ps_list[MAX_TAGS]; + +#define PS_EVENT_LEN 100 + +#ifdef __cplusplus +} +#endif + +#define RESERVED(p) if(p) ALOGI( "%s: reserved param", __FUNCTION__); + +/***************************************************************************** +** Functions +*****************************************************************************/ + +int is_bt_soc_ath() { + int ret = 0; + char bt_soc_type[PROPERTY_VALUE_MAX]; + ret = property_get("qcom.bluetooth.soc", bt_soc_type, NULL); + if (ret != 0) { + ALOGI("qcom.bluetooth.soc set to %s\n", bt_soc_type); + if (!strncasecmp(bt_soc_type, "ath3k", sizeof("ath3k"))) + return 1; + } else { + ALOGI("qcom.bluetooth.soc not set, so using default.\n"); + } + + return 0; +} + +/* + * Send HCI command and wait for command complete event. + * The event buffer has to be freed by the caller. + */ + +static int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event) +{ + int err; + uint8_t *hci_event; + uint8_t pkt_type = HCI_COMMAND_PKT; + + if (len == 0) + return len; + + if (write(dev, &pkt_type, 1) != 1) + return -EILSEQ; + if (write(dev, (unsigned char *)cmd, len) != len) + return -EILSEQ; + + hci_event = (uint8_t *)malloc(PS_EVENT_LEN); + if (!hci_event) + return -ENOMEM; + + err = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN); + if (err > 0) { + *event = hci_event; + } else { + free(hci_event); + return -EILSEQ; + } + + return len; +} + +static void convert_bdaddr(char *str_bdaddr, char *bdaddr) +{ + char bdbyte[3]; + char *str_byte = str_bdaddr; + int i, j; + int colon_present = 0; + + if (strstr(str_bdaddr, ":")) + colon_present = 1; + + bdbyte[2] = '\0'; + + /* Reverse the BDADDR to LSB first */ + for (i = 0, j = 5; i < 6; i++, j--) { + bdbyte[0] = str_byte[0]; + bdbyte[1] = str_byte[1]; + bdaddr[j] = strtol(bdbyte, NULL, 16); + + if (colon_present == 1) + str_byte += 3; + else + str_byte += 2; + } +} + +static int uart_speed(int s) +{ + switch (s) { + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; +#ifdef B2500000 + case 2500000: + return B2500000; +#endif +#ifdef B3000000 + case 3000000: + return B3000000; +#endif +#ifdef B3500000 + case 3500000: + return B3500000; +#endif +#ifdef B4000000 + case 4000000: + return B4000000; +#endif + default: + return B57600; + } +} + +int set_speed(int fd, struct termios *ti, int speed) +{ + if (cfsetospeed(ti, uart_speed(speed)) < 0) + return -errno; + + if (cfsetispeed(ti, uart_speed(speed)) < 0) + return -errno; + + if (tcsetattr(fd, TCSANOW, ti) < 0) + return -errno; + + return 0; +} + +static void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index) +{ + hci_command_hdr *ch = (void *)cmd; + + ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, + HCI_PS_CMD_OCF)); + ch->plen = len + PS_HDR_LEN; + cmd += HCI_COMMAND_HDR_SIZE; + + cmd[0] = ps_op; + cmd[1] = index; + cmd[2] = index >> 8; + cmd[3] = len; +} + + +static int read_ps_event(uint8_t *event, uint16_t ocf) +{ + hci_event_hdr *eh; + uint16_t opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, ocf)); + + event++; + + eh = (void *)event; + event += HCI_EVENT_HDR_SIZE; + + if (eh->evt == EVT_CMD_COMPLETE) { + evt_cmd_complete *cc = (void *)event; + + event += EVT_CMD_COMPLETE_SIZE; + + if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS) + return 0; + else + return -EILSEQ; + } + + return -EILSEQ; +} + +#define PS_WRITE 1 +#define PS_RESET 2 +#define WRITE_PATCH 8 +#define ENABLE_PATCH 11 + +#define HCI_PS_CMD_HDR_LEN 7 + +static int write_cmd(int fd, uint8_t *buffer, int len) +{ + uint8_t *event; + int err; + + err = send_hci_cmd_sync(fd, buffer, len, &event); + if (err < 0) + return err; + + err = read_ps_event(event, HCI_PS_CMD_OCF); + + free(event); + + return err; +} + +#define PS_RESET_PARAM_LEN 6 +#define PS_RESET_CMD_LEN (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN) + +#define PS_ID_MASK 0xFF + +/* Sends PS commands using vendor specficic HCI commands */ +static int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param) +{ + uint8_t cmd[HCI_MAX_CMD_SIZE]; + uint32_t i; + + switch (opcode) { + case ENABLE_PATCH: + load_hci_ps_hdr(cmd, opcode, 0, 0x00); + + if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0) + return -EILSEQ; + break; + + case PS_RESET: + load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00); + + cmd[7] = 0x00; + cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK; + cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK; + + if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0) + return -EILSEQ; + break; + + case PS_WRITE: + for (i = 0; i < ps_param; i++) { + load_hci_ps_hdr(cmd, opcode, ps_list[i].len, + ps_list[i].id); + + memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data, + ps_list[i].len); + + if (write_cmd(fd, cmd, ps_list[i].len + + HCI_PS_CMD_HDR_LEN) < 0) + return -EILSEQ; + } + break; + } + + return 0; +} + +#define PS_ASIC_FILE "PS_ASIC.pst" +#define PS_FPGA_FILE "PS_FPGA.pst" +#define MAXPATHLEN 4096 +static void get_ps_file_name(uint32_t devtype, uint32_t rom_version,char *path) +{ + char *filename; + + if (devtype == 0xdeadc0de) + filename = PS_ASIC_FILE; + else + filename = PS_FPGA_FILE; + + snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, filename); +} + +#define PATCH_FILE "RamPatch.txt" +#define FPGA_ROM_VERSION 0x99999999 +#define ROM_DEV_TYPE 0xdeadc0de + +static void get_patch_file_name(uint32_t dev_type, uint32_t rom_version, + uint32_t build_version, char *path) +{ + if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE + &&dev_type != 0 && build_version == 1) + path[0] = '\0'; + else + snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, PATCH_FILE); +} + +static int set_cntrlr_baud(int fd, int speed) +{ + int baud; + struct timespec tm = { 0, 500000}; + unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE]; + unsigned char *ptr = cmd + 1; + hci_command_hdr *ch = (void *)ptr; + + cmd[0] = HCI_COMMAND_PKT; + + /* set controller baud rate to user specified value */ + ptr = cmd + 1; + ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, + HCI_CHG_BAUD_CMD_OCF)); + ch->plen = 2; + ptr += HCI_COMMAND_HDR_SIZE; + + baud = speed/100; + ptr[0] = (char)baud; + ptr[1] = (char)(baud >> 8); + + if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) { + ALOGI("Failed to write change baud rate command"); + return -ETIMEDOUT; + } + + nanosleep(&tm, NULL); + + if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) + return -ETIMEDOUT; + + return 0; +} + +#define PS_UNDEF 0 +#define PS_ID 1 +#define PS_LEN 2 +#define PS_DATA 3 + +#define PS_MAX_LEN 500 +#define LINE_SIZE_MAX (PS_MAX_LEN * 2) +#define ENTRY_PER_LINE 16 + +#define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/')) +#define __skip_space(str) while (*(str) == ' ') ((str)++) + + +#define __is_delim(ch) ((ch) == ':') +#define MAX_PREAMBLE_LEN 4 + +/* Parse PS entry preamble of format [X:X] for main type and subtype */ +static int get_ps_type(char *ptr, int index, char *type, char *sub_type) +{ + int i; + int delim = FALSE; + + if (index > MAX_PREAMBLE_LEN) + return -EILSEQ; + + for (i = 1; i < index; i++) { + if (__is_delim(ptr[i])) { + delim = TRUE; + continue; + } + + if (isalpha(ptr[i])) { + if (delim == FALSE) + (*type) = toupper(ptr[i]); + else + (*sub_type) = toupper(ptr[i]); + } + } + + return 0; +} + +#define ARRAY 'A' +#define STRING 'S' +#define DECIMAL 'D' +#define BINARY 'B' + +#define PS_HEX 0 +#define PS_DEC 1 + +static int get_input_format(char *buf, struct ps_entry_type *format) +{ + char *ptr = NULL; + char type = '\0'; + char sub_type = '\0'; + + format->type = PS_HEX; + format->array = TRUE; + + if (strstr(buf, "[") != buf) + return 0; + + ptr = strstr(buf, "]"); + if (!ptr) + return -EILSEQ; + + if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0) + return -EILSEQ; + + /* Check is data type is of array */ + if (type == ARRAY || sub_type == ARRAY) + format->array = TRUE; + + if (type == STRING || sub_type == STRING) + format->array = FALSE; + + if (type == DECIMAL || type == BINARY) + format->type = PS_DEC; + else + format->type = PS_HEX; + + return 0; +} + + + +#define UNDEFINED 0xFFFF + +static unsigned int read_data_in_section(char *buf, struct ps_entry_type type) +{ + char *ptr = buf; + + if (!buf) + return UNDEFINED; + + if (buf == strstr(buf, "[")) { + ptr = strstr(buf, "]"); + if (!ptr) + return UNDEFINED; + + ptr++; + } + + if (type.type == PS_HEX && type.array != TRUE) + return strtol(ptr, NULL, 16); + + return UNDEFINED; +} + + +/* Read PS entries as string, convert and add to Hex array */ +static void update_tag_data(struct ps_cfg_entry *tag, + struct tag_info *info, const char *ptr) +{ + char buf[3]; + + buf[2] = '\0'; + + strlcpy(buf, &ptr[info->char_cnt],sizeof(buf)); + tag->data[info->byte_count] = strtol(buf, NULL, 16); + info->char_cnt += 3; + info->byte_count++; + + strlcpy(buf, &ptr[info->char_cnt], sizeof(buf)); + tag->data[info->byte_count] = strtol(buf, NULL, 16); + info->char_cnt += 3; + info->byte_count++; +} + +static inline int update_char_count(const char *buf) +{ + char *end_ptr; + + if (strstr(buf, "[") == buf) { + end_ptr = strstr(buf, "]"); + if (!end_ptr) + return 0; + else + return(end_ptr - buf) + 1; + } + + return 0; +} + +#define PS_HEX 0 +#define PS_DEC 1 + +static int ath_parse_ps(FILE *stream) +{ + char buf[LINE_SIZE_MAX + 1]; + char *ptr; + uint8_t tag_cnt = 0; + int16_t byte_count = 0; + struct ps_entry_type format; + struct tag_info status = { 0, 0, 0, 0}; + + do { + int read_count; + struct ps_cfg_entry *tag; + + ptr = fgets(buf, LINE_SIZE_MAX, stream); + if (!ptr) + break; + + __skip_space(ptr); + if (__check_comment(ptr)) + continue; + + /* Lines with a '#' will be followed by new PS entry */ + if (ptr == strstr(ptr, "#")) { + if (status.section != PS_UNDEF) { + return -EILSEQ; + } else { + status.section = PS_ID; + continue; + } + } + + tag = &ps_list[tag_cnt]; + + switch (status.section) { + case PS_ID: + if (get_input_format(ptr, &format) < 0) + return -EILSEQ; + + tag->id = read_data_in_section(ptr, format); + status.section = PS_LEN; + break; + + case PS_LEN: + if (get_input_format(ptr, &format) < 0) + return -EILSEQ; + + byte_count = read_data_in_section(ptr, format); + if (byte_count > PS_MAX_LEN) + return -EILSEQ; + + tag->len = byte_count; + tag->data = (uint8_t *)malloc(byte_count); + + status.section = PS_DATA; + status.line_count = 0; + break; + + case PS_DATA: + if (status.line_count == 0) + if (get_input_format(ptr, &format) < 0) + return -EILSEQ; + + __skip_space(ptr); + + status.char_cnt = update_char_count(ptr); + + read_count = (byte_count > ENTRY_PER_LINE) ? + ENTRY_PER_LINE : byte_count; + + if (format.type == PS_HEX && format.array == TRUE) { + while (read_count > 0) { + update_tag_data(tag, &status, ptr); + read_count -= 2; + } + + if (byte_count > ENTRY_PER_LINE) + byte_count -= ENTRY_PER_LINE; + else + byte_count = 0; + } + + status.line_count++; + + if (byte_count == 0) + memset(&status, 0x00, sizeof(struct tag_info)); + + if (status.section == PS_UNDEF) + tag_cnt++; + + if (tag_cnt == MAX_TAGS) + return -EILSEQ; + break; + } + } while (ptr); + + return tag_cnt; +} + +#define PS_RAM_SIZE 2048 + +static int ps_config_download(int fd, int tag_count) +{ + if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0) + return -1; + + if (tag_count > 0) + if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0) + return -1; + return 0; +} + +static int write_bdaddr(int pConfig, char *bdaddr) +{ + uint8_t *event; + int err; + uint8_t cmd[13]; + uint8_t *ptr = cmd; + hci_command_hdr *ch = (void *)cmd; + + memset(cmd, 0, sizeof(cmd)); + + ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, + HCI_PS_CMD_OCF)); + ch->plen = 10; + ptr += HCI_COMMAND_HDR_SIZE; + + ptr[0] = 0x01; + ptr[1] = 0x01; + ptr[2] = 0x00; + ptr[3] = 0x06; + + convert_bdaddr(bdaddr, (char *)&ptr[4]); + + err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event); + if (err < 0) + return err; + + err = read_ps_event(event, HCI_PS_CMD_OCF); + + free(event); + + return err; +} + +static void write_bdaddr_from_file(int rom_version, int fd) +{ + FILE *stream; + char bdaddr[PATH_MAX]; + char bdaddr_file[PATH_MAX]; + + snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s", + FW_PATH, rom_version, BDADDR_FILE); + + stream = fopen(bdaddr_file, "r"); + if (!stream) + return; + + if (fgets(bdaddr, PATH_MAX - 1, stream)) + write_bdaddr(fd, bdaddr); + + fclose(stream); +} + +#define HCI_EVT_CMD_CMPL_OPCODE 3 +#define HCI_EVT_CMD_CMPL_STATUS_RET_BYTE 5 + +void baswap(bdaddr_t *dst, const bdaddr_t *src) +{ + register unsigned char *d = (unsigned char *) dst; + register const unsigned char *s = (const unsigned char *) src; + register int i; + for (i = 0; i < 6; i++) + d[i] = s[5-i]; +} + + +int str2ba(const char *str, bdaddr_t *ba) +{ + uint8_t b[6]; + const char *ptr = str; + int i; + + for (i = 0; i < 6; i++) { + b[i] = (uint8_t) strtol(ptr, NULL, 16); + ptr = strchr(ptr, ':'); + if (i != 5 && !ptr) + ptr = ":00:00:00:00:00"; + ptr++; + } + baswap(ba, (bdaddr_t *) b); + return 0; +} + +#define DEV_REGISTER 0x4FFC +#define GET_DEV_TYPE_OCF 0x05 + +static int get_device_type(int dev, uint32_t *code) +{ + uint8_t cmd[8] = {0}; + uint8_t *event; + uint32_t reg; + int err; + uint8_t *ptr = cmd; + hci_command_hdr *ch = (void *)cmd; + + ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, + GET_DEV_TYPE_OCF)); + ch->plen = 5; + ptr += HCI_COMMAND_HDR_SIZE; + + ptr[0] = (uint8_t)DEV_REGISTER; + ptr[1] = (uint8_t)DEV_REGISTER >> 8; + ptr[2] = (uint8_t)DEV_REGISTER >> 16; + ptr[3] = (uint8_t)DEV_REGISTER >> 24; + ptr[4] = 0x04; + + err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event); + if (err < 0) + return err; + + err = read_ps_event(event, GET_DEV_TYPE_OCF); + if (err < 0) + goto cleanup; + + reg = event[10]; + reg = (reg << 8) | event[9]; + reg = (reg << 8) | event[8]; + reg = (reg << 8) | event[7]; + *code = reg; + +cleanup: + free(event); + + return err; +} + +#define GET_VERSION_OCF 0x1E + +static int read_ath3k_version(int pConfig, uint32_t *rom_version, + uint32_t *build_version) +{ + uint8_t cmd[3] = {0}; + uint8_t *event; + int err; + int status; + hci_command_hdr *ch = (void *)cmd; + + ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, + GET_VERSION_OCF)); + ch->plen = 0; + + err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event); + if (err < 0) + return err; + + err = read_ps_event(event, GET_VERSION_OCF); + if (err < 0) + goto cleanup; + + status = event[10]; + status = (status << 8) | event[9]; + status = (status << 8) | event[8]; + status = (status << 8) | event[7]; + *rom_version = status; + + status = event[14]; + status = (status << 8) | event[13]; + status = (status << 8) | event[12]; + status = (status << 8) | event[11]; + *build_version = status; + +cleanup: + free(event); + + return err; +} + +#define VERIFY_CRC 9 +#define PS_REGION 1 +#define PATCH_REGION 2 + +static int get_ath3k_crc(int dev) +{ + uint8_t cmd[7] = {0}; + uint8_t *event; + int err; + + load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION); + + err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event); + if (err < 0) + return err; + /* Send error code if CRC check patched */ + if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0) + err = -EILSEQ; + + free(event); + + return err; +} + +#define SET_PATCH_RAM_ID 0x0D +#define SET_PATCH_RAM_CMD_SIZE 11 +#define ADDRESS_LEN 4 +static int set_patch_ram(int dev, char *patch_loc, int len) +{ + int err; + uint8_t cmd[20] = {0}; + int i, j; + char loc_byte[3]; + uint8_t *event; + uint8_t *loc_ptr = &cmd[7]; + + RESERVED(len); + + if (!patch_loc) + return -1; + + loc_byte[2] = '\0'; + + load_hci_ps_hdr(cmd, SET_PATCH_RAM_ID, ADDRESS_LEN, 0); + + for (i = 0, j = 3; i < 4; i++, j--) { + loc_byte[0] = patch_loc[0]; + loc_byte[1] = patch_loc[1]; + loc_ptr[j] = strtol(loc_byte, NULL, 16); + patch_loc += 2; + } + + err = send_hci_cmd_sync(dev, cmd, SET_PATCH_RAM_CMD_SIZE, &event); + if (err < 0) + return err; + + err = read_ps_event(event, HCI_PS_CMD_OCF); + + free(event); + + return err; +} + +#define PATCH_LOC_KEY "DA:" +#define PATCH_LOC_STRING_LEN 8 +static int ps_patch_download(int fd, FILE *stream) +{ + char byte[3]; + char ptr[MAX_PATCH_CMD + 1]; + int byte_cnt; + int patch_count = 0; + char patch_loc[PATCH_LOC_STRING_LEN + 1]; + + byte[2] = '\0'; + + while (fgets(ptr, MAX_PATCH_CMD, stream)) { + if (strlen(ptr) <= 1) + continue; + else if (strstr(ptr, PATCH_LOC_KEY) == ptr) { + strlcpy(patch_loc, &ptr[sizeof(PATCH_LOC_KEY) - 1], + PATCH_LOC_STRING_LEN); + if (set_patch_ram(fd, patch_loc, sizeof(patch_loc)) < 0) + return -1; + } else if (isxdigit(ptr[0])) + break; + else + return -1; + } + + byte_cnt = strtol(ptr, NULL, 16); + + while (byte_cnt > 0) { + int i; + uint8_t cmd[HCI_MAX_CMD_SIZE] = {0}; + struct patch_entry patch; + + if (byte_cnt > MAX_PATCH_CMD) + patch.len = MAX_PATCH_CMD; + else + patch.len = byte_cnt; + + for (i = 0; i < patch.len; i++) { + if (!fgets(byte, 3, stream)) + return -1; + + patch.data[i] = strtoul(byte, NULL, 16); + } + + load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count); + memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len); + + if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0) + return -1; + + patch_count++; + byte_cnt = byte_cnt - MAX_PATCH_CMD; + } + + if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0) + return -1; + + return patch_count; +} + +static int ath_ps_download(int fd) +{ + int err = 0; + int tag_count; + int patch_count = 0; + uint32_t rom_version = 0; + uint32_t build_version = 0; + uint32_t dev_type = 0; + char patch_file[PATH_MAX]; + char ps_file[PATH_MAX]; + FILE *stream; + + /* + * Verfiy firmware version. depending on it select the PS + * config file to download. + */ + if (get_device_type(fd, &dev_type) < 0) { + err = -EILSEQ; + goto download_cmplete; + } + + if (read_ath3k_version(fd, &rom_version, &build_version) < 0) { + err = -EILSEQ; + goto download_cmplete; + } + + /* Do not download configuration if CRC passes */ + if (get_ath3k_crc(fd) < 0) { + err = 0; + goto download_cmplete; + } + + get_ps_file_name(dev_type, rom_version, ps_file); + get_patch_file_name(dev_type, rom_version, build_version, patch_file); + + stream = fopen(ps_file, "r"); + if (!stream) { + ALOGI("firmware file open error:%s, ver:%x\n",ps_file, rom_version); + if (rom_version == 0x1020201) + err = 0; + else + err = -EILSEQ; + goto download_cmplete; + } + tag_count = ath_parse_ps(stream); + + fclose(stream); + + if (tag_count < 0) { + err = -EILSEQ; + goto download_cmplete; + } + + /* + * It is not necessary that Patch file be available, + * continue with PS Operations if patch file is not available. + */ + if (patch_file[0] == '\0') + err = 0; + + stream = fopen(patch_file, "r"); + if (!stream) + err = 0; + else { + patch_count = ps_patch_download(fd, stream); + fclose(stream); + + if (patch_count < 0) { + err = -EILSEQ; + goto download_cmplete; + } + } + + err = ps_config_download(fd, tag_count); + +download_cmplete: + if (!err) + write_bdaddr_from_file(rom_version, fd); + + return err; +} + +int ath3k_init(int fd, int speed, int init_speed, char *bdaddr, struct termios *ti) +{ + ALOGI(" %s ", __FUNCTION__); + + int r; + int err = 0; + struct timespec tm = { 0, 500000}; + unsigned char cmd[MAX_CMD_LEN] = {0}; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + unsigned char *ptr = cmd + 1; + hci_command_hdr *ch = (void *)ptr; + int flags = 0; + + if (ioctl(fd, TIOCMGET, &flags) < 0) { + ALOGI("TIOCMGET failed in init\n"); + return -1; + } + flags |= TIOCM_RTS; + if (ioctl(fd, TIOCMSET, &flags) < 0) { + ALOGI("TIOCMSET failed in init: HW Flow-on error\n"); + return -1; + } + + /* set both controller and host baud rate to maximum possible value */ + err = set_cntrlr_baud(fd, speed); + ALOGI("set_cntrlr_baud : ret:%d \n", err); + if (err < 0) + return err; + + err = set_speed(fd, ti, speed); + if (err < 0) { + ALOGI("Can't set required baud rate"); + return err; + } + + /* Download PS and patch */ + r = ath_ps_download(fd); + if (r < 0) { + ALOGI("Failed to Download configuration"); + err = -ETIMEDOUT; + goto failed; + } + + ALOGI("ath_ps_download is done\n"); + + cmd[0] = HCI_COMMAND_PKT; + /* Write BDADDR */ + if (bdaddr) { + ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, + HCI_PS_CMD_OCF)); + ch->plen = 10; + ptr += HCI_COMMAND_HDR_SIZE; + + ptr[0] = 0x01; + ptr[1] = 0x01; + ptr[2] = 0x00; + ptr[3] = 0x06; + str2ba(bdaddr, (bdaddr_t *)(ptr + 4)); + + if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) != + WRITE_BDADDR_CMD_LEN) { + ALOGI("Failed to write BD_ADDR command\n"); + err = -ETIMEDOUT; + goto failed; + } + + if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) { + ALOGI("Failed to set BD_ADDR\n"); + err = -ETIMEDOUT; + goto failed; + } + } + + /* Send HCI Reset */ + cmd[1] = 0x03; + cmd[2] = 0x0C; + cmd[3] = 0x00; + + r = write(fd, cmd, 4); + if (r != 4) { + err = -ETIMEDOUT; + goto failed; + } + + nanosleep(&tm, NULL); + if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) { + err = -ETIMEDOUT; + goto failed; + } + + ALOGI("HCI Reset is done\n"); + err = set_cntrlr_baud(fd, speed); + if (err < 0) + ALOGI("set_cntrlr_baud0:%d,%d\n", speed, err); + +failed: + if (err < 0) { + set_cntrlr_baud(fd, init_speed); + set_speed(fd, ti, init_speed); + } + + return err; + +} +#define BTPROTO_HCI 1 + +/* Open HCI device. + * Returns device descriptor (dd). */ +int hci_open_dev(int dev_id) +{ + struct sockaddr_hci a; + int dd, err; + + /* Create HCI socket */ + dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (dd < 0) + return dd; + + /* Bind socket to the HCI device */ + memset(&a, 0, sizeof(a)); + a.hci_family = AF_BLUETOOTH; + a.hci_dev = dev_id; + if (bind(dd, (struct sockaddr *) &a, sizeof(a)) < 0) + goto failed; + + return dd; + +failed: + err = errno; + close(dd); + errno = err; + + return -1; +} + +int hci_close_dev(int dd) +{ + return close(dd); +} + +/* HCI functions that require open device + * dd - Device descriptor returned by hci_open_dev. */ + +int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param) +{ + uint8_t type = HCI_COMMAND_PKT; + hci_command_hdr hc; + struct iovec iv[3]; + int ivn; + + hc.opcode = htobs(cmd_opcode_pack(ogf, ocf)); + hc.plen= plen; + + iv[0].iov_base = &type; + iv[0].iov_len = 1; + iv[1].iov_base = &hc; + iv[1].iov_len = HCI_COMMAND_HDR_SIZE; + ivn = 2; + + if (plen) { + iv[2].iov_base = param; + iv[2].iov_len = plen; + ivn = 3; + } + + while (writev(dd, iv, ivn) < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + return -1; + } + return 0; +} + +#define HCI_SLEEP_CMD_OCF 0x04 +#define TIOCSETD 0x5423 +#define HCIUARTSETFLAGS _IOW('U', 204, int) +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETDEVICE _IOW('U', 202, int) +/* + * Atheros AR300x specific initialization post callback + */ +int ath3k_post(int fd, int pm) +{ + int dev_id, dd; + struct timespec tm = { 0, 50000}; + + sleep(1); + + dev_id = ioctl(fd, HCIUARTGETDEVICE, 0); + if (dev_id < 0) { + perror("cannot get device id"); + return dev_id; + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + return dd; + } + + if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) { + perror("hci down:Power management Disabled"); + hci_close_dev(dd); + return -1; + } + + /* send vendor specific command with Sleep feature Enabled */ + if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF, 1, &pm) < 0) + perror("PM command failed, power management Disabled"); + + nanosleep(&tm, NULL); + hci_close_dev(dd); + + return 0; +} + + + +#define FLOW_CTL 0x0001 +#define ENABLE_PM 1 +#define DISABLE_PM 0 + +/* Initialize UART driver */ +static int init_uart(char *dev, struct uart_t *u, int send_break, int raw) +{ + ALOGI(" %s ", __FUNCTION__); + + struct termios ti; + + int i, fd; + unsigned long flags = 0; + + if (raw) + flags |= 1 << HCI_UART_RAW_DEVICE; + + + fd = open(dev, O_RDWR | O_NOCTTY); + + if (fd < 0) { + ALOGI("Can't open serial port"); + return -1; + } + + + tcflush(fd, TCIOFLUSH); + + if (tcgetattr(fd, &ti) < 0) { + ALOGI("Can't get port settings: %d\n", errno); + return -1; + } + + cfmakeraw(&ti); + + ti.c_cflag |= CLOCAL; + if (u->flags & FLOW_CTL) + ti.c_cflag |= CRTSCTS; + else + ti.c_cflag &= ~CRTSCTS; + + if (tcsetattr(fd, TCSANOW, &ti) < 0) { + ALOGI("Can't set port settings"); + return -1; + } + + if (set_speed(fd, &ti, u->init_speed) < 0) { + ALOGI("Can't set initial baud rate"); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (send_break) { + tcsendbreak(fd, 0); + usleep(500000); + } + + ath3k_init(fd,u->speed,u->init_speed,u->bdaddr, &ti); + + ALOGI("Device setup complete\n"); + + + tcflush(fd, TCIOFLUSH); + + // Set actual baudrate + /* + if (set_speed(fd, &ti, u->speed) < 0) { + perror("Can't set baud rate"); + return -1; + } + + i = N_HCI; + if (ioctl(fd, TIOCSETD, &i) < 0) { + perror("Can't set line discipline"); + return -1; + } + + if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) { + perror("Can't set UART flags"); + return -1; + } + + if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) { + perror("Can't set device"); + return -1; + } + +#if !defined(SW_BOARD_HAVE_BLUETOOTH_RTK) + ath3k_post(fd, u->pm); +#endif + */ + + return fd; +} + + +int hw_config_ath3k(char *port_name) +{ + ALOGI(" %s ", __FUNCTION__); + PSCounter=0; + struct sigaction sa; + struct uart_t u ; + int n=0,send_break=0,raw=0; + + memset(&u, 0, sizeof(u)); + u.speed =3000000; + u.init_speed =115200; + u.flags |= FLOW_CTL; + u.pm = DISABLE_PM; + + n = init_uart(port_name, &u, send_break, raw); + if (n < 0) { + ALOGI("Can't initialize device"); + } + + return n; +} + +void lpm_set_ar3k(uint8_t pio, uint8_t action, uint8_t polarity) +{ + int rc; + int fd = -1; + char buffer; + + ALOGI("lpm mode: %d action: %d", pio, action); + + RESERVED(polarity); + + switch (pio) + { + case UPIO_LPM_MODE: + if (upio_state[UPIO_LPM_MODE] == action) + { + ALOGI("LPM is %s already", lpm_mode[action]); + return; + } + + fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY); + + if (fd < 0) + { + ALOGE("upio_set : open(%s) for write failed: %s (%d)", + VENDOR_LPM_PROC_NODE, strerror(errno), errno); + return; + } + + if (action == UPIO_ASSERT) + { + buffer = '1'; + } + else + { + buffer = '0'; + } + + if (write(fd, &buffer, 1) < 0) + { + ALOGE("upio_set : write(%s) failed: %s (%d)", + VENDOR_LPM_PROC_NODE, strerror(errno),errno); + } + else + { + upio_state[UPIO_LPM_MODE] = action; + ALOGI("LPM is set to %s", lpm_mode[action]); + } + + if (fd >= 0) + close(fd); + + break; + + case UPIO_BT_WAKE: + /* UPIO_DEASSERT should be allowed because in Rx case assert occur + * from the remote side where as deassert will be initiated from Host + */ + if ((action == UPIO_ASSERT) && (upio_state[UPIO_BT_WAKE] == action)) + { + ALOGI("BT_WAKE is %s already", lpm_state[action]); + + return; + } + + if (action == UPIO_DEASSERT) + buffer = '0'; + else + buffer = '1'; + + fd = open(VENDOR_BTWRITE_PROC_NODE, O_WRONLY); + + if (fd < 0) + { + ALOGE("upio_set : open(%s) for write failed: %s (%d)", + VENDOR_BTWRITE_PROC_NODE, strerror(errno), errno); + return; + } + + if (write(fd, &buffer, 1) < 0) + { + ALOGE("upio_set : write(%s) failed: %s (%d)", + VENDOR_BTWRITE_PROC_NODE, strerror(errno),errno); + } + else + { + upio_state[UPIO_BT_WAKE] = action; + ALOGI("BT_WAKE is set to %s", lpm_state[action]); + } + + ALOGI("proc btwrite assertion"); + + if (fd >= 0) + close(fd); + + break; + + case UPIO_HOST_WAKE: + ALOGI("upio_set: UPIO_HOST_WAKE"); + break; + } + +} diff --git a/sdm845/libbt-vendor/src/hw_rome.c b/sdm845/libbt-vendor/src/hw_rome.c new file mode 100644 index 0000000..ccfb137 --- /dev/null +++ b/sdm845/libbt-vendor/src/hw_rome.c @@ -0,0 +1,1950 @@ +/* + * + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * Copyright 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you + * may not use this file except in compliance with the License. You may + * obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + */ + +/****************************************************************************** + * + * Filename: hw_rome.c + * + * Description: Contains controller-specific functions, like + * firmware patch download + * low power mode operations + * + ******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +#define LOG_TAG "bt_vendor" + +#include <sys/socket.h> +#include <utils/Log.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <time.h> +#include <errno.h> +#include <fcntl.h> +#include <dirent.h> +#include <ctype.h> +#include <cutils/properties.h> +#include <stdlib.h> +#include <termios.h> +#include <string.h> +#include <stdbool.h> +#include "bt_hci_bdroid.h" +#include "bt_vendor_qcom.h" +#include "hci_uart.h" +#include "hw_rome.h" + +#define BT_VERSION_FILEPATH "/data/misc/bluedroid/bt_fw_version.txt" + +#ifdef __cplusplus +} +#endif + +#define RESERVED(p) if(p) ALOGI( "%s: reserved param", __FUNCTION__); + +int read_vs_hci_event(int fd, unsigned char* buf, int size); + +/****************************************************************************** +** Variables +******************************************************************************/ +FILE *file; +unsigned char *phdr_buffer; +unsigned char *pdata_buffer = NULL; +patch_info rampatch_patch_info; +int chipset_ver = 0; +unsigned char gTlv_type; +unsigned char gTlv_dwndCfg; +static unsigned int wipower_flag = 0; +static unsigned int wipower_handoff_ready = 0; +char *rampatch_file_path = NULL; +char *nvm_file_path = NULL; +char *fw_su_info = NULL; +unsigned short fw_su_offset =0; +extern char enable_extldo; +unsigned char wait_vsc_evt = TRUE; +bool patch_dnld_pending = FALSE; +int dnld_fd = -1; + +/****************************************************************************** +** Extern variables +******************************************************************************/ + +/***************************************************************************** +** Functions +*****************************************************************************/ +int do_write(int fd, unsigned char *buf,int len) +{ + int ret = 0; + int write_offset = 0; + int write_len = len; + do { + ret = write(fd,buf+write_offset,write_len); + if (ret < 0) + { + ALOGE("%s, write failed ret = %d err = %s",__func__,ret,strerror(errno)); + return -1; + } else if (ret == 0) { + ALOGE("%s, write failed with ret 0 err = %s",__func__,strerror(errno)); + return 0; + } else { + if (ret < write_len) { + ALOGD("%s, Write pending,do write ret = %d err = %s",__func__,ret, + strerror(errno)); + write_len = write_len - ret; + write_offset = ret; + } else { + ALOGV("Write successful"); + break; + } + } + } while(1); + return len; +} + +int get_vs_hci_event(unsigned char *rsp) +{ + int err = 0; + unsigned char paramlen = 0; + unsigned char EMBEDDED_MODE_CHECK = 0x02; + FILE *btversionfile = 0; + unsigned int soc_id = 0; + unsigned int productid = 0; + unsigned short patchversion = 0; + char build_label[255]; + int build_lbl_len; + unsigned short buildversion = 0; + + if( (rsp[EVENTCODE_OFFSET] == VSEVENT_CODE) || (rsp[EVENTCODE_OFFSET] == EVT_CMD_COMPLETE)) + ALOGI("%s: Received HCI-Vendor Specific event", __FUNCTION__); + else { + ALOGI("%s: Failed to receive HCI-Vendor Specific event", __FUNCTION__); + err = -EIO; + goto failed; + } + + ALOGI("%s: Parameter Length: 0x%x", __FUNCTION__, paramlen = rsp[EVT_PLEN]); + ALOGI("%s: Command response: 0x%x", __FUNCTION__, rsp[CMD_RSP_OFFSET]); + ALOGI("%s: Response type : 0x%x", __FUNCTION__, rsp[RSP_TYPE_OFFSET]); + + /* Check the status of the operation */ + switch ( rsp[CMD_RSP_OFFSET] ) + { + case EDL_CMD_REQ_RES_EVT: + ALOGI("%s: Command Request Response", __FUNCTION__); + switch(rsp[RSP_TYPE_OFFSET]) + { + case EDL_PATCH_VER_RES_EVT: + case EDL_APP_VER_RES_EVT: + ALOGI("\t Current Product ID\t\t: 0x%08x", + productid = (unsigned int)(rsp[PATCH_PROD_ID_OFFSET +3] << 24 | + rsp[PATCH_PROD_ID_OFFSET+2] << 16 | + rsp[PATCH_PROD_ID_OFFSET+1] << 8 | + rsp[PATCH_PROD_ID_OFFSET] )); + + /* Patch Version indicates FW patch version */ + ALOGI("\t Current Patch Version\t\t: 0x%04x", + (patchversion = (unsigned short)(rsp[PATCH_PATCH_VER_OFFSET + 1] << 8 | + rsp[PATCH_PATCH_VER_OFFSET] ))); + + /* ROM Build Version indicates ROM build version like 1.0/1.1/2.0 */ + ALOGI("\t Current ROM Build Version\t: 0x%04x", buildversion = + (int)(rsp[PATCH_ROM_BUILD_VER_OFFSET + 1] << 8 | + rsp[PATCH_ROM_BUILD_VER_OFFSET] )); + + /* In case rome 1.0/1.1, there is no SOC ID version available */ + if (paramlen - 10) + { + ALOGI("\t Current SOC Version\t\t: 0x%08x", soc_id = + (unsigned int)(rsp[PATCH_SOC_VER_OFFSET +3] << 24 | + rsp[PATCH_SOC_VER_OFFSET+2] << 16 | + rsp[PATCH_SOC_VER_OFFSET+1] << 8 | + rsp[PATCH_SOC_VER_OFFSET] )); + } + + if (NULL != (btversionfile = fopen(BT_VERSION_FILEPATH, "wb"))) { + fprintf(btversionfile, "Bluetooth Controller Product ID : 0x%08x\n", productid); + fprintf(btversionfile, "Bluetooth Controller Patch Version : 0x%04x\n", patchversion); + fprintf(btversionfile, "Bluetooth Controller Build Version : 0x%04x\n", buildversion); + fprintf(btversionfile, "Bluetooth Controller SOC Version : 0x%08x\n", soc_id); + fclose(btversionfile); + }else { + ALOGI("Failed to dump SOC version info. Errno:%d", errno); + } + /* Rome Chipset Version can be decided by Patch version and SOC version, + Upper 2 bytes will be used for Patch version and Lower 2 bytes will be + used for SOC as combination for BT host driver */ + chipset_ver = (buildversion << 16) |(soc_id & 0x0000ffff); + + break; + case EDL_TVL_DNLD_RES_EVT: + case EDL_CMD_EXE_STATUS_EVT: + switch (err = rsp[CMD_STATUS_OFFSET]) + { + case HCI_CMD_SUCCESS: + ALOGI("%s: Download Packet successfully!", __FUNCTION__); + break; + case PATCH_LEN_ERROR: + ALOGI("%s: Invalid patch length argument passed for EDL PATCH " + "SET REQ cmd", __FUNCTION__); + break; + case PATCH_VER_ERROR: + ALOGI("%s: Invalid patch version argument passed for EDL PATCH " + "SET REQ cmd", __FUNCTION__); + break; + case PATCH_CRC_ERROR: + ALOGI("%s: CRC check of patch failed!!!", __FUNCTION__); + break; + case PATCH_NOT_FOUND: + ALOGI("%s: Invalid patch data!!!", __FUNCTION__); + break; + case TLV_TYPE_ERROR: + ALOGI("%s: TLV Type Error !!!", __FUNCTION__); + break; + default: + ALOGI("%s: Undefined error (0x%x)", __FUNCTION__, err); + break; + } + break; + case HCI_VS_GET_BUILD_VER_EVT: + build_lbl_len = rsp[5]; + memcpy (build_label, &rsp[6], build_lbl_len); + *(build_label+build_lbl_len) = '\0'; + + ALOGI("BT SoC FW SU Build info: %s, %d", build_label, build_lbl_len); + if (NULL != (btversionfile = fopen(BT_VERSION_FILEPATH, "a+b"))) { + fprintf(btversionfile, "Bluetooth Contoller SU Build info : %s\n", build_label); + fclose(btversionfile); + } else { + ALOGI("Failed to dump FW SU build info. Errno:%d", errno); + } + break; + } + break; + + case NVM_ACCESS_CODE: + ALOGI("%s: NVM Access Code!!!", __FUNCTION__); + err = HCI_CMD_SUCCESS; + break; + case EDL_SET_BAUDRATE_RSP_EVT: + /* Rome 1.1 has bug with the response, so it should ignore it. */ + if (rsp[BAUDRATE_RSP_STATUS_OFFSET] != BAUDRATE_CHANGE_SUCCESS) + { + ALOGE("%s: Set Baudrate request failed - 0x%x", __FUNCTION__, + rsp[CMD_STATUS_OFFSET]); + err = -1; + } + break; + case EDL_WIP_QUERY_CHARGING_STATUS_EVT: + /* Query charging command has below return values + 0 - in embedded mode not charging + 1 - in embedded mode and charging + 2 - hadofff completed and in normal mode + 3 - no wipower supported on mtp. so irrepective of charging + handoff command has to be sent if return values are 0 or 1. + These change include logic to enable generic BT turn on sequence.*/ + if (rsp[4] < EMBEDDED_MODE_CHECK) + { + ALOGI("%s: WiPower Charging in Embedded Mode!!!", __FUNCTION__); + wipower_handoff_ready = rsp[4]; + wipower_flag = 1; + } + break; + case EDL_WIP_START_HANDOFF_TO_HOST_EVENT: + /*TODO: rsp code 00 mean no charging + this is going to change in FW soon*/ + if (rsp[4] == NON_WIPOWER_MODE) + { + ALOGE("%s: WiPower Charging hand off not ready!!!", __FUNCTION__); + } + break; + case HCI_VS_GET_ADDON_FEATURES_EVENT: + if ((rsp[4] & ADDON_FEATURES_EVT_WIPOWER_MASK)) + { + ALOGD("%s: WiPower feature supported!!", __FUNCTION__); + property_set("persist.bluetooth.a4wp", "true"); + } + break; + case HCI_VS_STRAY_EVT: + /* WAR to handle stray Power Apply EVT during patch download */ + ALOGD("%s: Stray HCI VS EVENT", __FUNCTION__); + if (patch_dnld_pending && dnld_fd != -1) + { + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + memset(rsp, 0x00, HCI_MAX_EVENT_SIZE); + read_vs_hci_event(dnld_fd, rsp, HCI_MAX_EVENT_SIZE); + } + else + { + ALOGE("%s: Not a valid status!!!", __FUNCTION__); + err = -1; + } + break; + default: + ALOGE("%s: Not a valid status!!!", __FUNCTION__); + err = -1; + break; + } + +failed: + return err; +} + + +/* + * Read an VS HCI event from the given file descriptor. + */ +int read_vs_hci_event(int fd, unsigned char* buf, int size) +{ + int remain, r; + int count = 0, i; + + if (size <= 0) { + ALOGE("Invalid size arguement!"); + return -1; + } + + ALOGI("%s: Wait for HCI-Vendor Specfic Event from SOC", __FUNCTION__); + + /* The first byte identifies the packet type. For HCI event packets, it + * should be 0x04, so we read until we get to the 0x04. */ + /* It will keep reading until find 0x04 byte */ + while (1) { + r = read(fd, buf, 1); + if (r <= 0) + return -1; + if (buf[0] == 0x04) + break; + } + count++; + + /* The next two bytes are the event code and parameter total length. */ + while (count < 3) { + r = read(fd, buf + count, 3 - count); + if ((r <= 0) || (buf[1] != 0xFF )) { + ALOGE("It is not VS event !! ret: %d, EVT: %d", r, buf[1]); + return -1; + } + count += r; + } + + /* Now we read the parameters. */ + if (buf[2] < (size - 3)) + remain = buf[2]; + else + remain = size - 3; + + while ((count - 3) < remain) { + r = read(fd, buf + count, remain - (count - 3)); + if (r <= 0) + return -1; + count += r; + } + + /* Check if the set patch command is successful or not */ + if(get_vs_hci_event(buf) != HCI_CMD_SUCCESS) + return -1; + + return count; +} + +/* + * For Hand-Off related Wipower commands, Command complete arrives first and + * the followd with VS event + * + */ +int hci_send_wipower_vs_cmd(int fd, unsigned char *cmd, unsigned char *rsp, int size) +{ + int ret = 0; + int err = 0; + + /* Send the HCI command packet to UART for transmission */ + ret = do_write(fd, cmd, size); + if (ret != size) { + ALOGE("%s: WP Send failed with ret value: %d", __FUNCTION__, ret); + goto failed; + } + + /* Wait for command complete event */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to charging status cmd on Controller", __FUNCTION__); + goto failed; + } + + ALOGI("%s: WP Received HCI command complete Event from SOC", __FUNCTION__); +failed: + return ret; +} + + +int hci_send_vs_cmd(int fd, unsigned char *cmd, unsigned char *rsp, int size) +{ + int ret = 0; + + /* Send the HCI command packet to UART for transmission */ + ret = do_write(fd, cmd, size); + if (ret != size) { + ALOGE("%s: Send failed with ret value: %d", __FUNCTION__, ret); + goto failed; + } + + if (wait_vsc_evt) { + /* Check for response from the Controller */ + if (read_vs_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE) < 0) { + ret = -ETIMEDOUT; + ALOGI("%s: Failed to get HCI-VS Event from SOC", __FUNCTION__); + goto failed; + } + ALOGI("%s: Received HCI-Vendor Specific Event from SOC", __FUNCTION__); + } + +failed: + return ret; +} + +void frame_hci_cmd_pkt( + unsigned char *cmd, + int edl_cmd, unsigned int p_base_addr, + int segtNo, int size + ) +{ + int offset = 0; + hci_command_hdr *cmd_hdr; + + memset(cmd, 0x0, HCI_MAX_CMD_SIZE); + + cmd_hdr = (void *) (cmd + 1); + + cmd[0] = HCI_COMMAND_PKT; + cmd_hdr->opcode = cmd_opcode_pack(HCI_VENDOR_CMD_OGF, HCI_PATCH_CMD_OCF); + cmd_hdr->plen = size; + cmd[4] = edl_cmd; + + switch (edl_cmd) + { + case EDL_PATCH_SET_REQ_CMD: + /* Copy the patch header info as CMD params */ + memcpy(&cmd[5], phdr_buffer, PATCH_HDR_LEN); + ALOGD("%s: Sending EDL_PATCH_SET_REQ_CMD", __FUNCTION__); + ALOGD("HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x", + segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + break; + case EDL_PATCH_DLD_REQ_CMD: + offset = ((segtNo - 1) * MAX_DATA_PER_SEGMENT); + p_base_addr += offset; + cmd_hdr->plen = (size + 6); + cmd[5] = (size + 4); + cmd[6] = EXTRACT_BYTE(p_base_addr, 0); + cmd[7] = EXTRACT_BYTE(p_base_addr, 1); + cmd[8] = EXTRACT_BYTE(p_base_addr, 2); + cmd[9] = EXTRACT_BYTE(p_base_addr, 3); + memcpy(&cmd[10], (pdata_buffer + offset), size); + + ALOGD("%s: Sending EDL_PATCH_DLD_REQ_CMD: size: %d bytes", + __FUNCTION__, size); + ALOGD("HCI-CMD %d:\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t" + "0x%x\t0x%x\t0x%x\t\n", segtNo, cmd[0], cmd[1], cmd[2], + cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]); + break; + case EDL_PATCH_ATCH_REQ_CMD: + ALOGD("%s: Sending EDL_PATCH_ATTACH_REQ_CMD", __FUNCTION__); + ALOGD("HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x", + segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + break; + case EDL_PATCH_RST_REQ_CMD: + ALOGD("%s: Sending EDL_PATCH_RESET_REQ_CMD", __FUNCTION__); + ALOGD("HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x", + segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + break; + case EDL_PATCH_VER_REQ_CMD: + ALOGD("%s: Sending EDL_PATCH_VER_REQ_CMD", __FUNCTION__); + ALOGD("HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x", + segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + break; + case EDL_PATCH_TLV_REQ_CMD: + ALOGD("%s: Sending EDL_PATCH_TLV_REQ_CMD", __FUNCTION__); + /* Parameter Total Length */ + cmd[3] = size +2; + + /* TLV Segment Length */ + cmd[5] = size; + ALOGD("HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x \t0x%x", + segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]); + offset = (segtNo * MAX_SIZE_PER_TLV_SEGMENT); + memcpy(&cmd[6], (pdata_buffer + offset), size); + break; + case EDL_GET_BUILD_INFO: + ALOGD("%s: Sending EDL_GET_BUILD_INFO", __FUNCTION__); + ALOGD("HCI-CMD %d:\t0x%x \t0x%x \t0x%x \t0x%x \t0x%x", + segtNo, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + break; + default: + ALOGE("%s: Unknown EDL CMD !!!", __FUNCTION__); + } +} + +void rome_extract_patch_header_info(unsigned char *buf) +{ + int index; + + /* Extract patch id */ + for (index = 0; index < 4; index++) + rampatch_patch_info.patch_id |= + (LSH(buf[index + P_ID_OFFSET], (index * 8))); + + /* Extract (ROM and BUILD) version information */ + for (index = 0; index < 2; index++) + rampatch_patch_info.patch_ver.rom_version |= + (LSH(buf[index + P_ROME_VER_OFFSET], (index * 8))); + + for (index = 0; index < 2; index++) + rampatch_patch_info.patch_ver.build_version |= + (LSH(buf[index + P_BUILD_VER_OFFSET], (index * 8))); + + /* Extract patch base and entry addresses */ + for (index = 0; index < 4; index++) + rampatch_patch_info.patch_base_addr |= + (LSH(buf[index + P_BASE_ADDR_OFFSET], (index * 8))); + + /* Patch BASE & ENTRY addresses are same */ + rampatch_patch_info.patch_entry_addr = rampatch_patch_info.patch_base_addr; + + /* Extract total length of the patch payload */ + for (index = 0; index < 4; index++) + rampatch_patch_info.patch_length |= + (LSH(buf[index + P_LEN_OFFSET], (index * 8))); + + /* Extract the CRC checksum of the patch payload */ + for (index = 0; index < 4; index++) + rampatch_patch_info.patch_crc |= + (LSH(buf[index + P_CRC_OFFSET], (index * 8))); + + /* Extract patch control value */ + for (index = 0; index < 4; index++) + rampatch_patch_info.patch_ctrl |= + (LSH(buf[index + P_CONTROL_OFFSET], (index * 8))); + + ALOGI("PATCH_ID\t : 0x%x", rampatch_patch_info.patch_id); + ALOGI("ROM_VERSION\t : 0x%x", rampatch_patch_info.patch_ver.rom_version); + ALOGI("BUILD_VERSION\t : 0x%x", rampatch_patch_info.patch_ver.build_version); + ALOGI("PATCH_LENGTH\t : 0x%x", rampatch_patch_info.patch_length); + ALOGI("PATCH_CRC\t : 0x%x", rampatch_patch_info.patch_crc); + ALOGI("PATCH_CONTROL\t : 0x%x\n", rampatch_patch_info.patch_ctrl); + ALOGI("PATCH_BASE_ADDR\t : 0x%x\n", rampatch_patch_info.patch_base_addr); + +} + +int rome_edl_set_patch_request(int fd) +{ + int size, err; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + + /* Frame the HCI CMD to be sent to the Controller */ + frame_hci_cmd_pkt(cmd, EDL_PATCH_SET_REQ_CMD, 0, + -1, PATCH_HDR_LEN + 1); + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]); + + /* Send HCI Command packet to Controller */ + err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to set the patch info to the Controller!"); + goto error; + } + + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to set patch info on Controller", __FUNCTION__); + goto error; + } + ALOGI("%s: Successfully set patch info on the Controller", __FUNCTION__); +error: + return err; +} + +int rome_edl_patch_download_request(int fd) +{ + int no_of_patch_segment; + int index = 1, err = 0, size = 0; + unsigned int p_base_addr; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + + no_of_patch_segment = (rampatch_patch_info.patch_length / + MAX_DATA_PER_SEGMENT); + ALOGI("%s: %d patch segments to be d'loaded from patch base addr: 0x%x", + __FUNCTION__, no_of_patch_segment, + rampatch_patch_info.patch_base_addr); + + /* Initialize the patch base address from the one read from bin file */ + p_base_addr = rampatch_patch_info.patch_base_addr; + + /* + * Depending upon size of the patch payload, download the patches in + * segments with a max. size of 239 bytes + */ + for (index = 1; index <= no_of_patch_segment; index++) { + + ALOGI("%s: Downloading patch segment: %d", __FUNCTION__, index); + + /* Frame the HCI CMD PKT to be sent to Controller*/ + frame_hci_cmd_pkt(cmd, EDL_PATCH_DLD_REQ_CMD, p_base_addr, + index, MAX_DATA_PER_SEGMENT); + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]); + + /* Initialize the RSP packet everytime to 0 */ + memset(rsp, 0x0, HCI_MAX_EVENT_SIZE); + + /* Send HCI Command packet to Controller */ + err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to send the patch payload to the Controller!"); + goto error; + } + + /* Read Command Complete Event */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to downlaod patch segment: %d!", + __FUNCTION__, index); + goto error; + } + ALOGI("%s: Successfully downloaded patch segment: %d", + __FUNCTION__, index); + } + + /* Check if any pending patch data to be sent */ + size = (rampatch_patch_info.patch_length < MAX_DATA_PER_SEGMENT) ? + rampatch_patch_info.patch_length : + (rampatch_patch_info.patch_length % MAX_DATA_PER_SEGMENT); + + if (size) + { + /* Frame the HCI CMD PKT to be sent to Controller*/ + frame_hci_cmd_pkt(cmd, EDL_PATCH_DLD_REQ_CMD, p_base_addr, index, size); + + /* Initialize the RSP packet everytime to 0 */ + memset(rsp, 0x0, HCI_MAX_EVENT_SIZE); + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]); + + /* Send HCI Command packet to Controller */ + err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to send the patch payload to the Controller!"); + goto error; + } + + /* Read Command Complete Event */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to downlaod patch segment: %d!", + __FUNCTION__, index); + goto error; + } + + ALOGI("%s: Successfully downloaded patch segment: %d", + __FUNCTION__, index); + } + +error: + return err; +} + +static int rome_download_rampatch(int fd) +{ + int c, tmp, size, index, ret = -1; + + ALOGI("%s: ", __FUNCTION__); + + /* Get handle to the RAMPATCH binary file */ + ALOGI("%s: Getting handle to the RAMPATCH binary file from %s", __FUNCTION__, ROME_FW_PATH); + file = fopen(ROME_FW_PATH, "r"); + if (file == NULL) { + ALOGE("%s: Failed to get handle to the RAMPATCH bin file!", + __FUNCTION__); + return -ENFILE; + } + + /* Allocate memory for the patch headder info */ + ALOGI("%s: Allocating memory for the patch header", __FUNCTION__); + phdr_buffer = (unsigned char *) malloc(PATCH_HDR_LEN + 1); + if (phdr_buffer == NULL) { + ALOGE("%s: Failed to allocate memory for patch header", + __FUNCTION__); + goto phdr_alloc_failed; + } + for (index = 0; index < PATCH_HDR_LEN + 1; index++) + phdr_buffer[index] = 0x0; + + /* Read 28 bytes of patch header information */ + ALOGI("%s: Reading patch header info", __FUNCTION__); + index = 0; + do { + c = fgetc (file); + phdr_buffer[index++] = (unsigned char)c; + } while (index != PATCH_HDR_LEN); + + /* Save the patch header info into local structure */ + ALOGI("%s: Saving patch hdr. info", __FUNCTION__); + rome_extract_patch_header_info((unsigned char *)phdr_buffer); + + /* Set the patch header info onto the Controller */ + ret = rome_edl_set_patch_request(fd); + if (ret < 0) { + ALOGE("%s: Error setting the patchheader info!", __FUNCTION__); + goto pdata_alloc_failed; + } + + /* Allocate memory for the patch payload */ + ALOGI("%s: Allocating memory for patch payload", __FUNCTION__); + size = rampatch_patch_info.patch_length; + pdata_buffer = (unsigned char *) malloc(size+1); + if (pdata_buffer == NULL) { + ALOGE("%s: Failed to allocate memory for patch payload", + __FUNCTION__); + goto pdata_alloc_failed; + } + for (index = 0; index < size+1; index++) + pdata_buffer[index] = 0x0; + + /* Read the patch data from Rampatch binary image */ + ALOGI("%s: Reading patch payload from RAMPATCH file", __FUNCTION__); + index = 0; + do { + c = fgetc (file); + pdata_buffer[index++] = (unsigned char)c; + } while (c != EOF); + + /* Downloading patches in segments to controller */ + ret = rome_edl_patch_download_request(fd); + if (ret < 0) { + ALOGE("%s: Error downloading patch segments!", __FUNCTION__); + goto cleanup; + } +cleanup: + free(pdata_buffer); +pdata_alloc_failed: + free(phdr_buffer); +phdr_alloc_failed: + fclose(file); +error: + return ret; +} + +int rome_attach_rampatch(int fd) +{ + int size, err; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + + /* Frame the HCI CMD to be sent to the Controller */ + frame_hci_cmd_pkt(cmd, EDL_PATCH_ATCH_REQ_CMD, 0, + -1, EDL_PATCH_CMD_LEN); + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]); + + /* Send HCI Command packet to Controller */ + err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to attach the patch payload to the Controller!"); + goto error; + } + + /* Read Command Complete Event */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to attach the patch segment(s)", __FUNCTION__); + goto error; + } +error: + return err; +} + +int rome_rampatch_reset(int fd) +{ + int size, err = 0, flags; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + struct timespec tm = { 0, 100*1000*1000 }; /* 100 ms */ + + /* Frame the HCI CMD to be sent to the Controller */ + frame_hci_cmd_pkt(cmd, EDL_PATCH_RST_REQ_CMD, 0, + -1, EDL_PATCH_CMD_LEN); + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_PATCH_CMD_LEN); + + /* Send HCI Command packet to Controller */ + err = do_write(fd, cmd, size); + if (err != size) { + ALOGE("%s: Send failed with ret value: %d", __FUNCTION__, err); + goto error; + } + + /* + * Controller doesn't sends any response for the patch reset + * command. HOST has to wait for 100ms before proceeding. + */ + nanosleep(&tm, NULL); + +error: + return err; +} + +/* This function is called with q_lock held and q is non-NULL */ +int rome_get_tlv_file(char *file_path) +{ + FILE * pFile; + long fileSize; + int readSize, err = 0, total_segment, remain_size, nvm_length, nvm_index, i; + unsigned short nvm_tag_len; + tlv_patch_info *ptlv_header; + tlv_nvm_hdr *nvm_ptr; + unsigned char data_buf[PRINT_BUF_SIZE]={0,}; + unsigned char *nvm_byte_ptr; + + ALOGI("File Open (%s)", file_path); + pFile = fopen ( file_path , "r" ); + if (pFile==NULL) {; + ALOGE("%s File Open Fail", file_path); + return -1; + } + + /* Get File Size */ + fseek (pFile , 0 , SEEK_END); + fileSize = ftell (pFile); + rewind (pFile); + + pdata_buffer = (unsigned char*) malloc (sizeof(char)*fileSize); + if (pdata_buffer == NULL) { + ALOGE("Allocated Memory failed"); + fclose (pFile); + return -1; + } + + /* Copy file into allocated buffer */ + readSize = fread (pdata_buffer,1,fileSize,pFile); + + /* File Close */ + fclose (pFile); + + if (readSize != fileSize) { + ALOGE("Read file size(%d) not matched with actual file size (%ld bytes)",readSize,fileSize); + return -1; + } + + ptlv_header = (tlv_patch_info *) pdata_buffer; + + /* To handle different event between rampatch and NVM */ + gTlv_type = ptlv_header->tlv_type; + gTlv_dwndCfg = ptlv_header->tlv.patch.dwnd_cfg; + + if(ptlv_header->tlv_type == TLV_TYPE_PATCH){ + ALOGI("===================================================="); + ALOGI("TLV Type\t\t\t : 0x%x", ptlv_header->tlv_type); + ALOGI("Length\t\t\t : %d bytes", (ptlv_header->tlv_length1) | + (ptlv_header->tlv_length2 << 8) | + (ptlv_header->tlv_length3 << 16)); + ALOGI("Total Length\t\t\t : %d bytes", ptlv_header->tlv.patch.tlv_data_len); + ALOGI("Patch Data Length\t\t\t : %d bytes",ptlv_header->tlv.patch.tlv_patch_data_len); + ALOGI("Signing Format Version\t : 0x%x", ptlv_header->tlv.patch.sign_ver); + ALOGI("Signature Algorithm\t\t : 0x%x", ptlv_header->tlv.patch.sign_algorithm); + ALOGI("Event Handling\t\t\t : 0x%x", ptlv_header->tlv.patch.dwnd_cfg); + ALOGI("Reserved\t\t\t : 0x%x", ptlv_header->tlv.patch.reserved1); + ALOGI("Product ID\t\t\t : 0x%04x\n", ptlv_header->tlv.patch.prod_id); + ALOGI("Rom Build Version\t\t : 0x%04x\n", ptlv_header->tlv.patch.build_ver); + ALOGI("Patch Version\t\t : 0x%04x\n", ptlv_header->tlv.patch.patch_ver); + ALOGI("Reserved\t\t\t : 0x%x\n", ptlv_header->tlv.patch.reserved2); + ALOGI("Patch Entry Address\t\t : 0x%x\n", (ptlv_header->tlv.patch.patch_entry_addr)); + ALOGI("===================================================="); + + } else if(ptlv_header->tlv_type == TLV_TYPE_NVM) { + ALOGI("===================================================="); + ALOGI("TLV Type\t\t\t : 0x%x", ptlv_header->tlv_type); + ALOGI("Length\t\t\t : %d bytes", nvm_length = (ptlv_header->tlv_length1) | + (ptlv_header->tlv_length2 << 8) | + (ptlv_header->tlv_length3 << 16)); + + if(nvm_length <= 0) + return readSize; + + for(nvm_byte_ptr=(unsigned char *)(nvm_ptr = &(ptlv_header->tlv.nvm)), nvm_index=0; + nvm_index < nvm_length ; nvm_ptr = (tlv_nvm_hdr *) nvm_byte_ptr) + { + ALOGI("TAG ID\t\t\t : %d", nvm_ptr->tag_id); + ALOGI("TAG Length\t\t\t : %d", nvm_tag_len = nvm_ptr->tag_len); + ALOGI("TAG Pointer\t\t\t : %d", nvm_ptr->tag_ptr); + ALOGI("TAG Extended Flag\t\t : %d", nvm_ptr->tag_ex_flag); + + /* Increase nvm_index to NVM data */ + nvm_index+=sizeof(tlv_nvm_hdr); + nvm_byte_ptr+=sizeof(tlv_nvm_hdr); + + /* Write BD Address */ + if(nvm_ptr->tag_id == TAG_NUM_2){ + memcpy(nvm_byte_ptr, q->bdaddr, 6); + ALOGI("BD Address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x", + *nvm_byte_ptr, *(nvm_byte_ptr+1), *(nvm_byte_ptr+2), + *(nvm_byte_ptr+3), *(nvm_byte_ptr+4), *(nvm_byte_ptr+5)); + } + + for(i =0;(i<nvm_ptr->tag_len && (i*3 + 2) <PRINT_BUF_SIZE);i++) + snprintf((char *) data_buf, PRINT_BUF_SIZE, "%s%.02x ", (char *)data_buf, *(nvm_byte_ptr + i)); + + ALOGI("TAG Data\t\t\t : %s", data_buf); + + /* Clear buffer */ + memset(data_buf, 0x0, PRINT_BUF_SIZE); + + /* increased by tag_len */ + nvm_index+=nvm_ptr->tag_len; + nvm_byte_ptr +=nvm_ptr->tag_len; + } + + ALOGI("===================================================="); + + } else { + ALOGI("TLV Header type is unknown (%d) ", ptlv_header->tlv_type); + } + + return readSize; +} + +int rome_tlv_dnld_segment(int fd, int index, int seg_size, unsigned char wait_cc_evt) +{ + int size=0, err = -1; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + + ALOGI("%s: Downloading TLV Patch segment no.%d, size:%d", __FUNCTION__, index, seg_size); + + /* Frame the HCI CMD PKT to be sent to Controller*/ + frame_hci_cmd_pkt(cmd, EDL_PATCH_TLV_REQ_CMD, 0, index, seg_size); + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + cmd[PLEN]); + + /* Initialize the RSP packet everytime to 0 */ + memset(rsp, 0x0, HCI_MAX_EVENT_SIZE); + + /* Send HCI Command packet to Controller */ + err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to send the patch payload to the Controller! 0x%x", err); + return err; + } + + if(wait_cc_evt) { + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to downlaod patch segment: %d!", __FUNCTION__, index); + return err; + } + } + + ALOGI("%s: Successfully downloaded patch segment: %d", __FUNCTION__, index); + return err; +} + +int rome_tlv_dnld_req(int fd, int tlv_size) +{ + int total_segment, remain_size, i, err = -1; + unsigned char wait_cc_evt = TRUE; + + total_segment = tlv_size/MAX_SIZE_PER_TLV_SEGMENT; + remain_size = (tlv_size < MAX_SIZE_PER_TLV_SEGMENT)?\ + tlv_size: (tlv_size%MAX_SIZE_PER_TLV_SEGMENT); + + ALOGI("%s: TLV size: %d, Total Seg num: %d, remain size: %d", + __FUNCTION__,tlv_size, total_segment, remain_size); + + if (gTlv_type == TLV_TYPE_PATCH) { + /* Prior to Rome version 3.2(including inital few rampatch release of Rome 3.2), the event + * handling mechanism is ROME_SKIP_EVT_NONE. After few release of rampatch for Rome 3.2, the + * mechamism is changed to ROME_SKIP_EVT_VSE_CC. Rest of the mechanism is not used for now + */ + switch(gTlv_dwndCfg) + { + case ROME_SKIP_EVT_NONE: + wait_vsc_evt = TRUE; + wait_cc_evt = TRUE; + ALOGI("Event handling type: ROME_SKIP_EVT_NONE"); + break; + case ROME_SKIP_EVT_VSE_CC: + wait_vsc_evt = FALSE; + wait_cc_evt = FALSE; + ALOGI("Event handling type: ROME_SKIP_EVT_VSE_CC"); + break; + /* Not handled for now */ + case ROME_SKIP_EVT_VSE: + case ROME_SKIP_EVT_CC: + default: + ALOGE("Unsupported Event handling: %d", gTlv_dwndCfg); + break; + } + } else { + wait_vsc_evt = TRUE; + wait_cc_evt = TRUE; + } + + for(i=0;i<total_segment ;i++){ + if ((i+1) == total_segment) { + if ((chipset_ver >= ROME_VER_1_1) && (chipset_ver < ROME_VER_3_2) && (gTlv_type == TLV_TYPE_PATCH)) { + /* If the Rome version is from 1.1 to 3.1 + * 1. No CCE for the last command segment but all other segment + * 2. All the command segments get VSE including the last one + */ + wait_cc_evt = !remain_size ? FALSE: TRUE; + } else if ((chipset_ver >= ROME_VER_3_2) && (gTlv_type == TLV_TYPE_PATCH)) { + /* If the Rome version is 3.2 + * 1. None of the command segments receive CCE + * 2. No command segments receive VSE except the last one + * 3. If gTlv_dwndCfg is ROME_SKIP_EVT_NONE then the logic is + * same as Rome 2.1, 2.2, 3.0 + */ + if (gTlv_dwndCfg == ROME_SKIP_EVT_NONE) { + wait_cc_evt = !remain_size ? FALSE: TRUE; + } else if (gTlv_dwndCfg == ROME_SKIP_EVT_VSE_CC) { + wait_vsc_evt = !remain_size ? TRUE: FALSE; + } + } + } + + patch_dnld_pending = TRUE; + if((err = rome_tlv_dnld_segment(fd, i, MAX_SIZE_PER_TLV_SEGMENT, wait_cc_evt )) < 0) + goto error; + patch_dnld_pending = FALSE; + } + + if ((chipset_ver >= ROME_VER_1_1) && (chipset_ver < ROME_VER_3_2) && (gTlv_type == TLV_TYPE_PATCH)) { + /* If the Rome version is from 1.1 to 3.1 + * 1. No CCE for the last command segment but all other segment + * 2. All the command segments get VSE including the last one + */ + wait_cc_evt = remain_size ? FALSE: TRUE; + } else if ((chipset_ver >= ROME_VER_3_2) && (gTlv_type == TLV_TYPE_PATCH)) { + /* If the Rome version is 3.2 + * 1. None of the command segments receive CCE + * 2. No command segments receive VSE except the last one + * 3. If gTlv_dwndCfg is ROME_SKIP_EVT_NONE then the logic is + * same as Rome 2.1, 2.2, 3.0 + */ + if (gTlv_dwndCfg == ROME_SKIP_EVT_NONE) { + wait_cc_evt = remain_size ? FALSE: TRUE; + } else if (gTlv_dwndCfg == ROME_SKIP_EVT_VSE_CC) { + wait_vsc_evt = remain_size ? TRUE: FALSE; + } + } + patch_dnld_pending = TRUE; + if(remain_size) err =rome_tlv_dnld_segment(fd, i, remain_size, wait_cc_evt); + patch_dnld_pending = FALSE; +error: + if(patch_dnld_pending) patch_dnld_pending = FALSE; + return err; +} + +int rome_download_tlv_file(int fd) +{ + int tlv_size, err = -1; + + /* Rampatch TLV file Downloading */ + pdata_buffer = NULL; + if((tlv_size = rome_get_tlv_file(rampatch_file_path)) < 0) + goto error; + + if((err =rome_tlv_dnld_req(fd, tlv_size)) <0 ) + goto error; + + if (pdata_buffer != NULL){ + free (pdata_buffer); + pdata_buffer = NULL; + } +nvm_download: + if(!nvm_file_path) { + ALOGI("%s: nvm file is not available", __FUNCTION__); + err = 0; // in case of nvm/rampatch is not available + goto error; + } + + /* NVM TLV file Downloading */ + if((tlv_size = rome_get_tlv_file(nvm_file_path)) <= 0) + goto error; + + if((err =rome_tlv_dnld_req(fd, tlv_size)) <0 ) + goto error; + +error: + if (pdata_buffer != NULL) + free (pdata_buffer); + + return err; +} + +int rome_1_0_nvm_tag_dnld(int fd) +{ + int i, size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + +#if (NVM_VERSION >= ROME_1_0_100019) + unsigned char cmds[MAX_TAG_CMD][HCI_MAX_CMD_SIZE] = + { + /* Tag 2 */ /* BD Address */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 9, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 2, + /* Tag Len */ 6, + /* Tag Value */ 0x77,0x78,0x23,0x01,0x56,0x22 + }, + /* Tag 6 */ /* Bluetooth Support Features */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 11, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 6, + /* Tag Len */ 8, + /* Tag Value */ 0xFF,0xFE,0x8B,0xFE,0xD8,0x3F,0x5B,0x8B + }, + /* Tag 17 */ /* HCI Transport Layer Setting */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 11, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 17, + /* Tag Len */ 8, + /* Tag Value */ 0x82,0x01,0x0E,0x08,0x04,0x32,0x0A,0x00 + }, + /* Tag 35 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 58, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 35, + /* Tag Len */ 55, + /* Tag Value */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x58, 0x59, + 0x0E, 0x0E, 0x16, 0x16, 0x16, 0x1E, 0x26, 0x5F, 0x2F, 0x5F, + 0x0E, 0x0E, 0x16, 0x16, 0x16, 0x1E, 0x26, 0x5F, 0x2F, 0x5F, + 0x0C, 0x18, 0x14, 0x24, 0x40, 0x4C, 0x70, 0x80, 0x80, 0x80, + 0x0C, 0x18, 0x14, 0x24, 0x40, 0x4C, 0x70, 0x80, 0x80, 0x80, + 0x1B, 0x14, 0x01, 0x04, 0x48 + }, + /* Tag 36 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 15, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 36, + /* Tag Len */ 12, + /* Tag Value */ 0x0F,0x00,0x03,0x03,0x03,0x03,0x00,0x00,0x03,0x03,0x04,0x00 + }, + /* Tag 39 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 7, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 39, + /* Tag Len */ 4, + /* Tag Value */ 0x12,0x00,0x00,0x00 + }, + /* Tag 41 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 91, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 41, + /* Tag Len */ 88, + /* Tag Value */ 0x15, 0x00, 0x00, 0x00, 0xF6, 0x02, 0x00, 0x00, 0x76, 0x00, + 0x1E, 0x00, 0x29, 0x02, 0x1F, 0x00, 0x61, 0x00, 0x1A, 0x00, + 0x76, 0x00, 0x1E, 0x00, 0x7D, 0x00, 0x40, 0x00, 0x91, 0x00, + 0x06, 0x00, 0x92, 0x00, 0x03, 0x00, 0xA6, 0x01, 0x50, 0x00, + 0xAA, 0x01, 0x15, 0x00, 0xAB, 0x01, 0x0A, 0x00, 0xAC, 0x01, + 0x00, 0x00, 0xB0, 0x01, 0xC5, 0x00, 0xB3, 0x01, 0x03, 0x00, + 0xB4, 0x01, 0x13, 0x00, 0xB5, 0x01, 0x0C, 0x00, 0xC5, 0x01, + 0x0D, 0x00, 0xC6, 0x01, 0x10, 0x00, 0xCA, 0x01, 0x2B, 0x00, + 0xCB, 0x01, 0x5F, 0x00, 0xCC, 0x01, 0x48, 0x00 + }, + /* Tag 42 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 63, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 42, + /* Tag Len */ 60, + /* Tag Value */ 0xD7, 0xC0, 0x00, 0x00, 0x8F, 0x5C, 0x02, 0x00, 0x80, 0x47, + 0x60, 0x0C, 0x70, 0x4C, 0x00, 0x00, 0x00, 0x01, 0x1F, 0x01, + 0x42, 0x01, 0x69, 0x01, 0x95, 0x01, 0xC7, 0x01, 0xFE, 0x01, + 0x3D, 0x02, 0x83, 0x02, 0xD1, 0x02, 0x29, 0x03, 0x00, 0x0A, + 0x10, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x7F, 0x00, 0xFD, 0x00, + 0xF9, 0x01, 0xF1, 0x03, 0xDE, 0x07, 0x00, 0x00, 0x9A, 0x01 + }, + /* Tag 84 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 153, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 84, + /* Tag Len */ 150, + /* Tag Value */ 0x7C, 0x6A, 0x59, 0x47, 0x19, 0x36, 0x35, 0x25, 0x25, 0x28, + 0x2C, 0x2B, 0x2B, 0x28, 0x2C, 0x28, 0x29, 0x28, 0x29, 0x28, + 0x29, 0x29, 0x2C, 0x29, 0x2C, 0x29, 0x2C, 0x28, 0x29, 0x28, + 0x29, 0x28, 0x29, 0x2A, 0x00, 0x00, 0x2C, 0x2A, 0x2C, 0x18, + 0x98, 0x98, 0x98, 0x98, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1E, 0x13, 0x1E, 0x1E, 0x1E, 0x1E, 0x13, 0x13, 0x11, 0x13, + 0x1E, 0x1E, 0x13, 0x12, 0x12, 0x12, 0x11, 0x12, 0x1F, 0x12, + 0x12, 0x12, 0x10, 0x0C, 0x18, 0x0D, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x0C, 0x01, 0x01, 0x01, 0x01, 0x0D, 0x0D, + 0x0E, 0x0D, 0x01, 0x01, 0x0D, 0x0D, 0x0D, 0x0D, 0x0F, 0x0D, + 0x10, 0x0D, 0x0D, 0x0D, 0x0D, 0x10, 0x05, 0x10, 0x03, 0x00, + 0x7E, 0x7B, 0x7B, 0x72, 0x71, 0x50, 0x50, 0x50, 0x00, 0x40, + 0x60, 0x60, 0x30, 0x08, 0x02, 0x0F, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x16, 0x16, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x1E, 0x34, 0x2B, 0x1B, 0x23, 0x2B, 0x15, 0x0D + }, + /* Tag 85 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 119, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 85, + /* Tag Len */ 116, + /* Tag Value */ 0x03, 0x00, 0x38, 0x00, 0x45, 0x77, 0x00, 0xE8, 0x00, 0x59, + 0x01, 0xCA, 0x01, 0x3B, 0x02, 0xAC, 0x02, 0x1D, 0x03, 0x8E, + 0x03, 0x00, 0x89, 0x01, 0x0E, 0x02, 0x5C, 0x02, 0xD7, 0x02, + 0xF8, 0x08, 0x01, 0x00, 0x1F, 0x00, 0x0A, 0x02, 0x55, 0x02, + 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xD7, 0x00, 0x00, + 0x00, 0x1E, 0xDE, 0x00, 0x00, 0x00, 0x14, 0x0F, 0x0A, 0x0F, + 0x0A, 0x0C, 0x0C, 0x0C, 0x0C, 0x04, 0x04, 0x04, 0x0C, 0x0C, + 0x0C, 0x0C, 0x06, 0x06, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x0F, 0x14, 0x05, 0x47, 0xCF, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xAC, 0x7C, 0xFF, 0x40, 0x00, 0x00, 0x00, + 0x12, 0x04, 0x04, 0x01, 0x04, 0x03 + }, + {TAG_END} + }; +#elif (NVM_VERSION == ROME_1_0_6002) + unsigned char cmds[MAX_TAG_CMD][HCI_MAX_CMD_SIZE] = + { + /* Tag 2 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 9, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 2, + /* Tag Len */ 6, + /* Tag Value */ 0x77,0x78,0x23,0x01,0x56,0x22 /* BD Address */ + }, + /* Tag 6 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 11, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 6, + /* Tag Len */ 8, + /* Tag Value */ 0xFF,0xFE,0x8B,0xFE,0xD8,0x3F,0x5B,0x8B + }, + /* Tag 17 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 11, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 17, + /* Tag Len */ 8, + /* Tag Value */ 0x82,0x01,0x0E,0x08,0x04,0x32,0x0A,0x00 + }, + /* Tag 36 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 15, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 36, + /* Tag Len */ 12, + /* Tag Value */ 0x0F,0x00,0x03,0x03,0x03,0x03,0x00,0x00,0x03,0x03,0x04,0x00 + }, + + /* Tag 39 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 7, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 39, + /* Tag Len */ 4, + /* Tag Value */ 0x12,0x00,0x00,0x00 + }, + + /* Tag 41 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 199, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 41, + /* Tag Len */ 196, + /* Tag Value */ 0x30,0x00,0x00,0x00,0xD5,0x00,0x0E,0x00,0xD6,0x00,0x0E,0x00, + 0xD7,0x00,0x16,0x00,0xD8,0x00,0x16,0x00,0xD9,0x00,0x16,0x00, + 0xDA,0x00,0x1E,0x00,0xDB,0x00,0x26,0x00,0xDC,0x00,0x5F,0x00, + 0xDD,0x00,0x2F,0x00,0xDE,0x00,0x5F,0x00,0xE0,0x00,0x0E,0x00, + 0xE1,0x00,0x0E,0x00,0xE2,0x00,0x16,0x00,0xE3,0x00,0x16,0x00, + 0xE4,0x00,0x16,0x00,0xE5,0x00,0x1E,0x00,0xE6,0x00,0x26,0x00, + 0xE7,0x00,0x5F,0x00,0xE8,0x00,0x2F,0x00,0xE9,0x00,0x5F,0x00, + 0xEC,0x00,0x0C,0x00,0xED,0x00,0x08,0x00,0xEE,0x00,0x14,0x00, + 0xEF,0x00,0x24,0x00,0xF0,0x00,0x40,0x00,0xF1,0x00,0x4C,0x00, + 0xF2,0x00,0x70,0x00,0xF3,0x00,0x80,0x00,0xF4,0x00,0x80,0x00, + 0xF5,0x00,0x80,0x00,0xF8,0x00,0x0C,0x00,0xF9,0x00,0x18,0x00, + 0xFA,0x00,0x14,0x00,0xFB,0x00,0x24,0x00,0xFC,0x00,0x40,0x00, + 0xFD,0x00,0x4C,0x00,0xFE,0x00,0x70,0x00,0xFF,0x00,0x80,0x00, + 0x00,0x01,0x80,0x00,0x01,0x01,0x80,0x00,0x04,0x01,0x1B,0x00, + 0x05,0x01,0x14,0x00,0x06,0x01,0x01,0x00,0x07,0x01,0x04,0x00, + 0x08,0x01,0x00,0x00,0x09,0x01,0x00,0x00,0x0A,0x01,0x03,0x00, + 0x0B,0x01,0x03,0x00 + }, + + /* Tag 44 */ + { /* Packet Type */HCI_COMMAND_PKT, + /* Opcode */ 0x0b,0xfc, + /* Total Len */ 44, + /* NVM CMD */ NVM_ACCESS_SET, + /* Tag Num */ 44, + /* Tag Len */ 41, + /* Tag Value */ 0x6F,0x0A,0x00,0x00,0x00,0x00,0x00,0x50,0xFF,0x10,0x02,0x02, + 0x01,0x00,0x14,0x01,0x06,0x28,0xA0,0x62,0x03,0x64,0x01,0x01, + 0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0xA0,0xFF,0x10,0x02,0x01, + 0x00,0x14,0x01,0x02,0x03 + }, + {TAG_END} + }; +#endif + + ALOGI("%s: Start sending NVM Tags (ver: 0x%x)", __FUNCTION__, (unsigned int) NVM_VERSION); + + for (i=0; (i < MAX_TAG_CMD) && (cmds[i][0] != TAG_END); i++) + { + /* Write BD Address */ + if(cmds[i][TAG_NUM_OFFSET] == TAG_NUM_2){ + memcpy(&cmds[i][TAG_BDADDR_OFFSET], q->bdaddr, 6); + ALOGI("BD Address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + cmds[i][TAG_BDADDR_OFFSET ], cmds[i][TAG_BDADDR_OFFSET + 1], + cmds[i][TAG_BDADDR_OFFSET + 2], cmds[i][TAG_BDADDR_OFFSET + 3], + cmds[i][TAG_BDADDR_OFFSET + 4], cmds[i][TAG_BDADDR_OFFSET + 5]); + } + size = cmds[i][3] + HCI_COMMAND_HDR_SIZE + 1; + /* Send HCI Command packet to Controller */ + err = hci_send_vs_cmd(fd, (unsigned char *)&cmds[i][0], rsp, size); + if ( err != size) { + ALOGE("Failed to attach the patch payload to the Controller!"); + goto error; + } + + /* Read Command Complete Event - This is extra routine for ROME 1.0. From ROM 2.0, it should be removed. */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to get patch version(s)", __FUNCTION__); + goto error; + } + } + +error: + return err; +} + + + +int rome_patch_ver_req(int fd) +{ + int size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + + /* Frame the HCI CMD to be sent to the Controller */ + frame_hci_cmd_pkt(cmd, EDL_PATCH_VER_REQ_CMD, 0, + -1, EDL_PATCH_CMD_LEN); + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_PATCH_CMD_LEN); + + /* Send HCI Command packet to Controller */ + err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to attach the patch payload to the Controller!"); + goto error; + } + + /* Read Command Complete Event - This is extra routine for ROME 1.0. From ROM 2.0, it should be removed. */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to get patch version(s)", __FUNCTION__); + goto error; + } +error: + return err; + +} + +int rome_get_build_info_req(int fd) +{ + int size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + + /* Frame the HCI CMD to be sent to the Controller */ + frame_hci_cmd_pkt(cmd, EDL_GET_BUILD_INFO, 0, + -1, EDL_PATCH_CMD_LEN); + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_PATCH_CMD_LEN); + + /* Send HCI Command packet to Controller */ + err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to send get build info cmd to the SoC!"); + goto error; + } + + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to get build info", __FUNCTION__); + goto error; + } +error: + return err; + +} + + +int rome_set_baudrate_req(int fd) +{ + int size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + hci_command_hdr *cmd_hdr; + int flags; + + memset(cmd, 0x0, HCI_MAX_CMD_SIZE); + + cmd_hdr = (void *) (cmd + 1); + cmd[0] = HCI_COMMAND_PKT; + cmd_hdr->opcode = cmd_opcode_pack(HCI_VENDOR_CMD_OGF, EDL_SET_BAUDRATE_CMD_OCF); + cmd_hdr->plen = VSC_SET_BAUDRATE_REQ_LEN; + cmd[4] = BAUDRATE_3000000; + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + VSC_SET_BAUDRATE_REQ_LEN); + + /* Flow off during baudrate change */ + if ((err = userial_vendor_ioctl(USERIAL_OP_FLOW_OFF , &flags)) < 0) + { + ALOGE("%s: HW Flow-off error: 0x%x\n", __FUNCTION__, err); + goto error; + } + + /* Send the HCI command packet to UART for transmission */ + err = do_write(fd, cmd, size); + if (err != size) { + ALOGE("%s: Send failed with ret value: %d", __FUNCTION__, err); + goto error; + } + + /* Change Local UART baudrate to high speed UART */ + userial_vendor_set_baud(USERIAL_BAUD_3M); + + /* Flow on after changing local uart baudrate */ + if ((err = userial_vendor_ioctl(USERIAL_OP_FLOW_ON , &flags)) < 0) + { + ALOGE("%s: HW Flow-on error: 0x%x \n", __FUNCTION__, err); + return err; + } + + /* Check for response from the Controller */ + if ((err =read_vs_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE)) < 0) { + ALOGE("%s: Failed to get HCI-VS Event from SOC", __FUNCTION__); + goto error; + } + + ALOGI("%s: Received HCI-Vendor Specific Event from SOC", __FUNCTION__); + + /* Wait for command complete event */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to set patch info on Controller", __FUNCTION__); + goto error; + } + +error: + return err; + +} + + +int rome_hci_reset_req(int fd) +{ + int size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + hci_command_hdr *cmd_hdr; + int flags; + + ALOGI("%s: HCI RESET ", __FUNCTION__); + + memset(cmd, 0x0, HCI_MAX_CMD_SIZE); + + cmd_hdr = (void *) (cmd + 1); + cmd[0] = HCI_COMMAND_PKT; + cmd_hdr->opcode = HCI_RESET; + cmd_hdr->plen = 0; + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE); + + /* Flow off during baudrate change */ + if ((err = userial_vendor_ioctl(USERIAL_OP_FLOW_OFF , &flags)) < 0) + { + ALOGE("%s: HW Flow-off error: 0x%x\n", __FUNCTION__, err); + goto error; + } + + /* Send the HCI command packet to UART for transmission */ + ALOGI("%s: HCI CMD: 0x%x 0x%x 0x%x 0x%x\n", __FUNCTION__, cmd[0], cmd[1], cmd[2], cmd[3]); + err = do_write(fd, cmd, size); + if (err != size) { + ALOGE("%s: Send failed with ret value: %d", __FUNCTION__, err); + goto error; + } + + /* Change Local UART baudrate to high speed UART */ + userial_vendor_set_baud(USERIAL_BAUD_3M); + + /* Flow on after changing local uart baudrate */ + if ((err = userial_vendor_ioctl(USERIAL_OP_FLOW_ON , &flags)) < 0) + { + ALOGE("%s: HW Flow-on error: 0x%x \n", __FUNCTION__, err); + return err; + } + + /* Wait for command complete event */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to set patch info on Controller", __FUNCTION__); + goto error; + } + +error: + return err; + +} + + +int rome_hci_reset(int fd) +{ + int size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + hci_command_hdr *cmd_hdr; + int flags; + + ALOGI("%s: HCI RESET ", __FUNCTION__); + + memset(cmd, 0x0, HCI_MAX_CMD_SIZE); + + cmd_hdr = (void *) (cmd + 1); + cmd[0] = HCI_COMMAND_PKT; + cmd_hdr->opcode = HCI_RESET; + cmd_hdr->plen = 0; + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE); + err = do_write(fd, cmd, size); + if (err != size) { + ALOGE("%s: Send failed with ret value: %d", __FUNCTION__, err); + err = -1; + goto error; + } + + /* Wait for command complete event */ + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( err < 0) { + ALOGE("%s: Failed to set patch info on Controller", __FUNCTION__); + goto error; + } + +error: + return err; + +} + +int rome_wipower_current_charging_status_req(int fd) +{ + int size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + hci_command_hdr *cmd_hdr; + int flags; + + memset(cmd, 0x0, HCI_MAX_CMD_SIZE); + + cmd_hdr = (void *) (cmd + 1); + cmd[0] = HCI_COMMAND_PKT; + cmd_hdr->opcode = cmd_opcode_pack(HCI_VENDOR_CMD_OGF, EDL_WIPOWER_VS_CMD_OCF); + cmd_hdr->plen = EDL_WIP_QUERY_CHARGING_STATUS_LEN; + cmd[4] = EDL_WIP_QUERY_CHARGING_STATUS_CMD; + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_WIP_QUERY_CHARGING_STATUS_LEN); + + ALOGD("%s: Sending EDL_WIP_QUERY_CHARGING_STATUS_CMD", __FUNCTION__); + ALOGD("HCI-CMD: \t0x%x \t0x%x \t0x%x \t0x%x \t0x%x", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + + err = hci_send_wipower_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to send EDL_WIP_QUERY_CHARGING_STATUS_CMD command!"); + goto error; + } + + /* Check for response from the Controller */ + if (read_vs_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE) < 0) { + err = -ETIMEDOUT; + ALOGI("%s: WP Failed to get HCI-VS Event from SOC", __FUNCTION__); + goto error; + } + + /* Read Command Complete Event - This is extra routine for ROME 1.0. From ROM 2.0, it should be removed. */ + if (rsp[4] >= NON_WIPOWER_MODE) { + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if (err < 0) { + ALOGE("%s: Failed to get charging status", __FUNCTION__); + goto error; + } + } + +error: + return err; +} + +int addon_feature_req(int fd) +{ + int size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + hci_command_hdr *cmd_hdr; + int flags; + + memset(cmd, 0x0, HCI_MAX_CMD_SIZE); + + cmd_hdr = (void *) (cmd + 1); + cmd[0] = HCI_COMMAND_PKT; + cmd_hdr->opcode = cmd_opcode_pack(HCI_VENDOR_CMD_OGF, HCI_VS_GET_ADDON_FEATURES_SUPPORT); + cmd_hdr->plen = 0x00; + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE); + + ALOGD("%s: Sending HCI_VS_GET_ADDON_FEATURES_SUPPORT", __FUNCTION__); + ALOGD("HCI-CMD: \t0x%x \t0x%x \t0x%x \t0x%x", cmd[0], cmd[1], cmd[2], cmd[3]); + err = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to send HCI_VS_GET_ADDON_FEATURES_SUPPORT command!"); + goto error; + } + + err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if (err < 0) { + ALOGE("%s: Failed to get feature request", __FUNCTION__); + goto error; + } +error: + return err; +} + + +int check_embedded_mode(int fd) { + int err = 0; + + wipower_flag = 0; + /* Get current wipower charging status */ + if ((err = rome_wipower_current_charging_status_req(fd)) < 0) + { + ALOGI("%s: Wipower status req failed (0x%x)", __FUNCTION__, err); + } + usleep(500); + + ALOGE("%s: wipower_flag: %d", __FUNCTION__, wipower_flag); + + return wipower_flag; +} + +int rome_get_addon_feature_list(int fd) { + int err = 0; + + /* Get addon features that are supported by FW */ + if ((err = addon_feature_req(fd)) < 0) + { + ALOGE("%s: failed (0x%x)", __FUNCTION__, err); + } + return err; +} + +int rome_wipower_forward_handoff_req(int fd) +{ + int size, err = 0; + unsigned char cmd[HCI_MAX_CMD_SIZE]; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + hci_command_hdr *cmd_hdr; + int flags; + + memset(cmd, 0x0, HCI_MAX_CMD_SIZE); + + cmd_hdr = (void *) (cmd + 1); + cmd[0] = HCI_COMMAND_PKT; + cmd_hdr->opcode = cmd_opcode_pack(HCI_VENDOR_CMD_OGF, EDL_WIPOWER_VS_CMD_OCF); + cmd_hdr->plen = EDL_WIP_START_HANDOFF_TO_HOST_LEN; + cmd[4] = EDL_WIP_START_HANDOFF_TO_HOST_CMD; + + /* Total length of the packet to be sent to the Controller */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_WIP_START_HANDOFF_TO_HOST_LEN); + + ALOGD("%s: Sending EDL_WIP_START_HANDOFF_TO_HOST_CMD", __FUNCTION__); + ALOGD("HCI-CMD: \t0x%x \t0x%x \t0x%x \t0x%x \t0x%x", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); + err = hci_send_wipower_vs_cmd(fd, (unsigned char *)cmd, rsp, size); + if ( err != size) { + ALOGE("Failed to send EDL_WIP_START_HANDOFF_TO_HOST_CMD command!"); + goto error; + } + + /* Check for response from the Controller */ + if (read_vs_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE) < 0) { + err = -ETIMEDOUT; + ALOGI("%s: WP Failed to get HCI-VS Event from SOC", __FUNCTION__); + goto error; + } + +error: + return err; +} + + +void enable_controller_log (int fd, unsigned char wait_for_evt) +{ + int ret = 0; + /* VS command to enable controller logging to the HOST. By default it is disabled */ + unsigned char cmd[6] = {0x01, 0x17, 0xFC, 0x02, 0x00, 0x00}; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + char value[PROPERTY_VALUE_MAX] = {'\0'}; + + property_get("persist.service.bdroid.soclog", value, "false"); + + // value at cmd[5]: 1 - to enable, 0 - to disable + ret = (strcmp(value, "true") == 0) ? cmd[5] = 0x01: 0; + ALOGI("%s: %d", __func__, ret); + /* Ignore vsc evt if wait_for_evt is true */ + if (wait_for_evt) wait_vsc_evt = FALSE; + + ret = hci_send_vs_cmd(fd, (unsigned char *)cmd, rsp, 6); + if (ret != 6) { + ALOGE("%s: command failed", __func__); + } + /*Ignore hci_event if wait_for_evt is true*/ + if (wait_for_evt) + goto end; + ret = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if (ret < 0) { + ALOGE("%s: Failed to get CC for enable SoC log", __FUNCTION__); + } +end: + wait_vsc_evt = TRUE; + return; +} + + +/* This function is called with q_lock held and q is non-NULL */ +static int disable_internal_ldo(int fd) +{ + int ret = 0; + if (q->enable_extldo) { + unsigned char cmd[5] = {0x01, 0x0C, 0xFC, 0x01, 0x32}; + unsigned char rsp[HCI_MAX_EVENT_SIZE]; + + ALOGI(" %s ", __FUNCTION__); + ret = do_write(fd, cmd, 5); + if (ret != 5) { + ALOGE("%s: Send failed with ret value: %d", __FUNCTION__, ret); + ret = -1; + } else { + /* Wait for command complete event */ + ret = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE); + if ( ret < 0) { + ALOGE("%s: Failed to get response from controller", __FUNCTION__); + } + } + } + return ret; +} + +int rome_soc_init(int fd, char *bdaddr) +{ + int err = -1, size = 0; + dnld_fd = fd; + ALOGI(" %s ", __FUNCTION__); + RESERVED(bdaddr); + + /* If wipower charging is going on in embedded mode then start hand off req */ + if (wipower_flag == WIPOWER_IN_EMBEDDED_MODE && wipower_handoff_ready != NON_WIPOWER_MODE) + { + wipower_flag = 0; + wipower_handoff_ready = 0; + if ((err = rome_wipower_forward_handoff_req(fd)) < 0) + { + ALOGI("%s: Wipower handoff failed (0x%x)", __FUNCTION__, err); + } + } + + /* Get Rome version information */ + if((err = rome_patch_ver_req(fd)) <0){ + ALOGI("%s: Fail to get Rome Version (0x%x)", __FUNCTION__, err); + goto error; + } + + ALOGI("%s: Chipset Version (0x%08x)", __FUNCTION__, chipset_ver); + + switch (chipset_ver){ + case ROME_VER_1_0: + { + /* Set and Download the RAMPATCH */ + ALOGI("%s: Setting Patch Header & Downloading Patches", __FUNCTION__); + err = rome_download_rampatch(fd); + if (err < 0) { + ALOGE("%s: DOWNLOAD RAMPATCH failed!", __FUNCTION__); + goto error; + } + ALOGI("%s: DOWNLOAD RAMPTACH complete", __FUNCTION__); + + /* Attach the RAMPATCH */ + ALOGI("%s: Attaching the patches", __FUNCTION__); + err = rome_attach_rampatch(fd); + if (err < 0) { + ALOGE("%s: ATTACH RAMPATCH failed!", __FUNCTION__); + goto error; + } + ALOGI("%s: ATTACH RAMPTACH complete", __FUNCTION__); + + /* Send Reset */ + size = (HCI_CMD_IND + HCI_COMMAND_HDR_SIZE + EDL_PATCH_CMD_LEN); + err = rome_rampatch_reset(fd); + if ( err < 0 ) { + ALOGE("Failed to RESET after RAMPATCH upgrade!"); + goto error; + } + + /* NVM download */ + ALOGI("%s: Downloading NVM", __FUNCTION__); + err = rome_1_0_nvm_tag_dnld(fd); + if ( err <0 ) { + ALOGE("Downloading NVM Failed !!"); + goto error; + } + + /* Change baud rate 115.2 kbps to 3Mbps*/ + err = rome_hci_reset_req(fd); + if (err < 0) { + ALOGE("HCI Reset Failed !!"); + goto error; + } + + ALOGI("HCI Reset is done\n"); + } + break; + case ROME_VER_1_1: + rampatch_file_path = ROME_RAMPATCH_TLV_PATH; + nvm_file_path = ROME_NVM_TLV_PATH; + goto download; + case ROME_VER_1_3: + rampatch_file_path = ROME_RAMPATCH_TLV_1_0_3_PATH; + nvm_file_path = ROME_NVM_TLV_1_0_3_PATH; + goto download; + case ROME_VER_2_1: + rampatch_file_path = ROME_RAMPATCH_TLV_2_0_1_PATH; + nvm_file_path = ROME_NVM_TLV_2_0_1_PATH; + goto download; + case ROME_VER_3_0: + rampatch_file_path = ROME_RAMPATCH_TLV_3_0_0_PATH; + nvm_file_path = ROME_NVM_TLV_3_0_0_PATH; + fw_su_info = ROME_3_1_FW_SU; + fw_su_offset = ROME_3_1_FW_SW_OFFSET; + goto download; + case ROME_VER_3_2: + rampatch_file_path = ROME_RAMPATCH_TLV_3_0_2_PATH; + nvm_file_path = ROME_NVM_TLV_3_0_2_PATH; + fw_su_info = ROME_3_2_FW_SU; + fw_su_offset = ROME_3_2_FW_SW_OFFSET; + +download: + /* Change baud rate 115.2 kbps to 3Mbps*/ + err = rome_set_baudrate_req(fd); + if (err < 0) { + ALOGE("%s: Baud rate change failed!", __FUNCTION__); + goto error; + } + ALOGI("%s: Baud rate changed successfully ", __FUNCTION__); + /* Donwload TLV files (rampatch, NVM) */ + err = rome_download_tlv_file(fd); + if (err < 0) { + ALOGE("%s: Download TLV file failed!", __FUNCTION__); + goto error; + } + ALOGI("%s: Download TLV file successfully ", __FUNCTION__); + + /* Get SU FM label information */ + if((err = rome_get_build_info_req(fd)) <0){ + ALOGI("%s: Fail to get Rome FW SU Build info (0x%x)", __FUNCTION__, err); + //Ignore the failure of ROME FW SU label information + err = 0; + } + + /* Disable internal LDO to use external LDO instead*/ + err = disable_internal_ldo(fd); + + /* Send HCI Reset */ + err = rome_hci_reset(fd); + if ( err <0 ) { + ALOGE("HCI Reset Failed !!"); + goto error; + } + + ALOGI("HCI Reset is done\n"); + + break; + default: + ALOGI("%s: Detected unknown SoC version: 0x%08x", __FUNCTION__, chipset_ver); + err = -1; + break; + } + +error: + dnld_fd = -1; + return err; +} diff --git a/sdm845/libbt-vendor/vnd_buildcfg.mk b/sdm845/libbt-vendor/vnd_buildcfg.mk new file mode 100644 index 0000000..d18e121 --- /dev/null +++ b/sdm845/libbt-vendor/vnd_buildcfg.mk @@ -0,0 +1,32 @@ +# +# Copyright 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +intermediates := $(local-intermediates-dir) + +SRC := $(call my-dir)/include/$(addprefix vnd_, $(addsuffix .txt,$(basename $(TARGET_DEVICE)))) +ifeq (,$(wildcard $(SRC))) +# configuration file does not exist. Use default one +SRC := $(call my-dir)/include/vnd_generic.txt +endif +GEN := $(intermediates)/vnd_buildcfg.h +TOOL := $(TOP_DIR)external/bluetooth/bluedroid/tools/gen-buildcfg.sh + +$(GEN): PRIVATE_PATH := $(call my-dir) +$(GEN): PRIVATE_CUSTOM_TOOL = $(TOOL) $< $@ +$(GEN): $(SRC) $(TOOL) + $(transform-generated-source) + +LOCAL_GENERATED_SOURCES += $(GEN) |