commit e5f9bb65ac83e35f272ae8f14d1dc8c456e75ac1 Author: leeboby Date: Fri Oct 30 09:50:39 2020 +0800 First Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..9eb4187363b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# +# NOTE! Don't add files that are generated in specific +# subdirectories here. Add them in the ".gitignore" file +# in that subdirectory instead. +# +# NOTE! Please use 'git ls-files -i --exclude-standard' +# command after changing this file, to see if there are +# any tracked files which get ignored after the change. +# +# Normal rules +# + +*.bak +*.tar.gz + +.tmp +kernel +output +u-boot +toolchains +userpatches + +!external/config/kernel + +external/cache/.gpg +external/cache/hash +external/cache/rootfs +external/cache/sources/extra +external/cache/sources/sunxi-tools +external/cache/sources/orangepi-firmware +external/cache/sources/orangepi-firmware-git +external/cache/sources/arm-trusted-firmware-sunxi-mainline diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000000..d7f105139782 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 000000000000..c60a82700333 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# orangepi-build + +Orangepi build is based on Armbian build, thanks to all armbian contributors. diff --git a/build.sh b/build.sh new file mode 100755 index 000000000000..65e723d43baa --- /dev/null +++ b/build.sh @@ -0,0 +1,225 @@ +#!/bin/bash +# +# Copyright (c) 2015 Igor Pecovnik, igor.pecovnik@gma**.com +# +# This file is licensed under the terms of the GNU General Public +# License version 2. This program is licensed "as is" without any +# warranty of any kind, whether express or implied. + +# DO NOT EDIT THIS FILE +# use configuration files like config-default.conf to set the build configuration +# check Orange Pi documentation for more info + +SRC="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" + +# check for whitespace in $SRC and exit for safety reasons +grep -q "[[:space:]]" <<<"${SRC}" && { echo "\"${SRC}\" contains whitespace. Not supported. Aborting." >&2 ; exit 1 ; } + +cd "${SRC}" || exit + +if [[ -f "${SRC}"/scripts/general.sh ]]; then + # shellcheck source=scripts/general.sh + source "${SRC}"/scripts/general.sh +else + echo "Error: missing build directory structure" + echo "Please clone the full repository by https://github.com/orangepi-xunlong/orangepi-build" + exit 255 +fi + +if [[ $EUID == 0 ]] || [[ "$1" == vagrant ]]; then + : +elif [[ "$1" == docker || "$1" == dockerpurge || "$1" == docker-shell ]] && grep -q `whoami` <(getent group docker); then + : +else + display_alert "This script requires root privileges, trying to use sudo" "" "wrn" + sudo "$SRC/build.sh" "$@" + exit $? +fi + +update_src() { + cd "${SRC}" || exit + if [[ ! -f $SRC/.ignore_changes ]]; then + echo -e "[\e[0;32m o.k. \x1B[0m] This script will try to update" + git pull + CHANGED_FILES=$(git diff --name-only) + if [[ -n $CHANGED_FILES ]]; then + echo -e "[\e[0;35m warn \x1B[0m] Can't update since you made changes to: \e[0;32m\n${CHANGED_FILES}\x1B[0m" + while true; do + echo -e "Press \e[0;33m\x1B[0m or \e[0;33mexit\x1B[0m to abort compilation, \e[0;33m\x1B[0m to ignore and continue, \e[0;33mdiff\x1B[0m to display changes" + read -r + if [[ "$REPLY" == "diff" ]]; then + git diff + elif [[ "$REPLY" == "exit" ]]; then + exit 1 + elif [[ "$REPLY" == "" ]]; then + break + else + echo "Unknown command!" + fi + done + else + git checkout "${LIB_TAG:-master}" + fi + fi +} + +#TMPFILE=`mktemp` && chmod 644 $TMPFILE +#echo SRC=$SRC > $TMPFILE +#echo LIB_TAG=$LIB_TAG >> $TMPFILE +#declare -f update_src >> $TMPFILE +#echo update_src >> $TMPFILE + +#do not update/checkout git with root privileges to messup files onwership. +#due to in docker/VM, we can't su to a normal user, so do not update/checkout git. +#if [[ `systemd-detect-virt` == 'none' ]]; then +# if [[ $EUID == 0 ]]; then +# su `stat --format=%U $SRC/.git` -c "bash $TMPFILE" +# else +# bash $TMPFILE +# fi +#fi + +#rm $TMPFILE + +# Check for required packages for compiling +if [[ -z "$(which whiptail)" ]]; then + sudo apt-get update + sudo apt-get install -y whiptail +fi +if [[ -z "$(which getfacl)" ]]; then + sudo apt-get update + sudo apt-get install -y acl +fi + +# Check for Vagrant +if [[ "$1" == vagrant && -z "$(which vagrant)" ]]; then + display_alert "Vagrant not installed." "Installing" + sudo apt-get update + sudo apt-get install -y vagrant virtualbox +fi + +if [[ "$1" == dockerpurge && -f /etc/debian_version ]]; then + display_alert "Purging Orange Pi Docker containers" "" "wrn" + docker container ls -a | grep orangepi | awk '{print $1}' | xargs docker container rm &> /dev/null + docker image ls | grep orangepi | awk '{print $3}' | xargs docker image rm &> /dev/null + shift + set -- "docker" "$@" +fi + +if [[ "$1" == docker-shell ]]; then + shift + SHELL_ONLY=yes + set -- "docker" "$@" +fi + +# Install Docker if not there but wanted. We cover only Debian based distro install. Else, manual Docker install is needed +if [[ "$1" == docker && -f /etc/debian_version && -z "$(which docker)" ]]; then + + # add exception for Ubuntu Focal until Docker provides dedicated binary + codename=$(lsb_release -sc) + codeid=$(lsb_release -is | awk '{print tolower($0)}') + [[ $codeid == linuxmint && $codename == debbie ]] && codename="buster" && codeid="debian" + [[ $codename == focal ]] && codename="bionic" + + display_alert "Docker not installed." "Installing" "Info" + echo "deb [arch=amd64] https://download.docker.com/linux/${codeid} ${codename} edge" > /etc/apt/sources.list.d/docker.list + + # minimal set of utilities that are needed for prep + packages=("curl" "gnupg" "apt-transport-https") + for i in "${packages[@]}" + do + [[ ! $(which $i) ]] && install_packages+=$i" " + done + [[ -z $install_packages ]] && apt-get update;apt-get install -y -qq --no-install-recommends $install_packages + + curl -fsSL "https://download.docker.com/linux/${codeid}/gpg" | apt-key add -qq - > /dev/null 2>&1 + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install -y -qq --no-install-recommends docker-ce + display_alert "Add yourself to docker group to avoid root privileges" "" "wrn" + "$SRC/build.sh" "$@" + exit $? +fi + +EXTER="${SRC}/external" + +# Create userpatches directory if not exists +mkdir -p $SRC/userpatches + +# Create example configs if none found in userpatches +if ! ls ${SRC}/userpatches/{config-example.conf,config-docker.conf,config-vagrant.conf} 1> /dev/null 2>&1; then + + display_alert "Create example config file using template" "config-default.conf" "info" + + # Create example config + if [[ ! -f "${SRC}"/userpatches/config-example.conf ]]; then + cp "${EXTER}"/config/templates/config-example.conf "${SRC}"/userpatches/config-example.conf || exit 1 + ln -fs config-example.conf "${SRC}"/userpatches/config-default.conf || exit 1 + fi + + # Create Docker config + if [[ ! -f "${SRC}"/userpatches/config-docker.conf ]]; then + cp "${EXTER}"/config/templates/config-docker.conf "${SRC}"/userpatches/config-docker.conf || exit 1 + fi + + # Create Docker file + if [[ ! -f "${SRC}"/userpatches/Dockerfile ]]; then + cp "${EXTER}"/config/templates/Dockerfile "${SRC}"/userpatches/Dockerfile || exit 1 + fi + + # Create Vagrant config + if [[ ! -f "${SRC}"/userpatches/config-vagrant.conf ]]; then + cp "${EXTER}"/config/templates/config-vagrant.conf "${SRC}"/userpatches/config-vagrant.conf || exit 1 + fi + + # Create Vagrant file + if [[ ! -f "${SRC}"/userpatches/Vagrantfile ]]; then + cp "${EXTER}"/config/templates/Vagrantfile "${SRC}"/userpatches/Vagrantfile || exit 1 + fi + +fi + +if [[ -z "$CONFIG" && -n "$1" && -f "${SRC}/userpatches/config-$1.conf" ]]; then + CONFIG="userpatches/config-$1.conf" + shift +fi + +# usind default if custom not found +if [[ -z "$CONFIG" && -f "${SRC}/userpatches/config-default.conf" ]]; then + CONFIG="$SRC/userpatches/config-default.conf" +fi + +# source build configuration file +CONFIG_FILE="$(realpath "$CONFIG")" + +if [[ ! -f $CONFIG_FILE ]]; then + display_alert "Config file does not exist" "$CONFIG" "error" + exit 254 +fi + +CONFIG_PATH=$(dirname "$CONFIG_FILE") + +display_alert "Using config file" "$CONFIG_FILE" "info" +pushd $CONFIG_PATH > /dev/null +# shellcheck source=/dev/null +source "$CONFIG_FILE" +popd > /dev/null + +[[ -z "${USERPATCHES_PATH}" ]] && USERPATCHES_PATH="$CONFIG_PATH" + +# Script parameters handling +while [[ $1 == *=* ]]; do + parameter=${1%%=*} + value=${1##*=} + shift + display_alert "Command line: setting $parameter to" "${value:-(empty)}" "info" + eval "$parameter=\"$value\"" +done + +if [[ $BUILD_ALL == yes || $BUILD_ALL == demo ]]; then + # shellcheck source=scripts/build-all-ng.sh + source "${SRC}"/scripts/build-all-ng.sh +else + # shellcheck source=scripts/main.sh + source "${SRC}"/scripts/main.sh +fi diff --git a/external/cache/debs/aptly/aptly_1.4.0+44+g24a0271_amd64.deb b/external/cache/debs/aptly/aptly_1.4.0+44+g24a0271_amd64.deb new file mode 100644 index 000000000000..09d3660a2367 Binary files /dev/null and b/external/cache/debs/aptly/aptly_1.4.0+44+g24a0271_amd64.deb differ diff --git a/external/cache/debs/extra/bionic-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/bionic-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..a70d139a4fc0 Binary files /dev/null and b/external/cache/debs/extra/bionic-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/bionic-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/bionic-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..865bc7dde2a7 Binary files /dev/null and b/external/cache/debs/extra/bionic-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/bionic-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/bionic-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..1aaeebb7d961 Binary files /dev/null and b/external/cache/debs/extra/bionic-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/bionic-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/bionic-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..8013ea5583ce Binary files /dev/null and b/external/cache/debs/extra/bionic-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/bionic-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/bionic-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..47dc2427c3b3 Binary files /dev/null and b/external/cache/debs/extra/bionic-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/bionic-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/bionic-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..612ba7de7e76 Binary files /dev/null and b/external/cache/debs/extra/bionic-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/bionic-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/bionic-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..2a9b5e794ace Binary files /dev/null and b/external/cache/debs/extra/bionic-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/bionic-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/bionic-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..7f73e7d1bcaf Binary files /dev/null and b/external/cache/debs/extra/bionic-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/bionic-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/bionic-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..220ab25ac6f4 Binary files /dev/null and b/external/cache/debs/extra/bionic-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/buster-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/buster-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..98e76b37fe08 Binary files /dev/null and b/external/cache/debs/extra/buster-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/buster-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/buster-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..c887b29c3a6b Binary files /dev/null and b/external/cache/debs/extra/buster-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/buster-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/buster-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..1c92f7b8ee44 Binary files /dev/null and b/external/cache/debs/extra/buster-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/buster-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/buster-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..94c693b2cdbb Binary files /dev/null and b/external/cache/debs/extra/buster-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/buster-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/buster-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..c996ecda5d0f Binary files /dev/null and b/external/cache/debs/extra/buster-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/buster-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/buster-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..11ea2a767370 Binary files /dev/null and b/external/cache/debs/extra/buster-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/buster-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/buster-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..ed9e5730eafb Binary files /dev/null and b/external/cache/debs/extra/buster-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/focal-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..813c3c12e19a Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/focal-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..388932a91a0d Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/focal-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..09fe136082e2 Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/focal-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..8e1821abb2b9 Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-desktop/libump-dev_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-desktop/libump-dev_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..cbe8a2bd04d1 Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/libump-dev_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-desktop/libump_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-desktop/libump_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..cbe1db464c82 Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/libump_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..2f8d6d73ec75 Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/focal-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..637a6ed1634d Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/focal-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..ddf1bc13b375 Binary files /dev/null and b/external/cache/debs/extra/focal-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/focal-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..887f3bd045e5 Binary files /dev/null and b/external/cache/debs/extra/focal-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/focal-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..e22c28a042aa Binary files /dev/null and b/external/cache/debs/extra/focal-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/focal-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..6a30235beafe Binary files /dev/null and b/external/cache/debs/extra/focal-utils/htop_2.2.0-5~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/focal-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..42fbae9d4564 Binary files /dev/null and b/external/cache/debs/extra/focal-utils/htop_2.2.0-5~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/focal-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..293a1eccf024 Binary files /dev/null and b/external/cache/debs/extra/focal-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/focal-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..663ee6d6d5af Binary files /dev/null and b/external/cache/debs/extra/focal-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/focal-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/focal-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..377b8cb9172b Binary files /dev/null and b/external/cache/debs/extra/focal-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/focal-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/focal-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..138b44248b31 Binary files /dev/null and b/external/cache/debs/extra/focal-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/stretch-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/stretch-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..d3f046776b4b Binary files /dev/null and b/external/cache/debs/extra/stretch-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/stretch-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/stretch-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..ea387b8ce084 Binary files /dev/null and b/external/cache/debs/extra/stretch-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/stretch-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/stretch-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..fce073a766bf Binary files /dev/null and b/external/cache/debs/extra/stretch-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/stretch-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/stretch-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..19b45471953a Binary files /dev/null and b/external/cache/debs/extra/stretch-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/stretch-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/stretch-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..eab57cc2994f Binary files /dev/null and b/external/cache/debs/extra/stretch-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/stretch-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/stretch-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..c88912cf02fc Binary files /dev/null and b/external/cache/debs/extra/stretch-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/stretch-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/stretch-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..3331e9a994e9 Binary files /dev/null and b/external/cache/debs/extra/stretch-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/xenial-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..fbeb17882bf4 Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..1ed0635dd090 Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libcedrus1-dev_1.0.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/xenial-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..b995891ec6d9 Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..f3be4aa8ac38 Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libcedrus1_1.0.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libglshim_0.9.2~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/libglshim_0.9.2~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..19ca75c0e8aa Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libglshim_0.9.2~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libmali-sunxi-dev_1.0-1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/libmali-sunxi-dev_1.0-1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..6c7849eaea5d Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libmali-sunxi-dev_1.0-1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libmali-sunxi-r3p0_1.0-1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/libmali-sunxi-r3p0_1.0-1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..a4ad5da61c77 Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libmali-sunxi-r3p0_1.0-1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libump-dev_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/libump-dev_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..73b5bf131a04 Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libump-dev_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/libump_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/libump_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..3dbf89edae7e Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/libump_3.0-0sunxi1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..201cf76b3876 Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-armsoc-sun4i_1.4.1~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..b9e08bf5a74e Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..5deea4d7ea84 Binary files /dev/null and b/external/cache/debs/extra/xenial-desktop/xserver-xorg-video-fbturbo_0.4.4~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/xenial-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..864f5f6754cd Binary files /dev/null and b/external/cache/debs/extra/xenial-utils/hostapd_2.9-102~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/xenial-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..3dad38bf5dff Binary files /dev/null and b/external/cache/debs/extra/xenial-utils/hostapd_2.9-102~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/xenial-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..4ed0f676b5f6 Binary files /dev/null and b/external/cache/debs/extra/xenial-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/xenial-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..745cfe0ef87e Binary files /dev/null and b/external/cache/debs/extra/xenial-utils/mmc-utils_0~gita3d3331-3~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/debs/extra/xenial-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb b/external/cache/debs/extra/xenial-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb new file mode 100644 index 000000000000..5860aaf06594 Binary files /dev/null and b/external/cache/debs/extra/xenial-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_arm64.deb differ diff --git a/external/cache/debs/extra/xenial-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb b/external/cache/debs/extra/xenial-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb new file mode 100644 index 000000000000..5c45b3a3b54e Binary files /dev/null and b/external/cache/debs/extra/xenial-utils/sunxi-tools_1.4.2-2~orangepi2.0.8+1_armhf.deb differ diff --git a/external/cache/sources/brcm_patchram_plus/Makefile b/external/cache/sources/brcm_patchram_plus/Makefile new file mode 100755 index 000000000000..4cb8a93286d6 --- /dev/null +++ b/external/cache/sources/brcm_patchram_plus/Makefile @@ -0,0 +1,20 @@ +# ---------------------------------------------------------------------------- +# Makefile for building tapp +# +# + +CFLAGS = -Wall -O2 +CC = gcc +INSTALL = install + +TARGET = brcm_patchram_plus + +all: $(TARGET) + +$(TARGET): brcm_patchram_plus.c + $(CC) $(CFLAGS) $< -o $@ +clean distclean: + rm -rf *.o $(TARGET) +# ---------------------------------------------------------------------------- + +.PHONY: $(PHONY) install clean distclean diff --git a/external/cache/sources/brcm_patchram_plus/brcm_patchram_plus.c b/external/cache/sources/brcm_patchram_plus/brcm_patchram_plus.c new file mode 100755 index 000000000000..e5fc6f1929e8 --- /dev/null +++ b/external/cache/sources/brcm_patchram_plus/brcm_patchram_plus.c @@ -0,0 +1,890 @@ +/******************************************************************************* + * + * Copyright (C) 2009-2011 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. + * + ******************************************************************************/ + +/***************************************************************************** +** +** Name: brcm_patchram_plus.c +** +** Description: This program downloads a patchram files in the HCD format +** to Broadcom Bluetooth based silicon and combo chips and +** and other utility functions. +** +** It can be invoked from the command line in the form +** <-d> to print a debug log +** <--patchram patchram_file> +** <--baudrate baud_rate> +** <--bd_addr bd_address> +** <--enable_lpm> +** <--enable_hci> +** <--use_baudrate_for_download> +** <--scopcm=sco_routing,pcm_interface_rate,frame_type, +** sync_mode,clock_mode,lsb_first,fill_bits, +** fill_method,fill_num,right_justify> +** +** Where +** +** sco_routing is 0 for PCM, 1 for Transport, +** 2 for Codec and 3 for I2S, +** +** pcm_interface_rate is 0 for 128KBps, 1 for +** 256 KBps, 2 for 512KBps, 3 for 1024KBps, +** and 4 for 2048Kbps, +** +** frame_type is 0 for short and 1 for long, +** +** sync_mode is 0 for slave and 1 for master, +** +** clock_mode is 0 for slabe and 1 for master, +** +** lsb_first is 0 for false aand 1 for true, +** +** fill_bits is the value in decimal for unused bits, +** +** fill_method is 0 for 0's and 1 for 1's, 2 for +** signed and 3 for programmable, +** +** fill_num is the number or bits to fill, +** +** right_justify is 0 for false and 1 for true +** +** <--i2s=i2s_enable,is_master,sample_rate,clock_rate> +** +** Where +** +** i2s_enable is 0 for disable and 1 for enable, +** +** is_master is 0 for slave and 1 for master, +** +** sample_rate is 0 for 8KHz, 1 for 16Khz and +** 2 for 4 KHz, +** +** clock_rate is 0 for 128KHz, 1 for 256KHz, 3 for +** 1024 KHz and 4 for 2048 KHz. +** +** <--no2bytes skips waiting for two byte confirmation +** before starting patchram download. Newer chips +** do not generate these two bytes.> +** <--tosleep=number of microsseconds to sleep before +** patchram download begins.> +** uart_device_name +** +** For example: +** +** brcm_patchram_plus -d --patchram \ +** BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0 +** +** It will return 0 for success and a number greater than 0 +** for any errors. +** +** For Android, this program invoked using a +** "system(2)" call from the beginning of the bt_enable +** function inside the file +** system/bluetooth/bluedroid/bluetooth.c. +** +** If the Android system property "ro.bt.bcm_bdaddr_path" is +** set, then the bd_addr will be read from this path. +** This is overridden by --bd_addr on the command line. +** +******************************************************************************/ + +// TODO: Integrate BCM support into Bluez hciattach + +#include +#include +#include + +#include +#include +#include + +#include + +#ifdef ANDROID +#include +#else +#include +#include +#include +#endif + +#include +#include + +#ifdef ANDROID +#include +#define LOG_TAG "brcm_patchram_plus" +#include +#undef printf +#define printf ALOGD +#undef fprintf +#define fprintf(x, ...) \ + { if(x==stderr) ALOGE(__VA_ARGS__); else fprintf(x, __VA_ARGS__); } + +#endif //ANDROID + +#ifndef N_HCI +#define N_HCI 15 +#endif + +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) +#define HCIUARTGETDEVICE _IOR('U', 202, int) + +#define HCI_UART_H4 0 +#define HCI_UART_BCSP 1 +#define HCI_UART_3WIRE 2 +#define HCI_UART_H4DS 3 +#define HCI_UART_LL 4 + +typedef unsigned char uchar; + +int uart_fd = -1; +int hcdfile_fd = -1; +int termios_baudrate = 0; +int bdaddr_flag = 0; +int enable_lpm = 0; +int enable_hci = 0; +int use_baudrate_for_download = 0; +int debug = 0; +int scopcm = 0; +int i2s = 0; +int no2bytes = 0; +int tosleep = 0; + +struct termios termios; +uchar buffer[1024]; + +uchar hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 }; + +uchar hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 }; + +uchar hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + +uchar hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +uchar hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + +uchar hci_write_sco_pcm_int[] = + { 0x01, 0x1C, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +uchar hci_write_pcm_data_format[] = + { 0x01, 0x1e, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +uchar hci_write_i2spcm_interface_param[] = + { 0x01, 0x6d, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00 }; + +#ifdef SAMSUNG_BLUETOOTH +char* get_samsung_bluetooth_type() +{ + char buf[10]; + int fd = open("/data/.cid.info", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "couldn't open file /data/.cid.info for reading\n"); + return NULL; + } + + if (read(fd, buf, sizeof(buf)) < 0) { + close(fd); + return NULL; + } + + close(fd); + + if (strncmp(buf, "murata", 6) == 0) + return "_murata"; + + if (strncmp(buf, "semcove", 7) == 0) + return "_semcove"; + + if (strncmp(buf, "semcosh", 7) == 0) + return "_semcosh"; + + return NULL; +} +#endif + +int +parse_patchram(char *optarg) +{ + char *p; + + if (!(p = strrchr(optarg, '.'))) { + fprintf(stderr, "file %s not an HCD file\n", optarg); + exit(3); + } + + p++; + + if (strcasecmp("hcd", p) != 0) { + fprintf(stderr, "file %s not an HCD file\n", optarg); + exit(4); + } + +#ifdef SAMSUNG_BLUETOOTH + char optarg2[256]; + char* type = get_samsung_bluetooth_type(); + char* fext = ".hcd"; + + if (type != NULL) { + memset(optarg2, 0, 256); + strncpy(optarg2, optarg, strlen(optarg) - 4); + strcpy(optarg2 + strlen(optarg2), type); + strcpy(optarg2 + strlen(optarg2), fext); + optarg = optarg2; + fprintf(stderr, "using %s as hcdfile\n", optarg); + } +#endif + + if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) { + fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno); + exit(5); + } + + return(0); +} + +void +BRCM_encode_baud_rate(uint baud_rate, uchar *encoded_baud) +{ + if(baud_rate == 0 || encoded_baud == NULL) { + fprintf(stderr, "Baudrate not supported!"); + return; + } + + encoded_baud[3] = (uchar)(baud_rate >> 24); + encoded_baud[2] = (uchar)(baud_rate >> 16); + encoded_baud[1] = (uchar)(baud_rate >> 8); + encoded_baud[0] = (uchar)(baud_rate & 0xFF); +} + +typedef struct { + int baud_rate; + int termios_value; +} tBaudRates; + +tBaudRates baud_rates[] = { + { 115200, B115200 }, + { 230400, B230400 }, + { 460800, B460800 }, + { 500000, B500000 }, + { 576000, B576000 }, + { 921600, B921600 }, + { 1000000, B1000000 }, + { 1152000, B1152000 }, + { 1500000, B1500000 }, + { 2000000, B2000000 }, + { 2500000, B2500000 }, + { 3000000, B3000000 }, +#ifndef __CYGWIN__ + { 3500000, B3500000 }, + { 4000000, B4000000 } +#endif +}; + +int +validate_baudrate(int baud_rate, int *value) +{ + unsigned int i; + + for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) { + if (baud_rates[i].baud_rate == baud_rate) { + *value = baud_rates[i].termios_value; + return(1); + } + } + + return(0); +} + +int +parse_baudrate(char *optarg) +{ + int baudrate = atoi(optarg); + + if (validate_baudrate(baudrate, &termios_baudrate)) { + BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]); + } + + return(0); +} + +int +parse_bdaddr(char *optarg) +{ + int bd_addr[6]; + int i; + + sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X", + &bd_addr[5], &bd_addr[4], &bd_addr[3], + &bd_addr[2], &bd_addr[1], &bd_addr[0]); + + for (i = 0; i < 6; i++) { + hci_write_bd_addr[4 + i] = bd_addr[i]; + } + + bdaddr_flag = 1; + + return(0); +} + +int +parse_enable_lpm(char *optarg) +{ + enable_lpm = 1; + return(0); +} + +int +parse_use_baudrate_for_download(char *optarg) +{ + use_baudrate_for_download = 1; + return(0); +} + +int +parse_enable_hci(char *optarg) +{ + enable_hci = 1; + return(0); +} + +int +parse_scopcm(char *optarg) +{ + int param[10]; + int ret; + int i; + + ret = sscanf(optarg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + ¶m[0], ¶m[1], ¶m[2], ¶m[3], ¶m[4], + ¶m[5], ¶m[6], ¶m[7], ¶m[8], ¶m[9]); + + if (ret != 10) { + return(1); + } + + scopcm = 1; + + for (i = 0; i < 5; i++) { + hci_write_sco_pcm_int[4 + i] = param[i]; + } + + for (i = 0; i < 5; i++) { + hci_write_pcm_data_format[4 + i] = param[5 + i]; + } + + return(0); +} + +int +parse_i2s(char *optarg) +{ + int param[4]; + int ret; + int i; + + ret = sscanf(optarg, "%d,%d,%d,%d", ¶m[0], ¶m[1], ¶m[2], + ¶m[3]); + + if (ret != 4) { + return(1); + } + + i2s = 1; + + for (i = 0; i < 4; i++) { + hci_write_i2spcm_interface_param[4 + i] = param[i]; + } + + return(0); +} + +int +parse_no2bytes(char *optarg) +{ + no2bytes = 1; + return(0); +} + +int +parse_tosleep(char *optarg) +{ + tosleep = atoi(optarg); + + if (tosleep <= 0) { + return(1); + } + + return(0); +} + +void +usage(char *argv0) +{ + printf("Usage %s:\n", argv0); + printf("\t<-d> to print a debug log\n"); + printf("\t<--patchram patchram_file>\n"); + printf("\t<--baudrate baud_rate>\n"); + printf("\t<--bd_addr bd_address>\n"); + printf("\t<--enable_lpm>\n"); + printf("\t<--enable_hci>\n"); + printf("\t<--use_baudrate_for_download> - Uses the\n"); + printf("\t\tbaudrate for downloading the firmware\n"); + printf("\t<--scopcm=sco_routing,pcm_interface_rate,frame_type,\n"); + printf("\t\tsync_mode,clock_mode,lsb_first,fill_bits,\n"); + printf("\t\tfill_method,fill_num,right_justify>\n"); + printf("\n\t\tWhere\n"); + printf("\n\t\tsco_routing is 0 for PCM, 1 for Transport,\n"); + printf("\t\t2 for Codec and 3 for I2S,\n"); + printf("\n\t\tpcm_interface_rate is 0 for 128KBps, 1 for\n"); + printf("\t\t256 KBps, 2 for 512KBps, 3 for 1024KBps,\n"); + printf("\t\tand 4 for 2048Kbps,\n"); + printf("\n\t\tframe_type is 0 for short and 1 for long,\n"); + printf("\t\tsync_mode is 0 for slave and 1 for master,\n"); + printf("\n\t\tclock_mode is 0 for slabe and 1 for master,\n"); + printf("\n\t\tlsb_first is 0 for false aand 1 for true,\n"); + printf("\n\t\tfill_bits is the value in decimal for unused bits,\n"); + printf("\n\t\tfill_method is 0 for 0's and 1 for 1's, 2 for\n"); + printf("\t\tsigned and 3 for programmable,\n"); + printf("\n\t\tfill_num is the number or bits to fill,\n"); + printf("\n\t\tright_justify is 0 for false and 1 for true\n"); + printf("\n\t<--i2s=i2s_enable,is_master,sample_rate,clock_rate>\n"); + printf("\n\t\tWhere\n"); + printf("\n\t\ti2s_enable is 0 for disable and 1 for enable,\n"); + printf("\n\t\tis_master is 0 for slave and 1 for master,\n"); + printf("\n\t\tsample_rate is 0 for 8KHz, 1 for 16Khz and\n"); + printf("\t\t2 for 4 KHz,\n"); + printf("\n\t\tclock_rate is 0 for 128KHz, 1 for 256KHz, 3 for\n"); + printf("\t\t1024 KHz and 4 for 2048 KHz.\n\n"); + printf("\t<--no2bytes skips waiting for two byte confirmation\n"); + printf("\t\tbefore starting patchram download. Newer chips\n"); + printf("\t\tdo not generate these two bytes.>\n"); + printf("\t<--tosleep=microseconds>\n"); + printf("\tuart_device_name\n"); +} + +int +parse_cmd_line(int argc, char **argv) +{ + int c; + int ret = 0; + + typedef int (*PFI)(); + + PFI parse[] = { parse_patchram, parse_baudrate, + parse_bdaddr, parse_enable_lpm, parse_enable_hci, + parse_use_baudrate_for_download, + parse_scopcm, parse_i2s, parse_no2bytes, parse_tosleep}; + + while (1) { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + + static struct option long_options[] = { + {"patchram", 1, 0, 0}, + {"baudrate", 1, 0, 0}, + {"bd_addr", 1, 0, 0}, + {"enable_lpm", 0, 0, 0}, + {"enable_hci", 0, 0, 0}, + {"use_baudrate_for_download", 0, 0, 0}, + {"scopcm", 1, 0, 0}, + {"i2s", 1, 0, 0}, + {"no2bytes", 0, 0, 0}, + {"tosleep", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long_only (argc, argv, "d", long_options, + &option_index); + + if (c == -1) { + break; + } + + switch (c) { + case 0: + if (debug) { + printf ("option %s", + long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + } + + ret = (*parse[option_index])(optarg); + + break; + case 'd': + debug = 1; + break; + + case '?': + //nobreak + default: + usage(argv[0]); + break; + } + + if (ret) { + usage(argv[0]); + break; + } + } + + if (ret) { + return(1); + } + + if (optind < argc) { + if (debug) + printf ("%s \n", argv[optind]); + if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) { + fprintf(stderr, "port %s could not be opened, error %d\n", + argv[optind], errno); + } + } + + return(0); +} + +void +init_uart() +{ +#ifdef BCM_INIT_DELAY + usleep(150*1000); +#endif + tcflush(uart_fd, TCIOFLUSH); + tcgetattr(uart_fd, &termios); + +#ifndef __CYGWIN__ + cfmakeraw(&termios); +#else + termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP + | INLCR | IGNCR | ICRNL | IXON); + termios.c_oflag &= ~OPOST; + termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + termios.c_cflag &= ~(CSIZE | PARENB); + termios.c_cflag |= CS8; +#endif + + termios.c_cflag |= CRTSCTS; + tcsetattr(uart_fd, TCSANOW, &termios); + tcflush(uart_fd, TCIOFLUSH); + tcsetattr(uart_fd, TCSANOW, &termios); + tcflush(uart_fd, TCIOFLUSH); + tcflush(uart_fd, TCIOFLUSH); + cfsetospeed(&termios, B115200); + cfsetispeed(&termios, B115200); + tcsetattr(uart_fd, TCSANOW, &termios); +} + +void +dump(uchar *out, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (i && !(i % 16)) { + fprintf(stderr, "\n"); + } + + fprintf(stderr, "%02x ", out[i]); + } + + fprintf(stderr, "\n"); +} + +void +read_event(int fd, uchar *buffer) +{ + int i = 0; + int len = 3; + int count; + + while ((count = read(fd, &buffer[i], len)) < len) { + i += count; + len -= count; + } + + i += count; + len = buffer[2]; + + while ((count = read(fd, &buffer[i], len)) < len) { + i += count; + len -= count; + } + + if (debug) { + count += i; + + fprintf(stderr, "received %d\n", count); + dump(buffer, count); + } +} + +void +hci_send_cmd(uchar *buf, int len) +{ + if (debug) { + fprintf(stderr, "writing\n"); + dump(buf, len); + } + + write(uart_fd, buf, len); +} + +void +expired(int sig) +{ + hci_send_cmd(hci_reset, sizeof(hci_reset)); + alarm(4); +} + +void +proc_reset() +{ + signal(SIGALRM, expired); + + + hci_send_cmd(hci_reset, sizeof(hci_reset)); + + alarm(4); + + read_event(uart_fd, buffer); + + alarm(0); +} + +void +proc_patchram() +{ + int len; + + hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver)); + + read_event(uart_fd, buffer); + + if (!no2bytes) { + read(uart_fd, &buffer[0], 2); + } + + if (tosleep) { + usleep(tosleep); + } + + while (read(hcdfile_fd, &buffer[1], 3)) { + buffer[0] = 0x01; + + len = buffer[3]; + + read(hcdfile_fd, &buffer[4], len); + + hci_send_cmd(buffer, len + 4); + + read_event(uart_fd, buffer); + } + + if (use_baudrate_for_download) { + cfsetospeed(&termios, B115200); + cfsetispeed(&termios, B115200); + tcsetattr(uart_fd, TCSANOW, &termios); + } + proc_reset(); +} + +void +proc_baudrate() +{ + hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate)); + + read_event(uart_fd, buffer); + + cfsetospeed(&termios, termios_baudrate); + cfsetispeed(&termios, termios_baudrate); + tcsetattr(uart_fd, TCSANOW, &termios); + + if (debug) { + fprintf(stderr, "Done setting baudrate\n"); + } +} + +void +proc_bdaddr() +{ + hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr)); + + read_event(uart_fd, buffer); +} + +void +proc_enable_lpm() +{ + hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode)); + + read_event(uart_fd, buffer); +} + +void +proc_scopcm() +{ + hci_send_cmd(hci_write_sco_pcm_int, + sizeof(hci_write_sco_pcm_int)); + + read_event(uart_fd, buffer); + + hci_send_cmd(hci_write_pcm_data_format, + sizeof(hci_write_pcm_data_format)); + + read_event(uart_fd, buffer); +} + +void +proc_i2s() +{ + hci_send_cmd(hci_write_i2spcm_interface_param, + sizeof(hci_write_i2spcm_interface_param)); + + read_event(uart_fd, buffer); +} + +void +proc_enable_hci() +{ + int i = N_HCI; + int proto = HCI_UART_H4; + if (ioctl(uart_fd, TIOCSETD, &i) < 0) { + fprintf(stderr, "Can't set line discipline\n"); + return; + } + + if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) { + fprintf(stderr, "Can't set hci protocol\n"); + return; + } + fprintf(stderr, "Done setting line discpline\n"); + return; +} + +#ifdef ANDROID +void +read_default_bdaddr() +{ + int sz; + int fd; + + char path[PROPERTY_VALUE_MAX]; + + char bdaddr[18]; + int len = 17; + memset(bdaddr, 0, (len + 1) * sizeof(char)); + + property_get("ro.bt.bdaddr_path", path, ""); + if (path[0] == 0) + return; + + fd = open(path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno), + errno); + return; + } + + sz = read(fd, bdaddr, len); + if (sz < 0) { + fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno), + errno); + close(fd); + return; + } else if (sz != len) { + fprintf(stderr, "read(%s) unexpected size %d", path, sz); + close(fd); + return; + } + + if (debug) { + printf("Read default bdaddr of %s\n", bdaddr); + } + + parse_bdaddr(bdaddr); +} +#endif + + +int +main (int argc, char **argv) +{ +#ifdef ANDROID + read_default_bdaddr(); +#endif + + if (parse_cmd_line(argc, argv)) { + exit(1); + } + + if (uart_fd < 0) { + exit(2); + } + + init_uart(); + + proc_reset(); + + if (use_baudrate_for_download) { + if (termios_baudrate) { + proc_baudrate(); + } + } + + if (hcdfile_fd > 0) { + proc_patchram(); + } + + if (termios_baudrate) { + proc_baudrate(); + } + + if (bdaddr_flag) { + proc_bdaddr(); + } + + if (enable_lpm) { + proc_enable_lpm(); + } + + if (scopcm) { + proc_scopcm(); + } + + if (i2s) { + proc_i2s(); + } + + if (enable_hci) { + proc_enable_hci(); + + while (1) { + sleep(UINT_MAX); + } + } + + exit(0); +} diff --git a/external/cache/sources/hcitools/Makefile b/external/cache/sources/hcitools/Makefile new file mode 100644 index 000000000000..d902df9973f8 --- /dev/null +++ b/external/cache/sources/hcitools/Makefile @@ -0,0 +1,95 @@ +#CFLAGS := $(CFLAGS) -g +CFLAGS = -I. -Ilib -Wall -DVERSION=\"5.10\" -Wno-strict-aliasing +CFLAGS += -Ilib/bluetooth + +# include rule.mk +include ./rule.mk + +# define objects collection variable +lib = \ + lib/bluetooth.o \ + lib/hci.o \ + lib/sdp.o + +hciattach_objs = \ + hciattach.o \ + hciattach_ath3k.o \ + hciattach_bcm43xx.o \ + hciattach_intel.o \ + hciattach_qualcomm.o \ + hciattach_st.o \ + hciattach_ti.o \ + hciattach_tialt.o \ + hciattach_rtk.o \ + hciattach_xr.o \ + hciattach_sprd.o + +hciconfig_objs = \ + hciconfig.o \ + csr.o + +hcitool_objs = \ + hcitool.o + +btmon_objs = \ + monitor/main.o \ + monitor/mainloop.o \ + monitor/display.o \ + monitor/hcidump.o \ + monitor/btsnoop.o \ + monitor/control.o \ + monitor/packet.o \ + monitor/vendor.o \ + monitor/lmp.o \ + monitor/l2cap.o \ + monitor/uuid.o \ + monitor/sdp.o \ + monitor/crc.o \ + monitor/ll.o + +# add your target(s) to all +.PHONY: all +all: hciattach_opi hciconfig hcitool btmon + +# directory +hciattach_opi: $(hciattach_objs) $(lib) + $(LINK_MSG) + $(LINKX) + +hciconfig: $(hciconfig_objs) $(lib) + $(LINK_MSG) + $(LINKX) + +hcitool: $(hcitool_objs) $(lib) + $(LINK_MSG) + $(LINKX) + +btmon: $(btmon_objs) $(lib) + $(LINK_MSG) + $(LINKX) + +# change objs to your objects collection variable +$(hciattach_objs): %.o: %.c + $(COMPILE_MSG) + $(COMPILEX) + +$(hciconfig_objs): %.o: %.c + $(COMPILE_MSG) + $(COMPILEX) + +$(hcitool_objs): %.o: %.c + $(COMPILE_MSG) + $(COMPILEX) + +$(btmon_objs): %.o: %.c + $(COMPILE_MSG) + $(COMPILEX) + +# clean temp files +clean: + -rm -rf $(hciattach_objs) $(hciattach_objs:.o=.d) + -rm -rf $(hciconfig_objs) $(hciconfig_objs:.o=.d) + -rm -rf $(hcitool_objs) $(hcitool_objs:.o=.d) + -rm -rf $(lib) $(lib:.o=.d) + -rm -rf $(btmon_objs) $(btmon_objs:.o=.d) + #-rm -rf output diff --git a/external/cache/sources/hcitools/NOTICE b/external/cache/sources/hcitools/NOTICE new file mode 100644 index 000000000000..52321cc57a4d --- /dev/null +++ b/external/cache/sources/hcitools/NOTICE @@ -0,0 +1,343 @@ +All of these programs are made available under version 2 of the GNU General +Public Licence. + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/external/cache/sources/hcitools/csr.c b/external/cache/sources/hcitools/csr.c new file mode 100644 index 000000000000..b4ea1fbbe1c7 --- /dev/null +++ b/external/cache/sources/hcitools/csr.c @@ -0,0 +1,2853 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2003-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "csr.h" + +struct psr_data { + uint16_t pskey; + uint8_t *value; + uint8_t size; + struct psr_data *next; +}; + +static struct psr_data *head = NULL, *tail = NULL; + +static struct { + uint16_t id; + char *str; +} csr_map[] = { + { 66, "HCI 9.8" }, + { 97, "HCI 10.3" }, + { 101, "HCI 10.5" }, + { 111, "HCI 11.0" }, + { 112, "HCI 11.1" }, + { 114, "HCI 11.2" }, + { 115, "HCI 11.3" }, + { 117, "HCI 12.0" }, + { 119, "HCI 12.1" }, + { 133, "HCI 12.2" }, + { 134, "HCI 12.3" }, + { 162, "HCI 12.4" }, + { 165, "HCI 12.5" }, + { 169, "HCI 12.6" }, + { 188, "HCI 12.7" }, + { 218, "HCI 12.8" }, + { 283, "HCI 12.9" }, + { 203, "HCI 13.2" }, + { 204, "HCI 13.2" }, + { 210, "HCI 13.3" }, + { 211, "HCI 13.3" }, + { 213, "HCI 13.4" }, + { 214, "HCI 13.4" }, + { 225, "HCI 13.5" }, + { 226, "HCI 13.5" }, + { 237, "HCI 13.6" }, + { 238, "HCI 13.6" }, + { 242, "HCI 14.0" }, + { 243, "HCI 14.0" }, + { 244, "HCI 14.0" }, + { 245, "HCI 14.0" }, + { 254, "HCI 13.7" }, + { 255, "HCI 13.7" }, + { 264, "HCI 14.1" }, + { 265, "HCI 14.1" }, + { 267, "HCI 14.2" }, + { 268, "HCI 14.2" }, + { 272, "HCI 14.3" }, + { 273, "HCI 14.3" }, + { 274, "HCI 13.8" }, + { 275, "HCI 13.8" }, + { 286, "HCI 13.9" }, + { 287, "HCI 13.9" }, + { 309, "HCI 13.10" }, + { 310, "HCI 13.10" }, + { 313, "HCI 14.4" }, + { 314, "HCI 14.4" }, + { 323, "HCI 14.5" }, + { 324, "HCI 14.5" }, + { 336, "HCI 14.6" }, + { 337, "HCI 14.6" }, + { 351, "HCI 13.11" }, + { 352, "HCI 13.11" }, + { 362, "HCI 15.0" }, + { 363, "HCI 15.0" }, + { 364, "HCI 15.0" }, + { 365, "HCI 15.0" }, + { 373, "HCI 14.7" }, + { 374, "HCI 14.7" }, + { 379, "HCI 15.1" }, + { 380, "HCI 15.1" }, + { 381, "HCI 15.1" }, + { 382, "HCI 15.1" }, + { 392, "HCI 15.2" }, + { 393, "HCI 15.2" }, + { 394, "HCI 15.2" }, + { 395, "HCI 15.2" }, + { 436, "HCI 16.0" }, + { 437, "HCI 16.0" }, + { 438, "HCI 16.0" }, + { 439, "HCI 16.0" }, + { 443, "HCI 15.3" }, + { 444, "HCI 15.3" }, + { 465, "HCI 16.1" }, + { 466, "HCI 16.1" }, + { 467, "HCI 16.1" }, + { 468, "HCI 16.1" }, + { 487, "HCI 14.8" }, + { 488, "HCI 14.8" }, + { 492, "HCI 16.2" }, + { 493, "HCI 16.2" }, + { 495, "HCI 16.2" }, + { 496, "HCI 16.2" }, + { 502, "HCI 16.1.1" }, + { 503, "HCI 16.1.1" }, + { 504, "HCI 16.1.1" }, + { 505, "HCI 16.1.1" }, + { 506, "HCI 16.1.2" }, + { 507, "HCI 16.1.2" }, + { 508, "HCI 16.1.2" }, + { 509, "HCI 16.1.2" }, + { 516, "HCI 16.3" }, + { 517, "HCI 16.3" }, + { 518, "HCI 16.3" }, + { 519, "HCI 16.3" }, + { 523, "HCI 16.4" }, + { 524, "HCI 16.4" }, + { 525, "HCI 16.4" }, + { 526, "HCI 16.4" }, + { 553, "HCI 15.3" }, + { 554, "HCI 15.3" }, + { 562, "HCI 16.5" }, + { 563, "HCI 16.5" }, + { 564, "HCI 16.5" }, + { 565, "HCI 16.5" }, + { 593, "HCI 17.0" }, + { 594, "HCI 17.0" }, + { 595, "HCI 17.0" }, + { 599, "HCI 17.0" }, + { 600, "HCI 17.0" }, + { 608, "HCI 13.10.1" }, + { 609, "HCI 13.10.1" }, + { 613, "HCI 17.1" }, + { 614, "HCI 17.1" }, + { 615, "HCI 17.1" }, + { 616, "HCI 17.1" }, + { 618, "HCI 17.1" }, + { 624, "HCI 17.2" }, + { 625, "HCI 17.2" }, + { 626, "HCI 17.2" }, + { 627, "HCI 17.2" }, + { 637, "HCI 16.6" }, + { 638, "HCI 16.6" }, + { 639, "HCI 16.6" }, + { 640, "HCI 16.6" }, + { 642, "HCI 13.10.2" }, + { 643, "HCI 13.10.2" }, + { 644, "HCI 13.10.3" }, + { 645, "HCI 13.10.3" }, + { 668, "HCI 13.10.4" }, + { 669, "HCI 13.10.4" }, + { 681, "HCI 16.7" }, + { 682, "HCI 16.7" }, + { 683, "HCI 16.7" }, + { 684, "HCI 16.7" }, + { 704, "HCI 16.8" }, + { 718, "HCI 16.4.1" }, + { 719, "HCI 16.4.1" }, + { 720, "HCI 16.4.1" }, + { 721, "HCI 16.4.1" }, + { 722, "HCI 16.7.1" }, + { 723, "HCI 16.7.1" }, + { 724, "HCI 16.7.1" }, + { 725, "HCI 16.7.1" }, + { 731, "HCI 16.7.2" }, + { 732, "HCI 16.7.2" }, + { 733, "HCI 16.7.2" }, + { 734, "HCI 16.7.2" }, + { 735, "HCI 16.4.2" }, + { 736, "HCI 16.4.2" }, + { 737, "HCI 16.4.2" }, + { 738, "HCI 16.4.2" }, + { 750, "HCI 16.7.3" }, + { 751, "HCI 16.7.3" }, + { 752, "HCI 16.7.3" }, + { 753, "HCI 16.7.3" }, + { 760, "HCI 16.7.4" }, + { 761, "HCI 16.7.4" }, + { 762, "HCI 16.7.4" }, + { 763, "HCI 16.7.4" }, + { 770, "HCI 16.9" }, + { 771, "HCI 16.9" }, + { 772, "HCI 16.9" }, + { 773, "HCI 16.9" }, + { 774, "HCI 17.3" }, + { 775, "HCI 17.3" }, + { 776, "HCI 17.3" }, + { 777, "HCI 17.3" }, + { 781, "HCI 16.7.5" }, + { 786, "HCI 16.10" }, + { 787, "HCI 16.10" }, + { 788, "HCI 16.10" }, + { 789, "HCI 16.10" }, + { 791, "HCI 16.4.3" }, + { 792, "HCI 16.4.3" }, + { 793, "HCI 16.4.3" }, + { 794, "HCI 16.4.3" }, + { 798, "HCI 16.11" }, + { 799, "HCI 16.11" }, + { 800, "HCI 16.11" }, + { 801, "HCI 16.11" }, + { 806, "HCI 16.7.5" }, + { 807, "HCI 16.12" }, + { 808, "HCI 16.12" }, + { 809, "HCI 16.12" }, + { 810, "HCI 16.12" }, + { 817, "HCI 16.13" }, + { 818, "HCI 16.13" }, + { 819, "HCI 16.13" }, + { 820, "HCI 16.13" }, + { 823, "HCI 13.10.5" }, + { 824, "HCI 13.10.5" }, + { 826, "HCI 16.14" }, + { 827, "HCI 16.14" }, + { 828, "HCI 16.14" }, + { 829, "HCI 16.14" }, + { 843, "HCI 17.3.1" }, + { 856, "HCI 17.3.2" }, + { 857, "HCI 17.3.2" }, + { 858, "HCI 17.3.2" }, + { 1120, "HCI 17.11" }, + { 1168, "HCI 18.1" }, + { 1169, "HCI 18.1" }, + { 1241, "HCI 18.x" }, + { 1298, "HCI 18.2" }, + { 1354, "HCI 18.2" }, + { 1392, "HCI 18.2" }, + { 1393, "HCI 18.2" }, + { 1501, "HCI 18.2" }, + { 1503, "HCI 18.2" }, + { 1504, "HCI 18.2" }, + { 1505, "HCI 18.2" }, + { 1506, "HCI 18.2" }, + { 1520, "HCI 18.2" }, + { 1586, "HCI 18.2" }, + { 1591, "HCI 18.2" }, + { 1592, "HCI 18.2" }, + { 1593, "HCI 18.2.1" }, + { 1733, "HCI 18.3" }, + { 1734, "HCI 18.3" }, + { 1735, "HCI 18.3" }, + { 1737, "HCI 18.3" }, + { 1915, "HCI 19.2" }, + { 1916, "HCI 19.2" }, + { 1958, "HCI 19.2" }, + { 1981, "Unified 20a" }, + { 1982, "Unified 20a" }, + { 1989, "HCI 18.4" }, + { 2062, "Unified 20a1" }, + { 2063, "Unified 20a1" }, + { 2067, "Unified 18f" }, + { 2068, "Unified 18f" }, + { 2243, "Unified 18e" }, + { 2244, "Unified 18e" }, + { 2258, "Unified 20d" }, + { 2259, "Unified 20d" }, + { 2361, "Unified 20e" }, + { 2362, "Unified 20e" }, + { 2386, "Unified 21a" }, + { 2387, "Unified 21a" }, + { 2423, "Unified 21a" }, + { 2424, "Unified 21a" }, + { 2623, "Unified 21c" }, + { 2624, "Unified 21c" }, + { 2625, "Unified 21c" }, + { 2626, "Unified 21c" }, + { 2627, "Unified 21c" }, + { 2628, "Unified 21c" }, + { 2629, "Unified 21c" }, + { 2630, "Unified 21c" }, + { 2631, "Unified 21c" }, + { 2632, "Unified 21c" }, + { 2633, "Unified 21c" }, + { 2634, "Unified 21c" }, + { 2635, "Unified 21c" }, + { 2636, "Unified 21c" }, + { 2649, "Unified 21c" }, + { 2650, "Unified 21c" }, + { 2651, "Unified 21c" }, + { 2652, "Unified 21c" }, + { 2653, "Unified 21c" }, + { 2654, "Unified 21c" }, + { 2655, "Unified 21c" }, + { 2656, "Unified 21c" }, + { 2658, "Unified 21c" }, + { 3057, "Unified 21d" }, + { 3058, "Unified 21d" }, + { 3059, "Unified 21d" }, + { 3060, "Unified 21d" }, + { 3062, "Unified 21d" }, + { 3063, "Unified 21d" }, + { 3064, "Unified 21d" }, + { 3164, "Unified 21e" }, + { 3413, "Unified 21f" }, + { 3414, "Unified 21f" }, + { 3415, "Unified 21f" }, + { 3424, "Unified 21f" }, + { 3454, "Unified 21f" }, + { 3684, "Unified 21f" }, + { 3764, "Unified 21f" }, + { 4276, "Unified 22b" }, + { 4277, "Unified 22b" }, + { 4279, "Unified 22b" }, + { 4281, "Unified 22b" }, + { 4282, "Unified 22b" }, + { 4283, "Unified 22b" }, + { 4284, "Unified 22b" }, + { 4285, "Unified 22b" }, + { 4289, "Unified 22b" }, + { 4290, "Unified 22b" }, + { 4291, "Unified 22b" }, + { 4292, "Unified 22b" }, + { 4293, "Unified 22b" }, + { 4294, "Unified 22b" }, + { 4295, "Unified 22b" }, + { 4363, "Unified 22c" }, + { 4373, "Unified 22c" }, + { 4374, "Unified 22c" }, + { 4532, "Unified 22d" }, + { 4533, "Unified 22d" }, + { 4698, "Unified 23c" }, + { 4839, "Unified 23c" }, + { 4841, "Unified 23c" }, + { 4866, "Unified 23c" }, + { 4867, "Unified 23c" }, + { 4868, "Unified 23c" }, + { 4869, "Unified 23c" }, + { 4870, "Unified 23c" }, + { 4871, "Unified 23c" }, + { 4872, "Unified 23c" }, + { 4874, "Unified 23c" }, + { 4875, "Unified 23c" }, + { 4876, "Unified 23c" }, + { 4877, "Unified 23c" }, + { 2526, "Marcel 1 (2005-09-26)" }, + { 2543, "Marcel 2 (2005-09-28)" }, + { 2622, "Marcel 3 (2005-10-27)" }, + { 3326, "Marcel 4 (2006-06-16)" }, + { 3612, "Marcel 5 (2006-10-24)" }, + { 4509, "Marcel 6 (2007-06-11)" }, + { 5417, "Marcel 7 (2008-08-26)" }, + { 195, "Sniff 1 (2001-11-27)" }, + { 220, "Sniff 2 (2002-01-03)" }, + { 269, "Sniff 3 (2002-02-22)" }, + { 270, "Sniff 4 (2002-02-26)" }, + { 284, "Sniff 5 (2002-03-12)" }, + { 292, "Sniff 6 (2002-03-20)" }, + { 305, "Sniff 7 (2002-04-12)" }, + { 306, "Sniff 8 (2002-04-12)" }, + { 343, "Sniff 9 (2002-05-02)" }, + { 346, "Sniff 10 (2002-05-03)" }, + { 355, "Sniff 11 (2002-05-16)" }, + { 256, "Sniff 11 (2002-05-16)" }, + { 390, "Sniff 12 (2002-06-26)" }, + { 450, "Sniff 13 (2002-08-16)" }, + { 451, "Sniff 13 (2002-08-16)" }, + { 533, "Sniff 14 (2002-10-11)" }, + { 580, "Sniff 15 (2002-11-14)" }, + { 623, "Sniff 16 (2002-12-12)" }, + { 678, "Sniff 17 (2003-01-29)" }, + { 847, "Sniff 18 (2003-04-17)" }, + { 876, "Sniff 19 (2003-06-10)" }, + { 997, "Sniff 22 (2003-09-05)" }, + { 1027, "Sniff 23 (2003-10-03)" }, + { 1029, "Sniff 24 (2003-10-03)" }, + { 1112, "Sniff 25 (2003-12-03)" }, + { 1113, "Sniff 25 (2003-12-03)" }, + { 1133, "Sniff 26 (2003-12-18)" }, + { 1134, "Sniff 26 (2003-12-18)" }, + { 1223, "Sniff 27 (2004-03-08)" }, + { 1224, "Sniff 27 (2004-03-08)" }, + { 1319, "Sniff 31 (2004-04-22)" }, + { 1320, "Sniff 31 (2004-04-22)" }, + { 1427, "Sniff 34 (2004-06-16)" }, + { 1508, "Sniff 35 (2004-07-19)" }, + { 1509, "Sniff 35 (2004-07-19)" }, + { 1587, "Sniff 36 (2004-08-18)" }, + { 1588, "Sniff 36 (2004-08-18)" }, + { 1641, "Sniff 37 (2004-09-16)" }, + { 1642, "Sniff 37 (2004-09-16)" }, + { 1699, "Sniff 38 (2004-10-07)" }, + { 1700, "Sniff 38 (2004-10-07)" }, + { 1752, "Sniff 39 (2004-11-02)" }, + { 1753, "Sniff 39 (2004-11-02)" }, + { 1759, "Sniff 40 (2004-11-03)" }, + { 1760, "Sniff 40 (2004-11-03)" }, + { 1761, "Sniff 40 (2004-11-03)" }, + { 2009, "Sniff 41 (2005-04-06)" }, + { 2010, "Sniff 41 (2005-04-06)" }, + { 2011, "Sniff 41 (2005-04-06)" }, + { 2016, "Sniff 42 (2005-04-11)" }, + { 2017, "Sniff 42 (2005-04-11)" }, + { 2018, "Sniff 42 (2005-04-11)" }, + { 2023, "Sniff 43 (2005-04-14)" }, + { 2024, "Sniff 43 (2005-04-14)" }, + { 2025, "Sniff 43 (2005-04-14)" }, + { 2032, "Sniff 44 (2005-04-18)" }, + { 2033, "Sniff 44 (2005-04-18)" }, + { 2034, "Sniff 44 (2005-04-18)" }, + { 2288, "Sniff 45 (2005-07-08)" }, + { 2289, "Sniff 45 (2005-07-08)" }, + { 2290, "Sniff 45 (2005-07-08)" }, + { 2388, "Sniff 46 (2005-08-17)" }, + { 2389, "Sniff 46 (2005-08-17)" }, + { 2390, "Sniff 46 (2005-08-17)" }, + { 2869, "Sniff 47 (2006-02-15)" }, + { 2870, "Sniff 47 (2006-02-15)" }, + { 2871, "Sniff 47 (2006-02-15)" }, + { 3214, "Sniff 48 (2006-05-16)" }, + { 3215, "Sniff 48 (2006-05-16)" }, + { 3216, "Sniff 48 (2006-05-16)" }, + { 3356, "Sniff 49 (2006-07-17)" }, + { 3529, "Sniff 50 (2006-09-21)" }, + { 3546, "Sniff 51 (2006-09-29)" }, + { 3683, "Sniff 52 (2006-11-03)" }, + { 0, } +}; + +char *csr_builddeftostr(uint16_t def) +{ + switch (def) { + case 0x0000: + return "NONE"; + case 0x0001: + return "CHIP_BASE_BC01"; + case 0x0002: + return "CHIP_BASE_BC02"; + case 0x0003: + return "CHIP_BC01B"; + case 0x0004: + return "CHIP_BC02_EXTERNAL"; + case 0x0005: + return "BUILD_HCI"; + case 0x0006: + return "BUILD_RFCOMM"; + case 0x0007: + return "BT_VER_1_1"; + case 0x0008: + return "TRANSPORT_ALL"; + case 0x0009: + return "TRANSPORT_BCSP"; + case 0x000a: + return "TRANSPORT_H4"; + case 0x000b: + return "TRANSPORT_USB"; + case 0x000c: + return "MAX_CRYPT_KEY_LEN_56"; + case 0x000d: + return "MAX_CRYPT_KEY_LEN_128"; + case 0x000e: + return "TRANSPORT_USER"; + case 0x000f: + return "CHIP_BC02_KATO"; + case 0x0010: + return "TRANSPORT_NONE"; + case 0x0012: + return "REQUIRE_8MBIT"; + case 0x0013: + return "RADIOTEST"; + case 0x0014: + return "RADIOTEST_LITE"; + case 0x0015: + return "INSTALL_FLASH"; + case 0x0016: + return "INSTALL_EEPROM"; + case 0x0017: + return "INSTALL_COMBO_DOT11"; + case 0x0018: + return "LOWPOWER_TX"; + case 0x0019: + return "TRANSPORT_TWUTL"; + case 0x001a: + return "COMPILER_GCC"; + case 0x001b: + return "CHIP_BC02_CLOUSEAU"; + case 0x001c: + return "CHIP_BC02_TOULOUSE"; + case 0x001d: + return "CHIP_BASE_BC3"; + case 0x001e: + return "CHIP_BC3_NICKNACK"; + case 0x001f: + return "CHIP_BC3_KALIMBA"; + case 0x0020: + return "INSTALL_HCI_MODULE"; + case 0x0021: + return "INSTALL_L2CAP_MODULE"; + case 0x0022: + return "INSTALL_DM_MODULE"; + case 0x0023: + return "INSTALL_SDP_MODULE"; + case 0x0024: + return "INSTALL_RFCOMM_MODULE"; + case 0x0025: + return "INSTALL_HIDIO_MODULE"; + case 0x0026: + return "INSTALL_PAN_MODULE"; + case 0x0027: + return "INSTALL_IPV4_MODULE"; + case 0x0028: + return "INSTALL_IPV6_MODULE"; + case 0x0029: + return "INSTALL_TCP_MODULE"; + case 0x002a: + return "BT_VER_1_2"; + case 0x002b: + return "INSTALL_UDP_MODULE"; + case 0x002c: + return "REQUIRE_0_WAIT_STATES"; + case 0x002d: + return "CHIP_BC3_PADDYWACK"; + case 0x002e: + return "CHIP_BC4_COYOTE"; + case 0x002f: + return "CHIP_BC4_ODDJOB"; + case 0x0030: + return "TRANSPORT_H4DS"; + case 0x0031: + return "CHIP_BASE_BC4"; + default: + return "UNKNOWN"; + } +} + +char *csr_buildidtostr(uint16_t id) +{ + static char str[12]; + int i; + + for (i = 0; csr_map[i].id; i++) + if (csr_map[i].id == id) + return csr_map[i].str; + + snprintf(str, 11, "Build %d", id); + return str; +} + +char *csr_chipvertostr(uint16_t ver, uint16_t rev) +{ + switch (ver) { + case 0x00: + return "BlueCore01a"; + case 0x01: + switch (rev) { + case 0x64: + return "BlueCore01b (ES)"; + case 0x65: + default: + return "BlueCore01b"; + } + case 0x02: + switch (rev) { + case 0x89: + return "BlueCore02-External (ES2)"; + case 0x8a: + return "BlueCore02-External"; + case 0x28: + return "BlueCore02-ROM/Audio/Flash"; + default: + return "BlueCore02"; + } + case 0x03: + switch (rev) { + case 0x43: + return "BlueCore3-MM"; + case 0x15: + return "BlueCore3-ROM"; + case 0xe2: + return "BlueCore3-Flash"; + case 0x26: + return "BlueCore4-External"; + case 0x30: + return "BlueCore4-ROM"; + default: + return "BlueCore3 or BlueCore4"; + } + default: + return "Unknown"; + } +} + +char *csr_pskeytostr(uint16_t pskey) +{ + switch (pskey) { + case CSR_PSKEY_BDADDR: + return "Bluetooth address"; + case CSR_PSKEY_COUNTRYCODE: + return "Country code"; + case CSR_PSKEY_CLASSOFDEVICE: + return "Class of device"; + case CSR_PSKEY_DEVICE_DRIFT: + return "Device drift"; + case CSR_PSKEY_DEVICE_JITTER: + return "Device jitter"; + case CSR_PSKEY_MAX_ACLS: + return "Maximum ACL links"; + case CSR_PSKEY_MAX_SCOS: + return "Maximum SCO links"; + case CSR_PSKEY_MAX_REMOTE_MASTERS: + return "Maximum remote masters"; + case CSR_PSKEY_ENABLE_MASTERY_WITH_SLAVERY: + return "Support master and slave roles simultaneously"; + case CSR_PSKEY_H_HC_FC_MAX_ACL_PKT_LEN: + return "Maximum HCI ACL packet length"; + case CSR_PSKEY_H_HC_FC_MAX_SCO_PKT_LEN: + return "Maximum HCI SCO packet length"; + case CSR_PSKEY_H_HC_FC_MAX_ACL_PKTS: + return "Maximum number of HCI ACL packets"; + case CSR_PSKEY_H_HC_FC_MAX_SCO_PKTS: + return "Maximum number of HCI SCO packets"; + case CSR_PSKEY_LC_FC_BUFFER_LOW_WATER_MARK: + return "Flow control low water mark"; + case CSR_PSKEY_LC_MAX_TX_POWER: + return "Maximum transmit power"; + case CSR_PSKEY_TX_GAIN_RAMP: + return "Transmit gain ramp rate"; + case CSR_PSKEY_LC_POWER_TABLE: + return "Radio power table"; + case CSR_PSKEY_LC_PEER_POWER_PERIOD: + return "Peer transmit power control interval"; + case CSR_PSKEY_LC_FC_POOLS_LOW_WATER_MARK: + return "Flow control pool low water mark"; + case CSR_PSKEY_LC_DEFAULT_TX_POWER: + return "Default transmit power"; + case CSR_PSKEY_LC_RSSI_GOLDEN_RANGE: + return "RSSI at bottom of golden receive range"; + case CSR_PSKEY_LC_COMBO_DISABLE_PIO_MASK: + return "Combo: PIO lines and logic to disable transmit"; + case CSR_PSKEY_LC_COMBO_PRIORITY_PIO_MASK: + return "Combo: priority activity PIO lines and logic"; + case CSR_PSKEY_LC_COMBO_DOT11_CHANNEL_PIO_BASE: + return "Combo: 802.11b channel number base PIO line"; + case CSR_PSKEY_LC_COMBO_DOT11_BLOCK_CHANNELS: + return "Combo: channels to block either side of 802.11b"; + case CSR_PSKEY_LC_MAX_TX_POWER_NO_RSSI: + return "Maximum transmit power when peer has no RSSI"; + case CSR_PSKEY_LC_CONNECTION_RX_WINDOW: + return "Receive window size during connections"; + case CSR_PSKEY_LC_COMBO_DOT11_TX_PROTECTION_MODE: + return "Combo: which TX packets shall we protect"; + case CSR_PSKEY_LC_ENHANCED_POWER_TABLE: + return "Radio power table"; + case CSR_PSKEY_LC_WIDEBAND_RSSI_CONFIG: + return "RSSI configuration for use with wideband RSSI"; + case CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_LEAD: + return "Combo: How much notice will we give the Combo Card"; + case CSR_PSKEY_BT_CLOCK_INIT: + return "Initial value of Bluetooth clock"; + case CSR_PSKEY_TX_MR_MOD_DELAY: + return "TX Mod delay"; + case CSR_PSKEY_RX_MR_SYNC_TIMING: + return "RX MR Sync Timing"; + case CSR_PSKEY_RX_MR_SYNC_CONFIG: + return "RX MR Sync Configuration"; + case CSR_PSKEY_LC_LOST_SYNC_SLOTS: + return "Time in ms for lost sync in low power modes"; + case CSR_PSKEY_RX_MR_SAMP_CONFIG: + return "RX MR Sync Configuration"; + case CSR_PSKEY_AGC_HYST_LEVELS: + return "AGC hysteresis levels"; + case CSR_PSKEY_RX_LEVEL_LOW_SIGNAL: + return "ANA_RX_LVL at low signal strengths"; + case CSR_PSKEY_AGC_IQ_LVL_VALUES: + return "ANA_IQ_LVL values for AGC algorithmn"; + case CSR_PSKEY_MR_FTRIM_OFFSET_12DB: + return "ANA_RX_FTRIM offset when using 12 dB IF atten "; + case CSR_PSKEY_MR_FTRIM_OFFSET_6DB: + return "ANA_RX_FTRIM offset when using 6 dB IF atten "; + case CSR_PSKEY_NO_CAL_ON_BOOT: + return "Do not calibrate radio on boot"; + case CSR_PSKEY_RSSI_HI_TARGET: + return "RSSI high target"; + case CSR_PSKEY_PREFERRED_MIN_ATTENUATION: + return "Preferred minimum attenuator setting"; + case CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_OVERRIDE: + return "Combo: Treat all packets as high priority"; + case CSR_PSKEY_LC_MULTISLOT_HOLDOFF: + return "Time till single slot packets are used for resync"; + case CSR_PSKEY_FREE_KEY_PIGEON_HOLE: + return "Link key store bitfield"; + case CSR_PSKEY_LINK_KEY_BD_ADDR0: + return "Bluetooth address + link key 0"; + case CSR_PSKEY_LINK_KEY_BD_ADDR1: + return "Bluetooth address + link key 1"; + case CSR_PSKEY_LINK_KEY_BD_ADDR2: + return "Bluetooth address + link key 2"; + case CSR_PSKEY_LINK_KEY_BD_ADDR3: + return "Bluetooth address + link key 3"; + case CSR_PSKEY_LINK_KEY_BD_ADDR4: + return "Bluetooth address + link key 4"; + case CSR_PSKEY_LINK_KEY_BD_ADDR5: + return "Bluetooth address + link key 5"; + case CSR_PSKEY_LINK_KEY_BD_ADDR6: + return "Bluetooth address + link key 6"; + case CSR_PSKEY_LINK_KEY_BD_ADDR7: + return "Bluetooth address + link key 7"; + case CSR_PSKEY_LINK_KEY_BD_ADDR8: + return "Bluetooth address + link key 8"; + case CSR_PSKEY_LINK_KEY_BD_ADDR9: + return "Bluetooth address + link key 9"; + case CSR_PSKEY_LINK_KEY_BD_ADDR10: + return "Bluetooth address + link key 10"; + case CSR_PSKEY_LINK_KEY_BD_ADDR11: + return "Bluetooth address + link key 11"; + case CSR_PSKEY_LINK_KEY_BD_ADDR12: + return "Bluetooth address + link key 12"; + case CSR_PSKEY_LINK_KEY_BD_ADDR13: + return "Bluetooth address + link key 13"; + case CSR_PSKEY_LINK_KEY_BD_ADDR14: + return "Bluetooth address + link key 14"; + case CSR_PSKEY_LINK_KEY_BD_ADDR15: + return "Bluetooth address + link key 15"; + case CSR_PSKEY_ENC_KEY_LMIN: + return "Minimum encryption key length"; + case CSR_PSKEY_ENC_KEY_LMAX: + return "Maximum encryption key length"; + case CSR_PSKEY_LOCAL_SUPPORTED_FEATURES: + return "Local supported features block"; + case CSR_PSKEY_LM_USE_UNIT_KEY: + return "Allow use of unit key for authentication?"; + case CSR_PSKEY_HCI_NOP_DISABLE: + return "Disable the HCI Command_Status event on boot"; + case CSR_PSKEY_LM_MAX_EVENT_FILTERS: + return "Maximum number of event filters"; + case CSR_PSKEY_LM_USE_ENC_MODE_BROADCAST: + return "Allow LM to use enc_mode=2"; + case CSR_PSKEY_LM_TEST_SEND_ACCEPTED_TWICE: + return "LM sends two LMP_accepted messages in test mode"; + case CSR_PSKEY_LM_MAX_PAGE_HOLD_TIME: + return "Maximum time we hold a device around page"; + case CSR_PSKEY_AFH_ADAPTATION_RESPONSE_TIME: + return "LM period for AFH adaption"; + case CSR_PSKEY_AFH_OPTIONS: + return "Options to configure AFH"; + case CSR_PSKEY_AFH_RSSI_RUN_PERIOD: + return "AFH RSSI reading period"; + case CSR_PSKEY_AFH_REENABLE_CHANNEL_TIME: + return "AFH good channel adding time"; + case CSR_PSKEY_NO_DROP_ON_ACR_MS_FAIL: + return "Complete link if acr barge-in role switch refused"; + case CSR_PSKEY_MAX_PRIVATE_KEYS: + return "Max private link keys stored"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR0: + return "Bluetooth address + link key 0"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR1: + return "Bluetooth address + link key 1"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR2: + return "Bluetooth address + link key 2"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR3: + return "Bluetooth address + link key 3"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR4: + return "Bluetooth address + link key 4"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR5: + return "Bluetooth address + link key 5"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR6: + return "Bluetooth address + link key 6"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR7: + return "Bluetooth address + link key 7"; + case CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS: + return "Local supported commands"; + case CSR_PSKEY_LM_MAX_ABSENCE_INDEX: + return "Maximum absence index allowed"; + case CSR_PSKEY_DEVICE_NAME: + return "Local device's \"user friendly\" name"; + case CSR_PSKEY_AFH_RSSI_THRESHOLD: + return "AFH RSSI threshold"; + case CSR_PSKEY_LM_CASUAL_SCAN_INTERVAL: + return "Scan interval in slots for casual scanning"; + case CSR_PSKEY_AFH_MIN_MAP_CHANGE: + return "The minimum amount to change an AFH map by"; + case CSR_PSKEY_AFH_RSSI_LP_RUN_PERIOD: + return "AFH RSSI reading period when in low power mode"; + case CSR_PSKEY_HCI_LMP_LOCAL_VERSION: + return "The HCI and LMP version reported locally"; + case CSR_PSKEY_LMP_REMOTE_VERSION: + return "The LMP version reported remotely"; + case CSR_PSKEY_HOLD_ERROR_MESSAGE_NUMBER: + return "Maximum number of queued HCI Hardware Error Events"; + case CSR_PSKEY_DFU_ATTRIBUTES: + return "DFU attributes"; + case CSR_PSKEY_DFU_DETACH_TO: + return "DFU detach timeout"; + case CSR_PSKEY_DFU_TRANSFER_SIZE: + return "DFU transfer size"; + case CSR_PSKEY_DFU_ENABLE: + return "DFU enable"; + case CSR_PSKEY_DFU_LIN_REG_ENABLE: + return "Linear Regulator enabled at boot in DFU mode"; + case CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_MSB: + return "DFU encryption VM application public key MSB"; + case CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_LSB: + return "DFU encryption VM application public key LSB"; + case CSR_PSKEY_DFUENC_VMAPP_PK_M_DASH: + return "DFU encryption VM application M dash"; + case CSR_PSKEY_DFUENC_VMAPP_PK_R2N_MSB: + return "DFU encryption VM application public key R2N MSB"; + case CSR_PSKEY_DFUENC_VMAPP_PK_R2N_LSB: + return "DFU encryption VM application public key R2N LSB"; + case CSR_PSKEY_BCSP_LM_PS_BLOCK: + return "BCSP link establishment block"; + case CSR_PSKEY_HOSTIO_FC_PS_BLOCK: + return "HCI flow control block"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO0: + return "Host transport channel 0 settings (BCSP ACK)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO1: + return "Host transport channel 1 settings (BCSP-LE)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO2: + return "Host transport channel 2 settings (BCCMD)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO3: + return "Host transport channel 3 settings (HQ)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO4: + return "Host transport channel 4 settings (DM)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO5: + return "Host transport channel 5 settings (HCI CMD/EVT)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO6: + return "Host transport channel 6 settings (HCI ACL)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO7: + return "Host transport channel 7 settings (HCI SCO)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO8: + return "Host transport channel 8 settings (L2CAP)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO9: + return "Host transport channel 9 settings (RFCOMM)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO10: + return "Host transport channel 10 settings (SDP)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO11: + return "Host transport channel 11 settings (TEST)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO12: + return "Host transport channel 12 settings (DFU)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO13: + return "Host transport channel 13 settings (VM)"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO14: + return "Host transport channel 14 settings"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO15: + return "Host transport channel 15 settings"; + case CSR_PSKEY_HOSTIO_UART_RESET_TIMEOUT: + return "UART reset counter timeout"; + case CSR_PSKEY_HOSTIO_USE_HCI_EXTN: + return "Use hci_extn to route non-hci channels"; + case CSR_PSKEY_HOSTIO_USE_HCI_EXTN_CCFC: + return "Use command-complete flow control for hci_extn"; + case CSR_PSKEY_HOSTIO_HCI_EXTN_PAYLOAD_SIZE: + return "Maximum hci_extn payload size"; + case CSR_PSKEY_BCSP_LM_CNF_CNT_LIMIT: + return "BCSP link establishment conf message count"; + case CSR_PSKEY_HOSTIO_MAP_SCO_PCM: + return "Map SCO over PCM"; + case CSR_PSKEY_HOSTIO_AWKWARD_PCM_SYNC: + return "PCM interface synchronisation is difficult"; + case CSR_PSKEY_HOSTIO_BREAK_POLL_PERIOD: + return "Break poll period (microseconds)"; + case CSR_PSKEY_HOSTIO_MIN_UART_HCI_SCO_SIZE: + return "Minimum SCO packet size sent to host over UART HCI"; + case CSR_PSKEY_HOSTIO_MAP_SCO_CODEC: + return "Map SCO over the built-in codec"; + case CSR_PSKEY_PCM_CVSD_TX_HI_FREQ_BOOST: + return "High frequency boost for PCM when transmitting CVSD"; + case CSR_PSKEY_PCM_CVSD_RX_HI_FREQ_BOOST: + return "High frequency boost for PCM when receiving CVSD"; + case CSR_PSKEY_PCM_CONFIG32: + return "PCM interface settings bitfields"; + case CSR_PSKEY_USE_OLD_BCSP_LE: + return "Use the old version of BCSP link establishment"; + case CSR_PSKEY_PCM_CVSD_USE_NEW_FILTER: + return "CVSD uses the new filter if available"; + case CSR_PSKEY_PCM_FORMAT: + return "PCM data format"; + case CSR_PSKEY_CODEC_OUT_GAIN: + return "Audio output gain when using built-in codec"; + case CSR_PSKEY_CODEC_IN_GAIN: + return "Audio input gain when using built-in codec"; + case CSR_PSKEY_CODEC_PIO: + return "PIO to enable when built-in codec is enabled"; + case CSR_PSKEY_PCM_LOW_JITTER_CONFIG: + return "PCM interface settings for low jitter master mode"; + case CSR_PSKEY_HOSTIO_SCO_PCM_THRESHOLDS: + return "Thresholds for SCO PCM buffers"; + case CSR_PSKEY_HOSTIO_SCO_HCI_THRESHOLDS: + return "Thresholds for SCO HCI buffers"; + case CSR_PSKEY_HOSTIO_MAP_SCO_PCM_SLOT: + return "Route SCO data to specified slot in pcm frame"; + case CSR_PSKEY_UART_BAUDRATE: + return "UART Baud rate"; + case CSR_PSKEY_UART_CONFIG_BCSP: + return "UART configuration when using BCSP"; + case CSR_PSKEY_UART_CONFIG_H4: + return "UART configuration when using H4"; + case CSR_PSKEY_UART_CONFIG_H5: + return "UART configuration when using H5"; + case CSR_PSKEY_UART_CONFIG_USR: + return "UART configuration when under VM control"; + case CSR_PSKEY_UART_TX_CRCS: + return "Use CRCs for BCSP or H5"; + case CSR_PSKEY_UART_ACK_TIMEOUT: + return "Acknowledgement timeout for BCSP and H5"; + case CSR_PSKEY_UART_TX_MAX_ATTEMPTS: + return "Max times to send reliable BCSP or H5 message"; + case CSR_PSKEY_UART_TX_WINDOW_SIZE: + return "Transmit window size for BCSP and H5"; + case CSR_PSKEY_UART_HOST_WAKE: + return "UART host wakeup"; + case CSR_PSKEY_HOSTIO_THROTTLE_TIMEOUT: + return "Host interface performance control."; + case CSR_PSKEY_PCM_ALWAYS_ENABLE: + return "PCM port is always enable when chip is running"; + case CSR_PSKEY_UART_HOST_WAKE_SIGNAL: + return "Signal to use for uart host wakeup protocol"; + case CSR_PSKEY_UART_CONFIG_H4DS: + return "UART configuration when using H4DS"; + case CSR_PSKEY_H4DS_WAKE_DURATION: + return "How long to spend waking the host when using H4DS"; + case CSR_PSKEY_H4DS_MAXWU: + return "Maximum number of H4DS Wake-Up messages to send"; + case CSR_PSKEY_H4DS_LE_TIMER_PERIOD: + return "H4DS Link Establishment Tsync and Tconf period"; + case CSR_PSKEY_H4DS_TWU_TIMER_PERIOD: + return "H4DS Twu timer period"; + case CSR_PSKEY_H4DS_UART_IDLE_TIMER_PERIOD: + return "H4DS Tuart_idle timer period"; + case CSR_PSKEY_ANA_FTRIM: + return "Crystal frequency trim"; + case CSR_PSKEY_WD_TIMEOUT: + return "Watchdog timeout (microseconds)"; + case CSR_PSKEY_WD_PERIOD: + return "Watchdog period (microseconds)"; + case CSR_PSKEY_HOST_INTERFACE: + return "Host interface"; + case CSR_PSKEY_HQ_HOST_TIMEOUT: + return "HQ host command timeout"; + case CSR_PSKEY_HQ_ACTIVE: + return "Enable host query task?"; + case CSR_PSKEY_BCCMD_SECURITY_ACTIVE: + return "Enable configuration security"; + case CSR_PSKEY_ANA_FREQ: + return "Crystal frequency"; + case CSR_PSKEY_PIO_PROTECT_MASK: + return "Access to PIO pins"; + case CSR_PSKEY_PMALLOC_SIZES: + return "pmalloc sizes array"; + case CSR_PSKEY_UART_BAUD_RATE: + return "UART Baud rate (pre 18)"; + case CSR_PSKEY_UART_CONFIG: + return "UART configuration bitfield"; + case CSR_PSKEY_STUB: + return "Stub"; + case CSR_PSKEY_TXRX_PIO_CONTROL: + return "TX and RX PIO control"; + case CSR_PSKEY_ANA_RX_LEVEL: + return "ANA_RX_LVL register initial value"; + case CSR_PSKEY_ANA_RX_FTRIM: + return "ANA_RX_FTRIM register initial value"; + case CSR_PSKEY_PSBC_DATA_VERSION: + return "Persistent store version"; + case CSR_PSKEY_PCM0_ATTENUATION: + return "Volume control on PCM channel 0"; + case CSR_PSKEY_LO_LVL_MAX: + return "Maximum value of LO level control register"; + case CSR_PSKEY_LO_ADC_AMPL_MIN: + return "Minimum value of the LO amplitude measured on the ADC"; + case CSR_PSKEY_LO_ADC_AMPL_MAX: + return "Maximum value of the LO amplitude measured on the ADC"; + case CSR_PSKEY_IQ_TRIM_CHANNEL: + return "IQ calibration channel"; + case CSR_PSKEY_IQ_TRIM_GAIN: + return "IQ calibration gain"; + case CSR_PSKEY_IQ_TRIM_ENABLE: + return "IQ calibration enable"; + case CSR_PSKEY_TX_OFFSET_HALF_MHZ: + return "Transmit offset"; + case CSR_PSKEY_GBL_MISC_ENABLES: + return "Global miscellaneous hardware enables"; + case CSR_PSKEY_UART_SLEEP_TIMEOUT: + return "Time in ms to deep sleep if nothing received"; + case CSR_PSKEY_DEEP_SLEEP_STATE: + return "Deep sleep state usage"; + case CSR_PSKEY_IQ_ENABLE_PHASE_TRIM: + return "IQ phase enable"; + case CSR_PSKEY_HCI_HANDLE_FREEZE_PERIOD: + return "Time for which HCI handle is frozen after link removal"; + case CSR_PSKEY_MAX_FROZEN_HCI_HANDLES: + return "Maximum number of frozen HCI handles"; + case CSR_PSKEY_PAGETABLE_DESTRUCTION_DELAY: + return "Delay from freezing buf handle to deleting page table"; + case CSR_PSKEY_IQ_TRIM_PIO_SETTINGS: + return "IQ PIO settings"; + case CSR_PSKEY_USE_EXTERNAL_CLOCK: + return "Device uses an external clock"; + case CSR_PSKEY_DEEP_SLEEP_WAKE_CTS: + return "Exit deep sleep on CTS line activity"; + case CSR_PSKEY_FC_HC2H_FLUSH_DELAY: + return "Delay from disconnect to flushing HC->H FC tokens"; + case CSR_PSKEY_RX_HIGHSIDE: + return "Disable the HIGHSIDE bit in ANA_CONFIG"; + case CSR_PSKEY_TX_PRE_LVL: + return "TX pre-amplifier level"; + case CSR_PSKEY_RX_SINGLE_ENDED: + return "RX single ended"; + case CSR_PSKEY_TX_FILTER_CONFIG: + return "TX filter configuration"; + case CSR_PSKEY_CLOCK_REQUEST_ENABLE: + return "External clock request enable"; + case CSR_PSKEY_RX_MIN_ATTEN: + return "Minimum attenuation allowed for receiver"; + case CSR_PSKEY_XTAL_TARGET_AMPLITUDE: + return "Crystal target amplitude"; + case CSR_PSKEY_PCM_MIN_CPU_CLOCK: + return "Minimum CPU clock speed with PCM port running"; + case CSR_PSKEY_HOST_INTERFACE_PIO_USB: + return "USB host interface selection PIO line"; + case CSR_PSKEY_CPU_IDLE_MODE: + return "CPU idle mode when radio is active"; + case CSR_PSKEY_DEEP_SLEEP_CLEAR_RTS: + return "Deep sleep clears the UART RTS line"; + case CSR_PSKEY_RF_RESONANCE_TRIM: + return "Frequency trim for IQ and LNA resonant circuits"; + case CSR_PSKEY_DEEP_SLEEP_PIO_WAKE: + return "PIO line to wake the chip from deep sleep"; + case CSR_PSKEY_DRAIN_BORE_TIMERS: + return "Energy consumption measurement settings"; + case CSR_PSKEY_DRAIN_TX_POWER_BASE: + return "Energy consumption measurement settings"; + case CSR_PSKEY_MODULE_ID: + return "Module serial number"; + case CSR_PSKEY_MODULE_DESIGN: + return "Module design ID"; + case CSR_PSKEY_MODULE_SECURITY_CODE: + return "Module security code"; + case CSR_PSKEY_VM_DISABLE: + return "VM disable"; + case CSR_PSKEY_MOD_MANUF0: + return "Module manufactuer data 0"; + case CSR_PSKEY_MOD_MANUF1: + return "Module manufactuer data 1"; + case CSR_PSKEY_MOD_MANUF2: + return "Module manufactuer data 2"; + case CSR_PSKEY_MOD_MANUF3: + return "Module manufactuer data 3"; + case CSR_PSKEY_MOD_MANUF4: + return "Module manufactuer data 4"; + case CSR_PSKEY_MOD_MANUF5: + return "Module manufactuer data 5"; + case CSR_PSKEY_MOD_MANUF6: + return "Module manufactuer data 6"; + case CSR_PSKEY_MOD_MANUF7: + return "Module manufactuer data 7"; + case CSR_PSKEY_MOD_MANUF8: + return "Module manufactuer data 8"; + case CSR_PSKEY_MOD_MANUF9: + return "Module manufactuer data 9"; + case CSR_PSKEY_DUT_VM_DISABLE: + return "VM disable when entering radiotest modes"; + case CSR_PSKEY_USR0: + return "User configuration data 0"; + case CSR_PSKEY_USR1: + return "User configuration data 1"; + case CSR_PSKEY_USR2: + return "User configuration data 2"; + case CSR_PSKEY_USR3: + return "User configuration data 3"; + case CSR_PSKEY_USR4: + return "User configuration data 4"; + case CSR_PSKEY_USR5: + return "User configuration data 5"; + case CSR_PSKEY_USR6: + return "User configuration data 6"; + case CSR_PSKEY_USR7: + return "User configuration data 7"; + case CSR_PSKEY_USR8: + return "User configuration data 8"; + case CSR_PSKEY_USR9: + return "User configuration data 9"; + case CSR_PSKEY_USR10: + return "User configuration data 10"; + case CSR_PSKEY_USR11: + return "User configuration data 11"; + case CSR_PSKEY_USR12: + return "User configuration data 12"; + case CSR_PSKEY_USR13: + return "User configuration data 13"; + case CSR_PSKEY_USR14: + return "User configuration data 14"; + case CSR_PSKEY_USR15: + return "User configuration data 15"; + case CSR_PSKEY_USR16: + return "User configuration data 16"; + case CSR_PSKEY_USR17: + return "User configuration data 17"; + case CSR_PSKEY_USR18: + return "User configuration data 18"; + case CSR_PSKEY_USR19: + return "User configuration data 19"; + case CSR_PSKEY_USR20: + return "User configuration data 20"; + case CSR_PSKEY_USR21: + return "User configuration data 21"; + case CSR_PSKEY_USR22: + return "User configuration data 22"; + case CSR_PSKEY_USR23: + return "User configuration data 23"; + case CSR_PSKEY_USR24: + return "User configuration data 24"; + case CSR_PSKEY_USR25: + return "User configuration data 25"; + case CSR_PSKEY_USR26: + return "User configuration data 26"; + case CSR_PSKEY_USR27: + return "User configuration data 27"; + case CSR_PSKEY_USR28: + return "User configuration data 28"; + case CSR_PSKEY_USR29: + return "User configuration data 29"; + case CSR_PSKEY_USR30: + return "User configuration data 30"; + case CSR_PSKEY_USR31: + return "User configuration data 31"; + case CSR_PSKEY_USR32: + return "User configuration data 32"; + case CSR_PSKEY_USR33: + return "User configuration data 33"; + case CSR_PSKEY_USR34: + return "User configuration data 34"; + case CSR_PSKEY_USR35: + return "User configuration data 35"; + case CSR_PSKEY_USR36: + return "User configuration data 36"; + case CSR_PSKEY_USR37: + return "User configuration data 37"; + case CSR_PSKEY_USR38: + return "User configuration data 38"; + case CSR_PSKEY_USR39: + return "User configuration data 39"; + case CSR_PSKEY_USR40: + return "User configuration data 40"; + case CSR_PSKEY_USR41: + return "User configuration data 41"; + case CSR_PSKEY_USR42: + return "User configuration data 42"; + case CSR_PSKEY_USR43: + return "User configuration data 43"; + case CSR_PSKEY_USR44: + return "User configuration data 44"; + case CSR_PSKEY_USR45: + return "User configuration data 45"; + case CSR_PSKEY_USR46: + return "User configuration data 46"; + case CSR_PSKEY_USR47: + return "User configuration data 47"; + case CSR_PSKEY_USR48: + return "User configuration data 48"; + case CSR_PSKEY_USR49: + return "User configuration data 49"; + case CSR_PSKEY_USB_VERSION: + return "USB specification version number"; + case CSR_PSKEY_USB_DEVICE_CLASS_CODES: + return "USB device class codes"; + case CSR_PSKEY_USB_VENDOR_ID: + return "USB vendor identifier"; + case CSR_PSKEY_USB_PRODUCT_ID: + return "USB product identifier"; + case CSR_PSKEY_USB_MANUF_STRING: + return "USB manufacturer string"; + case CSR_PSKEY_USB_PRODUCT_STRING: + return "USB product string"; + case CSR_PSKEY_USB_SERIAL_NUMBER_STRING: + return "USB serial number string"; + case CSR_PSKEY_USB_CONFIG_STRING: + return "USB configuration string"; + case CSR_PSKEY_USB_ATTRIBUTES: + return "USB attributes bitmap"; + case CSR_PSKEY_USB_MAX_POWER: + return "USB device maximum power consumption"; + case CSR_PSKEY_USB_BT_IF_CLASS_CODES: + return "USB Bluetooth interface class codes"; + case CSR_PSKEY_USB_LANGID: + return "USB language strings supported"; + case CSR_PSKEY_USB_DFU_CLASS_CODES: + return "USB DFU class codes block"; + case CSR_PSKEY_USB_DFU_PRODUCT_ID: + return "USB DFU product ID"; + case CSR_PSKEY_USB_PIO_DETACH: + return "USB detach/attach PIO line"; + case CSR_PSKEY_USB_PIO_WAKEUP: + return "USB wakeup PIO line"; + case CSR_PSKEY_USB_PIO_PULLUP: + return "USB D+ pullup PIO line"; + case CSR_PSKEY_USB_PIO_VBUS: + return "USB VBus detection PIO Line"; + case CSR_PSKEY_USB_PIO_WAKE_TIMEOUT: + return "Timeout for assertion of USB PIO wake signal"; + case CSR_PSKEY_USB_PIO_RESUME: + return "PIO signal used in place of bus resume"; + case CSR_PSKEY_USB_BT_SCO_IF_CLASS_CODES: + return "USB Bluetooth SCO interface class codes"; + case CSR_PSKEY_USB_SUSPEND_PIO_LEVEL: + return "USB PIO levels to set when suspended"; + case CSR_PSKEY_USB_SUSPEND_PIO_DIR: + return "USB PIO I/O directions to set when suspended"; + case CSR_PSKEY_USB_SUSPEND_PIO_MASK: + return "USB PIO lines to be set forcibly in suspend"; + case CSR_PSKEY_USB_ENDPOINT_0_MAX_PACKET_SIZE: + return "The maxmimum packet size for USB endpoint 0"; + case CSR_PSKEY_USB_CONFIG: + return "USB config params for new chips (>bc2)"; + case CSR_PSKEY_RADIOTEST_ATTEN_INIT: + return "Radio test initial attenuator"; + case CSR_PSKEY_RADIOTEST_FIRST_TRIM_TIME: + return "IQ first calibration period in test"; + case CSR_PSKEY_RADIOTEST_SUBSEQUENT_TRIM_TIME: + return "IQ subsequent calibration period in test"; + case CSR_PSKEY_RADIOTEST_LO_LVL_TRIM_ENABLE: + return "LO_LVL calibration enable"; + case CSR_PSKEY_RADIOTEST_DISABLE_MODULATION: + return "Disable modulation during radiotest transmissions"; + case CSR_PSKEY_RFCOMM_FCON_THRESHOLD: + return "RFCOMM aggregate flow control on threshold"; + case CSR_PSKEY_RFCOMM_FCOFF_THRESHOLD: + return "RFCOMM aggregate flow control off threshold"; + case CSR_PSKEY_IPV6_STATIC_ADDR: + return "Static IPv6 address"; + case CSR_PSKEY_IPV4_STATIC_ADDR: + return "Static IPv4 address"; + case CSR_PSKEY_IPV6_STATIC_PREFIX_LEN: + return "Static IPv6 prefix length"; + case CSR_PSKEY_IPV6_STATIC_ROUTER_ADDR: + return "Static IPv6 router address"; + case CSR_PSKEY_IPV4_STATIC_SUBNET_MASK: + return "Static IPv4 subnet mask"; + case CSR_PSKEY_IPV4_STATIC_ROUTER_ADDR: + return "Static IPv4 router address"; + case CSR_PSKEY_MDNS_NAME: + return "Multicast DNS name"; + case CSR_PSKEY_FIXED_PIN: + return "Fixed PIN"; + case CSR_PSKEY_MDNS_PORT: + return "Multicast DNS port"; + case CSR_PSKEY_MDNS_TTL: + return "Multicast DNS TTL"; + case CSR_PSKEY_MDNS_IPV4_ADDR: + return "Multicast DNS IPv4 address"; + case CSR_PSKEY_ARP_CACHE_TIMEOUT: + return "ARP cache timeout"; + case CSR_PSKEY_HFP_POWER_TABLE: + return "HFP power table"; + case CSR_PSKEY_DRAIN_BORE_TIMER_COUNTERS: + return "Energy consumption estimation timer counters"; + case CSR_PSKEY_DRAIN_BORE_COUNTERS: + return "Energy consumption estimation counters"; + case CSR_PSKEY_LOOP_FILTER_TRIM: + return "Trim value to optimise loop filter"; + case CSR_PSKEY_DRAIN_BORE_CURRENT_PEAK: + return "Energy consumption estimation current peak"; + case CSR_PSKEY_VM_E2_CACHE_LIMIT: + return "Maximum RAM for caching EEPROM VM application"; + case CSR_PSKEY_FORCE_16MHZ_REF_PIO: + return "PIO line to force 16 MHz reference to be assumed"; + case CSR_PSKEY_CDMA_LO_REF_LIMITS: + return "Local oscillator frequency reference limits for CDMA"; + case CSR_PSKEY_CDMA_LO_ERROR_LIMITS: + return "Local oscillator frequency error limits for CDMA"; + case CSR_PSKEY_CLOCK_STARTUP_DELAY: + return "Clock startup delay in milliseconds"; + case CSR_PSKEY_DEEP_SLEEP_CORRECTION_FACTOR: + return "Deep sleep clock correction factor"; + case CSR_PSKEY_TEMPERATURE_CALIBRATION: + return "Temperature in deg C for a given internal setting"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA: + return "Temperature for given internal PA adjustment"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL: + return "Temperature for a given TX_PRE_LVL adjustment"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB: + return "Temperature for a given TX_BB adjustment"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_ANA_FTRIM: + return "Temperature for given crystal trim adjustment"; + case CSR_PSKEY_TEST_DELTA_OFFSET: + return "Frequency offset applied to synthesiser in test mode"; + case CSR_PSKEY_RX_DYNAMIC_LVL_OFFSET: + return "Receiver dynamic level offset depending on channel"; + case CSR_PSKEY_TEST_FORCE_OFFSET: + return "Force use of exact value in PSKEY_TEST_DELTA_OFFSET"; + case CSR_PSKEY_RF_TRAP_BAD_DIVISION_RATIOS: + return "Trap bad division ratios in radio frequency tables"; + case CSR_PSKEY_RADIOTEST_CDMA_LO_REF_LIMITS: + return "LO frequency reference limits for CDMA in radiotest"; + case CSR_PSKEY_INITIAL_BOOTMODE: + return "Initial device bootmode"; + case CSR_PSKEY_ONCHIP_HCI_CLIENT: + return "HCI traffic routed internally"; + case CSR_PSKEY_RX_ATTEN_BACKOFF: + return "Receiver attenuation back-off"; + case CSR_PSKEY_RX_ATTEN_UPDATE_RATE: + return "Receiver attenuation update rate"; + case CSR_PSKEY_SYNTH_TXRX_THRESHOLDS: + return "Local oscillator tuning voltage limits for tx and rx"; + case CSR_PSKEY_MIN_WAIT_STATES: + return "Flash wait state indicator"; + case CSR_PSKEY_RSSI_CORRECTION: + return "RSSI correction factor."; + case CSR_PSKEY_SCHED_THROTTLE_TIMEOUT: + return "Scheduler performance control."; + case CSR_PSKEY_DEEP_SLEEP_USE_EXTERNAL_CLOCK: + return "Deep sleep uses external 32 kHz clock source"; + case CSR_PSKEY_TRIM_RADIO_FILTERS: + return "Trim rx and tx radio filters if true."; + case CSR_PSKEY_TRANSMIT_OFFSET: + return "Transmit offset in units of 62.5 kHz"; + case CSR_PSKEY_USB_VM_CONTROL: + return "VM application will supply USB descriptors"; + case CSR_PSKEY_MR_ANA_RX_FTRIM: + return "Medium rate value for the ANA_RX_FTRIM register"; + case CSR_PSKEY_I2C_CONFIG: + return "I2C configuration"; + case CSR_PSKEY_IQ_LVL_RX: + return "IQ demand level for reception"; + case CSR_PSKEY_MR_TX_FILTER_CONFIG: + return "TX filter configuration used for enhanced data rate"; + case CSR_PSKEY_MR_TX_CONFIG2: + return "TX filter configuration used for enhanced data rate"; + case CSR_PSKEY_USB_DONT_RESET_BOOTMODE_ON_HOST_RESET: + return "Don't reset bootmode if USB host resets"; + case CSR_PSKEY_LC_USE_THROTTLING: + return "Adjust packet selection on packet error rate"; + case CSR_PSKEY_CHARGER_TRIM: + return "Trim value for the current charger"; + case CSR_PSKEY_CLOCK_REQUEST_FEATURES: + return "Clock request is tristated if enabled"; + case CSR_PSKEY_TRANSMIT_OFFSET_CLASS1: + return "Transmit offset / 62.5 kHz for class 1 radios"; + case CSR_PSKEY_TX_AVOID_PA_CLASS1_PIO: + return "PIO line asserted in class1 operation to avoid PA"; + case CSR_PSKEY_MR_PIO_CONFIG: + return "PIO line asserted in class1 operation to avoid PA"; + case CSR_PSKEY_UART_CONFIG2: + return "The UART Sampling point"; + case CSR_PSKEY_CLASS1_IQ_LVL: + return "IQ demand level for class 1 power level"; + case CSR_PSKEY_CLASS1_TX_CONFIG2: + return "TX filter configuration used for class 1 tx power"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1: + return "Temperature for given internal PA adjustment"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1: + return "Temperature for given internal PA adjustment"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR: + return "Temperature adjustment for TX_PRE_LVL in EDR"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER: + return "Temperature for a given TX_BB in EDR header"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD: + return "Temperature for a given TX_BB in EDR payload"; + case CSR_PSKEY_RX_MR_EQ_TAPS: + return "Adjust receiver configuration for EDR"; + case CSR_PSKEY_TX_PRE_LVL_CLASS1: + return "TX pre-amplifier level in class 1 operation"; + case CSR_PSKEY_ANALOGUE_ATTENUATOR: + return "TX analogue attenuator setting"; + case CSR_PSKEY_MR_RX_FILTER_TRIM: + return "Trim for receiver used in EDR."; + case CSR_PSKEY_MR_RX_FILTER_RESPONSE: + return "Filter response for receiver used in EDR."; + case CSR_PSKEY_PIO_WAKEUP_STATE: + return "PIO deep sleep wake up state "; + case CSR_PSKEY_MR_TX_IF_ATTEN_OFF_TEMP: + return "TX IF atten off temperature when using EDR."; + case CSR_PSKEY_LO_DIV_LATCH_BYPASS: + return "Bypass latch for LO dividers"; + case CSR_PSKEY_LO_VCO_STANDBY: + return "Use standby mode for the LO VCO"; + case CSR_PSKEY_SLOW_CLOCK_FILTER_SHIFT: + return "Slow clock sampling filter constant"; + case CSR_PSKEY_SLOW_CLOCK_FILTER_DIVIDER: + return "Slow clock filter fractional threshold"; + case CSR_PSKEY_USB_ATTRIBUTES_POWER: + return "USB self powered"; + case CSR_PSKEY_USB_ATTRIBUTES_WAKEUP: + return "USB responds to wake-up"; + case CSR_PSKEY_DFU_ATTRIBUTES_MANIFESTATION_TOLERANT: + return "DFU manifestation tolerant"; + case CSR_PSKEY_DFU_ATTRIBUTES_CAN_UPLOAD: + return "DFU can upload"; + case CSR_PSKEY_DFU_ATTRIBUTES_CAN_DOWNLOAD: + return "DFU can download"; + case CSR_PSKEY_UART_CONFIG_STOP_BITS: + return "UART: stop bits"; + case CSR_PSKEY_UART_CONFIG_PARITY_BIT: + return "UART: parity bit"; + case CSR_PSKEY_UART_CONFIG_FLOW_CTRL_EN: + return "UART: hardware flow control"; + case CSR_PSKEY_UART_CONFIG_RTS_AUTO_EN: + return "UART: RTS auto-enabled"; + case CSR_PSKEY_UART_CONFIG_RTS: + return "UART: RTS asserted"; + case CSR_PSKEY_UART_CONFIG_TX_ZERO_EN: + return "UART: TX zero enable"; + case CSR_PSKEY_UART_CONFIG_NON_BCSP_EN: + return "UART: enable BCSP-specific hardware"; + case CSR_PSKEY_UART_CONFIG_RX_RATE_DELAY: + return "UART: RX rate delay"; + case CSR_PSKEY_UART_SEQ_TIMEOUT: + return "UART: BCSP ack timeout"; + case CSR_PSKEY_UART_SEQ_RETRIES: + return "UART: retry limit in sequencing layer"; + case CSR_PSKEY_UART_SEQ_WINSIZE: + return "UART: BCSP transmit window size"; + case CSR_PSKEY_UART_USE_CRC_ON_TX: + return "UART: use BCSP CRCs"; + case CSR_PSKEY_UART_HOST_INITIAL_STATE: + return "UART: initial host state"; + case CSR_PSKEY_UART_HOST_ATTENTION_SPAN: + return "UART: host attention span"; + case CSR_PSKEY_UART_HOST_WAKEUP_TIME: + return "UART: host wakeup time"; + case CSR_PSKEY_UART_HOST_WAKEUP_WAIT: + return "UART: host wakeup wait"; + case CSR_PSKEY_BCSP_LM_MODE: + return "BCSP link establishment mode"; + case CSR_PSKEY_BCSP_LM_SYNC_RETRIES: + return "BCSP link establishment sync retries"; + case CSR_PSKEY_BCSP_LM_TSHY: + return "BCSP link establishment Tshy"; + case CSR_PSKEY_UART_DFU_CONFIG_STOP_BITS: + return "DFU mode UART: stop bits"; + case CSR_PSKEY_UART_DFU_CONFIG_PARITY_BIT: + return "DFU mode UART: parity bit"; + case CSR_PSKEY_UART_DFU_CONFIG_FLOW_CTRL_EN: + return "DFU mode UART: hardware flow control"; + case CSR_PSKEY_UART_DFU_CONFIG_RTS_AUTO_EN: + return "DFU mode UART: RTS auto-enabled"; + case CSR_PSKEY_UART_DFU_CONFIG_RTS: + return "DFU mode UART: RTS asserted"; + case CSR_PSKEY_UART_DFU_CONFIG_TX_ZERO_EN: + return "DFU mode UART: TX zero enable"; + case CSR_PSKEY_UART_DFU_CONFIG_NON_BCSP_EN: + return "DFU mode UART: enable BCSP-specific hardware"; + case CSR_PSKEY_UART_DFU_CONFIG_RX_RATE_DELAY: + return "DFU mode UART: RX rate delay"; + case CSR_PSKEY_AMUX_AIO0: + return "Multiplexer for AIO 0"; + case CSR_PSKEY_AMUX_AIO1: + return "Multiplexer for AIO 1"; + case CSR_PSKEY_AMUX_AIO2: + return "Multiplexer for AIO 2"; + case CSR_PSKEY_AMUX_AIO3: + return "Multiplexer for AIO 3"; + case CSR_PSKEY_LOCAL_NAME_SIMPLIFIED: + return "Local Name (simplified)"; + case CSR_PSKEY_EXTENDED_STUB: + return "Extended stub"; + default: + return "Unknown"; + } +} + +char *csr_pskeytoval(uint16_t pskey) +{ + switch (pskey) { + case CSR_PSKEY_BDADDR: + return "BDADDR"; + case CSR_PSKEY_COUNTRYCODE: + return "COUNTRYCODE"; + case CSR_PSKEY_CLASSOFDEVICE: + return "CLASSOFDEVICE"; + case CSR_PSKEY_DEVICE_DRIFT: + return "DEVICE_DRIFT"; + case CSR_PSKEY_DEVICE_JITTER: + return "DEVICE_JITTER"; + case CSR_PSKEY_MAX_ACLS: + return "MAX_ACLS"; + case CSR_PSKEY_MAX_SCOS: + return "MAX_SCOS"; + case CSR_PSKEY_MAX_REMOTE_MASTERS: + return "MAX_REMOTE_MASTERS"; + case CSR_PSKEY_ENABLE_MASTERY_WITH_SLAVERY: + return "ENABLE_MASTERY_WITH_SLAVERY"; + case CSR_PSKEY_H_HC_FC_MAX_ACL_PKT_LEN: + return "H_HC_FC_MAX_ACL_PKT_LEN"; + case CSR_PSKEY_H_HC_FC_MAX_SCO_PKT_LEN: + return "H_HC_FC_MAX_SCO_PKT_LEN"; + case CSR_PSKEY_H_HC_FC_MAX_ACL_PKTS: + return "H_HC_FC_MAX_ACL_PKTS"; + case CSR_PSKEY_H_HC_FC_MAX_SCO_PKTS: + return "H_HC_FC_MAX_SCO_PKTS"; + case CSR_PSKEY_LC_FC_BUFFER_LOW_WATER_MARK: + return "LC_FC_BUFFER_LOW_WATER_MARK"; + case CSR_PSKEY_LC_MAX_TX_POWER: + return "LC_MAX_TX_POWER"; + case CSR_PSKEY_TX_GAIN_RAMP: + return "TX_GAIN_RAMP"; + case CSR_PSKEY_LC_POWER_TABLE: + return "LC_POWER_TABLE"; + case CSR_PSKEY_LC_PEER_POWER_PERIOD: + return "LC_PEER_POWER_PERIOD"; + case CSR_PSKEY_LC_FC_POOLS_LOW_WATER_MARK: + return "LC_FC_POOLS_LOW_WATER_MARK"; + case CSR_PSKEY_LC_DEFAULT_TX_POWER: + return "LC_DEFAULT_TX_POWER"; + case CSR_PSKEY_LC_RSSI_GOLDEN_RANGE: + return "LC_RSSI_GOLDEN_RANGE"; + case CSR_PSKEY_LC_COMBO_DISABLE_PIO_MASK: + return "LC_COMBO_DISABLE_PIO_MASK"; + case CSR_PSKEY_LC_COMBO_PRIORITY_PIO_MASK: + return "LC_COMBO_PRIORITY_PIO_MASK"; + case CSR_PSKEY_LC_COMBO_DOT11_CHANNEL_PIO_BASE: + return "LC_COMBO_DOT11_CHANNEL_PIO_BASE"; + case CSR_PSKEY_LC_COMBO_DOT11_BLOCK_CHANNELS: + return "LC_COMBO_DOT11_BLOCK_CHANNELS"; + case CSR_PSKEY_LC_MAX_TX_POWER_NO_RSSI: + return "LC_MAX_TX_POWER_NO_RSSI"; + case CSR_PSKEY_LC_CONNECTION_RX_WINDOW: + return "LC_CONNECTION_RX_WINDOW"; + case CSR_PSKEY_LC_COMBO_DOT11_TX_PROTECTION_MODE: + return "LC_COMBO_DOT11_TX_PROTECTION_MODE"; + case CSR_PSKEY_LC_ENHANCED_POWER_TABLE: + return "LC_ENHANCED_POWER_TABLE"; + case CSR_PSKEY_LC_WIDEBAND_RSSI_CONFIG: + return "LC_WIDEBAND_RSSI_CONFIG"; + case CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_LEAD: + return "LC_COMBO_DOT11_PRIORITY_LEAD"; + case CSR_PSKEY_BT_CLOCK_INIT: + return "BT_CLOCK_INIT"; + case CSR_PSKEY_TX_MR_MOD_DELAY: + return "TX_MR_MOD_DELAY"; + case CSR_PSKEY_RX_MR_SYNC_TIMING: + return "RX_MR_SYNC_TIMING"; + case CSR_PSKEY_RX_MR_SYNC_CONFIG: + return "RX_MR_SYNC_CONFIG"; + case CSR_PSKEY_LC_LOST_SYNC_SLOTS: + return "LC_LOST_SYNC_SLOTS"; + case CSR_PSKEY_RX_MR_SAMP_CONFIG: + return "RX_MR_SAMP_CONFIG"; + case CSR_PSKEY_AGC_HYST_LEVELS: + return "AGC_HYST_LEVELS"; + case CSR_PSKEY_RX_LEVEL_LOW_SIGNAL: + return "RX_LEVEL_LOW_SIGNAL"; + case CSR_PSKEY_AGC_IQ_LVL_VALUES: + return "AGC_IQ_LVL_VALUES"; + case CSR_PSKEY_MR_FTRIM_OFFSET_12DB: + return "MR_FTRIM_OFFSET_12DB"; + case CSR_PSKEY_MR_FTRIM_OFFSET_6DB: + return "MR_FTRIM_OFFSET_6DB"; + case CSR_PSKEY_NO_CAL_ON_BOOT: + return "NO_CAL_ON_BOOT"; + case CSR_PSKEY_RSSI_HI_TARGET: + return "RSSI_HI_TARGET"; + case CSR_PSKEY_PREFERRED_MIN_ATTENUATION: + return "PREFERRED_MIN_ATTENUATION"; + case CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_OVERRIDE: + return "LC_COMBO_DOT11_PRIORITY_OVERRIDE"; + case CSR_PSKEY_LC_MULTISLOT_HOLDOFF: + return "LC_MULTISLOT_HOLDOFF"; + case CSR_PSKEY_FREE_KEY_PIGEON_HOLE: + return "FREE_KEY_PIGEON_HOLE"; + case CSR_PSKEY_LINK_KEY_BD_ADDR0: + return "LINK_KEY_BD_ADDR0"; + case CSR_PSKEY_LINK_KEY_BD_ADDR1: + return "LINK_KEY_BD_ADDR1"; + case CSR_PSKEY_LINK_KEY_BD_ADDR2: + return "LINK_KEY_BD_ADDR2"; + case CSR_PSKEY_LINK_KEY_BD_ADDR3: + return "LINK_KEY_BD_ADDR3"; + case CSR_PSKEY_LINK_KEY_BD_ADDR4: + return "LINK_KEY_BD_ADDR4"; + case CSR_PSKEY_LINK_KEY_BD_ADDR5: + return "LINK_KEY_BD_ADDR5"; + case CSR_PSKEY_LINK_KEY_BD_ADDR6: + return "LINK_KEY_BD_ADDR6"; + case CSR_PSKEY_LINK_KEY_BD_ADDR7: + return "LINK_KEY_BD_ADDR7"; + case CSR_PSKEY_LINK_KEY_BD_ADDR8: + return "LINK_KEY_BD_ADDR8"; + case CSR_PSKEY_LINK_KEY_BD_ADDR9: + return "LINK_KEY_BD_ADDR9"; + case CSR_PSKEY_LINK_KEY_BD_ADDR10: + return "LINK_KEY_BD_ADDR10"; + case CSR_PSKEY_LINK_KEY_BD_ADDR11: + return "LINK_KEY_BD_ADDR11"; + case CSR_PSKEY_LINK_KEY_BD_ADDR12: + return "LINK_KEY_BD_ADDR12"; + case CSR_PSKEY_LINK_KEY_BD_ADDR13: + return "LINK_KEY_BD_ADDR13"; + case CSR_PSKEY_LINK_KEY_BD_ADDR14: + return "LINK_KEY_BD_ADDR14"; + case CSR_PSKEY_LINK_KEY_BD_ADDR15: + return "LINK_KEY_BD_ADDR15"; + case CSR_PSKEY_ENC_KEY_LMIN: + return "ENC_KEY_LMIN"; + case CSR_PSKEY_ENC_KEY_LMAX: + return "ENC_KEY_LMAX"; + case CSR_PSKEY_LOCAL_SUPPORTED_FEATURES: + return "LOCAL_SUPPORTED_FEATURES"; + case CSR_PSKEY_LM_USE_UNIT_KEY: + return "LM_USE_UNIT_KEY"; + case CSR_PSKEY_HCI_NOP_DISABLE: + return "HCI_NOP_DISABLE"; + case CSR_PSKEY_LM_MAX_EVENT_FILTERS: + return "LM_MAX_EVENT_FILTERS"; + case CSR_PSKEY_LM_USE_ENC_MODE_BROADCAST: + return "LM_USE_ENC_MODE_BROADCAST"; + case CSR_PSKEY_LM_TEST_SEND_ACCEPTED_TWICE: + return "LM_TEST_SEND_ACCEPTED_TWICE"; + case CSR_PSKEY_LM_MAX_PAGE_HOLD_TIME: + return "LM_MAX_PAGE_HOLD_TIME"; + case CSR_PSKEY_AFH_ADAPTATION_RESPONSE_TIME: + return "AFH_ADAPTATION_RESPONSE_TIME"; + case CSR_PSKEY_AFH_OPTIONS: + return "AFH_OPTIONS"; + case CSR_PSKEY_AFH_RSSI_RUN_PERIOD: + return "AFH_RSSI_RUN_PERIOD"; + case CSR_PSKEY_AFH_REENABLE_CHANNEL_TIME: + return "AFH_REENABLE_CHANNEL_TIME"; + case CSR_PSKEY_NO_DROP_ON_ACR_MS_FAIL: + return "NO_DROP_ON_ACR_MS_FAIL"; + case CSR_PSKEY_MAX_PRIVATE_KEYS: + return "MAX_PRIVATE_KEYS"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR0: + return "PRIVATE_LINK_KEY_BD_ADDR0"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR1: + return "PRIVATE_LINK_KEY_BD_ADDR1"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR2: + return "PRIVATE_LINK_KEY_BD_ADDR2"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR3: + return "PRIVATE_LINK_KEY_BD_ADDR3"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR4: + return "PRIVATE_LINK_KEY_BD_ADDR4"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR5: + return "PRIVATE_LINK_KEY_BD_ADDR5"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR6: + return "PRIVATE_LINK_KEY_BD_ADDR6"; + case CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR7: + return "PRIVATE_LINK_KEY_BD_ADDR7"; + case CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS: + return "LOCAL_SUPPORTED_COMMANDS"; + case CSR_PSKEY_LM_MAX_ABSENCE_INDEX: + return "LM_MAX_ABSENCE_INDEX"; + case CSR_PSKEY_DEVICE_NAME: + return "DEVICE_NAME"; + case CSR_PSKEY_AFH_RSSI_THRESHOLD: + return "AFH_RSSI_THRESHOLD"; + case CSR_PSKEY_LM_CASUAL_SCAN_INTERVAL: + return "LM_CASUAL_SCAN_INTERVAL"; + case CSR_PSKEY_AFH_MIN_MAP_CHANGE: + return "AFH_MIN_MAP_CHANGE"; + case CSR_PSKEY_AFH_RSSI_LP_RUN_PERIOD: + return "AFH_RSSI_LP_RUN_PERIOD"; + case CSR_PSKEY_HCI_LMP_LOCAL_VERSION: + return "HCI_LMP_LOCAL_VERSION"; + case CSR_PSKEY_LMP_REMOTE_VERSION: + return "LMP_REMOTE_VERSION"; + case CSR_PSKEY_HOLD_ERROR_MESSAGE_NUMBER: + return "HOLD_ERROR_MESSAGE_NUMBER"; + case CSR_PSKEY_DFU_ATTRIBUTES: + return "DFU_ATTRIBUTES"; + case CSR_PSKEY_DFU_DETACH_TO: + return "DFU_DETACH_TO"; + case CSR_PSKEY_DFU_TRANSFER_SIZE: + return "DFU_TRANSFER_SIZE"; + case CSR_PSKEY_DFU_ENABLE: + return "DFU_ENABLE"; + case CSR_PSKEY_DFU_LIN_REG_ENABLE: + return "DFU_LIN_REG_ENABLE"; + case CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_MSB: + return "DFUENC_VMAPP_PK_MODULUS_MSB"; + case CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_LSB: + return "DFUENC_VMAPP_PK_MODULUS_LSB"; + case CSR_PSKEY_DFUENC_VMAPP_PK_M_DASH: + return "DFUENC_VMAPP_PK_M_DASH"; + case CSR_PSKEY_DFUENC_VMAPP_PK_R2N_MSB: + return "DFUENC_VMAPP_PK_R2N_MSB"; + case CSR_PSKEY_DFUENC_VMAPP_PK_R2N_LSB: + return "DFUENC_VMAPP_PK_R2N_LSB"; + case CSR_PSKEY_BCSP_LM_PS_BLOCK: + return "BCSP_LM_PS_BLOCK"; + case CSR_PSKEY_HOSTIO_FC_PS_BLOCK: + return "HOSTIO_FC_PS_BLOCK"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO0: + return "HOSTIO_PROTOCOL_INFO0"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO1: + return "HOSTIO_PROTOCOL_INFO1"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO2: + return "HOSTIO_PROTOCOL_INFO2"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO3: + return "HOSTIO_PROTOCOL_INFO3"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO4: + return "HOSTIO_PROTOCOL_INFO4"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO5: + return "HOSTIO_PROTOCOL_INFO5"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO6: + return "HOSTIO_PROTOCOL_INFO6"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO7: + return "HOSTIO_PROTOCOL_INFO7"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO8: + return "HOSTIO_PROTOCOL_INFO8"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO9: + return "HOSTIO_PROTOCOL_INFO9"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO10: + return "HOSTIO_PROTOCOL_INFO10"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO11: + return "HOSTIO_PROTOCOL_INFO11"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO12: + return "HOSTIO_PROTOCOL_INFO12"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO13: + return "HOSTIO_PROTOCOL_INFO13"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO14: + return "HOSTIO_PROTOCOL_INFO14"; + case CSR_PSKEY_HOSTIO_PROTOCOL_INFO15: + return "HOSTIO_PROTOCOL_INFO15"; + case CSR_PSKEY_HOSTIO_UART_RESET_TIMEOUT: + return "HOSTIO_UART_RESET_TIMEOUT"; + case CSR_PSKEY_HOSTIO_USE_HCI_EXTN: + return "HOSTIO_USE_HCI_EXTN"; + case CSR_PSKEY_HOSTIO_USE_HCI_EXTN_CCFC: + return "HOSTIO_USE_HCI_EXTN_CCFC"; + case CSR_PSKEY_HOSTIO_HCI_EXTN_PAYLOAD_SIZE: + return "HOSTIO_HCI_EXTN_PAYLOAD_SIZE"; + case CSR_PSKEY_BCSP_LM_CNF_CNT_LIMIT: + return "BCSP_LM_CNF_CNT_LIMIT"; + case CSR_PSKEY_HOSTIO_MAP_SCO_PCM: + return "HOSTIO_MAP_SCO_PCM"; + case CSR_PSKEY_HOSTIO_AWKWARD_PCM_SYNC: + return "HOSTIO_AWKWARD_PCM_SYNC"; + case CSR_PSKEY_HOSTIO_BREAK_POLL_PERIOD: + return "HOSTIO_BREAK_POLL_PERIOD"; + case CSR_PSKEY_HOSTIO_MIN_UART_HCI_SCO_SIZE: + return "HOSTIO_MIN_UART_HCI_SCO_SIZE"; + case CSR_PSKEY_HOSTIO_MAP_SCO_CODEC: + return "HOSTIO_MAP_SCO_CODEC"; + case CSR_PSKEY_PCM_CVSD_TX_HI_FREQ_BOOST: + return "PCM_CVSD_TX_HI_FREQ_BOOST"; + case CSR_PSKEY_PCM_CVSD_RX_HI_FREQ_BOOST: + return "PCM_CVSD_RX_HI_FREQ_BOOST"; + case CSR_PSKEY_PCM_CONFIG32: + return "PCM_CONFIG32"; + case CSR_PSKEY_USE_OLD_BCSP_LE: + return "USE_OLD_BCSP_LE"; + case CSR_PSKEY_PCM_CVSD_USE_NEW_FILTER: + return "PCM_CVSD_USE_NEW_FILTER"; + case CSR_PSKEY_PCM_FORMAT: + return "PCM_FORMAT"; + case CSR_PSKEY_CODEC_OUT_GAIN: + return "CODEC_OUT_GAIN"; + case CSR_PSKEY_CODEC_IN_GAIN: + return "CODEC_IN_GAIN"; + case CSR_PSKEY_CODEC_PIO: + return "CODEC_PIO"; + case CSR_PSKEY_PCM_LOW_JITTER_CONFIG: + return "PCM_LOW_JITTER_CONFIG"; + case CSR_PSKEY_HOSTIO_SCO_PCM_THRESHOLDS: + return "HOSTIO_SCO_PCM_THRESHOLDS"; + case CSR_PSKEY_HOSTIO_SCO_HCI_THRESHOLDS: + return "HOSTIO_SCO_HCI_THRESHOLDS"; + case CSR_PSKEY_HOSTIO_MAP_SCO_PCM_SLOT: + return "HOSTIO_MAP_SCO_PCM_SLOT"; + case CSR_PSKEY_UART_BAUDRATE: + return "UART_BAUDRATE"; + case CSR_PSKEY_UART_CONFIG_BCSP: + return "UART_CONFIG_BCSP"; + case CSR_PSKEY_UART_CONFIG_H4: + return "UART_CONFIG_H4"; + case CSR_PSKEY_UART_CONFIG_H5: + return "UART_CONFIG_H5"; + case CSR_PSKEY_UART_CONFIG_USR: + return "UART_CONFIG_USR"; + case CSR_PSKEY_UART_TX_CRCS: + return "UART_TX_CRCS"; + case CSR_PSKEY_UART_ACK_TIMEOUT: + return "UART_ACK_TIMEOUT"; + case CSR_PSKEY_UART_TX_MAX_ATTEMPTS: + return "UART_TX_MAX_ATTEMPTS"; + case CSR_PSKEY_UART_TX_WINDOW_SIZE: + return "UART_TX_WINDOW_SIZE"; + case CSR_PSKEY_UART_HOST_WAKE: + return "UART_HOST_WAKE"; + case CSR_PSKEY_HOSTIO_THROTTLE_TIMEOUT: + return "HOSTIO_THROTTLE_TIMEOUT"; + case CSR_PSKEY_PCM_ALWAYS_ENABLE: + return "PCM_ALWAYS_ENABLE"; + case CSR_PSKEY_UART_HOST_WAKE_SIGNAL: + return "UART_HOST_WAKE_SIGNAL"; + case CSR_PSKEY_UART_CONFIG_H4DS: + return "UART_CONFIG_H4DS"; + case CSR_PSKEY_H4DS_WAKE_DURATION: + return "H4DS_WAKE_DURATION"; + case CSR_PSKEY_H4DS_MAXWU: + return "H4DS_MAXWU"; + case CSR_PSKEY_H4DS_LE_TIMER_PERIOD: + return "H4DS_LE_TIMER_PERIOD"; + case CSR_PSKEY_H4DS_TWU_TIMER_PERIOD: + return "H4DS_TWU_TIMER_PERIOD"; + case CSR_PSKEY_H4DS_UART_IDLE_TIMER_PERIOD: + return "H4DS_UART_IDLE_TIMER_PERIOD"; + case CSR_PSKEY_ANA_FTRIM: + return "ANA_FTRIM"; + case CSR_PSKEY_WD_TIMEOUT: + return "WD_TIMEOUT"; + case CSR_PSKEY_WD_PERIOD: + return "WD_PERIOD"; + case CSR_PSKEY_HOST_INTERFACE: + return "HOST_INTERFACE"; + case CSR_PSKEY_HQ_HOST_TIMEOUT: + return "HQ_HOST_TIMEOUT"; + case CSR_PSKEY_HQ_ACTIVE: + return "HQ_ACTIVE"; + case CSR_PSKEY_BCCMD_SECURITY_ACTIVE: + return "BCCMD_SECURITY_ACTIVE"; + case CSR_PSKEY_ANA_FREQ: + return "ANA_FREQ"; + case CSR_PSKEY_PIO_PROTECT_MASK: + return "PIO_PROTECT_MASK"; + case CSR_PSKEY_PMALLOC_SIZES: + return "PMALLOC_SIZES"; + case CSR_PSKEY_UART_BAUD_RATE: + return "UART_BAUD_RATE"; + case CSR_PSKEY_UART_CONFIG: + return "UART_CONFIG"; + case CSR_PSKEY_STUB: + return "STUB"; + case CSR_PSKEY_TXRX_PIO_CONTROL: + return "TXRX_PIO_CONTROL"; + case CSR_PSKEY_ANA_RX_LEVEL: + return "ANA_RX_LEVEL"; + case CSR_PSKEY_ANA_RX_FTRIM: + return "ANA_RX_FTRIM"; + case CSR_PSKEY_PSBC_DATA_VERSION: + return "PSBC_DATA_VERSION"; + case CSR_PSKEY_PCM0_ATTENUATION: + return "PCM0_ATTENUATION"; + case CSR_PSKEY_LO_LVL_MAX: + return "LO_LVL_MAX"; + case CSR_PSKEY_LO_ADC_AMPL_MIN: + return "LO_ADC_AMPL_MIN"; + case CSR_PSKEY_LO_ADC_AMPL_MAX: + return "LO_ADC_AMPL_MAX"; + case CSR_PSKEY_IQ_TRIM_CHANNEL: + return "IQ_TRIM_CHANNEL"; + case CSR_PSKEY_IQ_TRIM_GAIN: + return "IQ_TRIM_GAIN"; + case CSR_PSKEY_IQ_TRIM_ENABLE: + return "IQ_TRIM_ENABLE"; + case CSR_PSKEY_TX_OFFSET_HALF_MHZ: + return "TX_OFFSET_HALF_MHZ"; + case CSR_PSKEY_GBL_MISC_ENABLES: + return "GBL_MISC_ENABLES"; + case CSR_PSKEY_UART_SLEEP_TIMEOUT: + return "UART_SLEEP_TIMEOUT"; + case CSR_PSKEY_DEEP_SLEEP_STATE: + return "DEEP_SLEEP_STATE"; + case CSR_PSKEY_IQ_ENABLE_PHASE_TRIM: + return "IQ_ENABLE_PHASE_TRIM"; + case CSR_PSKEY_HCI_HANDLE_FREEZE_PERIOD: + return "HCI_HANDLE_FREEZE_PERIOD"; + case CSR_PSKEY_MAX_FROZEN_HCI_HANDLES: + return "MAX_FROZEN_HCI_HANDLES"; + case CSR_PSKEY_PAGETABLE_DESTRUCTION_DELAY: + return "PAGETABLE_DESTRUCTION_DELAY"; + case CSR_PSKEY_IQ_TRIM_PIO_SETTINGS: + return "IQ_TRIM_PIO_SETTINGS"; + case CSR_PSKEY_USE_EXTERNAL_CLOCK: + return "USE_EXTERNAL_CLOCK"; + case CSR_PSKEY_DEEP_SLEEP_WAKE_CTS: + return "DEEP_SLEEP_WAKE_CTS"; + case CSR_PSKEY_FC_HC2H_FLUSH_DELAY: + return "FC_HC2H_FLUSH_DELAY"; + case CSR_PSKEY_RX_HIGHSIDE: + return "RX_HIGHSIDE"; + case CSR_PSKEY_TX_PRE_LVL: + return "TX_PRE_LVL"; + case CSR_PSKEY_RX_SINGLE_ENDED: + return "RX_SINGLE_ENDED"; + case CSR_PSKEY_TX_FILTER_CONFIG: + return "TX_FILTER_CONFIG"; + case CSR_PSKEY_CLOCK_REQUEST_ENABLE: + return "CLOCK_REQUEST_ENABLE"; + case CSR_PSKEY_RX_MIN_ATTEN: + return "RX_MIN_ATTEN"; + case CSR_PSKEY_XTAL_TARGET_AMPLITUDE: + return "XTAL_TARGET_AMPLITUDE"; + case CSR_PSKEY_PCM_MIN_CPU_CLOCK: + return "PCM_MIN_CPU_CLOCK"; + case CSR_PSKEY_HOST_INTERFACE_PIO_USB: + return "HOST_INTERFACE_PIO_USB"; + case CSR_PSKEY_CPU_IDLE_MODE: + return "CPU_IDLE_MODE"; + case CSR_PSKEY_DEEP_SLEEP_CLEAR_RTS: + return "DEEP_SLEEP_CLEAR_RTS"; + case CSR_PSKEY_RF_RESONANCE_TRIM: + return "RF_RESONANCE_TRIM"; + case CSR_PSKEY_DEEP_SLEEP_PIO_WAKE: + return "DEEP_SLEEP_PIO_WAKE"; + case CSR_PSKEY_DRAIN_BORE_TIMERS: + return "DRAIN_BORE_TIMERS"; + case CSR_PSKEY_DRAIN_TX_POWER_BASE: + return "DRAIN_TX_POWER_BASE"; + case CSR_PSKEY_MODULE_ID: + return "MODULE_ID"; + case CSR_PSKEY_MODULE_DESIGN: + return "MODULE_DESIGN"; + case CSR_PSKEY_MODULE_SECURITY_CODE: + return "MODULE_SECURITY_CODE"; + case CSR_PSKEY_VM_DISABLE: + return "VM_DISABLE"; + case CSR_PSKEY_MOD_MANUF0: + return "MOD_MANUF0"; + case CSR_PSKEY_MOD_MANUF1: + return "MOD_MANUF1"; + case CSR_PSKEY_MOD_MANUF2: + return "MOD_MANUF2"; + case CSR_PSKEY_MOD_MANUF3: + return "MOD_MANUF3"; + case CSR_PSKEY_MOD_MANUF4: + return "MOD_MANUF4"; + case CSR_PSKEY_MOD_MANUF5: + return "MOD_MANUF5"; + case CSR_PSKEY_MOD_MANUF6: + return "MOD_MANUF6"; + case CSR_PSKEY_MOD_MANUF7: + return "MOD_MANUF7"; + case CSR_PSKEY_MOD_MANUF8: + return "MOD_MANUF8"; + case CSR_PSKEY_MOD_MANUF9: + return "MOD_MANUF9"; + case CSR_PSKEY_DUT_VM_DISABLE: + return "DUT_VM_DISABLE"; + case CSR_PSKEY_USR0: + return "USR0"; + case CSR_PSKEY_USR1: + return "USR1"; + case CSR_PSKEY_USR2: + return "USR2"; + case CSR_PSKEY_USR3: + return "USR3"; + case CSR_PSKEY_USR4: + return "USR4"; + case CSR_PSKEY_USR5: + return "USR5"; + case CSR_PSKEY_USR6: + return "USR6"; + case CSR_PSKEY_USR7: + return "USR7"; + case CSR_PSKEY_USR8: + return "USR8"; + case CSR_PSKEY_USR9: + return "USR9"; + case CSR_PSKEY_USR10: + return "USR10"; + case CSR_PSKEY_USR11: + return "USR11"; + case CSR_PSKEY_USR12: + return "USR12"; + case CSR_PSKEY_USR13: + return "USR13"; + case CSR_PSKEY_USR14: + return "USR14"; + case CSR_PSKEY_USR15: + return "USR15"; + case CSR_PSKEY_USR16: + return "USR16"; + case CSR_PSKEY_USR17: + return "USR17"; + case CSR_PSKEY_USR18: + return "USR18"; + case CSR_PSKEY_USR19: + return "USR19"; + case CSR_PSKEY_USR20: + return "USR20"; + case CSR_PSKEY_USR21: + return "USR21"; + case CSR_PSKEY_USR22: + return "USR22"; + case CSR_PSKEY_USR23: + return "USR23"; + case CSR_PSKEY_USR24: + return "USR24"; + case CSR_PSKEY_USR25: + return "USR25"; + case CSR_PSKEY_USR26: + return "USR26"; + case CSR_PSKEY_USR27: + return "USR27"; + case CSR_PSKEY_USR28: + return "USR28"; + case CSR_PSKEY_USR29: + return "USR29"; + case CSR_PSKEY_USR30: + return "USR30"; + case CSR_PSKEY_USR31: + return "USR31"; + case CSR_PSKEY_USR32: + return "USR32"; + case CSR_PSKEY_USR33: + return "USR33"; + case CSR_PSKEY_USR34: + return "USR34"; + case CSR_PSKEY_USR35: + return "USR35"; + case CSR_PSKEY_USR36: + return "USR36"; + case CSR_PSKEY_USR37: + return "USR37"; + case CSR_PSKEY_USR38: + return "USR38"; + case CSR_PSKEY_USR39: + return "USR39"; + case CSR_PSKEY_USR40: + return "USR40"; + case CSR_PSKEY_USR41: + return "USR41"; + case CSR_PSKEY_USR42: + return "USR42"; + case CSR_PSKEY_USR43: + return "USR43"; + case CSR_PSKEY_USR44: + return "USR44"; + case CSR_PSKEY_USR45: + return "USR45"; + case CSR_PSKEY_USR46: + return "USR46"; + case CSR_PSKEY_USR47: + return "USR47"; + case CSR_PSKEY_USR48: + return "USR48"; + case CSR_PSKEY_USR49: + return "USR49"; + case CSR_PSKEY_USB_VERSION: + return "USB_VERSION"; + case CSR_PSKEY_USB_DEVICE_CLASS_CODES: + return "USB_DEVICE_CLASS_CODES"; + case CSR_PSKEY_USB_VENDOR_ID: + return "USB_VENDOR_ID"; + case CSR_PSKEY_USB_PRODUCT_ID: + return "USB_PRODUCT_ID"; + case CSR_PSKEY_USB_MANUF_STRING: + return "USB_MANUF_STRING"; + case CSR_PSKEY_USB_PRODUCT_STRING: + return "USB_PRODUCT_STRING"; + case CSR_PSKEY_USB_SERIAL_NUMBER_STRING: + return "USB_SERIAL_NUMBER_STRING"; + case CSR_PSKEY_USB_CONFIG_STRING: + return "USB_CONFIG_STRING"; + case CSR_PSKEY_USB_ATTRIBUTES: + return "USB_ATTRIBUTES"; + case CSR_PSKEY_USB_MAX_POWER: + return "USB_MAX_POWER"; + case CSR_PSKEY_USB_BT_IF_CLASS_CODES: + return "USB_BT_IF_CLASS_CODES"; + case CSR_PSKEY_USB_LANGID: + return "USB_LANGID"; + case CSR_PSKEY_USB_DFU_CLASS_CODES: + return "USB_DFU_CLASS_CODES"; + case CSR_PSKEY_USB_DFU_PRODUCT_ID: + return "USB_DFU_PRODUCT_ID"; + case CSR_PSKEY_USB_PIO_DETACH: + return "USB_PIO_DETACH"; + case CSR_PSKEY_USB_PIO_WAKEUP: + return "USB_PIO_WAKEUP"; + case CSR_PSKEY_USB_PIO_PULLUP: + return "USB_PIO_PULLUP"; + case CSR_PSKEY_USB_PIO_VBUS: + return "USB_PIO_VBUS"; + case CSR_PSKEY_USB_PIO_WAKE_TIMEOUT: + return "USB_PIO_WAKE_TIMEOUT"; + case CSR_PSKEY_USB_PIO_RESUME: + return "USB_PIO_RESUME"; + case CSR_PSKEY_USB_BT_SCO_IF_CLASS_CODES: + return "USB_BT_SCO_IF_CLASS_CODES"; + case CSR_PSKEY_USB_SUSPEND_PIO_LEVEL: + return "USB_SUSPEND_PIO_LEVEL"; + case CSR_PSKEY_USB_SUSPEND_PIO_DIR: + return "USB_SUSPEND_PIO_DIR"; + case CSR_PSKEY_USB_SUSPEND_PIO_MASK: + return "USB_SUSPEND_PIO_MASK"; + case CSR_PSKEY_USB_ENDPOINT_0_MAX_PACKET_SIZE: + return "USB_ENDPOINT_0_MAX_PACKET_SIZE"; + case CSR_PSKEY_USB_CONFIG: + return "USB_CONFIG"; + case CSR_PSKEY_RADIOTEST_ATTEN_INIT: + return "RADIOTEST_ATTEN_INIT"; + case CSR_PSKEY_RADIOTEST_FIRST_TRIM_TIME: + return "RADIOTEST_FIRST_TRIM_TIME"; + case CSR_PSKEY_RADIOTEST_SUBSEQUENT_TRIM_TIME: + return "RADIOTEST_SUBSEQUENT_TRIM_TIME"; + case CSR_PSKEY_RADIOTEST_LO_LVL_TRIM_ENABLE: + return "RADIOTEST_LO_LVL_TRIM_ENABLE"; + case CSR_PSKEY_RADIOTEST_DISABLE_MODULATION: + return "RADIOTEST_DISABLE_MODULATION"; + case CSR_PSKEY_RFCOMM_FCON_THRESHOLD: + return "RFCOMM_FCON_THRESHOLD"; + case CSR_PSKEY_RFCOMM_FCOFF_THRESHOLD: + return "RFCOMM_FCOFF_THRESHOLD"; + case CSR_PSKEY_IPV6_STATIC_ADDR: + return "IPV6_STATIC_ADDR"; + case CSR_PSKEY_IPV4_STATIC_ADDR: + return "IPV4_STATIC_ADDR"; + case CSR_PSKEY_IPV6_STATIC_PREFIX_LEN: + return "IPV6_STATIC_PREFIX_LEN"; + case CSR_PSKEY_IPV6_STATIC_ROUTER_ADDR: + return "IPV6_STATIC_ROUTER_ADDR"; + case CSR_PSKEY_IPV4_STATIC_SUBNET_MASK: + return "IPV4_STATIC_SUBNET_MASK"; + case CSR_PSKEY_IPV4_STATIC_ROUTER_ADDR: + return "IPV4_STATIC_ROUTER_ADDR"; + case CSR_PSKEY_MDNS_NAME: + return "MDNS_NAME"; + case CSR_PSKEY_FIXED_PIN: + return "FIXED_PIN"; + case CSR_PSKEY_MDNS_PORT: + return "MDNS_PORT"; + case CSR_PSKEY_MDNS_TTL: + return "MDNS_TTL"; + case CSR_PSKEY_MDNS_IPV4_ADDR: + return "MDNS_IPV4_ADDR"; + case CSR_PSKEY_ARP_CACHE_TIMEOUT: + return "ARP_CACHE_TIMEOUT"; + case CSR_PSKEY_HFP_POWER_TABLE: + return "HFP_POWER_TABLE"; + case CSR_PSKEY_DRAIN_BORE_TIMER_COUNTERS: + return "DRAIN_BORE_TIMER_COUNTERS"; + case CSR_PSKEY_DRAIN_BORE_COUNTERS: + return "DRAIN_BORE_COUNTERS"; + case CSR_PSKEY_LOOP_FILTER_TRIM: + return "LOOP_FILTER_TRIM"; + case CSR_PSKEY_DRAIN_BORE_CURRENT_PEAK: + return "DRAIN_BORE_CURRENT_PEAK"; + case CSR_PSKEY_VM_E2_CACHE_LIMIT: + return "VM_E2_CACHE_LIMIT"; + case CSR_PSKEY_FORCE_16MHZ_REF_PIO: + return "FORCE_16MHZ_REF_PIO"; + case CSR_PSKEY_CDMA_LO_REF_LIMITS: + return "CDMA_LO_REF_LIMITS"; + case CSR_PSKEY_CDMA_LO_ERROR_LIMITS: + return "CDMA_LO_ERROR_LIMITS"; + case CSR_PSKEY_CLOCK_STARTUP_DELAY: + return "CLOCK_STARTUP_DELAY"; + case CSR_PSKEY_DEEP_SLEEP_CORRECTION_FACTOR: + return "DEEP_SLEEP_CORRECTION_FACTOR"; + case CSR_PSKEY_TEMPERATURE_CALIBRATION: + return "TEMPERATURE_CALIBRATION"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA: + return "TEMPERATURE_VS_DELTA_INTERNAL_PA"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL: + return "TEMPERATURE_VS_DELTA_TX_PRE_LVL"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB: + return "TEMPERATURE_VS_DELTA_TX_BB"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_ANA_FTRIM: + return "TEMPERATURE_VS_DELTA_ANA_FTRIM"; + case CSR_PSKEY_TEST_DELTA_OFFSET: + return "TEST_DELTA_OFFSET"; + case CSR_PSKEY_RX_DYNAMIC_LVL_OFFSET: + return "RX_DYNAMIC_LVL_OFFSET"; + case CSR_PSKEY_TEST_FORCE_OFFSET: + return "TEST_FORCE_OFFSET"; + case CSR_PSKEY_RF_TRAP_BAD_DIVISION_RATIOS: + return "RF_TRAP_BAD_DIVISION_RATIOS"; + case CSR_PSKEY_RADIOTEST_CDMA_LO_REF_LIMITS: + return "RADIOTEST_CDMA_LO_REF_LIMITS"; + case CSR_PSKEY_INITIAL_BOOTMODE: + return "INITIAL_BOOTMODE"; + case CSR_PSKEY_ONCHIP_HCI_CLIENT: + return "ONCHIP_HCI_CLIENT"; + case CSR_PSKEY_RX_ATTEN_BACKOFF: + return "RX_ATTEN_BACKOFF"; + case CSR_PSKEY_RX_ATTEN_UPDATE_RATE: + return "RX_ATTEN_UPDATE_RATE"; + case CSR_PSKEY_SYNTH_TXRX_THRESHOLDS: + return "SYNTH_TXRX_THRESHOLDS"; + case CSR_PSKEY_MIN_WAIT_STATES: + return "MIN_WAIT_STATES"; + case CSR_PSKEY_RSSI_CORRECTION: + return "RSSI_CORRECTION"; + case CSR_PSKEY_SCHED_THROTTLE_TIMEOUT: + return "SCHED_THROTTLE_TIMEOUT"; + case CSR_PSKEY_DEEP_SLEEP_USE_EXTERNAL_CLOCK: + return "DEEP_SLEEP_USE_EXTERNAL_CLOCK"; + case CSR_PSKEY_TRIM_RADIO_FILTERS: + return "TRIM_RADIO_FILTERS"; + case CSR_PSKEY_TRANSMIT_OFFSET: + return "TRANSMIT_OFFSET"; + case CSR_PSKEY_USB_VM_CONTROL: + return "USB_VM_CONTROL"; + case CSR_PSKEY_MR_ANA_RX_FTRIM: + return "MR_ANA_RX_FTRIM"; + case CSR_PSKEY_I2C_CONFIG: + return "I2C_CONFIG"; + case CSR_PSKEY_IQ_LVL_RX: + return "IQ_LVL_RX"; + case CSR_PSKEY_MR_TX_FILTER_CONFIG: + return "MR_TX_FILTER_CONFIG"; + case CSR_PSKEY_MR_TX_CONFIG2: + return "MR_TX_CONFIG2"; + case CSR_PSKEY_USB_DONT_RESET_BOOTMODE_ON_HOST_RESET: + return "USB_DONT_RESET_BOOTMODE_ON_HOST_RESET"; + case CSR_PSKEY_LC_USE_THROTTLING: + return "LC_USE_THROTTLING"; + case CSR_PSKEY_CHARGER_TRIM: + return "CHARGER_TRIM"; + case CSR_PSKEY_CLOCK_REQUEST_FEATURES: + return "CLOCK_REQUEST_FEATURES"; + case CSR_PSKEY_TRANSMIT_OFFSET_CLASS1: + return "TRANSMIT_OFFSET_CLASS1"; + case CSR_PSKEY_TX_AVOID_PA_CLASS1_PIO: + return "TX_AVOID_PA_CLASS1_PIO"; + case CSR_PSKEY_MR_PIO_CONFIG: + return "MR_PIO_CONFIG"; + case CSR_PSKEY_UART_CONFIG2: + return "UART_CONFIG2"; + case CSR_PSKEY_CLASS1_IQ_LVL: + return "CLASS1_IQ_LVL"; + case CSR_PSKEY_CLASS1_TX_CONFIG2: + return "CLASS1_TX_CONFIG2"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1: + return "TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1: + return "TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR: + return "TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER: + return "TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER"; + case CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD: + return "TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD"; + case CSR_PSKEY_RX_MR_EQ_TAPS: + return "RX_MR_EQ_TAPS"; + case CSR_PSKEY_TX_PRE_LVL_CLASS1: + return "TX_PRE_LVL_CLASS1"; + case CSR_PSKEY_ANALOGUE_ATTENUATOR: + return "ANALOGUE_ATTENUATOR"; + case CSR_PSKEY_MR_RX_FILTER_TRIM: + return "MR_RX_FILTER_TRIM"; + case CSR_PSKEY_MR_RX_FILTER_RESPONSE: + return "MR_RX_FILTER_RESPONSE"; + case CSR_PSKEY_PIO_WAKEUP_STATE: + return "PIO_WAKEUP_STATE"; + case CSR_PSKEY_MR_TX_IF_ATTEN_OFF_TEMP: + return "MR_TX_IF_ATTEN_OFF_TEMP"; + case CSR_PSKEY_LO_DIV_LATCH_BYPASS: + return "LO_DIV_LATCH_BYPASS"; + case CSR_PSKEY_LO_VCO_STANDBY: + return "LO_VCO_STANDBY"; + case CSR_PSKEY_SLOW_CLOCK_FILTER_SHIFT: + return "SLOW_CLOCK_FILTER_SHIFT"; + case CSR_PSKEY_SLOW_CLOCK_FILTER_DIVIDER: + return "SLOW_CLOCK_FILTER_DIVIDER"; + case CSR_PSKEY_USB_ATTRIBUTES_POWER: + return "USB_ATTRIBUTES_POWER"; + case CSR_PSKEY_USB_ATTRIBUTES_WAKEUP: + return "USB_ATTRIBUTES_WAKEUP"; + case CSR_PSKEY_DFU_ATTRIBUTES_MANIFESTATION_TOLERANT: + return "DFU_ATTRIBUTES_MANIFESTATION_TOLERANT"; + case CSR_PSKEY_DFU_ATTRIBUTES_CAN_UPLOAD: + return "DFU_ATTRIBUTES_CAN_UPLOAD"; + case CSR_PSKEY_DFU_ATTRIBUTES_CAN_DOWNLOAD: + return "DFU_ATTRIBUTES_CAN_DOWNLOAD"; + case CSR_PSKEY_UART_CONFIG_STOP_BITS: + return "UART_CONFIG_STOP_BITS"; + case CSR_PSKEY_UART_CONFIG_PARITY_BIT: + return "UART_CONFIG_PARITY_BIT"; + case CSR_PSKEY_UART_CONFIG_FLOW_CTRL_EN: + return "UART_CONFIG_FLOW_CTRL_EN"; + case CSR_PSKEY_UART_CONFIG_RTS_AUTO_EN: + return "UART_CONFIG_RTS_AUTO_EN"; + case CSR_PSKEY_UART_CONFIG_RTS: + return "UART_CONFIG_RTS"; + case CSR_PSKEY_UART_CONFIG_TX_ZERO_EN: + return "UART_CONFIG_TX_ZERO_EN"; + case CSR_PSKEY_UART_CONFIG_NON_BCSP_EN: + return "UART_CONFIG_NON_BCSP_EN"; + case CSR_PSKEY_UART_CONFIG_RX_RATE_DELAY: + return "UART_CONFIG_RX_RATE_DELAY"; + case CSR_PSKEY_UART_SEQ_TIMEOUT: + return "UART_SEQ_TIMEOUT"; + case CSR_PSKEY_UART_SEQ_RETRIES: + return "UART_SEQ_RETRIES"; + case CSR_PSKEY_UART_SEQ_WINSIZE: + return "UART_SEQ_WINSIZE"; + case CSR_PSKEY_UART_USE_CRC_ON_TX: + return "UART_USE_CRC_ON_TX"; + case CSR_PSKEY_UART_HOST_INITIAL_STATE: + return "UART_HOST_INITIAL_STATE"; + case CSR_PSKEY_UART_HOST_ATTENTION_SPAN: + return "UART_HOST_ATTENTION_SPAN"; + case CSR_PSKEY_UART_HOST_WAKEUP_TIME: + return "UART_HOST_WAKEUP_TIME"; + case CSR_PSKEY_UART_HOST_WAKEUP_WAIT: + return "UART_HOST_WAKEUP_WAIT"; + case CSR_PSKEY_BCSP_LM_MODE: + return "BCSP_LM_MODE"; + case CSR_PSKEY_BCSP_LM_SYNC_RETRIES: + return "BCSP_LM_SYNC_RETRIES"; + case CSR_PSKEY_BCSP_LM_TSHY: + return "BCSP_LM_TSHY"; + case CSR_PSKEY_UART_DFU_CONFIG_STOP_BITS: + return "UART_DFU_CONFIG_STOP_BITS"; + case CSR_PSKEY_UART_DFU_CONFIG_PARITY_BIT: + return "UART_DFU_CONFIG_PARITY_BIT"; + case CSR_PSKEY_UART_DFU_CONFIG_FLOW_CTRL_EN: + return "UART_DFU_CONFIG_FLOW_CTRL_EN"; + case CSR_PSKEY_UART_DFU_CONFIG_RTS_AUTO_EN: + return "UART_DFU_CONFIG_RTS_AUTO_EN"; + case CSR_PSKEY_UART_DFU_CONFIG_RTS: + return "UART_DFU_CONFIG_RTS"; + case CSR_PSKEY_UART_DFU_CONFIG_TX_ZERO_EN: + return "UART_DFU_CONFIG_TX_ZERO_EN"; + case CSR_PSKEY_UART_DFU_CONFIG_NON_BCSP_EN: + return "UART_DFU_CONFIG_NON_BCSP_EN"; + case CSR_PSKEY_UART_DFU_CONFIG_RX_RATE_DELAY: + return "UART_DFU_CONFIG_RX_RATE_DELAY"; + case CSR_PSKEY_AMUX_AIO0: + return "AMUX_AIO0"; + case CSR_PSKEY_AMUX_AIO1: + return "AMUX_AIO1"; + case CSR_PSKEY_AMUX_AIO2: + return "AMUX_AIO2"; + case CSR_PSKEY_AMUX_AIO3: + return "AMUX_AIO3"; + case CSR_PSKEY_LOCAL_NAME_SIMPLIFIED: + return "LOCAL_NAME_SIMPLIFIED"; + case CSR_PSKEY_EXTENDED_STUB: + return "EXTENDED_STUB"; + default: + return "UNKNOWN"; + } +} + +int csr_write_varid_valueless(int dd, uint16_t seqnum, uint16_t varid) +{ + unsigned char cmd[] = { 0x02, 0x00, 0x09, 0x00, + seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char cp[254], rp[254]; + struct hci_request rq; + + memset(&cp, 0, sizeof(cp)); + cp[0] = 0xc2; + memcpy(cp + 1, cmd, sizeof(cmd)); + + switch (varid) { + case CSR_VARID_COLD_RESET: + case CSR_VARID_WARM_RESET: + case CSR_VARID_COLD_HALT: + case CSR_VARID_WARM_HALT: + return hci_send_cmd(dd, OGF_VENDOR_CMD, 0x00, sizeof(cmd) + 1, cp); + } + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x00; + rq.event = EVT_VENDOR; + rq.cparam = cp; + rq.clen = sizeof(cmd) + 1; + rq.rparam = rp; + rq.rlen = sizeof(rp); + + if (hci_send_req(dd, &rq, 2000) < 0) + return -1; + + if (rp[0] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[9] + (rp[10] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + return 0; +} + +int csr_write_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length) +{ + unsigned char cmd[] = { 0x02, 0x00, ((length / 2) + 5) & 0xff, ((length / 2) + 5) >> 8, + seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char cp[254], rp[254]; + struct hci_request rq; + + memset(&cp, 0, sizeof(cp)); + cp[0] = 0xc2; + memcpy(cp + 1, cmd, sizeof(cmd)); + memcpy(cp + 11, value, length); + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x00; + rq.event = EVT_VENDOR; + rq.cparam = cp; + rq.clen = sizeof(cmd) + length + 1; + rq.rparam = rp; + rq.rlen = sizeof(rp); + + if (hci_send_req(dd, &rq, 2000) < 0) + return -1; + + if (rp[0] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[9] + (rp[10] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + return 0; +} + +int csr_read_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length) +{ + unsigned char cmd[] = { 0x00, 0x00, ((length / 2) + 5) & 0xff, ((length / 2) + 5) >> 8, + seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char cp[254], rp[254]; + struct hci_request rq; + + memset(&cp, 0, sizeof(cp)); + cp[0] = 0xc2; + memcpy(cp + 1, cmd, sizeof(cmd)); + memcpy(cp + 11, value, length); + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x00; + rq.event = EVT_VENDOR; + rq.cparam = cp; + rq.clen = sizeof(cmd) + length + 1; + rq.rparam = rp; + rq.rlen = sizeof(rp); + + if (hci_send_req(dd, &rq, 2000) < 0) + return -1; + + if (rp[0] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[9] + (rp[10] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + memcpy(value, rp + 11, length); + + return 0; +} + +int csr_read_varid_uint16(int dd, uint16_t seqnum, uint16_t varid, uint16_t *value) +{ + unsigned char cmd[] = { 0x00, 0x00, 0x09, 0x00, + seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char cp[254], rp[254]; + struct hci_request rq; + + memset(&cp, 0, sizeof(cp)); + cp[0] = 0xc2; + memcpy(cp + 1, cmd, sizeof(cmd)); + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x00; + rq.event = EVT_VENDOR; + rq.cparam = cp; + rq.clen = sizeof(cmd) + 1; + rq.rparam = rp; + rq.rlen = sizeof(rp); + + if (hci_send_req(dd, &rq, 2000) < 0) + return -1; + + if (rp[0] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[9] + (rp[10] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + *value = rp[11] + (rp[12] << 8); + + return 0; +} + +int csr_read_varid_uint32(int dd, uint16_t seqnum, uint16_t varid, uint32_t *value) +{ + unsigned char cmd[] = { 0x00, 0x00, 0x09, 0x00, + seqnum & 0xff, seqnum >> 8, varid & 0xff, varid >> 8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char cp[254], rp[254]; + struct hci_request rq; + + memset(&cp, 0, sizeof(cp)); + cp[0] = 0xc2; + memcpy(cp + 1, cmd, sizeof(cmd)); + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x00; + rq.event = EVT_VENDOR; + rq.cparam = cp; + rq.clen = sizeof(cmd) + 1; + rq.rparam = rp; + rq.rlen = sizeof(rp); + + if (hci_send_req(dd, &rq, 2000) < 0) + return -1; + + if (rp[0] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[9] + (rp[10] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + *value = ((rp[11] + (rp[12] << 8)) << 16) + (rp[13] + (rp[14] << 8)); + + return 0; +} + +int csr_read_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length) +{ + unsigned char cmd[] = { 0x00, 0x00, ((length / 2) + 8) & 0xff, ((length / 2) + 8) >> 8, + seqnum & 0xff, seqnum >> 8, 0x03, 0x70, 0x00, 0x00, + pskey & 0xff, pskey >> 8, + (length / 2) & 0xff, (length / 2) >> 8, + stores & 0xff, stores >> 8, 0x00, 0x00 }; + + unsigned char cp[254], rp[254]; + struct hci_request rq; + + memset(&cp, 0, sizeof(cp)); + cp[0] = 0xc2; + memcpy(cp + 1, cmd, sizeof(cmd)); + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x00; + rq.event = EVT_VENDOR; + rq.cparam = cp; + rq.clen = sizeof(cmd) + length - 1; + rq.rparam = rp; + rq.rlen = sizeof(rp); + + if (hci_send_req(dd, &rq, 2000) < 0) + return -1; + + if (rp[0] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[9] + (rp[10] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + memcpy(value, rp + 17, length); + + return 0; +} + +int csr_write_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length) +{ + unsigned char cmd[] = { 0x02, 0x00, ((length / 2) + 8) & 0xff, ((length / 2) + 8) >> 8, + seqnum & 0xff, seqnum >> 8, 0x03, 0x70, 0x00, 0x00, + pskey & 0xff, pskey >> 8, + (length / 2) & 0xff, (length / 2) >> 8, + stores & 0xff, stores >> 8, 0x00, 0x00 }; + + unsigned char cp[254], rp[254]; + struct hci_request rq; + + memset(&cp, 0, sizeof(cp)); + cp[0] = 0xc2; + memcpy(cp + 1, cmd, sizeof(cmd)); + + memcpy(cp + 17, value, length); + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x00; + rq.event = EVT_VENDOR; + rq.cparam = cp; + rq.clen = sizeof(cmd) + length - 1; + rq.rparam = rp; + rq.rlen = sizeof(rp); + + if (hci_send_req(dd, &rq, 2000) < 0) + return -1; + + if (rp[0] != 0xc2) { + errno = EIO; + return -1; + } + + if ((rp[9] + (rp[10] << 8)) != 0) { + errno = ENXIO; + return -1; + } + + return 0; +} + +int csr_read_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t *value) +{ + uint8_t array[2] = { 0x00, 0x00 }; + int err; + + err = csr_read_pskey_complex(dd, seqnum, pskey, stores, array, 2); + + *value = array[0] + (array[1] << 8); + + return err; +} + +int csr_write_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t value) +{ + uint8_t array[2] = { value & 0xff, value >> 8 }; + + return csr_write_pskey_complex(dd, seqnum, pskey, stores, array, 2); +} + +int csr_read_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t *value) +{ + uint8_t array[4] = { 0x00, 0x00, 0x00, 0x00 }; + int err; + + err = csr_read_pskey_complex(dd, seqnum, pskey, stores, array, 4); + + *value = ((array[0] + (array[1] << 8)) << 16) + + (array[2] + (array[3] << 8)); + + return err; +} + +int csr_write_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t value) +{ + uint8_t array[4] = { (value & 0xff0000) >> 16, value >> 24, + value & 0xff, (value & 0xff00) >> 8 }; + + return csr_write_pskey_complex(dd, seqnum, pskey, stores, array, 4); +} + +int psr_put(uint16_t pskey, uint8_t *value, uint16_t size) +{ + struct psr_data *item; + + item = malloc(sizeof(*item)); + if (!item) + return -ENOMEM; + + item->pskey = pskey; + + if (size > 0) { + item->value = malloc(size); + if (!item->value) { + free(item); + return -ENOMEM; + } + + memcpy(item->value, value, size); + item->size = size; + } else { + item->value = NULL; + item->size = 0; + } + + item->next = NULL; + + if (!head) + head = item; + else + tail->next = item; + + tail = item; + + return 0; +} + +int psr_get(uint16_t *pskey, uint8_t *value, uint16_t *size) +{ + struct psr_data *item = head; + + if (!head) + return -ENOENT; + + *pskey = item->pskey; + + if (item->value) { + if (value && item->size > 0) + memcpy(value, item->value, item->size); + free(item->value); + *size = item->size; + } else + *size = 0; + + if (head == tail) + tail = NULL; + + head = head->next; + free(item); + + return 0; +} + +static int parse_line(char *str) +{ + uint8_t array[256]; + uint16_t value, pskey, length = 0; + char *off, *end; + + pskey = strtol(str + 1, NULL, 16); + off = strstr(str, "=") + 1; + if (!off) + return -EIO; + + while (1) { + value = strtol(off, &end, 16); + if (value == 0 && off == end) + break; + + array[length++] = value & 0xff; + array[length++] = value >> 8; + + if (*end == '\0') + break; + + off = end + 1; + } + + return psr_put(pskey, array, length); +} + +int psr_read(const char *filename) +{ + struct stat st; + char *str, *map, *off, *end; + int fd, err = 0; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return fd; + + if (fstat(fd, &st) < 0) { + err = -errno; + goto close; + } + + map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (!map || map == MAP_FAILED) { + err = -errno; + goto close; + } + + off = map; + + while (1) { + if (*off == '\r' || *off == '\n') { + off++; + continue; + } + + end = strpbrk(off, "\r\n"); + if (!end) + break; + + str = malloc(end - off + 1); + if (!str) + break; + + memset(str, 0, end - off + 1); + strncpy(str, off, end - off); + if (*str == '&') + parse_line(str); + + free(str); + off = end + 1; + } + + munmap(map, st.st_size); + +close: + close(fd); + + return err; +} + +int psr_print(void) +{ + uint8_t array[256]; + uint16_t pskey, length; + char *str, val[7]; + int i; + + while (1) { + if (psr_get(&pskey, array, &length) < 0) + break; + + str = csr_pskeytoval(pskey); + if (!strcasecmp(str, "UNKNOWN")) { + sprintf(val, "0x%04x", pskey); + str = NULL; + } + + printf("// %s%s\n&%04x =", str ? "PSKEY_" : "", + str ? str : val, pskey); + for (i = 0; i < length / 2; i++) + printf(" %02x%02x", array[i * 2 + 1], array[i * 2]); + printf("\n"); + } + + return 0; +} diff --git a/external/cache/sources/hcitools/csr.h b/external/cache/sources/hcitools/csr.h new file mode 100644 index 000000000000..8b94d7b8a96e --- /dev/null +++ b/external/cache/sources/hcitools/csr.h @@ -0,0 +1,553 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2003-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +#define CSR_VARID_PS_CLR_ALL 0x000b /* valueless */ +#define CSR_VARID_PS_FACTORY_SET 0x000c /* valueless */ +#define CSR_VARID_PS_CLR_ALL_STORES 0x082d /* uint16 */ +#define CSR_VARID_BC01_STATUS 0x2801 /* uint16 */ +#define CSR_VARID_BUILDID 0x2819 /* uint16 */ +#define CSR_VARID_CHIPVER 0x281a /* uint16 */ +#define CSR_VARID_CHIPREV 0x281b /* uint16 */ +#define CSR_VARID_INTERFACE_VERSION 0x2825 /* uint16 */ +#define CSR_VARID_RAND 0x282a /* uint16 */ +#define CSR_VARID_MAX_CRYPT_KEY_LENGTH 0x282c /* uint16 */ +#define CSR_VARID_CHIPANAREV 0x2836 /* uint16 */ +#define CSR_VARID_BUILDID_LOADER 0x2838 /* uint16 */ +#define CSR_VARID_BT_CLOCK 0x2c00 /* uint32 */ +#define CSR_VARID_PS_NEXT 0x3005 /* complex */ +#define CSR_VARID_PS_SIZE 0x3006 /* complex */ +#define CSR_VARID_CRYPT_KEY_LENGTH 0x3008 /* complex */ +#define CSR_VARID_PICONET_INSTANCE 0x3009 /* complex */ +#define CSR_VARID_GET_CLR_EVT 0x300a /* complex */ +#define CSR_VARID_GET_NEXT_BUILDDEF 0x300b /* complex */ +#define CSR_VARID_PS_MEMORY_TYPE 0x3012 /* complex */ +#define CSR_VARID_READ_BUILD_NAME 0x301c /* complex */ +#define CSR_VARID_COLD_RESET 0x4001 /* valueless */ +#define CSR_VARID_WARM_RESET 0x4002 /* valueless */ +#define CSR_VARID_COLD_HALT 0x4003 /* valueless */ +#define CSR_VARID_WARM_HALT 0x4004 /* valueless */ +#define CSR_VARID_INIT_BT_STACK 0x4005 /* valueless */ +#define CSR_VARID_ACTIVATE_BT_STACK 0x4006 /* valueless */ +#define CSR_VARID_ENABLE_TX 0x4007 /* valueless */ +#define CSR_VARID_DISABLE_TX 0x4008 /* valueless */ +#define CSR_VARID_RECAL 0x4009 /* valueless */ +#define CSR_VARID_PS_FACTORY_RESTORE 0x400d /* valueless */ +#define CSR_VARID_PS_FACTORY_RESTORE_ALL 0x400e /* valueless */ +#define CSR_VARID_PS_DEFRAG_RESET 0x400f /* valueless */ +#define CSR_VARID_KILL_VM_APPLICATION 0x4010 /* valueless */ +#define CSR_VARID_HOPPING_ON 0x4011 /* valueless */ +#define CSR_VARID_CANCEL_PAGE 0x4012 /* valueless */ +#define CSR_VARID_PS_CLR 0x4818 /* uint16 */ +#define CSR_VARID_MAP_SCO_PCM 0x481c /* uint16 */ +#define CSR_VARID_SINGLE_CHAN 0x482e /* uint16 */ +#define CSR_VARID_RADIOTEST 0x5004 /* complex */ +#define CSR_VARID_PS_CLR_STORES 0x500c /* complex */ +#define CSR_VARID_NO_VARIABLE 0x6000 /* valueless */ +#define CSR_VARID_CONFIG_UART 0x6802 /* uint16 */ +#define CSR_VARID_PANIC_ARG 0x6805 /* uint16 */ +#define CSR_VARID_FAULT_ARG 0x6806 /* uint16 */ +#define CSR_VARID_MAX_TX_POWER 0x6827 /* int8 */ +#define CSR_VARID_DEFAULT_TX_POWER 0x682b /* int8 */ +#define CSR_VARID_PS 0x7003 /* complex */ + +#define CSR_PSKEY_BDADDR 0x0001 /* bdaddr / uint16[] = { 0x00A5A5, 0x5b, 0x0002 } */ +#define CSR_PSKEY_COUNTRYCODE 0x0002 /* uint16 */ +#define CSR_PSKEY_CLASSOFDEVICE 0x0003 /* bdcod */ +#define CSR_PSKEY_DEVICE_DRIFT 0x0004 /* uint16 */ +#define CSR_PSKEY_DEVICE_JITTER 0x0005 /* uint16 */ +#define CSR_PSKEY_MAX_ACLS 0x000d /* uint16 */ +#define CSR_PSKEY_MAX_SCOS 0x000e /* uint16 */ +#define CSR_PSKEY_MAX_REMOTE_MASTERS 0x000f /* uint16 */ +#define CSR_PSKEY_ENABLE_MASTERY_WITH_SLAVERY 0x0010 /* bool */ +#define CSR_PSKEY_H_HC_FC_MAX_ACL_PKT_LEN 0x0011 /* uint16 */ +#define CSR_PSKEY_H_HC_FC_MAX_SCO_PKT_LEN 0x0012 /* uint8 */ +#define CSR_PSKEY_H_HC_FC_MAX_ACL_PKTS 0x0013 /* uint16 */ +#define CSR_PSKEY_H_HC_FC_MAX_SCO_PKTS 0x0014 /* uint16 */ +#define CSR_PSKEY_LC_FC_BUFFER_LOW_WATER_MARK 0x0015 /* lc_fc_lwm */ +#define CSR_PSKEY_LC_MAX_TX_POWER 0x0017 /* int16 */ +#define CSR_PSKEY_TX_GAIN_RAMP 0x001d /* uint16 */ +#define CSR_PSKEY_LC_POWER_TABLE 0x001e /* power_setting[] */ +#define CSR_PSKEY_LC_PEER_POWER_PERIOD 0x001f /* TIME */ +#define CSR_PSKEY_LC_FC_POOLS_LOW_WATER_MARK 0x0020 /* lc_fc_lwm */ +#define CSR_PSKEY_LC_DEFAULT_TX_POWER 0x0021 /* int16 */ +#define CSR_PSKEY_LC_RSSI_GOLDEN_RANGE 0x0022 /* uint8 */ +#define CSR_PSKEY_LC_COMBO_DISABLE_PIO_MASK 0x0028 /* uint16[] */ +#define CSR_PSKEY_LC_COMBO_PRIORITY_PIO_MASK 0x0029 /* uint16[] */ +#define CSR_PSKEY_LC_COMBO_DOT11_CHANNEL_PIO_BASE 0x002a /* uint16 */ +#define CSR_PSKEY_LC_COMBO_DOT11_BLOCK_CHANNELS 0x002b /* uint16 */ +#define CSR_PSKEY_LC_MAX_TX_POWER_NO_RSSI 0x002d /* int8 */ +#define CSR_PSKEY_LC_CONNECTION_RX_WINDOW 0x002e /* uint16 */ +#define CSR_PSKEY_LC_COMBO_DOT11_TX_PROTECTION_MODE 0x0030 /* uint16 */ +#define CSR_PSKEY_LC_ENHANCED_POWER_TABLE 0x0031 /* enhanced_power_setting[] */ +#define CSR_PSKEY_LC_WIDEBAND_RSSI_CONFIG 0x0032 /* wideband_rssi_config */ +#define CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_LEAD 0x0033 /* uint16 */ +#define CSR_PSKEY_BT_CLOCK_INIT 0x0034 /* uint32 */ +#define CSR_PSKEY_TX_MR_MOD_DELAY 0x0038 /* uint8 */ +#define CSR_PSKEY_RX_MR_SYNC_TIMING 0x0039 /* uint16 */ +#define CSR_PSKEY_RX_MR_SYNC_CONFIG 0x003a /* uint16 */ +#define CSR_PSKEY_LC_LOST_SYNC_SLOTS 0x003b /* uint16 */ +#define CSR_PSKEY_RX_MR_SAMP_CONFIG 0x003c /* uint16 */ +#define CSR_PSKEY_AGC_HYST_LEVELS 0x003d /* agc_hyst_config */ +#define CSR_PSKEY_RX_LEVEL_LOW_SIGNAL 0x003e /* uint16 */ +#define CSR_PSKEY_AGC_IQ_LVL_VALUES 0x003f /* IQ_LVL_VAL[] */ +#define CSR_PSKEY_MR_FTRIM_OFFSET_12DB 0x0040 /* uint16 */ +#define CSR_PSKEY_MR_FTRIM_OFFSET_6DB 0x0041 /* uint16 */ +#define CSR_PSKEY_NO_CAL_ON_BOOT 0x0042 /* bool */ +#define CSR_PSKEY_RSSI_HI_TARGET 0x0043 /* uint8 */ +#define CSR_PSKEY_PREFERRED_MIN_ATTENUATION 0x0044 /* uint8 */ +#define CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_OVERRIDE 0x0045 /* bool */ +#define CSR_PSKEY_LC_MULTISLOT_HOLDOFF 0x0047 /* TIME */ +#define CSR_PSKEY_FREE_KEY_PIGEON_HOLE 0x00c9 /* uint16 */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR0 0x00ca /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR1 0x00cb /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR2 0x00cc /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR3 0x00cd /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR4 0x00ce /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR5 0x00cf /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR6 0x00d0 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR7 0x00d1 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR8 0x00d2 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR9 0x00d3 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR10 0x00d4 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR11 0x00d5 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR12 0x00d6 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR13 0x00d7 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR14 0x00d8 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LINK_KEY_BD_ADDR15 0x00d9 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_ENC_KEY_LMIN 0x00da /* uint16 */ +#define CSR_PSKEY_ENC_KEY_LMAX 0x00db /* uint16 */ +#define CSR_PSKEY_LOCAL_SUPPORTED_FEATURES 0x00ef /* uint16[] = { 0xffff, 0xfe8f, 0xf99b, 0x8000 }*/ +#define CSR_PSKEY_LM_USE_UNIT_KEY 0x00f0 /* bool */ +#define CSR_PSKEY_HCI_NOP_DISABLE 0x00f2 /* bool */ +#define CSR_PSKEY_LM_MAX_EVENT_FILTERS 0x00f4 /* uint8 */ +#define CSR_PSKEY_LM_USE_ENC_MODE_BROADCAST 0x00f5 /* bool */ +#define CSR_PSKEY_LM_TEST_SEND_ACCEPTED_TWICE 0x00f6 /* bool */ +#define CSR_PSKEY_LM_MAX_PAGE_HOLD_TIME 0x00f7 /* uint16 */ +#define CSR_PSKEY_AFH_ADAPTATION_RESPONSE_TIME 0x00f8 /* uint16 */ +#define CSR_PSKEY_AFH_OPTIONS 0x00f9 /* uint16 */ +#define CSR_PSKEY_AFH_RSSI_RUN_PERIOD 0x00fa /* uint16 */ +#define CSR_PSKEY_AFH_REENABLE_CHANNEL_TIME 0x00fb /* uint16 */ +#define CSR_PSKEY_NO_DROP_ON_ACR_MS_FAIL 0x00fc /* bool */ +#define CSR_PSKEY_MAX_PRIVATE_KEYS 0x00fd /* uint8 */ +#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR0 0x00fe /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR1 0x00ff /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR2 0x0100 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR3 0x0101 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR4 0x0102 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR5 0x0103 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR6 0x0104 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR7 0x0105 /* LM_LINK_KEY_BD_ADDR_T */ +#define CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS 0x0106 /* uint16[] = { 0xffff, 0x03ff, 0xfffe, 0xffff, 0xffff, 0xffff, 0x0ff3, 0xfff8, 0x003f } */ +#define CSR_PSKEY_LM_MAX_ABSENCE_INDEX 0x0107 /* uint8 */ +#define CSR_PSKEY_DEVICE_NAME 0x0108 /* uint16[] */ +#define CSR_PSKEY_AFH_RSSI_THRESHOLD 0x0109 /* uint16 */ +#define CSR_PSKEY_LM_CASUAL_SCAN_INTERVAL 0x010a /* uint16 */ +#define CSR_PSKEY_AFH_MIN_MAP_CHANGE 0x010b /* uint16[] */ +#define CSR_PSKEY_AFH_RSSI_LP_RUN_PERIOD 0x010c /* uint16 */ +#define CSR_PSKEY_HCI_LMP_LOCAL_VERSION 0x010d /* uint16 */ +#define CSR_PSKEY_LMP_REMOTE_VERSION 0x010e /* uint8 */ +#define CSR_PSKEY_HOLD_ERROR_MESSAGE_NUMBER 0x0113 /* uint16 */ +#define CSR_PSKEY_DFU_ATTRIBUTES 0x0136 /* uint8 */ +#define CSR_PSKEY_DFU_DETACH_TO 0x0137 /* uint16 */ +#define CSR_PSKEY_DFU_TRANSFER_SIZE 0x0138 /* uint16 */ +#define CSR_PSKEY_DFU_ENABLE 0x0139 /* bool */ +#define CSR_PSKEY_DFU_LIN_REG_ENABLE 0x013a /* bool */ +#define CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_MSB 0x015e /* uint16[] */ +#define CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_LSB 0x015f /* uint16[] */ +#define CSR_PSKEY_DFUENC_VMAPP_PK_M_DASH 0x0160 /* uint16 */ +#define CSR_PSKEY_DFUENC_VMAPP_PK_R2N_MSB 0x0161 /* uint16[] */ +#define CSR_PSKEY_DFUENC_VMAPP_PK_R2N_LSB 0x0162 /* uint16[] */ +#define CSR_PSKEY_BCSP_LM_PS_BLOCK 0x0192 /* BCSP_LM_PS_BLOCK */ +#define CSR_PSKEY_HOSTIO_FC_PS_BLOCK 0x0193 /* HOSTIO_FC_PS_BLOCK */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO0 0x0194 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO1 0x0195 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO2 0x0196 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO3 0x0197 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO4 0x0198 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO5 0x0199 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO6 0x019a /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO7 0x019b /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO8 0x019c /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO9 0x019d /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO10 0x019e /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO11 0x019f /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO12 0x01a0 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO13 0x01a1 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO14 0x01a2 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO15 0x01a3 /* PROTOCOL_INFO */ +#define CSR_PSKEY_HOSTIO_UART_RESET_TIMEOUT 0x01a4 /* TIME */ +#define CSR_PSKEY_HOSTIO_USE_HCI_EXTN 0x01a5 /* bool */ +#define CSR_PSKEY_HOSTIO_USE_HCI_EXTN_CCFC 0x01a6 /* bool */ +#define CSR_PSKEY_HOSTIO_HCI_EXTN_PAYLOAD_SIZE 0x01a7 /* uint16 */ +#define CSR_PSKEY_BCSP_LM_CNF_CNT_LIMIT 0x01aa /* uint16 */ +#define CSR_PSKEY_HOSTIO_MAP_SCO_PCM 0x01ab /* bool */ +#define CSR_PSKEY_HOSTIO_AWKWARD_PCM_SYNC 0x01ac /* bool */ +#define CSR_PSKEY_HOSTIO_BREAK_POLL_PERIOD 0x01ad /* TIME */ +#define CSR_PSKEY_HOSTIO_MIN_UART_HCI_SCO_SIZE 0x01ae /* uint16 */ +#define CSR_PSKEY_HOSTIO_MAP_SCO_CODEC 0x01b0 /* bool */ +#define CSR_PSKEY_PCM_CVSD_TX_HI_FREQ_BOOST 0x01b1 /* uint16 */ +#define CSR_PSKEY_PCM_CVSD_RX_HI_FREQ_BOOST 0x01b2 /* uint16 */ +#define CSR_PSKEY_PCM_CONFIG32 0x01b3 /* uint32 */ +#define CSR_PSKEY_USE_OLD_BCSP_LE 0x01b4 /* uint16 */ +#define CSR_PSKEY_PCM_CVSD_USE_NEW_FILTER 0x01b5 /* bool */ +#define CSR_PSKEY_PCM_FORMAT 0x01b6 /* uint16 */ +#define CSR_PSKEY_CODEC_OUT_GAIN 0x01b7 /* uint16 */ +#define CSR_PSKEY_CODEC_IN_GAIN 0x01b8 /* uint16 */ +#define CSR_PSKEY_CODEC_PIO 0x01b9 /* uint16 */ +#define CSR_PSKEY_PCM_LOW_JITTER_CONFIG 0x01ba /* uint32 */ +#define CSR_PSKEY_HOSTIO_SCO_PCM_THRESHOLDS 0x01bb /* uint16[] */ +#define CSR_PSKEY_HOSTIO_SCO_HCI_THRESHOLDS 0x01bc /* uint16[] */ +#define CSR_PSKEY_HOSTIO_MAP_SCO_PCM_SLOT 0x01bd /* uint16 */ +#define CSR_PSKEY_UART_BAUDRATE 0x01be /* uint16 */ +#define CSR_PSKEY_UART_CONFIG_BCSP 0x01bf /* uint16 */ +#define CSR_PSKEY_UART_CONFIG_H4 0x01c0 /* uint16 */ +#define CSR_PSKEY_UART_CONFIG_H5 0x01c1 /* uint16 */ +#define CSR_PSKEY_UART_CONFIG_USR 0x01c2 /* uint16 */ +#define CSR_PSKEY_UART_TX_CRCS 0x01c3 /* bool */ +#define CSR_PSKEY_UART_ACK_TIMEOUT 0x01c4 /* uint16 */ +#define CSR_PSKEY_UART_TX_MAX_ATTEMPTS 0x01c5 /* uint16 */ +#define CSR_PSKEY_UART_TX_WINDOW_SIZE 0x01c6 /* uint16 */ +#define CSR_PSKEY_UART_HOST_WAKE 0x01c7 /* uint16[] */ +#define CSR_PSKEY_HOSTIO_THROTTLE_TIMEOUT 0x01c8 /* TIME */ +#define CSR_PSKEY_PCM_ALWAYS_ENABLE 0x01c9 /* bool */ +#define CSR_PSKEY_UART_HOST_WAKE_SIGNAL 0x01ca /* uint16 */ +#define CSR_PSKEY_UART_CONFIG_H4DS 0x01cb /* uint16 */ +#define CSR_PSKEY_H4DS_WAKE_DURATION 0x01cc /* uint16 */ +#define CSR_PSKEY_H4DS_MAXWU 0x01cd /* uint16 */ +#define CSR_PSKEY_H4DS_LE_TIMER_PERIOD 0x01cf /* uint16 */ +#define CSR_PSKEY_H4DS_TWU_TIMER_PERIOD 0x01d0 /* uint16 */ +#define CSR_PSKEY_H4DS_UART_IDLE_TIMER_PERIOD 0x01d1 /* uint16 */ +#define CSR_PSKEY_ANA_FTRIM 0x01f6 /* uint16 */ +#define CSR_PSKEY_WD_TIMEOUT 0x01f7 /* TIME */ +#define CSR_PSKEY_WD_PERIOD 0x01f8 /* TIME */ +#define CSR_PSKEY_HOST_INTERFACE 0x01f9 /* phys_bus */ +#define CSR_PSKEY_HQ_HOST_TIMEOUT 0x01fb /* TIME */ +#define CSR_PSKEY_HQ_ACTIVE 0x01fc /* bool */ +#define CSR_PSKEY_BCCMD_SECURITY_ACTIVE 0x01fd /* bool */ +#define CSR_PSKEY_ANA_FREQ 0x01fe /* uint16 */ +#define CSR_PSKEY_PIO_PROTECT_MASK 0x0202 /* uint16 */ +#define CSR_PSKEY_PMALLOC_SIZES 0x0203 /* uint16[] */ +#define CSR_PSKEY_UART_BAUD_RATE 0x0204 /* uint16 */ +#define CSR_PSKEY_UART_CONFIG 0x0205 /* uint16 */ +#define CSR_PSKEY_STUB 0x0207 /* uint16 */ +#define CSR_PSKEY_TXRX_PIO_CONTROL 0x0209 /* uint16 */ +#define CSR_PSKEY_ANA_RX_LEVEL 0x020b /* uint16 */ +#define CSR_PSKEY_ANA_RX_FTRIM 0x020c /* uint16 */ +#define CSR_PSKEY_PSBC_DATA_VERSION 0x020d /* uint16 */ +#define CSR_PSKEY_PCM0_ATTENUATION 0x020f /* uint16 */ +#define CSR_PSKEY_LO_LVL_MAX 0x0211 /* uint16 */ +#define CSR_PSKEY_LO_ADC_AMPL_MIN 0x0212 /* uint16 */ +#define CSR_PSKEY_LO_ADC_AMPL_MAX 0x0213 /* uint16 */ +#define CSR_PSKEY_IQ_TRIM_CHANNEL 0x0214 /* uint16 */ +#define CSR_PSKEY_IQ_TRIM_GAIN 0x0215 /* uint16 */ +#define CSR_PSKEY_IQ_TRIM_ENABLE 0x0216 /* iq_trim_enable_flag */ +#define CSR_PSKEY_TX_OFFSET_HALF_MHZ 0x0217 /* int16 */ +#define CSR_PSKEY_GBL_MISC_ENABLES 0x0221 /* uint16 */ +#define CSR_PSKEY_UART_SLEEP_TIMEOUT 0x0222 /* uint16 */ +#define CSR_PSKEY_DEEP_SLEEP_STATE 0x0229 /* deep_sleep_state */ +#define CSR_PSKEY_IQ_ENABLE_PHASE_TRIM 0x022d /* bool */ +#define CSR_PSKEY_HCI_HANDLE_FREEZE_PERIOD 0x0237 /* TIME */ +#define CSR_PSKEY_MAX_FROZEN_HCI_HANDLES 0x0238 /* uint16 */ +#define CSR_PSKEY_PAGETABLE_DESTRUCTION_DELAY 0x0239 /* TIME */ +#define CSR_PSKEY_IQ_TRIM_PIO_SETTINGS 0x023a /* uint8 */ +#define CSR_PSKEY_USE_EXTERNAL_CLOCK 0x023b /* bool */ +#define CSR_PSKEY_DEEP_SLEEP_WAKE_CTS 0x023c /* uint16 */ +#define CSR_PSKEY_FC_HC2H_FLUSH_DELAY 0x023d /* TIME */ +#define CSR_PSKEY_RX_HIGHSIDE 0x023e /* bool */ +#define CSR_PSKEY_TX_PRE_LVL 0x0240 /* uint8 */ +#define CSR_PSKEY_RX_SINGLE_ENDED 0x0242 /* bool */ +#define CSR_PSKEY_TX_FILTER_CONFIG 0x0243 /* uint32 */ +#define CSR_PSKEY_CLOCK_REQUEST_ENABLE 0x0246 /* uint16 */ +#define CSR_PSKEY_RX_MIN_ATTEN 0x0249 /* uint16 */ +#define CSR_PSKEY_XTAL_TARGET_AMPLITUDE 0x024b /* uint8 */ +#define CSR_PSKEY_PCM_MIN_CPU_CLOCK 0x024d /* uint16 */ +#define CSR_PSKEY_HOST_INTERFACE_PIO_USB 0x0250 /* uint16 */ +#define CSR_PSKEY_CPU_IDLE_MODE 0x0251 /* cpu_idle_mode */ +#define CSR_PSKEY_DEEP_SLEEP_CLEAR_RTS 0x0252 /* bool */ +#define CSR_PSKEY_RF_RESONANCE_TRIM 0x0254 /* uint16 */ +#define CSR_PSKEY_DEEP_SLEEP_PIO_WAKE 0x0255 /* uint16 */ +#define CSR_PSKEY_DRAIN_BORE_TIMERS 0x0256 /* uint32[] */ +#define CSR_PSKEY_DRAIN_TX_POWER_BASE 0x0257 /* uint16 */ +#define CSR_PSKEY_MODULE_ID 0x0259 /* uint32 */ +#define CSR_PSKEY_MODULE_DESIGN 0x025a /* uint16 */ +#define CSR_PSKEY_MODULE_SECURITY_CODE 0x025c /* uint16[] */ +#define CSR_PSKEY_VM_DISABLE 0x025d /* bool */ +#define CSR_PSKEY_MOD_MANUF0 0x025e /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF1 0x025f /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF2 0x0260 /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF3 0x0261 /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF4 0x0262 /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF5 0x0263 /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF6 0x0264 /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF7 0x0265 /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF8 0x0266 /* uint16[] */ +#define CSR_PSKEY_MOD_MANUF9 0x0267 /* uint16[] */ +#define CSR_PSKEY_DUT_VM_DISABLE 0x0268 /* bool */ +#define CSR_PSKEY_USR0 0x028a /* uint16[] */ +#define CSR_PSKEY_USR1 0x028b /* uint16[] */ +#define CSR_PSKEY_USR2 0x028c /* uint16[] */ +#define CSR_PSKEY_USR3 0x028d /* uint16[] */ +#define CSR_PSKEY_USR4 0x028e /* uint16[] */ +#define CSR_PSKEY_USR5 0x028f /* uint16[] */ +#define CSR_PSKEY_USR6 0x0290 /* uint16[] */ +#define CSR_PSKEY_USR7 0x0291 /* uint16[] */ +#define CSR_PSKEY_USR8 0x0292 /* uint16[] */ +#define CSR_PSKEY_USR9 0x0293 /* uint16[] */ +#define CSR_PSKEY_USR10 0x0294 /* uint16[] */ +#define CSR_PSKEY_USR11 0x0295 /* uint16[] */ +#define CSR_PSKEY_USR12 0x0296 /* uint16[] */ +#define CSR_PSKEY_USR13 0x0297 /* uint16[] */ +#define CSR_PSKEY_USR14 0x0298 /* uint16[] */ +#define CSR_PSKEY_USR15 0x0299 /* uint16[] */ +#define CSR_PSKEY_USR16 0x029a /* uint16[] */ +#define CSR_PSKEY_USR17 0x029b /* uint16[] */ +#define CSR_PSKEY_USR18 0x029c /* uint16[] */ +#define CSR_PSKEY_USR19 0x029d /* uint16[] */ +#define CSR_PSKEY_USR20 0x029e /* uint16[] */ +#define CSR_PSKEY_USR21 0x029f /* uint16[] */ +#define CSR_PSKEY_USR22 0x02a0 /* uint16[] */ +#define CSR_PSKEY_USR23 0x02a1 /* uint16[] */ +#define CSR_PSKEY_USR24 0x02a2 /* uint16[] */ +#define CSR_PSKEY_USR25 0x02a3 /* uint16[] */ +#define CSR_PSKEY_USR26 0x02a4 /* uint16[] */ +#define CSR_PSKEY_USR27 0x02a5 /* uint16[] */ +#define CSR_PSKEY_USR28 0x02a6 /* uint16[] */ +#define CSR_PSKEY_USR29 0x02a7 /* uint16[] */ +#define CSR_PSKEY_USR30 0x02a8 /* uint16[] */ +#define CSR_PSKEY_USR31 0x02a9 /* uint16[] */ +#define CSR_PSKEY_USR32 0x02aa /* uint16[] */ +#define CSR_PSKEY_USR33 0x02ab /* uint16[] */ +#define CSR_PSKEY_USR34 0x02ac /* uint16[] */ +#define CSR_PSKEY_USR35 0x02ad /* uint16[] */ +#define CSR_PSKEY_USR36 0x02ae /* uint16[] */ +#define CSR_PSKEY_USR37 0x02af /* uint16[] */ +#define CSR_PSKEY_USR38 0x02b0 /* uint16[] */ +#define CSR_PSKEY_USR39 0x02b1 /* uint16[] */ +#define CSR_PSKEY_USR40 0x02b2 /* uint16[] */ +#define CSR_PSKEY_USR41 0x02b3 /* uint16[] */ +#define CSR_PSKEY_USR42 0x02b4 /* uint16[] */ +#define CSR_PSKEY_USR43 0x02b5 /* uint16[] */ +#define CSR_PSKEY_USR44 0x02b6 /* uint16[] */ +#define CSR_PSKEY_USR45 0x02b7 /* uint16[] */ +#define CSR_PSKEY_USR46 0x02b8 /* uint16[] */ +#define CSR_PSKEY_USR47 0x02b9 /* uint16[] */ +#define CSR_PSKEY_USR48 0x02ba /* uint16[] */ +#define CSR_PSKEY_USR49 0x02bb /* uint16[] */ +#define CSR_PSKEY_USB_VERSION 0x02bc /* uint16 */ +#define CSR_PSKEY_USB_DEVICE_CLASS_CODES 0x02bd /* usbclass */ +#define CSR_PSKEY_USB_VENDOR_ID 0x02be /* uint16 */ +#define CSR_PSKEY_USB_PRODUCT_ID 0x02bf /* uint16 */ +#define CSR_PSKEY_USB_MANUF_STRING 0x02c1 /* unicodestring */ +#define CSR_PSKEY_USB_PRODUCT_STRING 0x02c2 /* unicodestring */ +#define CSR_PSKEY_USB_SERIAL_NUMBER_STRING 0x02c3 /* unicodestring */ +#define CSR_PSKEY_USB_CONFIG_STRING 0x02c4 /* unicodestring */ +#define CSR_PSKEY_USB_ATTRIBUTES 0x02c5 /* uint8 */ +#define CSR_PSKEY_USB_MAX_POWER 0x02c6 /* uint16 */ +#define CSR_PSKEY_USB_BT_IF_CLASS_CODES 0x02c7 /* usbclass */ +#define CSR_PSKEY_USB_LANGID 0x02c9 /* uint16 */ +#define CSR_PSKEY_USB_DFU_CLASS_CODES 0x02ca /* usbclass */ +#define CSR_PSKEY_USB_DFU_PRODUCT_ID 0x02cb /* uint16 */ +#define CSR_PSKEY_USB_PIO_DETACH 0x02ce /* uint16 */ +#define CSR_PSKEY_USB_PIO_WAKEUP 0x02cf /* uint16 */ +#define CSR_PSKEY_USB_PIO_PULLUP 0x02d0 /* uint16 */ +#define CSR_PSKEY_USB_PIO_VBUS 0x02d1 /* uint16 */ +#define CSR_PSKEY_USB_PIO_WAKE_TIMEOUT 0x02d2 /* uint16 */ +#define CSR_PSKEY_USB_PIO_RESUME 0x02d3 /* uint16 */ +#define CSR_PSKEY_USB_BT_SCO_IF_CLASS_CODES 0x02d4 /* usbclass */ +#define CSR_PSKEY_USB_SUSPEND_PIO_LEVEL 0x02d5 /* uint16 */ +#define CSR_PSKEY_USB_SUSPEND_PIO_DIR 0x02d6 /* uint16 */ +#define CSR_PSKEY_USB_SUSPEND_PIO_MASK 0x02d7 /* uint16 */ +#define CSR_PSKEY_USB_ENDPOINT_0_MAX_PACKET_SIZE 0x02d8 /* uint8 */ +#define CSR_PSKEY_USB_CONFIG 0x02d9 /* uint16 */ +#define CSR_PSKEY_RADIOTEST_ATTEN_INIT 0x0320 /* uint16 */ +#define CSR_PSKEY_RADIOTEST_FIRST_TRIM_TIME 0x0326 /* TIME */ +#define CSR_PSKEY_RADIOTEST_SUBSEQUENT_TRIM_TIME 0x0327 /* TIME */ +#define CSR_PSKEY_RADIOTEST_LO_LVL_TRIM_ENABLE 0x0328 /* bool */ +#define CSR_PSKEY_RADIOTEST_DISABLE_MODULATION 0x032c /* bool */ +#define CSR_PSKEY_RFCOMM_FCON_THRESHOLD 0x0352 /* uint16 */ +#define CSR_PSKEY_RFCOMM_FCOFF_THRESHOLD 0x0353 /* uint16 */ +#define CSR_PSKEY_IPV6_STATIC_ADDR 0x0354 /* uint16[] */ +#define CSR_PSKEY_IPV4_STATIC_ADDR 0x0355 /* uint32 */ +#define CSR_PSKEY_IPV6_STATIC_PREFIX_LEN 0x0356 /* uint8 */ +#define CSR_PSKEY_IPV6_STATIC_ROUTER_ADDR 0x0357 /* uint16[] */ +#define CSR_PSKEY_IPV4_STATIC_SUBNET_MASK 0x0358 /* uint32 */ +#define CSR_PSKEY_IPV4_STATIC_ROUTER_ADDR 0x0359 /* uint32 */ +#define CSR_PSKEY_MDNS_NAME 0x035a /* char[] */ +#define CSR_PSKEY_FIXED_PIN 0x035b /* uint8[] */ +#define CSR_PSKEY_MDNS_PORT 0x035c /* uint16 */ +#define CSR_PSKEY_MDNS_TTL 0x035d /* uint8 */ +#define CSR_PSKEY_MDNS_IPV4_ADDR 0x035e /* uint32 */ +#define CSR_PSKEY_ARP_CACHE_TIMEOUT 0x035f /* uint16 */ +#define CSR_PSKEY_HFP_POWER_TABLE 0x0360 /* uint16[] */ +#define CSR_PSKEY_DRAIN_BORE_TIMER_COUNTERS 0x03e7 /* uint32[] */ +#define CSR_PSKEY_DRAIN_BORE_COUNTERS 0x03e6 /* uint32[] */ +#define CSR_PSKEY_LOOP_FILTER_TRIM 0x03e4 /* uint16 */ +#define CSR_PSKEY_DRAIN_BORE_CURRENT_PEAK 0x03e3 /* uint32[] */ +#define CSR_PSKEY_VM_E2_CACHE_LIMIT 0x03e2 /* uint16 */ +#define CSR_PSKEY_FORCE_16MHZ_REF_PIO 0x03e1 /* uint16 */ +#define CSR_PSKEY_CDMA_LO_REF_LIMITS 0x03df /* uint16 */ +#define CSR_PSKEY_CDMA_LO_ERROR_LIMITS 0x03de /* uint16 */ +#define CSR_PSKEY_CLOCK_STARTUP_DELAY 0x03dd /* uint16 */ +#define CSR_PSKEY_DEEP_SLEEP_CORRECTION_FACTOR 0x03dc /* int16 */ +#define CSR_PSKEY_TEMPERATURE_CALIBRATION 0x03db /* temperature_calibration */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA 0x03da /* temperature_calibration[] */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL 0x03d9 /* temperature_calibration[] */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB 0x03d8 /* temperature_calibration[] */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_ANA_FTRIM 0x03d7 /* temperature_calibration[] */ +#define CSR_PSKEY_TEST_DELTA_OFFSET 0x03d6 /* uint16 */ +#define CSR_PSKEY_RX_DYNAMIC_LVL_OFFSET 0x03d4 /* uint16 */ +#define CSR_PSKEY_TEST_FORCE_OFFSET 0x03d3 /* bool */ +#define CSR_PSKEY_RF_TRAP_BAD_DIVISION_RATIOS 0x03cf /* uint16 */ +#define CSR_PSKEY_RADIOTEST_CDMA_LO_REF_LIMITS 0x03ce /* uint16 */ +#define CSR_PSKEY_INITIAL_BOOTMODE 0x03cd /* int16 */ +#define CSR_PSKEY_ONCHIP_HCI_CLIENT 0x03cc /* bool */ +#define CSR_PSKEY_RX_ATTEN_BACKOFF 0x03ca /* uint16 */ +#define CSR_PSKEY_RX_ATTEN_UPDATE_RATE 0x03c9 /* uint16 */ +#define CSR_PSKEY_SYNTH_TXRX_THRESHOLDS 0x03c7 /* uint16 */ +#define CSR_PSKEY_MIN_WAIT_STATES 0x03c6 /* uint16 */ +#define CSR_PSKEY_RSSI_CORRECTION 0x03c5 /* int8 */ +#define CSR_PSKEY_SCHED_THROTTLE_TIMEOUT 0x03c4 /* TIME */ +#define CSR_PSKEY_DEEP_SLEEP_USE_EXTERNAL_CLOCK 0x03c3 /* bool */ +#define CSR_PSKEY_TRIM_RADIO_FILTERS 0x03c2 /* uint16 */ +#define CSR_PSKEY_TRANSMIT_OFFSET 0x03c1 /* int16 */ +#define CSR_PSKEY_USB_VM_CONTROL 0x03c0 /* bool */ +#define CSR_PSKEY_MR_ANA_RX_FTRIM 0x03bf /* uint16 */ +#define CSR_PSKEY_I2C_CONFIG 0x03be /* uint16 */ +#define CSR_PSKEY_IQ_LVL_RX 0x03bd /* uint16 */ +#define CSR_PSKEY_MR_TX_FILTER_CONFIG 0x03bb /* uint32 */ +#define CSR_PSKEY_MR_TX_CONFIG2 0x03ba /* uint16 */ +#define CSR_PSKEY_USB_DONT_RESET_BOOTMODE_ON_HOST_RESET 0x03b9 /* bool */ +#define CSR_PSKEY_LC_USE_THROTTLING 0x03b8 /* bool */ +#define CSR_PSKEY_CHARGER_TRIM 0x03b7 /* uint16 */ +#define CSR_PSKEY_CLOCK_REQUEST_FEATURES 0x03b6 /* uint16 */ +#define CSR_PSKEY_TRANSMIT_OFFSET_CLASS1 0x03b4 /* int16 */ +#define CSR_PSKEY_TX_AVOID_PA_CLASS1_PIO 0x03b3 /* uint16 */ +#define CSR_PSKEY_MR_PIO_CONFIG 0x03b2 /* uint16 */ +#define CSR_PSKEY_UART_CONFIG2 0x03b1 /* uint8 */ +#define CSR_PSKEY_CLASS1_IQ_LVL 0x03b0 /* uint16 */ +#define CSR_PSKEY_CLASS1_TX_CONFIG2 0x03af /* uint16 */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1 0x03ae /* temperature_calibration[] */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1 0x03ad /* temperature_calibration[] */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR 0x03ac /* temperature_calibration[] */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER 0x03ab /* temperature_calibration[] */ +#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD 0x03aa /* temperature_calibration[] */ +#define CSR_PSKEY_RX_MR_EQ_TAPS 0x03a9 /* uint16[] */ +#define CSR_PSKEY_TX_PRE_LVL_CLASS1 0x03a8 /* uint8 */ +#define CSR_PSKEY_ANALOGUE_ATTENUATOR 0x03a7 /* bool */ +#define CSR_PSKEY_MR_RX_FILTER_TRIM 0x03a6 /* uint16 */ +#define CSR_PSKEY_MR_RX_FILTER_RESPONSE 0x03a5 /* int16[] */ +#define CSR_PSKEY_PIO_WAKEUP_STATE 0x039f /* uint16 */ +#define CSR_PSKEY_MR_TX_IF_ATTEN_OFF_TEMP 0x0394 /* int16 */ +#define CSR_PSKEY_LO_DIV_LATCH_BYPASS 0x0393 /* bool */ +#define CSR_PSKEY_LO_VCO_STANDBY 0x0392 /* bool */ +#define CSR_PSKEY_SLOW_CLOCK_FILTER_SHIFT 0x0391 /* uint16 */ +#define CSR_PSKEY_SLOW_CLOCK_FILTER_DIVIDER 0x0390 /* uint16 */ +#define CSR_PSKEY_USB_ATTRIBUTES_POWER 0x03f2 /* bool */ +#define CSR_PSKEY_USB_ATTRIBUTES_WAKEUP 0x03f3 /* bool */ +#define CSR_PSKEY_DFU_ATTRIBUTES_MANIFESTATION_TOLERANT 0x03f4 /* bool */ +#define CSR_PSKEY_DFU_ATTRIBUTES_CAN_UPLOAD 0x03f5 /* bool */ +#define CSR_PSKEY_DFU_ATTRIBUTES_CAN_DOWNLOAD 0x03f6 /* bool */ +#define CSR_PSKEY_UART_CONFIG_STOP_BITS 0x03fc /* bool */ +#define CSR_PSKEY_UART_CONFIG_PARITY_BIT 0x03fd /* uint16 */ +#define CSR_PSKEY_UART_CONFIG_FLOW_CTRL_EN 0x03fe /* bool */ +#define CSR_PSKEY_UART_CONFIG_RTS_AUTO_EN 0x03ff /* bool */ +#define CSR_PSKEY_UART_CONFIG_RTS 0x0400 /* bool */ +#define CSR_PSKEY_UART_CONFIG_TX_ZERO_EN 0x0401 /* bool */ +#define CSR_PSKEY_UART_CONFIG_NON_BCSP_EN 0x0402 /* bool */ +#define CSR_PSKEY_UART_CONFIG_RX_RATE_DELAY 0x0403 /* uint16 */ +#define CSR_PSKEY_UART_SEQ_TIMEOUT 0x0405 /* uint16 */ +#define CSR_PSKEY_UART_SEQ_RETRIES 0x0406 /* uint16 */ +#define CSR_PSKEY_UART_SEQ_WINSIZE 0x0407 /* uint16 */ +#define CSR_PSKEY_UART_USE_CRC_ON_TX 0x0408 /* bool */ +#define CSR_PSKEY_UART_HOST_INITIAL_STATE 0x0409 /* hwakeup_state */ +#define CSR_PSKEY_UART_HOST_ATTENTION_SPAN 0x040a /* uint16 */ +#define CSR_PSKEY_UART_HOST_WAKEUP_TIME 0x040b /* uint16 */ +#define CSR_PSKEY_UART_HOST_WAKEUP_WAIT 0x040c /* uint16 */ +#define CSR_PSKEY_BCSP_LM_MODE 0x0410 /* uint16 */ +#define CSR_PSKEY_BCSP_LM_SYNC_RETRIES 0x0411 /* uint16 */ +#define CSR_PSKEY_BCSP_LM_TSHY 0x0412 /* uint16 */ +#define CSR_PSKEY_UART_DFU_CONFIG_STOP_BITS 0x0417 /* bool */ +#define CSR_PSKEY_UART_DFU_CONFIG_PARITY_BIT 0x0418 /* uint16 */ +#define CSR_PSKEY_UART_DFU_CONFIG_FLOW_CTRL_EN 0x0419 /* bool */ +#define CSR_PSKEY_UART_DFU_CONFIG_RTS_AUTO_EN 0x041a /* bool */ +#define CSR_PSKEY_UART_DFU_CONFIG_RTS 0x041b /* bool */ +#define CSR_PSKEY_UART_DFU_CONFIG_TX_ZERO_EN 0x041c /* bool */ +#define CSR_PSKEY_UART_DFU_CONFIG_NON_BCSP_EN 0x041d /* bool */ +#define CSR_PSKEY_UART_DFU_CONFIG_RX_RATE_DELAY 0x041e /* uint16 */ +#define CSR_PSKEY_AMUX_AIO0 0x041f /* ana_amux_sel */ +#define CSR_PSKEY_AMUX_AIO1 0x0420 /* ana_amux_sel */ +#define CSR_PSKEY_AMUX_AIO2 0x0421 /* ana_amux_sel */ +#define CSR_PSKEY_AMUX_AIO3 0x0422 /* ana_amux_sel */ +#define CSR_PSKEY_LOCAL_NAME_SIMPLIFIED 0x0423 /* local_name_complete */ +#define CSR_PSKEY_EXTENDED_STUB 0x2001 /* uint16 */ + +char *csr_builddeftostr(uint16_t def); +char *csr_buildidtostr(uint16_t id); +char *csr_chipvertostr(uint16_t ver, uint16_t rev); +char *csr_pskeytostr(uint16_t pskey); +char *csr_pskeytoval(uint16_t pskey); + +int csr_open_hci(char *device); +int csr_read_hci(uint16_t varid, uint8_t *value, uint16_t length); +int csr_write_hci(uint16_t varid, uint8_t *value, uint16_t length); +void csr_close_hci(void); + +int csr_open_usb(char *device); +int csr_read_usb(uint16_t varid, uint8_t *value, uint16_t length); +int csr_write_usb(uint16_t varid, uint8_t *value, uint16_t length); +void csr_close_usb(void); + +int csr_open_bcsp(char *device, speed_t bcsp_rate); +int csr_read_bcsp(uint16_t varid, uint8_t *value, uint16_t length); +int csr_write_bcsp(uint16_t varid, uint8_t *value, uint16_t length); +void csr_close_bcsp(void); + +int csr_open_h4(char *device); +int csr_read_h4(uint16_t varid, uint8_t *value, uint16_t length); +int csr_write_h4(uint16_t varid, uint8_t *value, uint16_t length); +void csr_close_h4(void); + +int csr_open_3wire(char *device); +int csr_read_3wire(uint16_t varid, uint8_t *value, uint16_t length); +int csr_write_3wire(uint16_t varid, uint8_t *value, uint16_t length); +void csr_close_3wire(void); + +int csr_write_varid_valueless(int dd, uint16_t seqnum, uint16_t varid); +int csr_write_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length); +int csr_read_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length); +int csr_read_varid_uint16(int dd, uint16_t seqnum, uint16_t varid, uint16_t *value); +int csr_read_varid_uint32(int dd, uint16_t seqnum, uint16_t varid, uint32_t *value); +int csr_read_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length); +int csr_write_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length); +int csr_read_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t *value); +int csr_write_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t value); +int csr_read_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t *value); +int csr_write_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t value); + +int psr_put(uint16_t pskey, uint8_t *value, uint16_t size); +int psr_get(uint16_t *pskey, uint8_t *value, uint16_t *size); +int psr_read(const char *filename); +int psr_print(void); diff --git a/external/cache/sources/hcitools/hciattach.c b/external/cache/sources/hcitools/hciattach.c new file mode 100644 index 000000000000..9e994f9c7b63 --- /dev/null +++ b/external/cache/sources/hcitools/hciattach.c @@ -0,0 +1,1513 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2002-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hciattach.h" + +static volatile sig_atomic_t __io_canceled = 0; + +static void sig_hup(int sig) +{ +} + +static void sig_term(int sig) +{ + __io_canceled = 1; +} + +static void sig_alarm(int sig) +{ + fprintf(stderr, "Initialization timed out.\n"); + exit(1); +} + +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 B3710000 + case 3710000 + return B3710000; +#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; +} + +/* + * Read an HCI event from the given file descriptor. + */ +int read_hci_event(int fd, unsigned char* buf, int size) +{ + int remain, r; + int count = 0; + + if (size <= 0) + return -1; + + /* 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; +} + +/* + * Ericsson specific initialization + */ +static int ericsson(int fd, struct uart_t *u, struct termios *ti) +{ + struct timespec tm = {0, 50000}; + char cmd[5]; + + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x09; + cmd[2] = 0xfc; + cmd[3] = 0x01; + + switch (u->speed) { + case 57600: + cmd[4] = 0x03; + break; + case 115200: + cmd[4] = 0x02; + break; + case 230400: + cmd[4] = 0x01; + break; + case 460800: + cmd[4] = 0x00; + break; + case 921600: + cmd[4] = 0x20; + break; + case 2000000: + cmd[4] = 0x25; + break; + case 3000000: + cmd[4] = 0x27; + break; + case 4000000: + cmd[4] = 0x2B; + break; + default: + cmd[4] = 0x03; + u->speed = 57600; + fprintf(stderr, "Invalid speed requested, using %d bps instead\n", u->speed); + break; + } + + /* Send initialization command */ + if (write(fd, cmd, 5) != 5) { + perror("Failed to write init command"); + return -1; + } + + nanosleep(&tm, NULL); + return 0; +} + +/* + * Digianswer specific initialization + */ +static int digi(int fd, struct uart_t *u, struct termios *ti) +{ + struct timespec tm = {0, 50000}; + char cmd[5]; + + /* DigiAnswer set baud rate command */ + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x07; + cmd[2] = 0xfc; + cmd[3] = 0x01; + + switch (u->speed) { + case 57600: + cmd[4] = 0x08; + break; + case 115200: + cmd[4] = 0x09; + break; + default: + cmd[4] = 0x09; + u->speed = 115200; + break; + } + + /* Send initialization command */ + if (write(fd, cmd, 5) != 5) { + perror("Failed to write init command"); + return -1; + } + + nanosleep(&tm, NULL); + return 0; +} + +static int texas(int fd, struct uart_t *u, struct termios *ti) +{ + return texas_init(fd, &u->speed, ti); +} + +static int texas2(int fd, struct uart_t *u, struct termios *ti) +{ + return texas_post(fd, ti); +} + +static int texasalt(int fd, struct uart_t *u, struct termios *ti) +{ + return texasalt_init(fd, u->speed, ti); +} + +static int ath3k_ps(int fd, struct uart_t *u, struct termios *ti) +{ + return ath3k_init(fd, u->speed, u->init_speed, u->bdaddr, ti); +} + +static int ath3k_pm(int fd, struct uart_t *u, struct termios *ti) +{ + return ath3k_post(fd, u->pm); +} + +static int qualcomm(int fd, struct uart_t *u, struct termios *ti) +{ + return qualcomm_init(fd, u->speed, ti, u->bdaddr); +} + +static int intel(int fd, struct uart_t *u, struct termios *ti) +{ + return intel_init(fd, u->init_speed, &u->speed, ti); +} + +static int bcm43xx(int fd, struct uart_t *u, struct termios *ti) +{ + return bcm43xx_init(fd, u->speed, ti, u->bdaddr); +} + +//Realtek_add_start +//add realtek Bluetooth init and post function. +static int realtek_init(int fd, struct uart_t *u, struct termios *ti) +{ + fprintf(stderr, "Realtek Bluetooth init uart with init speed:%d, final_speed:%d, type:HCI UART %s\n", u->init_speed, u->speed, (u->proto == HCI_UART_H4)? "H4":"H5" ); + return rtk_init(fd, u->proto, u->speed, ti); +} + +static int realtek_post(int fd, struct uart_t *u, struct termios *ti) +{ + fprintf(stderr, "Realtek Bluetooth post process\n"); + return rtk_post(fd, u->proto, ti); +} + +// add xradio Bluetooth init and post function. +static int xradio_init(int fd, struct uart_t *u, struct termios *ti) +{ + fprintf(stderr, "XRADIO Bluetooth init uart with init speed:%d, final_speed:%d, type:HCI UART %s\n", u->init_speed, u->speed, (u->proto == HCI_UART_H4)? "H4":"H5" ); + return xr_init(fd, u, ti); +} + +static int xradio_post(int fd, struct uart_t *u, struct termios *ti) +{ + fprintf(stderr, "XRADIO Bluetooth post process\n"); + return xr_post(fd, u, ti); +} + +// add sprd Bluetooth init and post function. +static int sprd_init(int fd, struct uart_t *u, struct termios *ti) +{ + fprintf(stderr, "SPRD Bluetooth init uart with init speed:%d, final_speed:%d, type:HCI UART %s\n", u->init_speed, u->speed, (u->proto == HCI_UART_H4)? "H4":"H5" ); + return sprd_config_init(fd, u, ti); +} + +static int sprd_post(int fd, struct uart_t *u, struct termios *ti) +{ + fprintf(stderr, "SPRD Bluetooth post process\n"); + return sprd_config_post(fd, u, ti); +} + +static int read_check(int fd, void *buf, int count) +{ + int res; + + do { + res = read(fd, buf, count); + if (res != -1) { + buf += res; + count -= res; + } + } while (count && (errno == 0 || errno == EINTR)); + + if (count) + return -1; + + return 0; +} + +/* + * BCSP specific initialization + */ +static int serial_fd; +static int bcsp_max_retries = 10; + +static void bcsp_tshy_sig_alarm(int sig) +{ + unsigned char bcsp_sync_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0}; + static int retries = 0; + + if (retries < bcsp_max_retries) { + retries++; + if (write(serial_fd, &bcsp_sync_pkt, 10) < 0) + return; + alarm(1); + return; + } + + tcflush(serial_fd, TCIOFLUSH); + fprintf(stderr, "BCSP initialization timed out\n"); + exit(1); +} + +static void bcsp_tconf_sig_alarm(int sig) +{ + unsigned char bcsp_conf_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xad,0xef,0xac,0xed,0xc0}; + static int retries = 0; + + if (retries < bcsp_max_retries){ + retries++; + if (write(serial_fd, &bcsp_conf_pkt, 10) < 0) + return; + alarm(1); + return; + } + + tcflush(serial_fd, TCIOFLUSH); + fprintf(stderr, "BCSP initialization timed out\n"); + exit(1); +} + +static int bcsp(int fd, struct uart_t *u, struct termios *ti) +{ + unsigned char byte, bcsph[4], bcspp[4], + bcsp_sync_resp_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xac,0xaf,0xef,0xee,0xc0}, + bcsp_conf_resp_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xde,0xad,0xd0,0xd0,0xc0}, + bcspsync[4] = {0xda, 0xdc, 0xed, 0xed}, + bcspsyncresp[4] = {0xac,0xaf,0xef,0xee}, + bcspconf[4] = {0xad,0xef,0xac,0xed}, + bcspconfresp[4] = {0xde,0xad,0xd0,0xd0}; + struct sigaction sa; + int len; + + if (set_speed(fd, ti, u->speed) < 0) { + perror("Can't set default baud rate"); + return -1; + } + + ti->c_cflag |= PARENB; + ti->c_cflag &= ~(PARODD); + + if (tcsetattr(fd, TCSANOW, ti) < 0) { + perror("Can't set port settings"); + return -1; + } + + alarm(0); + + serial_fd = fd; + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = bcsp_tshy_sig_alarm; + sigaction(SIGALRM, &sa, NULL); + + /* State = shy */ + + bcsp_tshy_sig_alarm(0); + while (1) { + do { + if (read_check(fd, &byte, 1) == -1){ + perror("Failed to read"); + return -1; + } + } while (byte != 0xC0); + + do { + if ( read_check(fd, &bcsph[0], 1) == -1){ + perror("Failed to read"); + return -1; + } + } while (bcsph[0] == 0xC0); + + if ( read_check(fd, &bcsph[1], 3) == -1){ + perror("Failed to read"); + return -1; + } + + if (((bcsph[0] + bcsph[1] + bcsph[2]) & 0xFF) != (unsigned char)~bcsph[3]) + continue; + if (bcsph[1] != 0x41 || bcsph[2] != 0x00) + continue; + + if (read_check(fd, &bcspp, 4) == -1){ + perror("Failed to read"); + return -1; + } + + if (!memcmp(bcspp, bcspsync, 4)) { + if (write(fd, &bcsp_sync_resp_pkt,10) < 0) + return -1; + } else if (!memcmp(bcspp, bcspsyncresp, 4)) + break; + } + + /* State = curious */ + + alarm(0); + sa.sa_handler = bcsp_tconf_sig_alarm; + sigaction(SIGALRM, &sa, NULL); + alarm(1); + + while (1) { + do { + if (read_check(fd, &byte, 1) == -1){ + perror("Failed to read"); + return -1; + } + } while (byte != 0xC0); + + do { + if (read_check(fd, &bcsph[0], 1) == -1){ + perror("Failed to read"); + return -1; + } + } while (bcsph[0] == 0xC0); + + if (read_check(fd, &bcsph[1], 3) == -1){ + perror("Failed to read"); + return -1; + } + + if (((bcsph[0] + bcsph[1] + bcsph[2]) & 0xFF) != (unsigned char)~bcsph[3]) + continue; + + if (bcsph[1] != 0x41 || bcsph[2] != 0x00) + continue; + + if (read_check(fd, &bcspp, 4) == -1){ + perror("Failed to read"); + return -1; + } + + if (!memcmp(bcspp, bcspsync, 4)) + len = write(fd, &bcsp_sync_resp_pkt, 10); + else if (!memcmp(bcspp, bcspconf, 4)) + len = write(fd, &bcsp_conf_resp_pkt, 10); + else if (!memcmp(bcspp, bcspconfresp, 4)) + break; + else + continue; + + if (len < 0) + return -errno; + } + + /* State = garrulous */ + + return 0; +} + +/* + * CSR specific initialization + * Inspired strongly by code in OpenBT and experimentations with Brainboxes + * Pcmcia card. + * Jean Tourrilhes - 14.11.01 + */ +static int csr(int fd, struct uart_t *u, struct termios *ti) +{ + struct timespec tm = {0, 10000000}; /* 10ms - be generous */ + unsigned char cmd[30]; /* Command */ + unsigned char resp[30]; /* Response */ + int clen = 0; /* Command len */ + static int csr_seq = 0; /* Sequence number of command */ + int divisor; + + /* It seems that if we set the CSR UART speed straight away, it + * won't work, the CSR UART gets into a state where we can't talk + * to it anymore. + * On the other hand, doing a read before setting the CSR speed + * seems to be ok. + * Therefore, the strategy is to read the build ID (useful for + * debugging) and only then set the CSR UART speed. Doing like + * this is more complex but at least it works ;-) + * The CSR UART control may be slow to wake up or something because + * every time I read its speed, its bogus... + * Jean II */ + + /* Try to read the build ID of the CSR chip */ + clen = 5 + (5 + 6) * 2; + /* HCI header */ + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x00; /* CSR command */ + cmd[2] = 0xfc; /* MANUFACTURER_SPEC */ + cmd[3] = 1 + (5 + 6) * 2; /* len */ + /* CSR MSG header */ + cmd[4] = 0xC2; /* first+last+channel=BCC */ + /* CSR BCC header */ + cmd[5] = 0x00; /* type = GET-REQ */ + cmd[6] = 0x00; /* - msB */ + cmd[7] = 5 + 4; /* len */ + cmd[8] = 0x00; /* - msB */ + cmd[9] = csr_seq & 0xFF;/* seq num */ + cmd[10] = (csr_seq >> 8) & 0xFF; /* - msB */ + csr_seq++; + cmd[11] = 0x19; /* var_id = CSR_CMD_BUILD_ID */ + cmd[12] = 0x28; /* - msB */ + cmd[13] = 0x00; /* status = STATUS_OK */ + cmd[14] = 0x00; /* - msB */ + /* CSR BCC payload */ + memset(cmd + 15, 0, 6 * 2); + + /* Send command */ + do { + if (write(fd, cmd, clen) != clen) { + perror("Failed to write init command (GET_BUILD_ID)"); + return -1; + } + + /* Read reply. */ + if (read_hci_event(fd, resp, 100) < 0) { + perror("Failed to read init response (GET_BUILD_ID)"); + return -1; + } + + /* Event code 0xFF is for vendor-specific events, which is + * what we're looking for. */ + } while (resp[1] != 0xFF); + +#ifdef CSR_DEBUG + { + char temp[512]; + int i; + for (i=0; i < rlen; i++) + sprintf(temp + (i*3), "-%02X", resp[i]); + fprintf(stderr, "Reading CSR build ID %d [%s]\n", rlen, temp + 1); + // In theory, it should look like : + // 04-FF-13-FF-01-00-09-00-00-00-19-28-00-00-73-00-00-00-00-00-00-00 + } +#endif + /* Display that to user */ + fprintf(stderr, "CSR build ID 0x%02X-0x%02X\n", + resp[15] & 0xFF, resp[14] & 0xFF); + + /* Try to read the current speed of the CSR chip */ + clen = 5 + (5 + 4)*2; + /* -- HCI header */ + cmd[3] = 1 + (5 + 4)*2; /* len */ + /* -- CSR BCC header -- */ + cmd[9] = csr_seq & 0xFF; /* seq num */ + cmd[10] = (csr_seq >> 8) & 0xFF; /* - msB */ + csr_seq++; + cmd[11] = 0x02; /* var_id = CONFIG_UART */ + cmd[12] = 0x68; /* - msB */ + +#ifdef CSR_DEBUG + /* Send command */ + do { + if (write(fd, cmd, clen) != clen) { + perror("Failed to write init command (GET_BUILD_ID)"); + return -1; + } + + /* Read reply. */ + if (read_hci_event(fd, resp, 100) < 0) { + perror("Failed to read init response (GET_BUILD_ID)"); + return -1; + } + + /* Event code 0xFF is for vendor-specific events, which is + * what we're looking for. */ + } while (resp[1] != 0xFF); + + { + char temp[512]; + int i; + for (i=0; i < rlen; i++) + sprintf(temp + (i*3), "-%02X", resp[i]); + fprintf(stderr, "Reading CSR UART speed %d [%s]\n", rlen, temp+1); + } +#endif + + if (u->speed > 1500000) { + fprintf(stderr, "Speed %d too high. Remaining at %d baud\n", + u->speed, u->init_speed); + u->speed = u->init_speed; + } else if (u->speed != 57600 && uart_speed(u->speed) == B57600) { + /* Unknown speed. Why oh why can't we just pass an int to the kernel? */ + fprintf(stderr, "Speed %d unrecognised. Remaining at %d baud\n", + u->speed, u->init_speed); + u->speed = u->init_speed; + } + if (u->speed == u->init_speed) + return 0; + + /* Now, create the command that will set the UART speed */ + /* CSR BCC header */ + cmd[5] = 0x02; /* type = SET-REQ */ + cmd[6] = 0x00; /* - msB */ + cmd[9] = csr_seq & 0xFF; /* seq num */ + cmd[10] = (csr_seq >> 8) & 0xFF;/* - msB */ + csr_seq++; + + divisor = (u->speed*64+7812)/15625; + + /* No parity, one stop bit -> divisor |= 0x0000; */ + cmd[15] = (divisor) & 0xFF; /* divider */ + cmd[16] = (divisor >> 8) & 0xFF; /* - msB */ + /* The rest of the payload will be 0x00 */ + +#ifdef CSR_DEBUG + { + char temp[512]; + int i; + for(i = 0; i < clen; i++) + sprintf(temp + (i*3), "-%02X", cmd[i]); + fprintf(stderr, "Writing CSR UART speed %d [%s]\n", clen, temp + 1); + // In theory, it should look like : + // 01-00-FC-13-C2-02-00-09-00-03-00-02-68-00-00-BF-0E-00-00-00-00-00-00 + // 01-00-FC-13-C2-02-00-09-00-01-00-02-68-00-00-D8-01-00-00-00-00-00-00 + } +#endif + + /* Send the command to set the CSR UART speed */ + if (write(fd, cmd, clen) != clen) { + perror("Failed to write init command (SET_UART_SPEED)"); + return -1; + } + + nanosleep(&tm, NULL); + return 0; +} + +/* + * Silicon Wave specific initialization + * Thomas Moser + */ +static int swave(int fd, struct uart_t *u, struct termios *ti) +{ + struct timespec tm = { 0, 500000 }; + char cmd[10], rsp[100]; + int r; + + // Silicon Wave set baud rate command + // see HCI Vendor Specific Interface from Silicon Wave + // first send a "param access set" command to set the + // appropriate data fields in RAM. Then send a "HCI Reset + // Subcommand", e.g. "soft reset" to make the changes effective. + + cmd[0] = HCI_COMMAND_PKT; // it's a command packet + cmd[1] = 0x0B; // OCF 0x0B = param access set + cmd[2] = 0xfc; // OGF bx111111 = vendor specific + cmd[3] = 0x06; // 6 bytes of data following + cmd[4] = 0x01; // param sub command + cmd[5] = 0x11; // tag 17 = 0x11 = HCI Transport Params + cmd[6] = 0x03; // length of the parameter following + cmd[7] = 0x01; // HCI Transport flow control enable + cmd[8] = 0x01; // HCI Transport Type = UART + + switch (u->speed) { + case 19200: + cmd[9] = 0x03; + break; + case 38400: + cmd[9] = 0x02; + break; + case 57600: + cmd[9] = 0x01; + break; + case 115200: + cmd[9] = 0x00; + break; + default: + u->speed = 115200; + cmd[9] = 0x00; + break; + } + + /* Send initialization command */ + if (write(fd, cmd, 10) != 10) { + perror("Failed to write init command"); + return -1; + } + + // We should wait for a "GET Event" to confirm the success of + // the baud rate setting. Wait some time before reading. Better: + // read with timeout, parse data + // until correct answer, else error handling ... todo ... + + nanosleep(&tm, NULL); + + r = read(fd, rsp, sizeof(rsp)); + if (r > 0) { + // guess it's okay, but we should parse the reply. But since + // I don't react on an error anyway ... todo + // Response packet format: + // 04 Event + // FF Vendor specific + // 07 Parameter length + // 0B Subcommand + // 01 Setevent + // 11 Tag specifying HCI Transport Layer Parameter + // 03 length + // 01 flow on + // 01 Hci Transport type = Uart + // xx Baud rate set (see above) + } else { + // ups, got error. + return -1; + } + + // we probably got the reply. Now we must send the "soft reset" + // which is standard HCI RESET. + + cmd[0] = HCI_COMMAND_PKT; // it's a command packet + cmd[1] = 0x03; + cmd[2] = 0x0c; + cmd[3] = 0x00; + + /* Send reset command */ + if (write(fd, cmd, 4) != 4) { + perror("Can't write Silicon Wave reset cmd."); + return -1; + } + + nanosleep(&tm, NULL); + + // now the uart baud rate on the silicon wave module is set and effective. + // change our own baud rate as well. Then there is a reset event coming in + // on the *new* baud rate. This is *undocumented*! The packet looks like this: + // 04 FF 01 0B (which would make that a confirmation of 0x0B = "Param + // subcommand class". So: change to new baud rate, read with timeout, parse + // data, error handling. BTW: all param access in Silicon Wave is done this way. + // Maybe this code would belong in a separate file, or at least code reuse... + + return 0; +} + +/* + * ST Microelectronics specific initialization + * Marcel Holtmann + */ +static int st(int fd, struct uart_t *u, struct termios *ti) +{ + struct timespec tm = {0, 50000}; + char cmd[5]; + + /* ST Microelectronics set baud rate command */ + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x46; // OCF = Hci_Cmd_ST_Set_Uart_Baud_Rate + cmd[2] = 0xfc; // OGF = Vendor specific + cmd[3] = 0x01; + + switch (u->speed) { + case 9600: + cmd[4] = 0x09; + break; + case 19200: + cmd[4] = 0x0b; + break; + case 38400: + cmd[4] = 0x0d; + break; + case 57600: + cmd[4] = 0x0e; + break; + case 115200: + cmd[4] = 0x10; + break; + case 230400: + cmd[4] = 0x12; + break; + case 460800: + cmd[4] = 0x13; + break; + case 921600: + cmd[4] = 0x14; + break; + default: + cmd[4] = 0x10; + u->speed = 115200; + break; + } + + /* Send initialization command */ + if (write(fd, cmd, 5) != 5) { + perror("Failed to write init command"); + return -1; + } + + nanosleep(&tm, NULL); + return 0; +} + +static int stlc2500(int fd, struct uart_t *u, struct termios *ti) +{ + bdaddr_t bdaddr; + unsigned char resp[10]; + int n; + int rvalue; + + /* STLC2500 has an ericsson core */ + rvalue = ericsson(fd, u, ti); + if (rvalue != 0) + return rvalue; + +#ifdef STLC2500_DEBUG + fprintf(stderr, "Setting speed\n"); +#endif + if (set_speed(fd, ti, u->speed) < 0) { + perror("Can't set baud rate"); + return -1; + } + +#ifdef STLC2500_DEBUG + fprintf(stderr, "Speed set...\n"); +#endif + + /* Read reply */ + if ((n = read_hci_event(fd, resp, 10)) < 0) { + fprintf(stderr, "Failed to set baud rate on chip\n"); + return -1; + } + +#ifdef STLC2500_DEBUG + for (i = 0; i < n; i++) { + fprintf(stderr, "resp[%d] = %02x\n", i, resp[i]); + } +#endif + + str2ba(u->bdaddr, &bdaddr); + return stlc2500_init(fd, &bdaddr); +} + +static int bgb2xx(int fd, struct uart_t *u, struct termios *ti) +{ + bdaddr_t bdaddr; + + str2ba(u->bdaddr, &bdaddr); + + return bgb2xx_init(fd, &bdaddr); +} + +/* + * Broadcom specific initialization + * Extracted from Jungo openrg + */ +static int bcm2035(int fd, struct uart_t *u, struct termios *ti) +{ + int n; + unsigned char cmd[30], resp[30]; + + /* Reset the BT Chip */ + memset(cmd, 0, sizeof(cmd)); + memset(resp, 0, sizeof(resp)); + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x03; + cmd[2] = 0x0c; + cmd[3] = 0x00; + + /* Send command */ + if (write(fd, cmd, 4) != 4) { + fprintf(stderr, "Failed to write reset command\n"); + return -1; + } + + /* Read reply */ + if ((n = read_hci_event(fd, resp, 4)) < 0) { + fprintf(stderr, "Failed to reset chip\n"); + return -1; + } + + if (u->bdaddr != NULL) { + /* Set BD_ADDR */ + memset(cmd, 0, sizeof(cmd)); + memset(resp, 0, sizeof(resp)); + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x01; + cmd[2] = 0xfc; + cmd[3] = 0x06; + str2ba(u->bdaddr, (bdaddr_t *) (cmd + 4)); + + /* Send command */ + if (write(fd, cmd, 10) != 10) { + fprintf(stderr, "Failed to write BD_ADDR command\n"); + return -1; + } + + /* Read reply */ + if ((n = read_hci_event(fd, resp, 10)) < 0) { + fprintf(stderr, "Failed to set BD_ADDR\n"); + return -1; + } + } + + /* Read the local version info */ + memset(cmd, 0, sizeof(cmd)); + memset(resp, 0, sizeof(resp)); + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x01; + cmd[2] = 0x10; + cmd[3] = 0x00; + + /* Send command */ + if (write(fd, cmd, 4) != 4) { + fprintf(stderr, "Failed to write \"read local version\" " + "command\n"); + return -1; + } + + /* Read reply */ + if ((n = read_hci_event(fd, resp, 4)) < 0) { + fprintf(stderr, "Failed to read local version\n"); + return -1; + } + + /* Read the local supported commands info */ + memset(cmd, 0, sizeof(cmd)); + memset(resp, 0, sizeof(resp)); + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x02; + cmd[2] = 0x10; + cmd[3] = 0x00; + + /* Send command */ + if (write(fd, cmd, 4) != 4) { + fprintf(stderr, "Failed to write \"read local supported " + "commands\" command\n"); + return -1; + } + + /* Read reply */ + if ((n = read_hci_event(fd, resp, 4)) < 0) { + fprintf(stderr, "Failed to read local supported commands\n"); + return -1; + } + + /* Set the baud rate */ + memset(cmd, 0, sizeof(cmd)); + memset(resp, 0, sizeof(resp)); + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x18; + cmd[2] = 0xfc; + cmd[3] = 0x02; + switch (u->speed) { + case 57600: + cmd[4] = 0x00; + cmd[5] = 0xe6; + break; + case 230400: + cmd[4] = 0x22; + cmd[5] = 0xfa; + break; + case 460800: + cmd[4] = 0x22; + cmd[5] = 0xfd; + break; + case 921600: + cmd[4] = 0x55; + cmd[5] = 0xff; + break; + default: + /* Default is 115200 */ + cmd[4] = 0x00; + cmd[5] = 0xf3; + break; + } + fprintf(stderr, "Baud rate parameters: DHBR=0x%2x,DLBR=0x%2x\n", + cmd[4], cmd[5]); + + /* Send command */ + if (write(fd, cmd, 6) != 6) { + fprintf(stderr, "Failed to write \"set baud rate\" command\n"); + return -1; + } + + if ((n = read_hci_event(fd, resp, 6)) < 0) { + fprintf(stderr, "Failed to set baud rate\n"); + return -1; + } + + return 0; +} + +struct uart_t uart[] = { + { "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, NULL, NULL }, + + { "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, + FLOW_CTL, DISABLE_PM, NULL, ericsson, NULL }, + + { "digi", 0x0000, 0x0000, HCI_UART_H4, 9600, 115200, + FLOW_CTL, DISABLE_PM, NULL, digi, NULL }, + + { "bcsp", 0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200, + 0, DISABLE_PM, NULL, bcsp, NULL }, + + /* Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter */ + { "xircom", 0x0105, 0x080a, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, NULL, NULL }, + + /* CSR Casira serial adapter or BrainBoxes serial dongle (BL642) */ + { "csr", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, csr, NULL }, + + /* BrainBoxes PCMCIA card (BL620) */ + { "bboxes", 0x0160, 0x0002, HCI_UART_H4, 115200, 460800, + FLOW_CTL, DISABLE_PM, NULL, csr, NULL }, + + /* Silicon Wave kits */ + { "swave", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, swave, NULL }, + + /* Texas Instruments Bluelink (BRF) modules */ + { "texas", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, texas, texas2 }, + + { "texasalt", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, texasalt, NULL }, + + /* ST Microelectronics minikits based on STLC2410/STLC2415 */ + { "st", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, + FLOW_CTL, DISABLE_PM, NULL, st, NULL }, + + /* ST Microelectronics minikits based on STLC2500 */ + { "stlc2500", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, "00:80:E1:00:AB:BA", stlc2500, NULL }, + + /* Philips generic Ericsson IP core based */ + { "philips", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, NULL, NULL }, + + /* Philips BGB2xx Module */ + { "bgb2xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, "BD:B2:10:00:AB:BA", bgb2xx, NULL }, + + /* Sphinx Electronics PICO Card */ + { "picocard", 0x025e, 0x1000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, NULL, NULL }, + + /* Inventel BlueBird Module */ + { "inventel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, NULL, NULL }, + + /* COM One Platinium Bluetooth PC Card */ + { "comone", 0xffff, 0x0101, HCI_UART_BCSP, 115200, 115200, + 0, DISABLE_PM, NULL, bcsp, NULL }, + + /* TDK Bluetooth PC Card and IBM Bluetooth PC Card II */ + { "tdk", 0x0105, 0x4254, HCI_UART_BCSP, 115200, 115200, + 0, DISABLE_PM, NULL, bcsp, NULL }, + + /* Socket Bluetooth CF Card (Rev G) */ + { "socket", 0x0104, 0x0096, HCI_UART_BCSP, 230400, 230400, + 0, DISABLE_PM, NULL, bcsp, NULL }, + + /* 3Com Bluetooth Card (Version 3.0) */ + { "3com", 0x0101, 0x0041, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, csr, NULL }, + + /* AmbiCom BT2000C Bluetooth PC/CF Card */ + { "bt2000c", 0x022d, 0x2000, HCI_UART_H4, 57600, 460800, + FLOW_CTL, DISABLE_PM, NULL, csr, NULL }, + + /* Zoom Bluetooth PCMCIA Card */ + { "zoom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, + 0, DISABLE_PM, NULL, bcsp, NULL }, + + /* Sitecom CN-504 PCMCIA Card */ + { "sitecom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, + 0, DISABLE_PM, NULL, bcsp, NULL }, + + /* Billionton PCBTC1 PCMCIA Card */ + { "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, + 0, DISABLE_PM, NULL, bcsp, NULL }, + + /* Broadcom BCM2035 */ + { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, + FLOW_CTL, DISABLE_PM, NULL, bcm2035, NULL }, + + /* Broadcom BCM43XX */ + { "bcm43xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 3000000, + FLOW_CTL, DISABLE_PM, NULL, bcm43xx, NULL }, + + { "ath3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, ath3k_ps, ath3k_pm }, + + /* QUALCOMM BTS */ + { "qualcomm", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, qualcomm, NULL }, + + /* Intel Bluetooth Module */ + { "intel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + FLOW_CTL, DISABLE_PM, NULL, intel, NULL }, + + /* Three-wire UART */ + { "3wire", 0x0000, 0x0000, HCI_UART_3WIRE, 115200, 115200, + 0, DISABLE_PM, NULL, NULL, NULL }, + + /* AMP controller UART */ + { "amp", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, + AMP_DEV, DISABLE_PM, NULL, NULL, NULL }, + +//Realtek_add_start + /* Realtek Bluetooth H4*/ + /* H4 will set 115200 baudrate and flow control enable by default*/ + { "rtk_h4", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, DISABLE_PM, NULL, realtek_init, realtek_post}, + /* Realtek Bluetooth H5*/ + /* H5 will set 921600 baudrate and flow control disable by default */ + /* H5 will be realtek's recommanded protocol */ + { "rtk_h5", 0x0000, 0x0000, HCI_UART_3WIRE, 115200,115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post}, +//Realtek_add_end + + { "xradio", 0x0000, 0x0000, HCI_UART_H4, 115200, 1500000, 0, DISABLE_PM, NULL, xradio_init, xradio_post}, + { "sprd", 0x0000, 0x0000, NULL, 115200, 1500000, FLOW_CTL, DISABLE_PM, NULL, sprd_init, sprd_post}, + + { NULL, 0 } +}; + +static struct uart_t * get_by_id(int m_id, int p_id) +{ + int i; + for (i = 0; uart[i].type; i++) { + if (uart[i].m_id == m_id && uart[i].p_id == p_id) + return &uart[i]; + } + return NULL; +} + +static struct uart_t * get_by_type(char *type) +{ + int i; + for (i = 0; uart[i].type; i++) { + if (!strcmp(uart[i].type, type)) + return &uart[i]; + } + return NULL; +} + +/* Initialize UART driver */ +static int init_uart(char *dev, struct uart_t *u, int send_break, int raw) +{ + struct termios ti; + int fd, i; + unsigned long flags = 0; + + if (raw) + flags |= 1 << HCI_UART_RAW_DEVICE; + + if (u->flags & AMP_DEV) + flags |= 1 << HCI_UART_CREATE_AMP; + + fd = open(dev, O_RDWR | O_NOCTTY); + if (fd < 0) { + perror("Can't open serial port"); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (tcgetattr(fd, &ti) < 0) { + perror("Can't get port settings"); + 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) { + perror("Can't set port settings"); + return -1; + } + + /* Set initial baudrate */ + if (set_speed(fd, &ti, u->init_speed) < 0) { + perror("Can't set initial baud rate"); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (send_break) { + tcsendbreak(fd, 0); + usleep(500000); + } + + if (u->init && u->init(fd, u, &ti) < 0) + return -1; + + tcflush(fd, TCIOFLUSH); + + /* Set actual baudrate */ + if (set_speed(fd, &ti, u->speed) < 0) { + perror("Can't set baud rate"); + return -1; + } + + /* Set TTY to N_HCI line discipline */ + 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 (u->post && u->post(fd, u, &ti) < 0) + return -1; + + return fd; +} + +static void usage(void) +{ + printf("hciattach - HCI UART driver initialization utility\n"); + printf("Usage:\n"); + printf("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] [speed] [flow|noflow] [bdaddr]\n"); + printf("\thciattach -l\n"); +} + +int main(int argc, char *argv[]) +{ + struct uart_t *u = NULL; + int detach, printpid, raw, opt, i, n, ld, err; + int to = 10; + int init_speed = 0; + int send_break = 0; + pid_t pid; + struct sigaction sa; + struct pollfd p; + sigset_t sigs; + char dev[PATH_MAX]; + + detach = 1; + printpid = 0; + raw = 0; + + while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) { + switch(opt) { + case 'b': + send_break = 1; + break; + + case 'n': + detach = 0; + break; + + case 'p': + printpid = 1; + break; + + case 't': + to = atoi(optarg); + break; + + case 's': + init_speed = atoi(optarg); + break; + + case 'l': + for (i = 0; uart[i].type; i++) { + printf("%-10s0x%04x,0x%04x\n", uart[i].type, + uart[i].m_id, uart[i].p_id); + } + exit(0); + + case 'r': + raw = 1; + break; + + default: + usage(); + exit(1); + } + } + + n = argc - optind; + if (n < 2) { + usage(); + exit(1); + } + + for (n = 0; optind < argc; n++, optind++) { + char *opt; + + opt = argv[optind]; + + switch(n) { + case 0: + dev[0] = 0; + if (!strchr(opt, '/')) + strcpy(dev, "/dev/"); + strcat(dev, opt); + break; + + case 1: + if (strchr(argv[optind], ',')) { + uint32_t m_id, p_id; + sscanf(argv[optind], "%x,%x", &m_id, &p_id); + u = get_by_id(m_id, p_id); + } else { + u = get_by_type(opt); + } + + if (!u) { + fprintf(stderr, "Unknown device type or id\n"); + exit(1); + } + + break; + + case 2: + u->speed = atoi(argv[optind]); + break; + + case 3: + if (!strcmp("flow", argv[optind])) + u->flags |= FLOW_CTL; + else + u->flags &= ~FLOW_CTL; + break; + + case 4: + if (!strcmp("sleep", argv[optind])) + u->pm = ENABLE_PM; + else + u->pm = DISABLE_PM; + break; + + case 5: + u->bdaddr = argv[optind]; + break; + } + } + + if (!u) { + fprintf(stderr, "Unknown device type or id\n"); + exit(1); + } + + /* If user specified a initial speed, use that instead of + the hardware's default */ + if (init_speed) + u->init_speed = init_speed; + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = sig_alarm; + sigaction(SIGALRM, &sa, NULL); + + /* 10 seconds should be enough for initialization */ + alarm(to); + bcsp_max_retries = to; + + n = init_uart(dev, u, send_break, raw); + if (n < 0) { + perror("Can't initialize device"); + exit(1); + } + + printf("Device setup complete\n"); + + alarm(0); + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + + sa.sa_handler = sig_term; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + sa.sa_handler = sig_hup; + sigaction(SIGHUP, &sa, NULL); + + if (detach) { + if ((pid = fork())) { + if (printpid) + printf("%d\n", pid); + return 0; + } + + for (i = 0; i < 20; i++) + if (i != n) + close(i); + } + + p.fd = n; + p.events = POLLERR | POLLHUP; + + sigfillset(&sigs); + sigdelset(&sigs, SIGCHLD); + sigdelset(&sigs, SIGPIPE); + sigdelset(&sigs, SIGTERM); + sigdelset(&sigs, SIGINT); + sigdelset(&sigs, SIGHUP); + + while (!__io_canceled) { + p.revents = 0; + err = ppoll(&p, 1, NULL, &sigs); + if (err < 0 && errno == EINTR) + continue; + if (err) + break; + } + + /* Restore TTY line discipline */ + ld = N_TTY; + if (ioctl(n, TIOCSETD, &ld) < 0) { + perror("Can't restore line discipline"); + exit(1); + } + + return 0; +} diff --git a/external/cache/sources/hcitools/hciattach.h b/external/cache/sources/hcitools/hciattach.h new file mode 100644 index 000000000000..f92af74aa2ba --- /dev/null +++ b/external/cache/sources/hcitools/hciattach.h @@ -0,0 +1,96 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2003-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include + +#ifndef N_HCI +#define N_HCI 15 +#endif + +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) +#define HCIUARTGETDEVICE _IOR('U', 202, int) +#define HCIUARTSETFLAGS _IOW('U', 203, int) +#define HCIUARTGETFLAGS _IOR('U', 204, int) + +#define HCI_UART_H4 0 +#define HCI_UART_BCSP 1 +#define HCI_UART_3WIRE 2 +#define HCI_UART_H4DS 3 +#define HCI_UART_LL 4 +#define HCI_UART_ATH3K 5 + +#define HCI_UART_RAW_DEVICE 0 +#define HCI_UART_RESET_ON_INIT 1 +#define HCI_UART_CREATE_AMP 2 + +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); +}; + +#define FLOW_CTL 0x0001 +#define AMP_DEV 0x0002 +#define ENABLE_PM 1 +#define DISABLE_PM 0 + +int read_hci_event(int fd, unsigned char *buf, int size); +int set_speed(int fd, struct termios *ti, int speed); +int uart_speed(int speed); + +int texas_init(int fd, int *speed, struct termios *ti); +int texas_post(int fd, struct termios *ti); +int texasalt_init(int fd, int speed, struct termios *ti); +int stlc2500_init(int fd, bdaddr_t *bdaddr); +int bgb2xx_init(int dd, bdaddr_t *bdaddr); +int ath3k_init(int fd, int speed, int init_speed, char *bdaddr, + struct termios *ti); +int ath3k_post(int fd, int pm); +int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr); +int intel_init(int fd, int init_speed, int *speed, struct termios *ti); +int bcm43xx_init(int fd, int speed, struct termios *ti, const char *bdaddr); + +//Realtek_add_start +//add realtek init and post process for realtek Bluetooth chip +int rtk_init(int fd, int proto, int speed, struct termios *ti); +int rtk_post(int fd, int proto, struct termios *ti); +//Realtek_add_end + +// add xradio init and post process for xradio Bluetooth chip (xr829) +int xr_init(int fd, struct uart_t *u, struct termios *ti); +int xr_post(int fd, struct uart_t *u, struct termios *ti); + +// add sprd init and post process for sprd Bluetooth chip (UWE5622) +int sprd_config_init(int fd, struct uart_t *u, struct termios *ti); +int sprd_config_post(int fd, struct uart_t *u, struct termios *ti); diff --git a/external/cache/sources/hcitools/hciattach_ath3k.c b/external/cache/sources/hcitools/hciattach_ath3k.c new file mode 100644 index 000000000000..23208c66c044 --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_ath3k.c @@ -0,0 +1,1044 @@ +/* + * Copyright (c) 2009-2010 Atheros Communications Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hciattach.h" + +#define TRUE 1 +#define FALSE 0 + +#define FW_PATH "/lib/firmware/ar3k/" + +struct ps_cfg_entry { + uint32_t id; + uint32_t len; + uint8_t *data; +}; + +struct ps_entry_type { + unsigned char type; + unsigned char array; +}; + +#define MAX_TAGS 50 +#define PS_HDR_LEN 4 +#define HCI_VENDOR_CMD_OGF 0x3F +#define HCI_PS_CMD_OCF 0x0B + +struct ps_cfg_entry ps_list[MAX_TAGS]; + +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; +} + +#define PS_EVENT_LEN 100 + +/* + * 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; +} + +#define HCI_EV_SUCCESS 0x00 + +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; +} + +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_WRITE 1 +#define PS_RESET 2 +#define WRITE_PATCH 8 +#define ENABLE_PATCH 11 + +#define HCI_PS_CMD_HDR_LEN 7 + +#define PS_RESET_PARAM_LEN 6 +#define HCI_MAX_CMD_SIZE 260 +#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 __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; +} + +struct tag_info { + unsigned section; + unsigned line_count; + unsigned char_cnt; + unsigned 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; +} + +/* 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'; + + strncpy(buf, &ptr[info->char_cnt], 2); + tag->data[info->byte_count] = strtol(buf, NULL, 16); + info->char_cnt += 3; + info->byte_count++; + + strncpy(buf, &ptr[info->char_cnt], 2); + tag->data[info->byte_count] = strtol(buf, NULL, 16); + info->char_cnt += 3; + info->byte_count++; +} + +#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)++) + +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 MAX_PATCH_CMD 244 +struct patch_entry { + int16_t len; + uint8_t data[MAX_PATCH_CMD]; +}; + +#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]; + int i, j; + char loc_byte[3]; + uint8_t *event; + uint8_t *loc_ptr = &cmd[7]; + + 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) { + strncpy(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]; + 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; +} + +#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; +} + +#define PS_ASIC_FILE "PS_ASIC.pst" +#define PS_FPGA_FILE "PS_FPGA.pst" + +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); +} + +#define VERIFY_CRC 9 +#define PS_REGION 1 +#define PATCH_REGION 2 + +static int get_ath3k_crc(int dev) +{ + uint8_t cmd[7]; + 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 DEV_REGISTER 0x4FFC +#define GET_DEV_TYPE_OCF 0x05 + +static int get_device_type(int dev, uint32_t *code) +{ + uint8_t cmd[8]; + 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]; + 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; +} + +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 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; +} + +#define BDADDR_FILE "ar3kbdaddr.pst" + +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); +} + +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) { + perror("firmware file open error\n"); + 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; +} + +#define HCI_SLEEP_CMD_OCF 0x04 + +/* + * 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 HCI_VENDOR_CMD_OGF 0x3F +#define HCI_PS_CMD_OCF 0x0B +#define HCI_CHG_BAUD_CMD_OCF 0x0C + +#define WRITE_BDADDR_CMD_LEN 14 +#define WRITE_BAUD_CMD_LEN 6 +#define MAX_CMD_LEN WRITE_BDADDR_CMD_LEN + +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) { + perror("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; +} + +/* + * Atheros AR300x specific initialization and configuration file + * download + */ +int ath3k_init(int fd, int speed, int init_speed, char *bdaddr, + struct termios *ti) +{ + int r; + int err = 0; + 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 both controller and host baud rate to maximum possible value */ + err = set_cntrlr_baud(fd, speed); + if (err < 0) + return err; + + err = set_speed(fd, ti, speed); + if (err < 0) { + perror("Can't set required baud rate"); + return err; + } + + /* Download PS and patch */ + r = ath_ps_download(fd); + if (r < 0) { + perror("Failed to Download configuration"); + err = -ETIMEDOUT; + goto failed; + } + + /* 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) { + perror("Failed to write BD_ADDR command\n"); + err = -ETIMEDOUT; + goto failed; + } + + if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) { + perror("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; + } + + err = set_cntrlr_baud(fd, speed); + if (err < 0) + return err; + +failed: + if (err < 0) { + set_cntrlr_baud(fd, init_speed); + set_speed(fd, ti, init_speed); + } + + return err; +} diff --git a/external/cache/sources/hcitools/hciattach_bcm43xx.c b/external/cache/sources/hcitools/hciattach_bcm43xx.c new file mode 100644 index 000000000000..ad9b239be4c7 --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_bcm43xx.c @@ -0,0 +1,378 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2014 Intel Corporation. All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hciattach.h" + +#ifndef FIRMWARE_DIR +#define FIRMWARE_DIR "/etc/firmware" +#endif + +#define FW_EXT ".hcd" + +#define BCM43XX_CLOCK_48 1 +#define BCM43XX_CLOCK_24 2 + +#define CMD_SUCCESS 0x00 + +#define CC_MIN_SIZE 7 + +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) + +static int bcm43xx_read_local_name(int fd, char *name, size_t size) +{ + unsigned char cmd[] = { HCI_COMMAND_PKT, 0x14, 0x0C, 0x00 }; + unsigned char *resp; + unsigned int name_len; + + resp = malloc(size + CC_MIN_SIZE); + if (!resp) + return -1; + + tcflush(fd, TCIOFLUSH); + + if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) { + fprintf(stderr, "Failed to write read local name command\n"); + goto fail; + } + + if (read_hci_event(fd, resp, size) < CC_MIN_SIZE) { + fprintf(stderr, "Failed to read local name, invalid HCI event\n"); + goto fail; + } + + if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) { + fprintf(stderr, "Failed to read local name, command failure\n"); + goto fail; + } + + name_len = resp[2] - 1; + + strncpy(name, (char *) &resp[7], MIN(name_len, size)); + name[size - 1] = 0; + + free(resp); + return 0; + +fail: + free(resp); + return -1; +} + +static int bcm43xx_reset(int fd) +{ + unsigned char cmd[] = { HCI_COMMAND_PKT, 0x03, 0x0C, 0x00 }; + unsigned char resp[CC_MIN_SIZE]; + + if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) { + fprintf(stderr, "Failed to write reset command\n"); + return -1; + } + + if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) { + fprintf(stderr, "Failed to reset chip, invalid HCI event\n"); + return -1; + } + + if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) { + fprintf(stderr, "Failed to reset chip, command failure\n"); + return -1; + } + + return 0; +} + +static int bcm43xx_set_bdaddr(int fd, const char *bdaddr) +{ + unsigned char cmd[] = + { HCI_COMMAND_PKT, 0x01, 0xfc, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + unsigned char resp[CC_MIN_SIZE]; + + printf("Set BDADDR UART: %s\n", bdaddr); + + if (str2ba(bdaddr, (bdaddr_t *) (&cmd[4])) < 0) { + fprintf(stderr, "Incorrect bdaddr\n"); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) { + fprintf(stderr, "Failed to write set bdaddr command\n"); + return -1; + } + + if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) { + fprintf(stderr, "Failed to set bdaddr, invalid HCI event\n"); + return -1; + } + + if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) { + fprintf(stderr, "Failed to set bdaddr, command failure\n"); + return -1; + } + + return 0; +} + +static int bcm43xx_set_speed(int fd, uint32_t speed) +{ + unsigned char cmd[] = + { HCI_COMMAND_PKT, 0x18, 0xfc, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + unsigned char resp[CC_MIN_SIZE]; + + printf("Set Controller UART speed to %d bit/s\n", speed); + + cmd[6] = (uint8_t) (speed); + cmd[7] = (uint8_t) (speed >> 8); + cmd[8] = (uint8_t) (speed >> 16); + cmd[9] = (uint8_t) (speed >> 24); + + tcflush(fd, TCIOFLUSH); + + if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) { + fprintf(stderr, "Failed to write update baudrate command\n"); + return -1; + } + + if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) { + fprintf(stderr, "Failed to update baudrate, invalid HCI event\n"); + return -1; + } + + if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) { + fprintf(stderr, "Failed to update baudrate, command failure\n"); + return -1; + } + + return 0; +} + +static int bcm43xx_set_clock(int fd, unsigned char clock) +{ + unsigned char cmd[] = { HCI_COMMAND_PKT, 0x45, 0xfc, 0x01, 0x00 }; + unsigned char resp[CC_MIN_SIZE]; + + printf("Set Controller clock (%d)\n", clock); + + cmd[4] = clock; + + tcflush(fd, TCIOFLUSH); + + if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) { + fprintf(stderr, "Failed to write update clock command\n"); + return -1; + } + + if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) { + fprintf(stderr, "Failed to update clock, invalid HCI event\n"); + return -1; + } + + if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) { + fprintf(stderr, "Failed to update clock, command failure\n"); + return -1; + } + + return 0; +} + +static int bcm43xx_load_firmware(int fd, const char *fw) +{ + unsigned char cmd[] = { HCI_COMMAND_PKT, 0x2e, 0xfc, 0x00 }; + struct timespec tm_mode = { 0, 50000 }; + struct timespec tm_ready = { 0, 2000000 }; + unsigned char resp[CC_MIN_SIZE]; + unsigned char tx_buf[1024]; + int len, fd_fw, n; + + printf("Flash firmware %s\n", fw); + + fd_fw = open(fw, O_RDONLY); + if (fd_fw < 0) { + fprintf(stderr, "Unable to open firmware (%s)\n", fw); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) { + fprintf(stderr, "Failed to write download mode command\n"); + goto fail; + } + + if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) { + fprintf(stderr, "Failed to load firmware, invalid HCI event\n"); + goto fail; + } + + if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) { + fprintf(stderr, "Failed to load firmware, command failure\n"); + goto fail; + } + + /* Wait 50ms to let the firmware placed in download mode */ + nanosleep(&tm_mode, NULL); + + tcflush(fd, TCIOFLUSH); + + while ((n = read(fd_fw, &tx_buf[1], 3))) { + if (n < 0) { + fprintf(stderr, "Failed to read firmware\n"); + goto fail; + } + + tx_buf[0] = HCI_COMMAND_PKT; + + len = tx_buf[3]; + + if (read(fd_fw, &tx_buf[4], len) < 0) { + fprintf(stderr, "Failed to read firmware\n"); + goto fail; + } + + if (write(fd, tx_buf, len + 4) != (len + 4)) { + fprintf(stderr, "Failed to write firmware\n"); + goto fail; + } + + read_hci_event(fd, resp, sizeof(resp)); + tcflush(fd, TCIOFLUSH); + } + + /* Wait for firmware ready */ + nanosleep(&tm_ready, NULL); + + close(fd_fw); + return 0; + +fail: + close(fd_fw); + return -1; +} + +static int bcm43xx_locate_patch(const char *dir_name, + const char *chip_name, char *location) +{ + DIR *dir; + int ret = -1; + + dir = opendir(dir_name); + if (!dir) { + fprintf(stderr, "Cannot open directory '%s': %s\n", + dir_name, strerror(errno)); + return -1; + } + + /* Recursively look for a BCM43XX*.hcd */ + while (1) { + struct dirent *entry = readdir(dir); + if (!entry) + break; + + if (entry->d_type & DT_DIR) { + char path[PATH_MAX]; + + if (!strcmp(entry->d_name, "..") || !strcmp(entry->d_name, ".")) + continue; + + snprintf(path, PATH_MAX, "%s/%s", dir_name, entry->d_name); + + ret = bcm43xx_locate_patch(path, chip_name, location); + if (!ret) + break; + } else if (!strncmp(chip_name, entry->d_name, strlen(chip_name))) { + unsigned int name_len = strlen(entry->d_name); + size_t curs_ext = name_len - sizeof(FW_EXT) + 1; + + if (curs_ext > name_len) + break; + + if (strncmp(FW_EXT, &entry->d_name[curs_ext], sizeof(FW_EXT))) + break; + + /* found */ + snprintf(location, PATH_MAX, "%s/%s", dir_name, entry->d_name); + ret = 0; + break; + } + } + + closedir(dir); + + return ret; +} + +int bcm43xx_init(int fd, int speed, struct termios *ti, const char *bdaddr) +{ + char chip_name[20]; + char fw_path[PATH_MAX]; + + printf("bcm43xx_init\n"); + + if (bcm43xx_reset(fd)) + return -1; + + if (bcm43xx_read_local_name(fd, chip_name, sizeof(chip_name))) + return -1; + + if (bcm43xx_locate_patch(FIRMWARE_DIR, chip_name, fw_path)) { + fprintf(stderr, "Patch not found, continue anyway\n"); + } else { + if (bcm43xx_load_firmware(fd, fw_path)) + return -1; + + if (bcm43xx_reset(fd)) + return -1; + } + + if (bdaddr) + bcm43xx_set_bdaddr(fd, bdaddr); + + if (speed > 3000000 && bcm43xx_set_clock(fd, BCM43XX_CLOCK_48)) + return -1; + + if (bcm43xx_set_speed(fd, speed)) + return -1; + + return 0; +} diff --git a/external/cache/sources/hcitools/hciattach_intel.c b/external/cache/sources/hcitools/hciattach_intel.c new file mode 100644 index 000000000000..749098ef92e0 --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_intel.c @@ -0,0 +1,595 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hciattach.h" + +#ifdef INTEL_DEBUG +#define DBGPRINT(fmt, args...) printf("DBG: " fmt "\n", ## args) +#define PRINT_PACKET(buf, len, msg) { \ + int i; \ + printf("%s\n", msg); \ + for (i = 0; i < len; i++) \ + printf("%02X ", buf[i]); \ + printf("\n"); \ + } +#else +#define DBGPRINT(fmt, args...) +#define PRINT_PACKET(buf, len, msg) +#endif + +#define PATCH_SEQ_EXT ".bseq" +#define PATCH_FILE_PATH "/lib/firmware/intel/" +#define PATCH_MAX_LEN 260 +#define PATCH_TYPE_CMD 1 +#define PATCH_TYPE_EVT 2 + +#define INTEL_VER_PARAM_LEN 9 +#define INTEL_MFG_PARAM_LEN 2 + +/** + * A data structure for a patch entry. + */ +struct patch_entry { + int type; + int len; + unsigned char data[PATCH_MAX_LEN]; +}; + +/** + * A structure for patch context + */ +struct patch_ctx { + int dev; + int fd; + int patch_error; + int reset_enable_patch; +}; + +/** + * Send HCI command to the controller + */ +static int intel_write_cmd(int dev, unsigned char *buf, int len) +{ + int ret; + + PRINT_PACKET(buf, len, "<----- SEND CMD: "); + + ret = write(dev, buf, len); + if (ret < 0) + return -errno; + + if (ret != len) + return -1; + + return ret; +} + +/** + * Read the event from the controller + */ +static int intel_read_evt(int dev, unsigned char *buf, int len) +{ + int ret; + + ret = read_hci_event(dev, buf, len); + if (ret < 0) + return -1; + + PRINT_PACKET(buf, ret, "-----> READ EVT: "); + + return ret; +} + +/** + * Validate HCI events + */ +static int validate_events(struct patch_entry *event, + struct patch_entry *entry) +{ + if (event == NULL || entry == NULL) { + DBGPRINT("invalid patch entry parameters"); + return -1; + } + + if (event->len != entry->len) { + DBGPRINT("lengths are mismatched:[%d|%d]", + event->len, entry->len); + return -1; + } + + if (memcmp(event->data, entry->data, event->len)) { + DBGPRINT("data is mismatched"); + return -1; + } + + return 0; +} + +/** + * Read the next patch entry one line at a time + */ +static int get_next_patch_entry(int fd, struct patch_entry *entry) +{ + int size; + char rb; + + if (read(fd, &rb, 1) <= 0) + return 0; + + entry->type = rb; + + switch (entry->type) { + case PATCH_TYPE_CMD: + entry->data[0] = HCI_COMMAND_PKT; + + if (read(fd, &entry->data[1], 3) < 0) + return -1; + + size = (int)entry->data[3]; + + if (read(fd, &entry->data[4], size) < 0) + return -1; + + entry->len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + size; + + break; + + case PATCH_TYPE_EVT: + entry->data[0] = HCI_EVENT_PKT; + + if (read(fd, &entry->data[1], 2) < 0) + return -1; + + size = (int)entry->data[2]; + + if (read(fd, &entry->data[3], size) < 0) + return -1; + + entry->len = HCI_TYPE_LEN + HCI_EVENT_HDR_SIZE + size; + + break; + + default: + fprintf(stderr, "invalid patch entry(%d)\n", entry->type); + return -1; + } + + return entry->len; +} + +/** + * Download the patch set to the controller and verify the event + */ +static int intel_download_patch(struct patch_ctx *ctx) +{ + int ret; + struct patch_entry entry; + struct patch_entry event; + + DBGPRINT("start patch downloading"); + + do { + ret = get_next_patch_entry(ctx->fd, &entry); + if (ret <= 0) { + ctx->patch_error = 1; + break; + } + + switch (entry.type) { + case PATCH_TYPE_CMD: + ret = intel_write_cmd(ctx->dev, + entry.data, + entry.len); + if (ret <= 0) { + fprintf(stderr, "failed to send cmd(%d)\n", + ret); + return ret; + } + break; + + case PATCH_TYPE_EVT: + ret = intel_read_evt(ctx->dev, event.data, + sizeof(event.data)); + if (ret <= 0) { + fprintf(stderr, "failed to read evt(%d)\n", + ret); + return ret; + } + event.len = ret; + + if (validate_events(&event, &entry) < 0) { + DBGPRINT("events are mismatched"); + ctx->patch_error = 1; + return -1; + } + break; + + default: + fprintf(stderr, "unknown patch type(%d)\n", + entry.type); + return -1; + } + } while (1); + + return ret; +} + +static int open_patch_file(struct patch_ctx *ctx, char *fw_ver) +{ + char patch_file[PATH_MAX]; + + snprintf(patch_file, PATH_MAX, "%s%s%s", PATCH_FILE_PATH, + fw_ver, PATCH_SEQ_EXT); + DBGPRINT("PATCH_FILE: %s", patch_file); + + ctx->fd = open(patch_file, O_RDONLY); + if (ctx->fd < 0) { + DBGPRINT("cannot open patch file. go to post patch"); + return -1; + } + + return 0; +} + +/** + * Prepare the controller for patching. + */ +static int pre_patch(struct patch_ctx *ctx) +{ + int ret, i; + struct patch_entry entry; + char fw_ver[INTEL_VER_PARAM_LEN * 2]; + + DBGPRINT("start pre_patch"); + + entry.data[0] = HCI_COMMAND_PKT; + entry.data[1] = 0x11; + entry.data[2] = 0xFC; + entry.data[3] = 0x02; + entry.data[4] = 0x01; + entry.data[5] = 0x00; + entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + INTEL_MFG_PARAM_LEN; + + ret = intel_write_cmd(ctx->dev, entry.data, entry.len); + if (ret < 0) { + fprintf(stderr, "failed to send cmd(%d)\n", ret); + return ret; + } + + ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data)); + if (ret < 0) { + fprintf(stderr, "failed to read evt(%d)\n", ret); + return ret; + } + entry.len = ret; + + if (entry.data[6] != 0x00) { + DBGPRINT("command failed. status=%02x", entry.data[6]); + ctx->patch_error = 1; + return -1; + } + + entry.data[0] = HCI_COMMAND_PKT; + entry.data[1] = 0x05; + entry.data[2] = 0xFC; + entry.data[3] = 0x00; + entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE; + + ret = intel_write_cmd(ctx->dev, entry.data, entry.len); + if (ret < 0) { + fprintf(stderr, "failed to send cmd(%d)\n", ret); + return ret; + } + + ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data)); + if (ret < 0) { + fprintf(stderr, "failed to read evt(%d)\n", ret); + return ret; + } + entry.len = ret; + + if (entry.data[6] != 0x00) { + DBGPRINT("command failed. status=%02x", entry.data[6]); + ctx->patch_error = 1; + return -1; + } + + for (i = 0; i < INTEL_VER_PARAM_LEN; i++) + sprintf(&fw_ver[i*2], "%02x", entry.data[7+i]); + + if (open_patch_file(ctx, fw_ver) < 0) { + ctx->patch_error = 1; + return -1; + } + + return ret; +} + +/* + * check the event is startup event + */ +static int is_startup_evt(unsigned char *buf) +{ + if (buf[1] == 0xFF && buf[2] == 0x01 && buf[3] == 0x00) + return 1; + + return 0; +} + +/** + * Finalize the patch process and reset the controller + */ +static int post_patch(struct patch_ctx *ctx) +{ + int ret; + struct patch_entry entry; + + DBGPRINT("start post_patch"); + + entry.data[0] = HCI_COMMAND_PKT; + entry.data[1] = 0x11; + entry.data[2] = 0xFC; + entry.data[3] = 0x02; + entry.data[4] = 0x00; + if (ctx->reset_enable_patch) + entry.data[5] = 0x02; + else + entry.data[5] = 0x01; + + entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + INTEL_MFG_PARAM_LEN; + + ret = intel_write_cmd(ctx->dev, entry.data, entry.len); + if (ret < 0) { + fprintf(stderr, "failed to send cmd(%d)\n", ret); + return ret; + } + + ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data)); + if (ret < 0) { + fprintf(stderr, "failed to read evt(%d)\n", ret); + return ret; + } + entry.len = ret; + + if (entry.data[6] != 0x00) { + fprintf(stderr, "cmd failed. st=%02x\n", entry.data[6]); + return -1; + } + + do { + ret = intel_read_evt(ctx->dev, entry.data, + sizeof(entry.data)); + if (ret < 0) { + fprintf(stderr, "failed to read cmd(%d)\n", ret); + return ret; + } + entry.len = ret; + } while (!is_startup_evt(entry.data)); + + return ret; +} + +/** + * Main routine that handles the device patching process. + */ +static int intel_patch_device(struct patch_ctx *ctx) +{ + int ret; + + ret = pre_patch(ctx); + if (ret < 0) { + if (!ctx->patch_error) { + fprintf(stderr, "I/O error: pre_patch failed\n"); + return ret; + } + + DBGPRINT("patch failed. proceed to post patch"); + goto post_patch; + } + + ret = intel_download_patch(ctx); + if (ret < 0) { + if (!ctx->patch_error) { + fprintf(stderr, "I/O error: download_patch failed\n"); + close(ctx->fd); + return ret; + } + } else { + DBGPRINT("patch done"); + ctx->reset_enable_patch = 1; + } + + close(ctx->fd); + +post_patch: + ret = post_patch(ctx); + if (ret < 0) { + fprintf(stderr, "post_patch failed(%d)\n", ret); + return ret; + } + + return 0; +} + +static int set_rts(int dev, int rtsval) +{ + int arg; + + if (ioctl(dev, TIOCMGET, &arg) < 0) { + perror("cannot get TIOCMGET"); + return -errno; + } + if (rtsval) + arg |= TIOCM_RTS; + else + arg &= ~TIOCM_RTS; + + if (ioctl(dev, TIOCMSET, &arg) == -1) { + perror("cannot set TIOCMGET"); + return -errno; + } + + return 0; +} + +static unsigned char get_intel_speed(int speed) +{ + switch (speed) { + case 9600: + return 0x00; + case 19200: + return 0x01; + case 38400: + return 0x02; + case 57600: + return 0x03; + case 115200: + return 0x04; + case 230400: + return 0x05; + case 460800: + return 0x06; + case 921600: + return 0x07; + case 1843200: + return 0x08; + case 3250000: + return 0x09; + case 2000000: + return 0x0A; + case 3000000: + return 0x0B; + default: + return 0xFF; + } +} + +/** + * if it failed to change to new baudrate, it will rollback + * to initial baudrate + */ +static int change_baudrate(int dev, int init_speed, int *speed, + struct termios *ti) +{ + int ret; + unsigned char br; + unsigned char cmd[5]; + unsigned char evt[7]; + + DBGPRINT("start baudrate change"); + + ret = set_rts(dev, 0); + if (ret < 0) { + fprintf(stderr, "failed to clear RTS\n"); + return ret; + } + + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x06; + cmd[2] = 0xFC; + cmd[3] = 0x01; + + br = get_intel_speed(*speed); + if (br == 0xFF) { + fprintf(stderr, "speed %d is not supported\n", *speed); + return -1; + } + cmd[4] = br; + + ret = intel_write_cmd(dev, cmd, sizeof(cmd)); + if (ret < 0) { + fprintf(stderr, "failed to send cmd(%d)\n", ret); + return ret; + } + + /* + * wait for buffer to be consumed by the controller + */ + usleep(300000); + + if (set_speed(dev, ti, *speed) < 0) { + fprintf(stderr, "can't set to new baud rate\n"); + return -1; + } + + ret = set_rts(dev, 1); + if (ret < 0) { + fprintf(stderr, "failed to set RTS\n"); + return ret; + } + + ret = intel_read_evt(dev, evt, sizeof(evt)); + if (ret < 0) { + fprintf(stderr, "failed to read evt(%d)\n", ret); + return ret; + } + + if (evt[4] != 0x00) { + fprintf(stderr, + "failed to change speed. use default speed %d\n", + init_speed); + *speed = init_speed; + } + + return 0; +} + +/** + * An entry point for Intel specific initialization + */ +int intel_init(int dev, int init_speed, int *speed, struct termios *ti) +{ + int ret = 0; + struct patch_ctx ctx; + + if (change_baudrate(dev, init_speed, speed, ti) < 0) + return -1; + + ctx.dev = dev; + ctx.patch_error = 0; + ctx.reset_enable_patch = 0; + + ret = intel_patch_device(&ctx); + if (ret < 0) + fprintf(stderr, "failed to initialize the device"); + + return ret; +} diff --git a/external/cache/sources/hcitools/hciattach_qualcomm.c b/external/cache/sources/hcitools/hciattach_qualcomm.c new file mode 100644 index 000000000000..0e02e1e92adc --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_qualcomm.c @@ -0,0 +1,273 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2010 Marcel Holtmann + * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hciattach.h" + +#define FAILIF(x, args...) do { \ + if (x) { \ + fprintf(stderr, ##args); \ + return -1; \ + } \ +} while (0) + +typedef struct { + uint8_t uart_prefix; + hci_event_hdr hci_hdr; + evt_cmd_complete cmd_complete; + uint8_t status; + uint8_t data[16]; +} __attribute__((packed)) command_complete_t; + +static int read_command_complete(int fd, + unsigned short opcode, + unsigned char len) +{ + command_complete_t resp; + unsigned char vsevent[512]; + int n; + + /* Read reply. */ + n = read_hci_event(fd, vsevent, sizeof(vsevent)); + FAILIF(n < 0, "Failed to read response"); + + FAILIF(vsevent[1] != 0xFF, "Failed to read response"); + + n = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp)); + FAILIF(n < 0, "Failed to read response"); + + /* event must be event-complete */ + FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE, + "Error in response: not a cmd-complete event, " + "but 0x%02x!\n", resp.hci_hdr.evt); + + FAILIF(resp.hci_hdr.plen < 4, /* plen >= 4 for EVT_CMD_COMPLETE */ + "Error in response: plen is not >= 4, but 0x%02x!\n", + resp.hci_hdr.plen); + + /* cmd-complete event: opcode */ + FAILIF(resp.cmd_complete.opcode != 0, + "Error in response: opcode is 0x%04x, not 0!", + resp.cmd_complete.opcode); + + return resp.status == 0 ? 0 : -1; +} + +static int qualcomm_load_firmware(int fd, const char *firmware, const char *bdaddr_s) +{ + + int fw = open(firmware, O_RDONLY); + + fprintf(stdout, "Opening firmware file: %s\n", firmware); + + FAILIF(fw < 0, + "Could not open firmware file %s: %s (%d).\n", + firmware, strerror(errno), errno); + + fprintf(stdout, "Uploading firmware...\n"); + do { + /* Read each command and wait for a response. */ + unsigned char data[1024]; + unsigned char cmdp[1 + sizeof(hci_command_hdr)]; + hci_command_hdr *cmd = (hci_command_hdr *) (cmdp + 1); + int nr; + + nr = read(fw, cmdp, sizeof(cmdp)); + if (!nr) + break; + + FAILIF(nr != sizeof(cmdp), + "Could not read H4 + HCI header!\n"); + FAILIF(*cmdp != HCI_COMMAND_PKT, + "Command is not an H4 command packet!\n"); + + FAILIF(read(fw, data, cmd->plen) != cmd->plen, + "Could not read %d bytes of data \ + for command with opcode %04x!\n", + cmd->plen, cmd->opcode); + + if ((data[0] == 1) && (data[1] == 2) && (data[2] == 6)) { + bdaddr_t bdaddr; + if (bdaddr_s != NULL) { + str2ba(bdaddr_s, &bdaddr); + memcpy(&data[3], &bdaddr, sizeof(bdaddr_t)); + } + } + + { + int nw; + struct iovec iov_cmd[2]; + iov_cmd[0].iov_base = cmdp; + iov_cmd[0].iov_len = sizeof(cmdp); + iov_cmd[1].iov_base = data; + iov_cmd[1].iov_len = cmd->plen; + nw = writev(fd, iov_cmd, 2); + FAILIF(nw != (int) sizeof(cmdp) + cmd->plen, + "Could not send entire command \ + (sent only %d bytes)!\n", + nw); + } + + /* Wait for response */ + if (read_command_complete(fd, cmd->opcode, cmd->plen) < 0) + return -1; + } while (1); + fprintf(stdout, "Firmware upload successful.\n"); + + close(fw); + + return 0; +} + +int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr) +{ + struct timespec tm = {0, 50000}; + char cmd[5]; + unsigned char resp[100]; /* Response */ + char fw[100]; + int n; + + memset(resp, 0, 100); + + /* Get Manufacturer and LMP version */ + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x01; + cmd[2] = 0x10; + cmd[3] = 0x00; + + do { + n = write(fd, cmd, 4); + if (n < 4) { + perror("Failed to write init command"); + return -1; + } + + /* Read reply. */ + if (read_hci_event(fd, resp, 100) < 0) { + perror("Failed to read init response"); + return -1; + } + + /* Wait for command complete event for our Opcode */ + } while (resp[4] != cmd[1] && resp[5] != cmd[2]); + + /* Verify manufacturer */ + if ((resp[11] & 0xFF) != 0x1d) + fprintf(stderr, + "WARNING : module's manufacturer is not Qualcomm\n"); + + /* Print LMP version */ + fprintf(stderr, + "Qualcomm module LMP version : 0x%02x\n", resp[10] & 0xFF); + + /* Print LMP subversion */ + { + unsigned short lmp_subv = resp[13] | (resp[14] << 8); + + fprintf(stderr, "Qualcomm module LMP sub-version : 0x%04x\n", + lmp_subv); + } + + /* Get SoC type */ + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x00; + cmd[2] = 0xFC; + cmd[3] = 0x01; + cmd[4] = 0x06; + + do { + n = write(fd, cmd, 5); + if (n < 5) { + perror("Failed to write vendor init command"); + return -1; + } + + /* Read reply. */ + if ((n = read_hci_event(fd, resp, 100)) < 0) { + perror("Failed to read vendor init response"); + return -1; + } + + } while (resp[3] != 0 && resp[4] != 2); + + snprintf(fw, sizeof(fw), "/etc/firmware/%c%c%c%c%c%c_%c%c%c%c.bin", + resp[18], resp[19], resp[20], resp[21], + resp[22], resp[23], + resp[32], resp[33], resp[34], resp[35]); + + /* Wait for command complete event for our Opcode */ + if (read_hci_event(fd, resp, 100) < 0) { + perror("Failed to read init response"); + return -1; + } + + qualcomm_load_firmware(fd, fw, bdaddr); + + /* Reset */ + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x03; + cmd[2] = 0x0C; + cmd[3] = 0x00; + + do { + n = write(fd, cmd, 4); + if (n < 4) { + perror("Failed to write reset command"); + return -1; + } + + /* Read reply. */ + if ((n = read_hci_event(fd, resp, 100)) < 0) { + perror("Failed to read reset response"); + return -1; + } + + } while (resp[4] != cmd[1] && resp[5] != cmd[2]); + + nanosleep(&tm, NULL); + + return 0; +} diff --git a/external/cache/sources/hcitools/hciattach_rtk.c b/external/cache/sources/hcitools/hciattach_rtk.c new file mode 100644 index 000000000000..6739406ece69 --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_rtk.c @@ -0,0 +1,2563 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2010 Marcel Holtmann + * Copyright (C) 2013-2014 Realtek Semiconductor Corp. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#define Config_Android 0 /*1 for android; 0 for Linux*/ + +#if Config_Android //for Android +#include +#include +#include +#else //for Linux +#include +#include +#include +#include +#include +#endif + +#include "hciattach.h" + +#define BAUDRATE_4BYTES +#define RTK_VERSION "2.3" +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cpu_to_le16(d) (d) +#define cpu_to_le32(d) (d) +#define le16_to_cpu(d) (d) +#define le32_to_cpu(d) (d) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_le16(d) bswap_16(d) +#define cpu_to_le32(d) bswap_32(d) +#define le16_to_cpu(d) bswap_16(d) +#define le32_to_cpu(d) bswap_32(d) +#else +#error "Unknown byte order" +#endif + +/* log related */ +#define LOG_STR "Realtek Bluetooth" +#define DBG_ON 1 + +#define RS_DBG(fmt, arg...) \ + do { \ + if (DBG_ON) \ + fprintf(stderr, "%s: " fmt "\n", LOG_STR, ##arg); \ + } while (0) + +#define RS_ERR(fmt, arg...) \ + do { \ + fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg);\ + perror("reason: "); \ + } while (0) + +#define RS_DUMP(buffer, len) \ + do { \ + fprintf(stderr, "%s: ", LOG_STR); \ + for (int i = 0; i < len; i++) { \ + if (i && !(i % 16)) { \ + fprintf(stderr, "\n"); \ + fprintf(stderr, "%s: ", LOG_STR); \ + } \ + fprintf(stderr, "%02x ", buffer[i]); \ + } \ + fprintf(stderr, "\n"); \ + } while (0) + +struct sk_buff { + uint32_t max_len; + uint32_t data_len; + uint8_t data[0]; +}; + +/* Skb helpers */ +struct bt_skb_cb { + uint8_t pkt_type; + uint8_t incoming; + uint16_t expect; + uint8_t tx_seq; + uint8_t retries; + uint8_t sar; + uint16_t channel; +}; + +typedef struct { + uint8_t index; + uint8_t data[252]; +} __attribute__ ((packed)) download_vendor_patch_cp; + +struct hci_command_hdr { + uint16_t opcode; /* OCF & OGF */ + uint8_t plen; +} __attribute__ ((packed)); + +struct hci_event_hdr { + uint8_t evt; + uint8_t plen; +} __attribute__ ((packed)); + +struct hci_ev_cmd_complete { + uint8_t ncmd; + uint16_t opcode; +} __attribute__ ((packed)); + +#define HCI_COMMAND_HDR_SIZE 3 +#define HCI_EVENT_HDR_SIZE 2 + +#define HCI_CMD_READ_BD_ADDR 0x1009 +#define HCI_VENDOR_CHANGE_BDRATE 0xfc17 +#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d +#define HCI_VENDOR_READ_LMP_VERISION 0x1001 +#define HCI_VENDOR_READ_CHIP_TYPE 0xfc61 + +#define ROM_LMP_8723a 0x1200 + +#define RTK_VENDOR_CONFIG_MAGIC 0x8723ab55 + +#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) + +#if Config_Android +#define FIRMWARE_DIRECTORY "/system/vendor/etc/firmware" +#define BT_CONFIG_DIRECTORY "/system/vendor/etc/firmware" +#else +#define FIRMWARE_DIRECTORY "/system/vendor/etc/firmware" +#define BT_CONFIG_DIRECTORY "/system/vendor/etc/firmware" +#endif + +#define BT_ADDR_DIR "/data/misc/bluetooth/" +#define BT_ADDR_FILE "/data/misc/bluetooth/btmac.txt" + +#define PATCH_DATA_FIELD_MAX_SIZE 252 +#define READ_DATA_SIZE 16 + +/* HCI data types */ +#define H5_ACK_PKT 0x00 +#define HCI_COMMAND_PKT 0x01 +#define HCI_ACLDATA_PKT 0x02 +#define HCI_SCODATA_PKT 0x03 +#define HCI_EVENT_PKT 0x04 +#define H5_VDRSPEC_PKT 0x0E +#define H5_LINK_CTL_PKT 0x0F + + +#define HCI_VERSION_MASK_10 (1<<0) // Bluetooth Core Spec 1.0b +#define HCI_VERSION_MASK_11 (1<<1) // Bluetooth Core Spec 1.1 +#define HCI_VERSION_MASK_12 (1<<2) // Bluetooth Core Spec 1.2 +#define HCI_VERSION_MASK_20 (1<<3) // Bluetooth Core Spec 2.0+EDR +#define HCI_VERSION_MASK_21 (1<<4) // Bluetooth Core Spec 2.1+EDR +#define HCI_VERSION_MASK_30 (1<<5) // Bluetooth Core Spec 3.0+HS +#define HCI_VERSION_MASK_40 (1<<6) // Bluetooth Core Spec 4.0 +#define HCI_VERSION_MASK_41 (1<<7) // Bluetooth Core Spec 4.1 +#define HCI_VERSION_MASK_42 (1<<8) // Bluetooth Core Spec 4.2 +#define HCI_VERSION_MASK_ALL (0xFFFFFFFF) + +#define HCI_REVISION_MASK_ALL (0xFFFFFFFF) + +#define LMP_SUBVERSION_NONE (0x0) + +#define CHIPTYPE_NONE (0x1F) // Chip Type's range: 0x0 ~ 0xF +#define CHIP_TYPE_MASK_ALL (0xFFFFFFFF) + +#define PROJECT_ID_MASK_ALL (0xFFFFFFFF) // temp used for unknow project id for a new chip + +#define CONFIG_MAC_OFFSET_GEN_1_2 (0x3C) // MAC's OFFSET in config/efuse for realtek generation 1~2 bluetooth chip +#define CONFIG_MAC_OFFSET_GEN_3PLUS (0x44) // MAC's OFFSET in config/efuse for rtk generation 3+ bluetooth chip +#define CONFIG_MAC_OFFSET_GEN_4PLUS (0x30) // MAC's OFFSET in config/efuse for rtk generation 4+ bluetooth chip + +#define PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE (0x1) + +#define MAX_PATCH_SIZE_24K (1024*24) // 24K +#define MAX_PATCH_SIZE_40K (1024*40) // 40K + +struct rtk_bt_vendor_config_entry { + uint16_t offset; + uint8_t entry_len; + uint8_t entry_data[0]; +} __attribute__ ((packed)); + +struct rtk_bt_vendor_config { + uint32_t signature; + uint16_t data_len; + struct rtk_bt_vendor_config_entry entry[0]; +} __attribute__ ((packed)); + +struct rtk_epatch_entry { + uint16_t chipID; + uint16_t patch_length; + uint32_t start_offset; +} __attribute__ ((packed)); + +struct rtk_epatch { + uint8_t signature[8]; + uint32_t fm_version; + uint16_t number_of_total_patch; + struct rtk_epatch_entry entry[0]; +} __attribute__ ((packed)); + +typedef enum _RTK_ROM_VERSION_CMD_STATE { + cmd_not_send, + cmd_has_sent, + event_received +} RTK_ROM_VERSION_CMD_STATE; + +#pragma pack(1) +#if __BYTE_ORDER == __LITTLE_ENDIAN +typedef struct _H5_PKT_HEADER { + uint8_t SeqNumber:3; + uint8_t AckNumber:3; + uint8_t DicPresent:1; /* Data Integrity Check Present */ + uint8_t ReliablePkt:1; + uint16_t PktType:4; + uint16_t PayloadLen:12; + uint8_t HdrChecksum; +} H5_PKT_HEADER; +#else +typedef struct _H5_PKT_HEADER { + uint8_t ReliablePkt:1; + uint8_t DicPresent:1; /* Data Integrity Check Present */ + uint8_t AckNumber:3; + uint8_t SeqNumber:3; + uint16_t PayloadLen:12; + uint16_t PktType:4; + uint8_t HdrChecksum; +} H5_PKT_HEADER; +#endif + +typedef enum _H5_RX_STATE { + H5_W4_PKT_DELIMITER, + H5_W4_PKT_START, + H5_W4_HDR, + H5_W4_DATA, + H5_W4_CRC +} H5_RX_STATE; + +typedef enum _H5_RX_ESC_STATE { + H5_ESCSTATE_NOESC, + H5_ESCSTATE_ESC +} H5_RX_ESC_STATE; + +typedef enum _H5_LINK_STATE { + H5_SYNC, + H5_CONFIG, + H5_INIT, + H5_PATCH, + H5_ACTIVE +} H5_LINK_STATE; + +typedef enum _PATCH_PROTOCOL { + PATCH_PROTOCAL_H4, + PATCH_PROTOCAL_H5 +} PATCH_PROTOCOL; + +struct rtk_h5_struct { + uint8_t rxseq_txack; /* rxseq == txack. expected rx SeqNumber */ + uint8_t rxack; /* Last packet sent by us that the peer ack'ed */ + uint8_t use_crc; + uint8_t is_txack_req; /* txack required? Do we need to send ack's to the peer? */ + /* Reliable packet sequence number - used to assign seq to each rel pkt. */ + uint8_t msgq_txseq; /* next pkt seq */ + uint16_t message_crc; + uint32_t rx_count; /* expected pkts to recv */ + H5_RX_STATE rx_state; + H5_RX_ESC_STATE rx_esc_state; + H5_LINK_STATE link_estab_state; + struct sk_buff *rx_skb; + struct sk_buff *host_last_cmd; +}; + +struct patch_struct { + int nTxIndex; /* current sending pkt number */ + int nTotal; /* total pkt number */ + int nRxIndex; /* ack index from board */ + int nNeedRetry; /* if no response from board */ +}; + +typedef struct { + uint16_t lmp_subversion; + uint32_t hci_version_mask; + uint32_t hci_revision_mask; + uint32_t chip_type_mask; + uint32_t project_id_mask; + char *patch_name; + char *config_name; + uint16_t mac_offset; + uint32_t max_patch_size; +} patch_info; + +/* h/w config control block */ +typedef struct { + uint32_t max_patch_size; + uint32_t baudrate; + uint16_t lmp_subversion; + uint16_t lmp_subversion_default; + uint16_t lmp_sub_current; + uint8_t state; /* Hardware configuration state */ + uint8_t eversion; + uint32_t project_id_mask; + uint8_t hci_version; + uint8_t hci_revision; + uint8_t chip_type; +} bt_hw_cfg_cb_t; + +static patch_info patch_table[] = { +/* lmp_subv hci_version_mask hci_revision_mask chip_type_mask project_id_mask fw name config name mac offset max_patch_size */ + {0x1200, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<0, "rtl8723as_fw", "rtl8723as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8723AS +#ifdef RTL_8723BS_BT_USED + {0x8723, ~(HCI_VERSION_MASK_21), ~(1<<0xd), CHIP_TYPE_MASK_ALL, 1<<1, "rtl8723bs_fw", "rtl8723bs_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8723BS +#else + {0x8723, ~(HCI_VERSION_MASK_21), ~(1<<0xd), CHIP_TYPE_MASK_ALL, 1<<1, "rtl8723bs_VQ0_fw", "rtl8723bs_VQ0_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8723BS_VQ0 +#endif + {0x8821, HCI_VERSION_MASK_ALL, ~(1<<0xc), CHIP_TYPE_MASK_ALL, 1<<2, "rtl8821as_fw", "rtl8821as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8821AS +/* {0x8761, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<3, "rtl8761at_fw", "rtl8761at_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8761AW */ + {0x8761, HCI_VERSION_MASK_ALL, ~(1<<0xb), CHIP_TYPE_MASK_ALL, 1<<3, "rtl8761at_fw", "rtl8761at_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8761AW + {0x8761, HCI_VERSION_MASK_ALL, (1<<0xb), CHIP_TYPE_MASK_ALL, 1<<14, "rtl8761bt_fw", "rtl8761bt_config", CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, //Rtl8761BW + + {0x8723, HCI_VERSION_MASK_21, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<4, "rtl8703as_fw", "rtl8703as_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, //Rtl8703AS + + {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<7, 1<<6, "rtl8703bs_fw", "rtl8703bs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //Rtl8703BS + {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<5, 1<<7, "rtl8723cs_xx_fw", "rtl8723cs_xx_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_xx + {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<3, 1<<7, "rtl8723cs_cg_fw", "rtl8723cs_cg_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_cg + {0x8703, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, 1<<4, 1<<7, "rtl8723cs_vf_fw", "rtl8723cs_vf_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //rtl8723cs_vf +/* {0x8822, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, 1<<8, "rtl8822bs_fw", "rtl8822bs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //Rtl8822BS */ + {0x8822, HCI_VERSION_MASK_ALL, ~(1<<0xc), CHIP_TYPE_MASK_ALL, 1<<8, "rtl8822bs_fw", "rtl8822bs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, //Rtl8822BS + {0x8822, HCI_VERSION_MASK_ALL, (1<<0xc), CHIP_TYPE_MASK_ALL, 1<<13, "rtl8822cs_fw", "rtl8822cs_config", CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, //Rtl8822CS + + {0x8723, HCI_VERSION_MASK_ALL, (1<<0xd), ~(1<<7), 1<<9, "rtl8723ds_fw", "rtl8723ds_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //Rtl8723ds + {0x8723, HCI_VERSION_MASK_ALL, (1<<0xd), 1<<7, 1<<9, "rtl8703cs_fw", "rtl8703cs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //Rtl8703cs + {0x8821, HCI_VERSION_MASK_ALL, (1<<0xc), CHIP_TYPE_MASK_ALL, 1<<10, "rtl8821cs_fw", "rtl8821cs_config", CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, //RTL8821CS +/* todo: RTL8703CS */ + {LMP_SUBVERSION_NONE, HCI_VERSION_MASK_ALL, HCI_REVISION_MASK_ALL, CHIP_TYPE_MASK_ALL, PROJECT_ID_MASK_ALL, "rtl_none_fw", "rtl_none_config", CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K} +}; + +static bt_hw_cfg_cb_t hw_cfg_cb; +static uint8_t gEVersion; +static RTK_ROM_VERSION_CMD_STATE gRom_version_cmd_state; +static RTK_ROM_VERSION_CMD_STATE ghci_version_cmd_state; +static RTK_ROM_VERSION_CMD_STATE gchip_type_cmd_state; +static int gHwFlowControlEnable; +static int gFinalSpeed; + +/* signature: Realtech */ +static const uint8_t RTK_EPATCH_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; +/* Extension Section IGNATURE:0x77FD0451 */ +static const uint8_t Extension_Section_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; + +static int serial_fd; +static int h5_max_retries = 40; +static struct rtk_h5_struct rtk_h5; +static struct patch_struct rtk_patch; + +/* bite reverse in bytes + 00000001 -> 10000000 + 00000100 -> 00100000 + */ +static const uint8_t byte_rev_table[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +/* reverse bit */ +static __inline uint8_t bit_rev8(uint8_t byte) +{ + return byte_rev_table[byte]; +} + +/* reverse bit */ +static __inline uint16_t bit_rev16(uint16_t x) +{ + return (bit_rev8(x & 0xff) << 8) | bit_rev8(x >> 8); +} + +static const uint16_t crc_table[] = { + 0x0000, 0x1081, 0x2102, 0x3183, + 0x4204, 0x5285, 0x6306, 0x7387, + 0x8408, 0x9489, 0xa50a, 0xb58b, + 0xc60c, 0xd68d, 0xe70e, 0xf78f +}; + +/** +* Malloc the socket buffer +* +* @param skb socket buffer +* @return the point to the malloc buffer +*/ +static __inline struct sk_buff *skb_alloc(uint32_t len) +{ + struct sk_buff *skb = NULL; + skb = malloc(len + 8); + if (skb) { + skb->max_len = len; + skb->data_len = 0; + memset(skb->data, 0, len); + } else { + RS_ERR("Allocate skb fails!!!"); + skb = NULL; + } + return skb; +} + +/** +* Free the socket buffer +* +* @param skb socket buffer +*/ +static __inline void skb_free(struct sk_buff *skb) +{ + free(skb); + return; +} + +/** +* Increase the date length in sk_buffer by len, +* and return the increased header pointer +* +* @param skb socket buffer +* @param len length want to increase +* @return the pointer to increased header +*/ +static uint8_t *skb_put(struct sk_buff *skb, uint32_t len) +{ + uint32_t old_len = skb->data_len; + if ((skb->data_len + len) > (skb->max_len)) { + RS_ERR("Buffer too small"); + return NULL; + } + skb->data_len += len; + return (skb->data + old_len); +} + +/** +* decrease data length in sk_buffer by to len by cut the tail +* +* @warning len should be less than skb->len +* +* @param skb socket buffer +* @param len length want to be changed +*/ +static void skb_trim(struct sk_buff *skb, int len) +{ + if (skb->data_len > len) { + skb->data_len = len; + } else { + RS_ERR("Error: skb->data_len(%ld) < len(%d)", (long int)skb->data_len, len); + } +} + +/** +* Decrease the data length in sk_buffer by len, +* and move the content forward to the header. +* the data in header will be removed. +* +* @param skb socket buffer +* @param len length of data +* @return new data +*/ +static uint8_t *skb_pull(struct sk_buff *skb, uint32_t len) +{ + skb->data_len -= len; + char *buf; + buf = malloc(skb->data_len); + if (!buf) { + RS_ERR("Unable to allocate file buffer"); + exit(1); + } + memcpy(buf, skb->data+len, skb->data_len); + memcpy(skb->data, buf, skb->data_len); + free(buf); + return skb->data; +} + +/** +* Add "d" into crc scope, caculate the new crc value +* +* @param crc crc data +* @param d one byte data +*/ +static void h5_crc_update(uint16_t *crc, uint8_t d) +{ + uint16_t reg = *crc; + + reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; + reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; + + *crc = reg; +} + +struct __una_u16 { uint16_t x; }; + +static __inline uint16_t __get_unaligned_cpu16(const void *p) +{ + const struct __una_u16 *ptr = (const struct __una_u16 *)p; + return ptr->x; +} + +static __inline uint16_t get_unaligned_be16(const void *p) +{ + return __get_unaligned_cpu16((const uint8_t *)p); +} + +/** +* Get crc data. +* +* @param h5 realtek h5 struct +* @return crc data +*/ +static uint16_t h5_get_crc(struct rtk_h5_struct *h5) +{ + uint16_t crc = 0; + uint8_t *data = h5->rx_skb->data + h5->rx_skb->data_len - 2; + crc = data[1] + (data[0] << 8); + return crc; +} + +/** +* Just add 0xc0 at the end of skb, +* we can also use this to add 0xc0 at start while there is no data in skb +* +* @param skb socket buffer +*/ +static void h5_slip_msgdelim(struct sk_buff *skb) +{ + const char pkt_delim = 0xc0; + memcpy(skb_put(skb, 1), &pkt_delim, 1); +} + +/** +* Slip ecode one byte in h5 proto, as follows: +* 0xc0 -> 0xdb, 0xdc +* 0xdb -> 0xdb, 0xdd +* 0x11 -> 0xdb, 0xde +* 0x13 -> 0xdb, 0xdf +* others will not change +* +* @param skb socket buffer +* @c pure data in the one byte +*/ +static void h5_slip_one_byte(struct sk_buff *skb, uint8_t c) +{ + const int8_t esc_c0[2] = { 0xdb, 0xdc }; + const int8_t esc_db[2] = { 0xdb, 0xdd }; + const int8_t esc_11[2] = { 0xdb, 0xde }; + const int8_t esc_13[2] = { 0xdb, 0xdf }; + + switch (c) { + case 0xc0: + memcpy(skb_put(skb, 2), &esc_c0, 2); + break; + case 0xdb: + memcpy(skb_put(skb, 2), &esc_db, 2); + break; + case 0x11: + memcpy(skb_put(skb, 2), &esc_11, 2); + break; + case 0x13: + memcpy(skb_put(skb, 2), &esc_13, 2); + break; + default: + memcpy(skb_put(skb, 1), &c, 1); + } +} + +/** +* Decode one byte in h5 proto, as follows: +* 0xdb, 0xdc -> 0xc0 +* 0xdb, 0xdd -> 0xdb +* 0xdb, 0xde -> 0x11 +* 0xdb, 0xdf -> 0x13 +* others will not change +* +* @param h5 realtek h5 struct +* @byte pure data in the one byte +*/ +static void h5_unslip_one_byte(struct rtk_h5_struct *h5, char byte) +{ + const uint8_t c0 = 0xc0, db = 0xdb; + const uint8_t oof1 = 0x11, oof2 = 0x13; + //RS_DBG("HCI 3wire h5_unslip_one_byte"); + + if (H5_ESCSTATE_NOESC == h5->rx_esc_state) { + if (0xdb == byte) { + h5->rx_esc_state = H5_ESCSTATE_ESC; + } else { + memcpy(skb_put(h5->rx_skb, 1), &byte, 1); + //Check Pkt Header's CRC enable bit + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) { + h5_crc_update(&h5->message_crc, byte); + } + h5->rx_count--; + } + } else if (H5_ESCSTATE_ESC == h5->rx_esc_state) { + switch (byte) { + case 0xdc: + memcpy(skb_put(h5->rx_skb, 1), &c0, 1); + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) + h5_crc_update(&h5->message_crc, 0xc0); + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->rx_count--; + break; + case 0xdd: + memcpy(skb_put(h5->rx_skb, 1), &db, 1); + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) + h5_crc_update(&h5->message_crc, 0xdb); + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->rx_count--; + break; + case 0xde: + memcpy(skb_put(h5->rx_skb, 1), &oof1, 1); + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) + h5_crc_update(&h5->message_crc, oof1); + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->rx_count--; + break; + case 0xdf: + memcpy(skb_put(h5->rx_skb, 1), &oof2, 1); + if ((h5->rx_skb->data[0] & 0x40) != 0 && h5->rx_state != H5_W4_CRC) + h5_crc_update(&h5->message_crc, oof2); + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->rx_count--; + break; + default: + RS_ERR("Error: Invalid byte %02x after esc byte", byte); + skb_free(h5->rx_skb); + h5->rx_skb = NULL; + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + break; + } + } +} + +/** +* Prepare h5 packet, packet format as follow: +* | LSB 4 octets | 0 ~ 4095 | 2 MSB +* |packet header | payload | data integrity check | +* +* pakcket header fromat is show below: +* | LSB 3 bits | 3 bits | 1 bits | 1 bits | +* | 4 bits | 12 bits | 8 bits MSB +* |sequence number | acknowledgement number | data integrity check present | reliable packet | +* |packet type | payload length | header checksum +* +* @param h5 realtek h5 struct +* @param data pure data +* @param len the length of data +* @param pkt_type packet type +* @return socket buff after prepare in h5 proto +*/ +static struct sk_buff *h5_prepare_pkt(struct rtk_h5_struct *h5, uint8_t *data, int32_t len, int32_t pkt_type) +{ + struct sk_buff *nskb; + uint8_t hdr[4]; + uint16_t h5_txmsg_crc = 0xffff; + int rel, i; + + switch (pkt_type) { + case HCI_ACLDATA_PKT: + case HCI_COMMAND_PKT: + case HCI_EVENT_PKT: + rel = 1; /* reliable */ + break; + case H5_ACK_PKT: + case H5_VDRSPEC_PKT: + case H5_LINK_CTL_PKT: + rel = 0; /* unreliable */ + break; + default: + RS_ERR("Unknown packet type"); + return NULL; + } + + /* Max len of packet: (original len +4(h5 hdr) + 2(crc)) * 2 + * (because bytes 0xc0 and 0xdb are escaped, worst case is + * when the packet is all made of 0xc0 and 0xdb :)) + * + 2 (0xc0 delimiters at start and end). */ + nskb = skb_alloc((len + 6) * 2 + 2); + if (!nskb) + return NULL; + + /* Add SLIP start byte: 0xc0 */ + h5_slip_msgdelim(nskb); + /* set AckNumber in SlipHeader */ + hdr[0] = h5->rxseq_txack << 3; + h5->is_txack_req = 0; + + if (rel) { + /* set reliable pkt bit and SeqNumber */ + hdr[0] |= 0x80 + h5->msgq_txseq; + ++(h5->msgq_txseq); + h5->msgq_txseq = (h5->msgq_txseq) & 0x07; + } + + /* set DicPresent bit */ + if (h5->use_crc) + hdr[0] |= 0x40; + + /* set packet type and payload length */ + hdr[1] = ((len << 4) & 0xff) | pkt_type; + hdr[2] = (uint8_t)(len >> 4); + /* set checksum */ + hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); + + /* Put h5 header */ + for (i = 0; i < 4; i++) { + h5_slip_one_byte(nskb, hdr[i]); + + if (h5->use_crc) + h5_crc_update(&h5_txmsg_crc, hdr[i]); + } + + /* Put payload */ + for (i = 0; i < len; i++) { + h5_slip_one_byte(nskb, data[i]); + + if (h5->use_crc) + h5_crc_update(&h5_txmsg_crc, data[i]); + } + + /* Put CRC */ + if (h5->use_crc) { + h5_txmsg_crc = bit_rev16(h5_txmsg_crc); + h5_slip_one_byte(nskb, (uint8_t) ((h5_txmsg_crc >> 8) & 0x00ff)); + h5_slip_one_byte(nskb, (uint8_t) (h5_txmsg_crc & 0x00ff)); + } + + /* Add SLIP end byte: 0xc0 */ + h5_slip_msgdelim(nskb); + return nskb; +} + +/** +* Removed controller acked packet from Host's unacked lists +* +* @param h5 realtek h5 struct +*/ +static void h5_remove_acked_pkt(struct rtk_h5_struct *h5) +{ + int pkts_to_be_removed = 0; + int seqno = 0; + int i = 0; + + seqno = h5->msgq_txseq; + + while (pkts_to_be_removed) { + if (h5->rxack == seqno) + break; + + pkts_to_be_removed--; + seqno = (seqno - 1) & 0x07; + } + + if (h5->rxack != seqno) { + RS_DBG("Peer acked invalid packet"); + } + + i = 0; + for (i = 0; i < 5; ++i) { + if (i >= pkts_to_be_removed) + break; + i++; + } + + if (i != pkts_to_be_removed) + RS_DBG("Removed only (%d) out of (%d) pkts", i, pkts_to_be_removed); +} + +/** +* Realtek send pure ack, send a packet only with an ack +* +* @param fd uart file descriptor +* +*/ +static void rtk_send_pure_ack_down(int fd) +{ + struct sk_buff *nskb = h5_prepare_pkt(&rtk_h5, NULL, 0, H5_ACK_PKT); + write(fd, nskb->data, nskb->data_len); + skb_free(nskb); + return; +} + +/** +* Parse hci event command complete, pull the cmd complete event header +* +* @param skb socket buffer +* +*/ +static void hci_event_cmd_complete(struct sk_buff *skb) +{ + struct hci_ev_cmd_complete *ev = NULL; + uint16_t opcode = 0; + uint8_t status = 0; + + /* omit length check */ + /* pull hdr */ + skb_pull(skb, HCI_EVENT_HDR_SIZE); + ev = (struct hci_ev_cmd_complete *)skb->data; + opcode = le16_to_cpu(ev->opcode); + + RS_DBG("receive hci command complete event with command: %x", opcode); + if (DBG_ON) { + RS_DBG("Dump event data with event header (header size %d):", sizeof(struct hci_ev_cmd_complete)); + RS_DUMP(skb->data, skb->data_len); + } + + /* pull command complete event header */ + skb_pull(skb, sizeof(struct hci_ev_cmd_complete)); + + switch (opcode) { + case HCI_VENDOR_CHANGE_BDRATE: + status = skb->data[0]; + RS_DBG("Change BD Rate with status:%x", status); + skb_free(rtk_h5.host_last_cmd); + rtk_h5.host_last_cmd = NULL; + rtk_h5.link_estab_state = H5_PATCH; + break; + case HCI_CMD_READ_BD_ADDR: + status = skb->data[0]; + RS_DBG("Read BD Address with Status:%x", status); + if (!status) { + RS_DBG("BD Address: %8x%8x", *(int *)&skb->data[1], *(int *)&skb->data[5]); + } + break; + case HCI_VENDOR_READ_LMP_VERISION: + ghci_version_cmd_state = event_received; + status = skb->data[0]; + RS_DBG("Read RTK LMP version with Status:%x", status); + if (0 == status) { + hw_cfg_cb.hci_version = *(uint8_t *)(&skb->data[1]); + hw_cfg_cb.hci_revision = *(uint8_t *)(&skb->data[2]); + hw_cfg_cb.lmp_subversion = le16_to_cpu(*(uint16_t *)(&skb->data[7])); + } else { + RS_ERR("READ_RTK_ROM_VERISION return status error!"); + /* Need to do more */ + } + skb_free(rtk_h5.host_last_cmd); + rtk_h5.host_last_cmd = NULL; + break; + case HCI_VENDOR_READ_CHIP_TYPE: + gchip_type_cmd_state = event_received; + status = skb->data[0]; + RS_DBG("Read RTK CHIP TYPE with Status:%x", status); + if (0 == status) { + hw_cfg_cb.chip_type = *(uint8_t *)(&skb->data[1]); + } else { + RS_ERR("READ_RTK_CHIP_TYPE return status error!"); + } + skb_free(rtk_h5.host_last_cmd); + rtk_h5.host_last_cmd = NULL; + break; + case HCI_VENDOR_READ_RTK_ROM_VERISION: + gRom_version_cmd_state = event_received; + status = skb->data[0]; + RS_DBG("Read RTK rom version with Status:%x", status); + if (0 == status) + gEVersion = skb->data[1]; + else if (1 == status) + gEVersion = 0; + else { + gEVersion = 0; + RS_ERR("READ_RTK_ROM_VERISION return status error!"); + /* Need to do more */ + } + skb_free(rtk_h5.host_last_cmd); + rtk_h5.host_last_cmd = NULL; + break; + } +} + +/** +* Check if it's a hci frame, if it is, complete it with response or parse the cmd complete event +* +* @param skb socket buffer +* +*/ +static void hci_recv_frame(struct sk_buff *skb) +{ + char h5sync[2] = {0x01, 0x7E}, + h5syncresp[2] = {0x02, 0x7D}, + h5_sync_resp_pkt[0x8] = {0xc0, 0x00, 0x2F, 0x00, 0xD0, 0x02, 0x7D, 0xc0}, + h5_conf_resp_pkt_to_Ctrl[0x8] = {0xc0, 0x00, 0x2F, 0x00, 0xD0, 0x04, 0x7B, 0xc0}, + h5conf[3] = {0x03, 0xFC, 0x10}, + h5confresp[3] = {0x04, 0x7B, 0x10}, + cmd_complete_evt_code = 0xe; + + if (rtk_h5.link_estab_state == H5_SYNC) { /* sync */ + if (!memcmp(skb->data, h5sync, 2)) { + RS_DBG("Get Sync Pkt\n"); + write(serial_fd, &h5_sync_resp_pkt, 0x8); + } else if (!memcmp(skb->data, h5syncresp, 2)) { + RS_DBG("Get Sync Resp Pkt\n"); + rtk_h5.link_estab_state = H5_CONFIG; + } + skb_free(skb); + } else if (rtk_h5.link_estab_state == H5_CONFIG) { /* config */ + if (!memcmp(skb->data, h5sync, 0x2)) { + write(serial_fd, &h5_sync_resp_pkt, 0x8); + RS_DBG("Get SYNC pkt-active mode\n"); + } else if (!memcmp(skb->data, h5conf, 0x2)) { + write(serial_fd, &h5_conf_resp_pkt_to_Ctrl, 0x8); + RS_DBG("Get CONFG pkt-active mode\n"); + } else if (!memcmp(skb->data, h5confresp, 0x2)) { + RS_DBG("Get CONFG resp pkt-active mode\n"); + rtk_h5.link_estab_state = H5_INIT;//H5_PATCH; + //rtk_send_pure_ack_down(serial_fd); + } else { + RS_DBG("H5_CONFIG receive event\n"); + rtk_send_pure_ack_down(serial_fd); + } + skb_free(skb); + } else if (rtk_h5.link_estab_state == H5_INIT) { + if (skb->data[0] == cmd_complete_evt_code) { + hci_event_cmd_complete(skb); + } + + rtk_send_pure_ack_down(serial_fd); + usleep(10000); + rtk_send_pure_ack_down(serial_fd); + usleep(10000); + rtk_send_pure_ack_down(serial_fd); + skb_free(skb); + } else if (rtk_h5.link_estab_state == H5_PATCH) { /* patch */ + rtk_patch.nRxIndex = skb->data[6]; + if (rtk_patch.nRxIndex & 0x80) + rtk_patch.nRxIndex &= ~0x80; + + RS_DBG("rtk_patch.nRxIndex %d\n", rtk_patch.nRxIndex); + if (rtk_patch.nRxIndex == rtk_patch.nTotal) + rtk_h5.link_estab_state = H5_ACTIVE; + skb_free(skb); + } else { + RS_ERR("receive packets in active state"); + skb_free(skb); + } +} + +/** +* after rx data is parsed, and we got a rx frame saved in h5->rx_skb, +* this routinue is called. +* things todo in this function: +* 1. check if it's a hci frame, if it is, complete it with response or ack +* 2. see the ack number, free acked frame in queue +* 3. reset h5->rx_state, set rx_skb to null. +* +* @param h5 realtek h5 struct +* +*/ +static void h5_complete_rx_pkt(struct rtk_h5_struct *h5) +{ + int pass_up = 1; + uint16_t *valuep, value_t; + H5_PKT_HEADER *h5_hdr = NULL; + /* 1 is offset of uint16_t in H5_PKT_HEADER */ + valuep = (uint16_t *)(h5->rx_skb->data+1); + value_t = le16_to_cpu(*valuep); + *valuep = value_t; + h5_hdr = (H5_PKT_HEADER *)(h5->rx_skb->data); + if (h5_hdr->ReliablePkt) { + RS_DBG("Received reliable seqno %u from card", h5->rxseq_txack); + h5->rxseq_txack = h5_hdr->SeqNumber + 1; + h5->rxseq_txack %= 8; + h5->is_txack_req = 1; + /* send down an empty ack if needed. */ + } + + h5->rxack = h5_hdr->AckNumber; + + switch (h5_hdr->PktType) { + case HCI_ACLDATA_PKT: + case HCI_EVENT_PKT: + case HCI_SCODATA_PKT: + case HCI_COMMAND_PKT: + case H5_LINK_CTL_PKT: + pass_up = 1; + break; + default: + pass_up = 0; + } + + h5_remove_acked_pkt(h5); + + /* decide if we need to pass up. */ + if (pass_up) { + /* remove h5 header and send packet to hci */ + skb_pull(h5->rx_skb, sizeof(H5_PKT_HEADER)); + hci_recv_frame(h5->rx_skb); + /* should skb be freed here? */ + } else { + /* free skb buffer */ + skb_free(h5->rx_skb); + } + + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_skb = NULL; +} + +/** +* Parse the receive data in h5 proto. +* +* @param h5 realtek h5 struct +* @param data point to data received before parse +* @param count num of data +* @return reserved count +*/ +static int h5_recv(struct rtk_h5_struct *h5, void *data, int count) +{ + char *ptr; + ptr = (char *)data; + + while (count) { + if (h5->rx_count) { + if (*ptr == 0xc0) { + RS_ERR("short h5 packet"); + skb_free(h5->rx_skb); + h5->rx_state = H5_W4_PKT_START; + h5->rx_count = 0; + } else { + h5_unslip_one_byte(h5, *ptr); + } + ptr++; + count--; + continue; + } + + switch (h5->rx_state) { + case H5_W4_HDR: + /* check header checksum. see Core Spec V4 "3-wire uart" page 67 */ + if ((0xff & (uint8_t) ~(h5->rx_skb->data[0] + h5->rx_skb->data[1] + + h5->rx_skb->data[2])) != h5->rx_skb->data[3]) { + RS_ERR("h5 hdr checksum error!!!"); + skb_free(h5->rx_skb); + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + continue; + } + + if (h5->rx_skb->data[0] & 0x80 /* reliable pkt */ + && (h5->rx_skb->data[0] & 0x07) != h5->rxseq_txack) { + RS_ERR("Out-of-order packet arrived, got(%d)expected(%u)", + h5->rx_skb->data[0] & 0x07, h5->rxseq_txack); + h5->is_txack_req = 1; + skb_free(h5->rx_skb); + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + + if (rtk_patch.nTxIndex == rtk_patch.nTotal) { + /* depend on weather remote will reset ack numb or not!!!!!!!!!!!!!!!special */ + rtk_h5.rxseq_txack = h5->rx_skb->data[0] & 0x07; + } + continue; + } + + h5->rx_state = H5_W4_DATA; + + /* payload length: May be 0 */ + h5->rx_count = (h5->rx_skb->data[1] >> 4) + (h5->rx_skb->data[2] << 4); + continue; + case H5_W4_DATA: + if (h5->rx_skb->data[0] & 0x40) { /* pkt with crc */ + h5->rx_state = H5_W4_CRC; + h5->rx_count = 2; + } else { + h5_complete_rx_pkt(h5); /* Send ACK */ + } + continue; + + case H5_W4_CRC: + if (bit_rev16(h5->message_crc) != h5_get_crc(h5)) { + RS_ERR("Checksum failed, computed(%04x)received(%04x)", + bit_rev16(h5->message_crc), h5_get_crc(h5)); + skb_free(h5->rx_skb); + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + continue; + } + skb_trim(h5->rx_skb, h5->rx_skb->data_len - 2); + h5_complete_rx_pkt(h5); + continue; + + case H5_W4_PKT_DELIMITER: + switch (*ptr) { + case 0xc0: + h5->rx_state = H5_W4_PKT_START; + break; + default: + break; + } + ptr++; + count--; + break; + + case H5_W4_PKT_START: + switch (*ptr) { + case 0xc0: + ptr++; + count--; + break; + default: + h5->rx_state = H5_W4_HDR; + h5->rx_count = 4; + h5->rx_esc_state = H5_ESCSTATE_NOESC; + h5->message_crc = 0xffff; + + /* Do not increment ptr or decrement count + * Allocate packet. Max len of a H5 pkt= + * 0xFFF (payload) +4 (header) +2 (crc) */ + h5->rx_skb = skb_alloc(0x1005); + if (!h5->rx_skb) { + h5->rx_state = H5_W4_PKT_DELIMITER; + h5->rx_count = 0; + return 0; + } + break; + } + break; + } + } + return count; +} + +/** +* Read data to buf from uart. +* +* @param fd uart file descriptor +* @param buf point to the addr where read data stored +* @param count num of data want to read +* @return num of data successfully read +*/ +static int read_check(int fd, void *buf, int count) +{ + int res; + do { + res = read(fd, buf, count); + if (res != -1) { + buf = (uint8_t *)buf + res; + count -= res; + return res; + } + } while (count && (errno == 0 || errno == EINTR)); + return res; +} + +/** +* Retry to sync when timeout in h5 proto, max retry times is 10. +* +* @warning Each time to retry, the time for timeout will be set as 1s. +* +* @param sig signaction for timeout +* +*/ +static void h5_tshy_sig_alarm(int sig) +{ + uint8_t h5sync[2] = {0x01, 0x7E}; + static int retries; + struct itimerval value; + + if (retries < h5_max_retries) { + retries++; + struct sk_buff *nskb = h5_prepare_pkt(&rtk_h5, h5sync, sizeof(h5sync), H5_LINK_CTL_PKT); + int len = write(serial_fd, nskb->data, nskb->data_len); + RS_DBG("3-wire sync pattern resend : %d, len: %d\n", retries, len); + skb_free(nskb); + + /* retry per 250ms */ + value.it_value.tv_sec = 0; + value.it_value.tv_usec = 250000; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 250000; + setitimer(ITIMER_REAL, &value, NULL); + + return; + } + + tcflush(serial_fd, TCIOFLUSH); + RS_ERR("H5 sync timed out\n"); + exit(1); +} + +/** +* Retry to config when timeout in h5 proto, max retry times is 10. +* +* @warning Each time to retry, the time for timeout will be set as 1s. +* +* @param sig signaction for timeout +* +*/ +static void h5_tconf_sig_alarm(int sig) +{ + uint8_t h5conf[3] = {0x03, 0xFC, 0x14}; + static int retries; + struct itimerval value; + + if (retries < h5_max_retries) { + retries++; + struct sk_buff *nskb = h5_prepare_pkt(&rtk_h5, h5conf, 3, H5_LINK_CTL_PKT); + int len = write(serial_fd, nskb->data, nskb->data_len); + RS_DBG("3-wire config pattern resend : %d , len: %d", retries, len); + skb_free(nskb); + + /* retry per 250ms */ + value.it_value.tv_sec = 0; + value.it_value.tv_usec = 250000; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 250000; + setitimer(ITIMER_REAL, &value, NULL); + + return; + } + + tcflush(serial_fd, TCIOFLUSH); + RS_ERR("H5 config timed out\n"); + exit(1); +} + +/** +* Retry to init when timeout in h5 proto, max retry times is 10. +* +* @warning Each time to retry, the time for timeout will be set as 1s. +* +* @param sig signaction for timeout +* +*/ +static void h5_tinit_sig_alarm(int sig) +{ + static int retries; + if (retries < h5_max_retries) { + retries++; + if (rtk_h5.host_last_cmd) { + int len = write(serial_fd, rtk_h5.host_last_cmd->data, rtk_h5.host_last_cmd->data_len); + RS_DBG("3-wire change baudrate re send:%d, len:%d", retries, len); + alarm(1); + return; + } else { + RS_DBG("3-wire init timeout without last command stored\n"); + } + } + + tcflush(serial_fd, TCIOFLUSH); + RS_ERR("H5 init process timed out"); + exit(1); +} + +/** +* Retry to download patch when timeout in h5 proto, max retry times is 10. +* +* @warning Each time to retry, the time for timeout will be set as 3s. +* +* @param sig signaction for timeout +* +*/ +static void h5_tpatch_sig_alarm(int sig) +{ + static int retries; + if (retries < h5_max_retries) { + RS_DBG("patch timerout, retry:\n"); + if (rtk_h5.host_last_cmd) { + write(serial_fd, rtk_h5.host_last_cmd->data, rtk_h5.host_last_cmd->data_len); + RS_DBG("3-wire download patch re send:%d", retries); + } + retries++; + alarm(3); + return; + } + RS_ERR("H5 patch timed out\n"); + exit(1); +} + +/** +* Download patch using hci. For h5 proto, not recv reply for 2s will timeout. +* Call h5_tpatch_sig_alarm for retry. +* +* @param dd uart file descriptor +* @param index current index +* @param data point to the config file +* @param len current buf length +* @return #0 on success +* +*/ +static int hci_download_patch(int dd, int index, uint8_t *data, int len, struct termios *ti) +{ + uint8_t hcipatch[256] = {0x20, 0xfc, 00}; + char bytes[READ_DATA_SIZE]; + int retlen; + struct sigaction sa; + + sa.sa_handler = h5_tpatch_sig_alarm; + sigaction(SIGALRM, &sa, NULL); + alarm(2); + + download_vendor_patch_cp cp; + memset(&cp, 0, sizeof(cp)); + cp.index = index; + if (data != NULL) { + memcpy(cp.data, data, len); + } + + int nValue = rtk_patch.nTotal|0x80; + if (index == nValue) { + rtk_patch.nTxIndex = rtk_patch.nTotal; + } else { + rtk_patch.nTxIndex = index; + } + hcipatch[2] = len+1; + memcpy(hcipatch+3, &cp, len+1); + + struct sk_buff *nskb = h5_prepare_pkt(&rtk_h5, hcipatch, len+4, HCI_COMMAND_PKT); /* data: len + head: 4 */ + + if (rtk_h5.host_last_cmd) { + skb_free(rtk_h5.host_last_cmd); + rtk_h5.host_last_cmd = NULL; + } + + rtk_h5.host_last_cmd = nskb; + + len = write(dd, nskb->data, nskb->data_len); + RS_DBG("hci_download_patch nTxIndex:%d nRxIndex: %d\n", rtk_patch.nTxIndex, rtk_patch.nRxIndex); + + if (index & 0x80) { + RS_DBG("Hw Flow Control enable after last command sent before last event recv ! "); + if (tcsetattr(dd, TCSADRAIN, ti) < 0) { + RS_ERR("Can't set port settings"); + return -1; + } + } + + while (rtk_patch.nRxIndex != rtk_patch.nTxIndex) { /* receive data and wait last pkt */ + retlen = read_check(dd, &bytes, READ_DATA_SIZE); + if (retlen == -1) { + perror("read fail"); + return -1; + } + h5_recv(&rtk_h5, &bytes, retlen); + } + + alarm(0); + return 0; +} + +/** +* Download h4 patch +* +* @param dd uart file descriptor +* @param index current index +* @param data point to the config file +* @param len current buf length +* @return ret_index +* +*/ +static int hci_download_patch_h4(int dd, int index, uint8_t *data, int len) +{ + char bytes[257] = {0}; + char buf[257] = {0x01, 0x20, 0xfc, 00}; + + RS_DBG("dd:%d, index:%d, len:%d", dd, index, len); + if (NULL != data) { + memcpy(&buf[5], data, len); + } + + int cur_index = index; + int ret_Index = -1; + + /* Set data struct. */ + buf[3] = len + 1; /* add index */ + buf[4] = cur_index; + size_t total_len = len + 5; + + /* write */ + uint16_t w_len; + w_len = write(dd, buf, total_len); + RS_DBG("h4 write success with len: %d.\n", w_len); + + uint16_t res; + res = read(dd, bytes, 8); + + if (DBG_ON) { + RS_DBG("h4 read success with len: %d.\n", res); + int i = 0; + for (i = 0; i < 8; i++) { + fprintf(stderr, "byte[%d] = 0x%x\n", i, bytes[i]); + } + } + + uint8_t rstatus; + if ((0x04 == bytes[0]) && (0x20 == bytes[4]) && (0xfc == bytes[5])) { + ret_Index = bytes[7]; + rstatus = bytes[6]; + RS_DBG("---->ret_Index:%d, ----->rstatus:%d\n", ret_Index, rstatus); + if (0x00 != rstatus) { + RS_ERR("---->read event status is wrong.\n"); + return -1; + } + } else { + RS_ERR("==========>Didn't read curret data.\n"); + return -1; + } + + return ret_Index; +} + +/** +* Realtek change speed with h4 proto. Using vendor specified command packet to achieve this. +* +* @warning before write, need to wait 1s for device up +* +* @param fd uart file descriptor +* @param baudrate the speed want to change +* @return #0 on success +*/ +static int rtk_vendor_change_speed_h4(int fd, uint32_t baudrate) +{ + char bytes[257]; + uint8_t cmd[8] = {0}; + + cmd[0] = 1; /* cmd */ + cmd[1] = 0x17; /* ocf */ + cmd[2] = 0xfc; /* ogf, vendor specified */ + + cmd[3] = 4; /* length */ +#ifdef BAUDRATE_4BYTES + memcpy((uint16_t *)&cmd[4], &baudrate, 4); +#else + memcpy((uint16_t *)&cmd[4], &baudrate, 2); + + cmd[6] = 0; + cmd[7] = 0; +#endif + + /* wait for a while for device to up, just h4 need it */ + sleep(1); + + if (write(fd, cmd, 8) != 8) { + RS_ERR("H4 change uart speed error when writing vendor command"); + return -1; + } + RS_DBG("H4 Change uart Baudrate after write "); + int res; + res = read(fd, bytes, sizeof(bytes)); + + if (DBG_ON) { + RS_DBG("Realtek Receving H4 change uart speed event:%x", res); + RS_DUMP(bytes, res); + } + if ((0x04 == bytes[0]) && (0x17 == bytes[4]) && (0xfc == bytes[5])) { + RS_DBG("H4 change uart speed success, receving status:%x", bytes[6]); + if (bytes[6] == 0) + return 0; + } + return -1; +} + +/** +* Parse realtek Bluetooth config file. +* The config file if begin with vendor magic: RTK_VENDOR_CONFIG_MAGIC(8723ab55) +* bt_addr is followed by 0x3c offset, it will be changed by bt_addr param +* proto, baudrate and flow control is followed by 0xc offset, +* +* @param config_buf point to config file content +* @param filelen length of config file +* @param bt_addr where bt addr is stored +* @return baudrate in config file +* +*/ + +static uint32_t rtk_parse_config_file(uint8_t *config_buf, size_t filelen, char bt_addr[6]) +{ + struct rtk_bt_vendor_config *config = (struct rtk_bt_vendor_config *) config_buf; + uint16_t config_len = le16_to_cpu(config->data_len), temp = 0; + struct rtk_bt_vendor_config_entry *entry = config->entry; + + uint16_t i; + uint32_t baudrate = 0; + + if (le32_to_cpu(config->signature) != RTK_VENDOR_CONFIG_MAGIC) { + RS_ERR("config signature magic number(%x) is not set to RTK_VENDOR_CONFIG_MAGIC", (int)config->signature); + return 0; + } + + if (config_len != filelen - sizeof(struct rtk_bt_vendor_config)) { + RS_ERR("config len(%x) is not right(%x)", config_len, filelen-sizeof(struct rtk_bt_vendor_config)); + return 0; + } + + for (i = 0; i < config_len;) { + switch (le16_to_cpu(entry->offset)) { + case 0x3c: + { + int j = 0; + for (j = 0; j < entry->entry_len; j++) + entry->entry_data[j] = bt_addr[entry->entry_len - 1 - j]; + } + break; + case 0xc: +#ifdef BAUDRATE_4BYTES + baudrate = *(uint32_t *)entry->entry_data; +#else + baudrate = *(uint16_t *)entry->entry_data; +#endif + gHwFlowControlEnable = 0; + if (entry->entry_len >= 12) { //0ffset 0x18 - 0xc + gHwFlowControlEnable = (entry->entry_data[12] & 0x4) ? 1:0; //0x18 byte bit2 + } + RS_DBG("config baud rate to :%x, hwflowcontrol:%x, %x", (int)baudrate, entry->entry_data[12], gHwFlowControlEnable); + break; + default: + RS_DBG("config offset(%x),length(%x)", entry->offset, entry->entry_len); + break; + } + temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry); + i += temp; + entry = (struct rtk_bt_vendor_config_entry *)((uint8_t *)entry + temp); + } + + return baudrate; +} + +/** +* get random realtek Bluetooth addr. +* +* @param bt_addr where bt addr is stored +* +*/ +static void rtk_get_ram_addr(char bt_addr[0]) +{ + srand(time(NULL)+getpid()+getpid()*987654+rand()); + + uint32_t addr = rand(); + memcpy(bt_addr, &addr, sizeof(uint8_t)); +} + +/** +* Write the random bt addr to the file /data/misc/bluetooth/btmac.txt. +* +* @param bt_addr where bt addr is stored +* +*/ +static void rtk_write_btmac2file(char bt_addr[6]) +{ + int fd; + mkdir(BT_ADDR_DIR, 0777); + fd = open(BT_ADDR_FILE, O_CREAT|O_RDWR|O_TRUNC, 0666); + + if (fd > 0) { + chmod(BT_ADDR_FILE, 0666); + char addr[18] = {0}; + addr[17] = '\0'; + sprintf(addr, "%2x:%2x:%2x:%2x:%2x:%2x", bt_addr[0], bt_addr[1], bt_addr[2], bt_addr[3], bt_addr[4], bt_addr[5]); + write(fd, addr, strlen(addr)); + close(fd); + } else { + RS_ERR("open file error:%s\n", BT_ADDR_FILE); + } +} + +/** +* Get realtek Bluetooth config file. The bt addr arg is stored in /data/btmac.txt, if there is not this file, +* change to /data/misc/bluetooth/btmac.txt. If both of them are not found, using +* random bt addr. +* +* The config file is rtk8723_bt_config whose bt addr will be changed by the one read previous +* +* @param config_buf point to the content of realtek Bluetooth config file +* @param config_baud_rate the baudrate set in the config file +* @return file_len the length of config file +*/ +static int rtk_get_bt_config(uint8_t **config_buf, uint32_t *config_baud_rate, patch_info *info) +{ + char bt_config_file_name[PATH_MAX] = {0}; + char bt_addr[6] = {0x00, 0xe0, 0x4c, 0x88, 0x88, 0x88}; + struct stat st; + size_t filelen; + int fd; + FILE *file = NULL; + int i = 0; + + sprintf(bt_config_file_name, "%s/%s", BT_CONFIG_DIRECTORY, "btmac.txt"); + RS_DBG("BT mac addr file: %s", bt_config_file_name); + if (stat(bt_config_file_name, &st) < 0) { + RS_ERR("can't access bt bt_mac_addr file:%s, try use another path", bt_config_file_name); + sprintf(bt_config_file_name, BT_ADDR_FILE); + if (stat(bt_config_file_name, &st) < 0) { + RS_ERR("can't access bt bt_mac_addr file:%s, try use ramdom BT Addr", bt_config_file_name); + + for (i = 0; i < 6; i++) + rtk_get_ram_addr(&bt_addr[i]); + rtk_write_btmac2file(bt_addr); + goto GET_CONFIG; + } + } + + filelen = st.st_size; + file = fopen(bt_config_file_name, "rb"); + if (file == NULL) { + RS_ERR("Can't open bt btaddr file, just use preset BT Addr"); + } else { + fscanf(file, "%2x:%2x:%2x:%2x:%2x:%2x", (int *)&bt_addr[0], (uint32_t *)&bt_addr[1], (uint32_t *)&bt_addr[2], (uint32_t *)&bt_addr[3], (uint32_t *)&bt_addr[4], (uint32_t *)&bt_addr[5]); + /* do not set bt_add[0] to zero */ + /* reserve LAP addr from 0x9e8b00 to 0x9e8b3f, change to 0x008b */ + if (0x9e == bt_addr[3] && 0x8b == bt_addr[4] && (bt_addr[5] <= 0x3f)) { + /* get random value */ + bt_addr[3] = 0x00; + } + RS_DBG("BT MAC IS : %02X:%02X:%02X:%02X:%02X:%02X", bt_addr[0], bt_addr[1], bt_addr[2], bt_addr[3], bt_addr[4], bt_addr[5]); + } + +GET_CONFIG: + if (info != NULL) { + sprintf(bt_config_file_name, "%s/%s", BT_CONFIG_DIRECTORY, info->config_name); + } else { + sprintf(bt_config_file_name, "%s/%s", BT_CONFIG_DIRECTORY, "rtlbt_config"); + } + RS_DBG("Final bt config file: %s", bt_config_file_name); + + if (stat(bt_config_file_name, &st) < 0) { + RS_ERR("Can't access firmware, errno:%d", errno); + return -1; + } + + filelen = st.st_size; + + fd = open(bt_config_file_name, O_RDONLY); + if (fd < 0) { + perror("Can't open bt config file"); + return -1; + } + + *config_buf = malloc(filelen); + if (*config_buf == NULL) { + RS_DBG("malloc buffer for config file fail(%x)\n", filelen); + close(fd); + return -1; + } + + /* we may need to parse this config file. */ + /* for easy debug, only get need data. */ + if (read(fd, *config_buf, filelen) < (ssize_t)filelen) { + perror("Can't load bt config file"); + free(*config_buf); + *config_buf = NULL; + close(fd); + return -1; + } + + *config_baud_rate = rtk_parse_config_file(*config_buf, filelen, bt_addr); + RS_DBG("Get config baud rate(4 bytes) from config file:%x", (int)*config_baud_rate); + + close(fd); + return filelen; +} + +/** +* Realtek change speed with h5 proto. Using vendor specified command packet to achieve this. +* +* @warning it will waiting 2s for reply. +* +* @param fd uart file descriptor +* @param baudrate the speed want to change +* +*/ +static int rtk_vendor_change_speed_h5(int fd, uint32_t baudrate) +{ + struct sk_buff *cmd_change_bdrate = NULL; + uint8_t cmd[7] = {0}; + int retlen; + char bytes[READ_DATA_SIZE]; + struct sigaction sa; + + sa.sa_handler = h5_tinit_sig_alarm; + sigaction(SIGALRM, &sa, NULL); + + cmd[0] = 0x17; /* ocf */ + cmd[1] = 0xfc; /* ogf, vendor specified */ + + cmd[2] = 4; /* length */ +#ifdef BAUDRATE_4BYTES + memcpy((uint16_t *)&cmd[3], &baudrate, 4); +#else + memcpy((uint16_t *)&cmd[3], &baudrate, 2); + cmd[5] = 0; + cmd[6] = 0; +#endif + + if (DBG_ON) { + RS_DUMP(cmd, 7); + RS_DBG("change speed command ready baudrate=%d n", baudrate); + } + cmd_change_bdrate = h5_prepare_pkt(&rtk_h5, cmd, 7, HCI_COMMAND_PKT); + if (!cmd_change_bdrate) { + RS_ERR("Prepare command packet for change speed fail"); + return -1; + } + + rtk_h5.host_last_cmd = cmd_change_bdrate; + alarm(1); + write(fd, cmd_change_bdrate->data, cmd_change_bdrate->data_len); + + while (rtk_h5.link_estab_state == H5_INIT) { + retlen = read_check(fd, &bytes, READ_DATA_SIZE); + if (retlen == -1) { + perror("read fail"); + return -1; + } + + /* add pure ack check */ + h5_recv(&rtk_h5, &bytes, retlen); + } + + alarm(0); + return 0; +} + +/** +* Init realtek Bluetooth h5 proto. h5 proto is added by realtek in the right kernel. +* Generally there are two steps: h5 sync and h5 config +* +* @param fd uart file descriptor +* @param ti termios struct +* +*/ +static int rtk_init_h5(int fd, struct termios *ti) +{ + char bytes[READ_DATA_SIZE]; + struct sigaction sa; + int retlen; + struct itimerval value; + + /* set even parity here */ + ti->c_cflag |= PARENB; + ti->c_cflag &= ~(PARODD); + if (tcsetattr(fd, TCSANOW, ti) < 0) { + RS_ERR("Can't set port settings"); + return -1; + } + + alarm(0); + serial_fd = fd; + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = h5_tshy_sig_alarm; + sigaction(SIGALRM, &sa, NULL); + + /* h5 sync */ + h5_tshy_sig_alarm(0); + memset(&rtk_h5, 0, sizeof(rtk_h5)); + rtk_h5.link_estab_state = H5_SYNC; + while (rtk_h5.link_estab_state == H5_SYNC) { + retlen = read_check(fd, &bytes, READ_DATA_SIZE); + if (retlen == -1) { + RS_ERR("H5 Read Sync Response Failed"); + /* retry per 250ms */ + value.it_value.tv_sec = 0; + value.it_value.tv_usec = 0; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &value, NULL); + return -1; + } + h5_recv(&rtk_h5, &bytes, retlen); + } + + /* retry per 250ms */ + value.it_value.tv_sec = 0; + value.it_value.tv_usec = 0; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &value, NULL); + + /* h5 config */ + sa.sa_handler = h5_tconf_sig_alarm; + sigaction(SIGALRM, &sa, NULL); + h5_tconf_sig_alarm(0); + while (rtk_h5.link_estab_state == H5_CONFIG) { + retlen = read_check(fd, &bytes, READ_DATA_SIZE); + if (retlen == -1) { + RS_ERR("H5 Read Config Response Failed"); + /* retry per 250ms */ + value.it_value.tv_sec = 0; + value.it_value.tv_usec = 0; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &value, NULL); + return -1; + } + h5_recv(&rtk_h5, &bytes, retlen); + } + /* retry per 250ms */ + value.it_value.tv_sec = 0; + value.it_value.tv_usec = 0; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &value, NULL); + + rtk_send_pure_ack_down(fd); + RS_DBG("H5 init finished\n"); + return 0; +} + +/** +* Download realtek firmware and config file from uart with the proto. +* Parse the content to serval packets follow the proto and then write the packets from uart +* +* @param fd uart file descriptor +* @param buf addr where stor the content of firmware and config file +* @param filesize length of buf +* @param is_sent_changerate if baudrate need to be changed +* @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE +* +*/ +static void rtk_download_fw_config(int fd, uint8_t *buf, size_t filesize, int is_sent_changerate, int proto, struct termios *ti) +{ + uint8_t iCurIndex = 0; + uint8_t iCurLen = 0; + uint8_t iEndIndex = 0; + uint8_t iLastPacketLen = 0; + uint8_t iAdditionPkt = 0; + uint8_t iTotalIndex = 0; + uint8_t iCmdSentNum = 0; /* the number of CMDs which have been sent */ + uint8_t *bufpatch; + + iEndIndex = (uint8_t)((filesize-1)/PATCH_DATA_FIELD_MAX_SIZE); + iLastPacketLen = (filesize)%PATCH_DATA_FIELD_MAX_SIZE; + + if (is_sent_changerate) + iCmdSentNum++; + if (gRom_version_cmd_state >= cmd_has_sent) + iCmdSentNum++; + if (ghci_version_cmd_state >= cmd_has_sent) + iCmdSentNum++; + if (gchip_type_cmd_state >= cmd_has_sent) + iCmdSentNum++; + + iAdditionPkt = (iEndIndex+1+iCmdSentNum)%8?(8-(iEndIndex+1+iCmdSentNum)%8):0; + iTotalIndex = iAdditionPkt + iEndIndex; + rtk_patch.nTotal = iTotalIndex; /* init TotalIndex */ + + RS_DBG("iEndIndex:%d iLastPacketLen:%d iAdditionpkt:%d\n", iEndIndex, iLastPacketLen, iAdditionPkt); + + if (iLastPacketLen == 0) + iLastPacketLen = PATCH_DATA_FIELD_MAX_SIZE; + + bufpatch = buf; + + int i; + for (i = 0; i <= iTotalIndex; i++) { + if (iCurIndex < iEndIndex) { + iCurIndex = iCurIndex&0x7F; + iCurLen = PATCH_DATA_FIELD_MAX_SIZE; + } else if (iCurIndex == iEndIndex) { /* send last data packet */ + if (iCurIndex == iTotalIndex) + iCurIndex = iCurIndex | 0x80; + else + iCurIndex = iCurIndex&0x7F; + iCurLen = iLastPacketLen; + } else if (iCurIndex < iTotalIndex) { + iCurIndex = iCurIndex&0x7F; + bufpatch = NULL; + iCurLen = 0; + } else { /* send end packet */ + bufpatch = NULL; + iCurLen = 0; + iCurIndex = iCurIndex|0x80; + } + + if (iCurIndex & 0x80) + RS_DBG("Send FW last command"); + + if (proto == HCI_UART_H4) { + iCurIndex = hci_download_patch_h4(fd, iCurIndex, bufpatch, iCurLen); + if ((iCurIndex != i) && (i != rtk_patch.nTotal)) { + /* check index but ignore last pkt */ + RS_DBG("index mismatch i:%d iCurIndex:%d, patch fail\n", i, iCurIndex); + return; + } + } else if (proto == HCI_UART_3WIRE) + hci_download_patch(fd, iCurIndex, bufpatch, iCurLen, ti); + + if (iCurIndex < iEndIndex) { + bufpatch += PATCH_DATA_FIELD_MAX_SIZE; + } + iCurIndex++; + } + + /* set last ack packet down */ + if (proto == HCI_UART_3WIRE) { + rtk_send_pure_ack_down(fd); + } +} + +/** +* Get realtek Bluetooth firmaware file. The content will be saved in *fw_buf which is malloc here. +* The length malloc here will be lager than length of firmware file if there is a config file. +* The content of config file will copy to the tail of *fw_buf in rtk_config. +* +* @param fw_buf point to the addr where stored the content of firmware. +* @param addi_len length of config file. +* @return length of *fw_buf. +* +*/ +static int rtk_get_bt_firmware(uint8_t **fw_buf, size_t addi_len, patch_info *info) +{ + char filename[PATH_MAX] = {0}; + struct stat st; + int fd = -1; + size_t fwsize, buf_size; + + if (info != NULL) { + sprintf(filename, "%s/%s", FIRMWARE_DIRECTORY, info->patch_name); + } else { + sprintf(filename, "%s/%s", FIRMWARE_DIRECTORY, "rtlbt_fw"); + } + + RS_DBG("Final bt firmware file: %s", filename); + + if (stat(filename, &st) < 0) { + RS_ERR("Can't access firmware, errno:%d", errno); + return -1; + } + + fwsize = st.st_size; + buf_size = fwsize + addi_len; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + RS_ERR("Can't open firmware, errno:%d", errno); + return -1; + } + + *fw_buf = malloc(buf_size); + if (!(*fw_buf)) { + RS_ERR("Can't alloc memory for fw&config, errno:%d", errno); + close(fd); + return -1; + } + + if (read(fd, *fw_buf, fwsize) < (ssize_t) fwsize) { + free(*fw_buf); + *fw_buf = NULL; + close(fd); + return -1; + } + RS_DBG("Load FW OK"); + close(fd); + return buf_size; +} + +/* These two function(rtk<-->uart speed transfer) need check Host uart speed at first!!!! IMPORTANT + * add more speed if neccessary */ +typedef struct _baudrate_ex { + uint32_t rtk_speed; + int uart_speed; +} baudrate_ex; + +#ifdef BAUDRATE_4BYTES +static baudrate_ex baudrates[] = { + {0x00006004, 921600}, + {0x05F75004, 921600}, // RTL8723BS + {0x00004003, 1500000}, + {0x04928002, 1500000}, // RTL8723BS + {0x00005002, 2000000}, // same as RTL8723AS + {0x00008001, 3000000}, + {0x00009001, 3000000}, // Lory add new, t169 and t9e use 0x00009001. + {0x06DD8001, 3000000}, // RTL8723BS, Baudrate: 2920000 + {0x036D8001, 3000000}, // RTL8723BS, Baudrate: 2929999 + {0x06B58001, 3000000}, // RTL8723BS, Baudrate: 2940000 + {0x02B58001, 3000000}, // RTL8723BS, Baudrate: 2945000 + {0x02D58001, 3000000}, // RTL8723BS, Baudrate: 2950000 + {0x05558001, 3000000}, // RTL8723BS, Baudrate: 2960000 + {0x02AA8001, 3000000}, // RTL8723BS, Baudrate: 2969999 + {0x052A8001, 3000000}, // RTL8723BS, Baudrate: 2980000 + {0x04928001, 3000000}, // RTL8723BS, Baudrate: 2998000 + {0x00007001, 3500000}, + {0x052A6001, 3500000}, // RTL8723BS + {0x00005001, 4000000}, // same as RTL8723AS + {0x05AD9005, 547000}, + {0x0252C00A, 230400}, + {0x0000701d, 115200}, + {0x0252C002, 115200}, // RTL8723BS + {0x0252C014, 115200} // RTL8723BS +}; + +#else +static baudrate_ex baudrates[] = { + {0x7001, 3500000}, + {0x6004, 921600}, + {0x4003, 1500000}, + {0x5001, 4000000}, + {0x5002, 2000000}, + {0x8001, 3000000}, + {0x9001, 3000000}, + {0x701d, 115200} +}; + +#endif + + +/** +* Change realtek Bluetooth speed to uart speed. It is matching in the struct baudrates: +* +* @code +* baudrate_ex baudrates[] = +* { +* {0x7001, 3500000}, +* {0x6004, 921600}, +* {0x4003, 1500000}, +* {0x5001, 4000000}, +* {0x5002, 2000000}, +* {0x8001, 3000000}, +* {0x701d, 115200} +* }; +* @endcode +* +* If there is no match in baudrates, uart speed will be set as #115200. +* +* @param rtk_speed realtek Bluetooth speed +* @param uart_speed uart speed +* +*/ +static void rtk_speed_to_uart_speed(uint32_t rtk_speed, uint32_t *uart_speed) +{ + *uart_speed = 115200; + + int i; + for (i = 0; i < sizeof(baudrates)/sizeof(baudrate_ex); i++) { + if (baudrates[i].rtk_speed == le32_to_cpu(rtk_speed)) { + *uart_speed = baudrates[i].uart_speed; + return; + } + } + return; +} + +/** +* Change uart speed to realtek Bluetooth speed. It is matching in the struct baudrates: +* +* @code +* baudrate_ex baudrates[] = +* { +* {0x7001, 3500000}, +* {0x6004, 921600}, +* {0x4003, 1500000}, +* {0x5001, 4000000}, +* {0x5002, 2000000}, +* {0x8001, 3000000}, +* {0x701d, 115200} +* }; +* @endcode +* +* If there is no match in baudrates, realtek Bluetooth speed will be set as #0x701D. +* +* @param uart_speed uart speed +* @param rtk_speed realtek Bluetooth speed +* +*/ +static inline void uart_speed_to_rtk_speed(int uart_speed, uint32_t *rtk_speed) +{ + *rtk_speed = 0x701D; + + int i; + for (i = 0; i < sizeof(baudrates) / sizeof(baudrate_ex); i++) { + if (baudrates[i].uart_speed == uart_speed) { + *rtk_speed = baudrates[i].rtk_speed; + return; + } + } + + return; +} + +static void rtk_get_eversion_timeout(int sig) +{ + static int retries; + RS_DBG("RTK get HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n"); + if (retries < h5_max_retries) { + RS_DBG("patch timerout, retry:\n"); + if (rtk_h5.host_last_cmd) { + write(serial_fd, rtk_h5.host_last_cmd->data, rtk_h5.host_last_cmd->data_len); + RS_DBG("3-wire download patch re send:%d", retries); + } + retries++; + alarm(3); + return; + } + tcflush(serial_fd, TCIOFLUSH); + RS_ERR("rtk get eversion cmd complete event timed out\n"); + exit(1); +} + +/** +* Send vendor cmd to get eversion: 0xfc6d +* If Rom code does not support this cmd, use default. +*/ +static void rtk_get_eversion(int dd) +{ + char bytes[READ_DATA_SIZE]; + int retlen; + struct sigaction sa; + /* send HCI_VENDOR_READ_RTK_ROM_VERISION Command */ + uint8_t read_rom_patch_cmd[3] = {0x6d, 0xfc, 0x00}; + struct sk_buff *nskb = h5_prepare_pkt(&rtk_h5, read_rom_patch_cmd, 3, HCI_COMMAND_PKT); /* data: len+head: 4 */ + + if (rtk_h5.host_last_cmd) { + skb_free(rtk_h5.host_last_cmd); + rtk_h5.host_last_cmd = NULL; + } + + rtk_h5.host_last_cmd = nskb; + + write(dd, nskb->data, nskb->data_len); + gRom_version_cmd_state = cmd_has_sent; + RS_DBG("RTK send HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n"); + + alarm(0); + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = rtk_get_eversion_timeout; + sigaction(SIGALRM, &sa, NULL); + + alarm(3); + while (gRom_version_cmd_state != event_received) { + retlen = read_check(dd, &bytes, READ_DATA_SIZE); + if (retlen == -1) { + perror("read fail"); + return; + } + h5_recv(&rtk_h5, &bytes, retlen); + } + alarm(0); + return; +} + +static void rtk_get_lmp_version_timeout(int sig) +{ + static int retries; + RS_DBG("RTK get HCI_VENDOR_READ_RTK_LMP_VERISION_Command\n"); + if (retries < h5_max_retries) { + RS_DBG("patch timerout, retry:\n"); + if (rtk_h5.host_last_cmd) { + write(serial_fd, rtk_h5.host_last_cmd->data, rtk_h5.host_last_cmd->data_len); + RS_DBG("3-wire download patch re send:%d", retries); + } + retries++; + alarm(3); + return; + } + tcflush(serial_fd, TCIOFLUSH); + RS_ERR("rtk get lmp version cmd complete event timed out\n"); + exit(1); +} + +static void rtk_get_lmp_version(int dd) +{ + char bytes[READ_DATA_SIZE]; + int retlen; + struct sigaction sa; + /* send HCI_VENDOR_READ_RTK_ROM_VERISION_Command */ + uint8_t read_rom_patch_cmd[3] = {0x01, 0x10, 00}; + struct sk_buff *nskb = h5_prepare_pkt(&rtk_h5, read_rom_patch_cmd, 3, HCI_COMMAND_PKT); /* data: len+head: 4 */ + + if (rtk_h5.host_last_cmd) { + skb_free(rtk_h5.host_last_cmd); + rtk_h5.host_last_cmd = NULL; + } + + rtk_h5.host_last_cmd = nskb; + + write(dd, nskb->data, nskb->data_len); + ghci_version_cmd_state = cmd_has_sent; + RS_DBG("RTK send HCI_VENDOR_READ_RTK_ROM_VERISION_Command\n"); + + alarm(0); + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = rtk_get_lmp_version_timeout; + sigaction(SIGALRM, &sa, NULL); + + alarm(3); + while (ghci_version_cmd_state != event_received) { + retlen = read_check(dd, &bytes, READ_DATA_SIZE); + if (retlen == -1) { + perror("read fail"); + return; + } + h5_recv(&rtk_h5, &bytes, retlen); + } + alarm(0); + return; +} + +static void rtk_get_chip_type(int dd) +{ + char bytes[READ_DATA_SIZE]; + int retlen; + struct sigaction sa; + uint8_t read_rom_patch_cmd[8] = {0x61, 0xfc, 0x05, 0x00, 0x94, 0xa0, 0x00, 0xb0}; + struct sk_buff *nskb = h5_prepare_pkt(&rtk_h5, read_rom_patch_cmd, 8, HCI_COMMAND_PKT); /* data: len+head: 4 */ + + if (rtk_h5.host_last_cmd) { + skb_free(rtk_h5.host_last_cmd); + rtk_h5.host_last_cmd = NULL; + } + + rtk_h5.host_last_cmd = nskb; + + write(dd, nskb->data, nskb->data_len); + gchip_type_cmd_state = cmd_has_sent; + RS_DBG("RTK send HCI_VENDOR_READ_CHIP_TYPE Command"); + + alarm(0); + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = rtk_get_lmp_version_timeout; + sigaction(SIGALRM, &sa, NULL); + + alarm(3); + while (gchip_type_cmd_state != event_received) { + retlen = read_check(dd, &bytes, READ_DATA_SIZE); + if (retlen == -1) { + perror("read fail"); + return; + } + h5_recv(&rtk_h5, &bytes, retlen); + } + alarm(0); + return; +} + +static int check_match_state(bt_hw_cfg_cb_t *cfg, uint32_t mask) +{ + patch_info *patch_entry; + int res = 0; + + for (patch_entry = patch_table; patch_entry->lmp_subversion != LMP_SUBVERSION_NONE; patch_entry++) { + if (patch_entry->lmp_subversion != cfg->lmp_subversion) + continue; + if ((patch_entry->hci_version_mask != HCI_VERSION_MASK_ALL) && ((patch_entry->hci_version_mask & (1 << cfg->hci_version)) == 0)) + continue; + if ((patch_entry->hci_revision_mask != HCI_REVISION_MASK_ALL) && ((patch_entry->hci_revision_mask & (1 << cfg->hci_revision)) == 0)) + continue; + if ((mask & PATCH_OPTIONAL_MATCH_FLAG_CHIPTYPE) && (patch_entry->chip_type_mask != CHIP_TYPE_MASK_ALL) && ((patch_entry->chip_type_mask & (1 << cfg->chip_type)) == 0)) + continue; + res++; + } + RS_DBG("check_match_state return %d(cfg->lmp_subversion:0x%x cfg->hci_vesion:0x%x cfg->hci_revision:0x%x cfg->chip_type:0x%x mask:%08x)", + res, cfg->lmp_subversion, cfg->hci_version, cfg->hci_revision, cfg->chip_type, mask); + return res; +} + +static patch_info *get_patch_entry(bt_hw_cfg_cb_t *cfg) +{ + patch_info *patch_entry; + + RS_DBG("get_patch_entry(lmp_subversion:0x%x hci_vesion:0x%x cfg->hci_revision:0x%x chip_type:0x%x)", + cfg->lmp_subversion, cfg->hci_version, cfg->hci_revision, cfg->chip_type); + for (patch_entry = patch_table; patch_entry->lmp_subversion != LMP_SUBVERSION_NONE; patch_entry++) { + if (patch_entry->lmp_subversion != cfg->lmp_subversion) + continue; + if ((patch_entry->hci_version_mask != HCI_VERSION_MASK_ALL) && ((patch_entry->hci_version_mask & (1 << cfg->hci_version)) == 0)) + continue; + if ((patch_entry->hci_revision_mask != HCI_REVISION_MASK_ALL) && ((patch_entry->hci_revision_mask & (1<hci_revision)) == 0)) + continue; + if ((patch_entry->chip_type_mask != CHIP_TYPE_MASK_ALL) && ((patch_entry->chip_type_mask & (1<chip_type)) == 0)) + continue; + break; + } + RS_DBG("get_patch_entry return(patch_name:%s config_name:%s mac_offset:0x%x)", + patch_entry->patch_name, patch_entry->config_name, patch_entry->mac_offset); + return patch_entry; +} + +/** +* Config realtek Bluetooth. The configuration parameter is get from config file and fw. +* +* @warning maybe only one of config file and fw file exists. The bt_addr arg is stored in "/data/btmac.txt" +* or "/data/misc/bluetoothd/bt_mac/btmac.txt", +* +* @param fd uart file descriptor +* @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE +* @param speed init_speed in uart struct +* @param ti termios struct +* @returns #0 on success +*/ +static int rtk_config(int fd, int proto, int speed, struct termios *ti) +{ + int config_len = -1, buf_len = -1, final_speed = 0; + uint8_t *config_file_buf = NULL; + uint8_t *buf = NULL; + uint32_t baudrate = 0; + + uint8_t *epatch_buf = NULL; + struct rtk_epatch *epatch_info = NULL; + struct rtk_epatch_entry current_entry; + uint8_t need_download_fw = 1; + patch_info *prtk_patch_file_info = NULL; + + current_entry.start_offset = 0; + current_entry.patch_length = 0; + current_entry.chipID = 0; + + /* + * 1. if both config file and fw exists, use it and change rate according to config file + * 2. if config file not exists while fw does, not change baudrate and only download fw + * 3. if fw doesnot exist, only change rate to 3.25M or from config file if it exist. This case is only for early debug before any efuse is setting. + */ + + /* Get version from ROM */ + rtk_get_lmp_version(fd); + if (check_match_state(&hw_cfg_cb, 0) > 1) { + rtk_get_chip_type(fd); + RS_DBG("lmp_subversion = 0x%x, hci_version = 0x%x, hci_revision = 0x%x, chip_type = 0x%x", + hw_cfg_cb.lmp_subversion, hw_cfg_cb.hci_version, hw_cfg_cb.hci_revision, hw_cfg_cb.chip_type); + } + + prtk_patch_file_info = get_patch_entry(&hw_cfg_cb); + + if (prtk_patch_file_info == NULL) { + RS_ERR("lmp_version is %x, no matched project found!", hw_cfg_cb.lmp_subversion); + need_download_fw = 0; + goto FETCH_DONE; + } + + config_len = rtk_get_bt_config(&config_file_buf, &baudrate, prtk_patch_file_info); + if (config_len < 0) { + RS_ERR("Get Config file error, just use efuse settings"); + config_len = 0; + } + + buf_len = rtk_get_bt_firmware(&epatch_buf, config_len, prtk_patch_file_info); + if (buf_len < 0) { + RS_ERR("Get BT firmware error, continue without bt firmware"); + goto FETCH_DONE; + } + + if (hw_cfg_cb.lmp_subversion == ROM_LMP_8723a) { + if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) == 0) { + RS_ERR("8723as Check signature error!"); + need_download_fw = 0; + goto FETCH_DONE; + } + + buf = malloc(buf_len); + if (!buf) { + RS_ERR("Can't alloc memory for fw&config, errno:%d", errno); + buf_len = -1; + goto FETCH_DONE; + } + + RS_DBG("8723as, fw copy direct"); + memcpy(buf, epatch_buf, buf_len); + } else { + /* Get version from ROM */ + rtk_get_eversion(fd); /* gEVersion is set. */ + RS_DBG("gEVersion=%d", gEVersion); + /* check Extension Section Field */ + if (memcmp(epatch_buf + buf_len - config_len - 4, Extension_Section_SIGNATURE, 4) != 0) { + RS_ERR("Check Extension_Section_SIGNATURE error! do not download fw"); + need_download_fw = 0; + goto FETCH_DONE; + } + + if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) != 0) { + RS_DBG("Check signature error!"); + need_download_fw = 0; + goto FETCH_DONE; + } + + int i = 0; + uint32_t value_t = 0; + epatch_info = (struct rtk_epatch *)epatch_buf; + value_t = le32_to_cpu(epatch_info->fm_version); + epatch_info->fm_version = (uint32_t)value_t; + value_t = le16_to_cpu(epatch_info->number_of_total_patch); + epatch_info->number_of_total_patch = (uint16_t)value_t; + RS_DBG("fm_version = 0x%x", epatch_info->fm_version); + RS_DBG("number_of_total_patch = %d", epatch_info->number_of_total_patch); + /* get right epatch entry */ + for (i = 0; i < epatch_info->number_of_total_patch; i++) { + if (le16_to_cpu(*(uint16_t *)(epatch_buf + 14 + 2 * i)) == gEVersion + 1) { + current_entry.chipID = gEVersion + 1; + current_entry.patch_length = le16_to_cpu(*(uint16_t *)(epatch_buf + 14 + 2 * epatch_info->number_of_total_patch + 2 * i)); + current_entry.start_offset = le32_to_cpu(*(uint32_t *)(epatch_buf + 14 + 4 * epatch_info->number_of_total_patch + 4 * i)); + break; + } + } + RS_DBG("chipID = %d", current_entry.chipID); + RS_DBG("patch_length = 0x%x", current_entry.patch_length); + RS_DBG("start_offset = 0x%x", current_entry.start_offset); + /* get right version patch: buf, buf_len */ + buf_len = current_entry.patch_length + config_len; + RS_DBG("buf_len = 0x%x", buf_len); + buf = malloc(buf_len); + if (!buf) { + RS_ERR("Can't alloc memory for multi fw&config, errno:%d", errno); + buf_len = -1; + goto FETCH_DONE; + } + memcpy(buf, &epatch_buf[current_entry.start_offset], current_entry.patch_length); + value_t = cpu_to_le32(epatch_info->fm_version); + epatch_info->fm_version = (uint32_t)value_t; + memcpy(&buf[current_entry.patch_length-4], &epatch_info->fm_version, 4); + value_t = cpu_to_le32(epatch_info->fm_version); + epatch_info->fm_version = value_t; + } + + if (config_len) { + memcpy(&buf[buf_len - config_len], config_file_buf, config_len); + } + +FETCH_DONE: + free(epatch_buf); + epatch_buf = NULL; + if (config_file_buf) + free(config_file_buf); + + RS_DBG("Fw:%s exists, config file:%s exists", (buf_len > 0) ? "" : "not", (config_len > 0) ? "" : "not"); + if ((buf_len > 0) && (config_len == 0)) { + rtk_h5.link_estab_state = H5_PATCH; + goto DOWNLOAD_FW; + } + + /* change baudrate if needed */ + if (baudrate == 0) { + uart_speed_to_rtk_speed(speed, &baudrate); + RS_DBG("Since no config file to set uart baudrate, so use user input parameters:%x, %x", (int)speed, (uint32_t)baudrate); + } else + rtk_speed_to_uart_speed(baudrate, (uint32_t *)&gFinalSpeed); + + if (proto == HCI_UART_3WIRE) + rtk_vendor_change_speed_h5(fd, baudrate); + else + rtk_vendor_change_speed_h4(fd, baudrate); + + usleep(50000); + final_speed = gFinalSpeed ? gFinalSpeed : speed; + RS_DBG("final_speed %d\n", final_speed); + if (set_speed(fd, ti, final_speed) < 0) { + RS_ERR("Can't set baud rate:%x, %x, %x", final_speed, gFinalSpeed, speed); + return -1; + } + + if (gHwFlowControlEnable) { + RS_DBG("Hw Flow Control enable"); + ti->c_cflag |= CRTSCTS; + } else { + RS_DBG("Hw Flow Control disable"); + ti->c_cflag &= ~CRTSCTS; + } + RS_DBG("Hw Flow Control do not enable before download fw! "); + + /* wait for while for controller to setup */ + usleep(10000); + +DOWNLOAD_FW: + if (buf && (buf_len > 0) && (need_download_fw)) { + /* baudrate 0 means no change baudrate send */ + memset(&rtk_patch, 0, sizeof(rtk_patch)); + rtk_patch.nRxIndex = -1; + + rtk_download_fw_config(fd, buf, buf_len, baudrate, proto, ti); + free(buf); + } + RS_DBG("Init Process finished"); + return 0; +} + +/** +* Init uart by realtek Bluetooth. +* +* @param fd uart file descriptor +* @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE +* @param speed init_speed in uart struct +* @param ti termios struct +* @returns #0 on success, depend on rtk_config +*/ +int rtk_init(int fd, int proto, int speed, struct termios *ti) +{ + RS_DBG("Realtek hciattach version %s \n", RTK_VERSION); + + if (proto == HCI_UART_3WIRE) { /*h4 will do nothing for init */ + rtk_init_h5(fd, ti); + } + return rtk_config(fd, proto, speed, ti); +} + +/** +* Post uart by realtek Bluetooth. If gFinalSpeed is set, set uart speed with it. +* +* @param fd uart file descriptor +* @param proto realtek Bluetooth protocol, shall be either HCI_UART_H4 or HCI_UART_3WIRE +* @param ti termios struct +* @returns #0 on success. +*/ +int rtk_post(int fd, int proto, struct termios *ti) +{ + if (gFinalSpeed) { + return set_speed(fd, ti, gFinalSpeed); + } + return 0; +} diff --git a/external/cache/sources/hcitools/hciattach_sprd.c b/external/cache/sources/hcitools/hciattach_sprd.c new file mode 100644 index 000000000000..604d11bfda91 --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_sprd.c @@ -0,0 +1,707 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hciattach.h" + +/****************************************************************************** +** Constants & Macros +******************************************************************************/ +#define LOG_STR "SPRD Bluetooth" +#define DBG_ON 1 + +#define SPRD_DBG(fmt, arg...) \ + do { \ + if (DBG_ON) \ + fprintf(stderr, "%s: " fmt "\n" , LOG_STR, ##arg); \ + } while(0) + +#define SPRD_ERR(fmt, arg...) \ + do { \ + fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg);\ + perror(LOG_STR" ERROR reason"); \ + } while(0) + +#define SPRD_DUMP(buffer, len) \ + fprintf(stderr, "%s: ", LOG_STR); \ + do { \ + for (int i = 0; i < len; i++) { \ + if (i && !(i % 16)) { \ + fprintf(stderr, "\n"); \ + fprintf(stderr, "%s: ", LOG_STR); \ + } \ + fprintf(stderr, "%02x ", buffer[i]); \ + } \ + fprintf(stderr, "\n"); \ + } while (0) + +#define CONF_ITEM_TABLE(ITEM, ACTION, BUF, LEN) \ + { #ITEM, ACTION, &(BUF.ITEM), LEN, (sizeof(BUF.ITEM) / LEN) } + +#define UINT8_TO_STREAM(p, u8) \ + { *(p)++ = (uint8_t)(u8); } + +#define STREAM_TO_UINT8(u8, p) \ + { \ + (u8) = (uint8_t)(*(p)); \ + (p) += 1; \ + } + +#define UINT16_TO_STREAM(p, u16) \ + { \ + *(p)++ = (uint8_t)(u16); \ + *(p)++ = (uint8_t)((u16) >> 8); \ + } + +#define STREAM_TO_UINT16(u16, p) \ + { \ + (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \ + (p) += 2; \ + } + +#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 CONF_COMMENT '#' +#define CONF_DELIMITERS " =\n\r\t" +#define CONF_VALUES_DELIMITERS "=\n\r\t#" +#define CONF_VALUES_PARTITION " ,=\n\r\t#" +#define CONF_MAX_LINE_LEN 255 + +#define HCI_PSKEY 0xFCA0 +#define HCI_VSC_ENABLE_COMMMAND 0xFCA1 +#define HCI_RF_PARA 0xFCA2 + +#define RESPONSE_LENGTH 100 +#define HCI_CMD_MAX_LEN 258 +#define HCI_EVT_CMD_CMPL_OPCODE 3 +#define HCI_PACKET_TYPE_COMMAND 1 +#define HCI_CMD_PREAMBLE_SIZE 3 + +#define FW_NODE_BYTE 6 +#define FW_DATE_D_BYTE 8 +#define FW_DATE_M_BYTE 9 +#define FW_DATE_Y_BYTE 10 + +#define BT_CONFIG_PATH "/lib/firmware" +#define BT_HC_HDR_SIZE (sizeof(HC_BT_HDR)) +#define BT_VND_OP_RESULT_SUCCESS 0 +#define BT_VND_OP_RESULT_FAIL 1 +#define MSG_STACK_TO_HC_HCI_CMD 0x2000 +#define START_STOP_CMD_SIZE 3 +#define DUAL_MODE 0 +#define DISABLE_BT 0 +#define ENABLE_BT 1 + +typedef void (*hci_cback)(void *); +typedef int (conf_action_t)(char *p_conf_name, char *p_conf_value, void *buf, int len, int size); + +typedef struct { + uint16_t event; + uint16_t len; + uint16_t offset; + uint16_t layer_specific; + uint8_t data[]; +} HC_BT_HDR; + +typedef struct { + uint32_t device_class; + uint8_t feature_set[16]; + uint8_t device_addr[6]; + uint16_t comp_id; + uint8_t g_sys_uart0_communication_supported; + uint8_t cp2_log_mode; + uint8_t LogLevel; + uint8_t g_central_or_perpheral; + uint16_t Log_BitMask; + uint8_t super_ssp_enable; + uint8_t common_rfu_b3; + uint32_t common_rfu_w[2]; + uint32_t le_rfu_w[2]; + uint32_t lmp_rfu_w[2]; + uint32_t lc_rfu_w[2]; + uint16_t g_wbs_nv_117; + uint16_t g_wbs_nv_118; + uint16_t g_nbv_nv_117; + uint16_t g_nbv_nv_118; + uint8_t g_sys_sco_transmit_mode; + uint8_t audio_rfu_b1; + uint8_t audio_rfu_b2; + uint8_t audio_rfu_b3; + uint32_t audio_rfu_w[2]; + uint8_t g_sys_sleep_in_standby_supported; + uint8_t g_sys_sleep_master_supported; + uint8_t g_sys_sleep_slave_supported; + uint8_t power_rfu_b1; + uint32_t power_rfu_w[2]; + uint32_t win_ext; + uint8_t edr_tx_edr_delay; + uint8_t edr_rx_edr_delay; + uint8_t tx_delay; + uint8_t rx_delay; + uint32_t bb_rfu_w[2]; + uint8_t agc_mode; + uint8_t diff_or_eq; + uint8_t ramp_mode; + uint8_t modem_rfu_b1; + uint32_t modem_rfu_w[2]; + uint32_t BQB_BitMask_1; + uint32_t BQB_BitMask_2; + uint16_t bt_coex_threshold[8]; + uint32_t other_rfu_w[6]; +} pskey_config_t; + +typedef struct { + uint16_t g_GainValue_A[6]; + uint16_t g_ClassicPowerValue_A[10]; + uint16_t g_LEPowerValue_A[16]; + uint16_t g_BRChannelpwrvalue_A[8]; + uint16_t g_EDRChannelpwrvalue_A[8]; + uint16_t g_LEChannelpwrvalue_A[8]; + uint16_t g_GainValue_B[6]; + uint16_t g_ClassicPowerValue_B[10]; + uint16_t g_LEPowerValue_B[16]; + uint16_t g_BRChannelpwrvalue_B[8]; + uint16_t g_EDRChannelpwrvalue_B[8]; + uint16_t g_LEChannelpwrvalue_B[8]; + uint16_t LE_fix_powerword; + uint8_t Classic_pc_by_channel; + uint8_t LE_pc_by_channel; + uint8_t RF_switch_mode; + uint8_t Data_Capture_Mode; + uint8_t Analog_IQ_Debug_Mode; + uint8_t RF_common_rfu_b3; + uint32_t RF_common_rfu_w[5]; +} rf_config_t; + +typedef struct { + const char *conf_entry; + conf_action_t *p_action; + void *buf; + int len; + int size; +} conf_entry_t; + +static uint8_t local_bdaddr[6]={0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; +static pskey_config_t marlin3_pskey; +static rf_config_t marlin3_rf_config; +static int s_bt_fd = -1; + +static const conf_entry_t marlin3_pksey_table[] = { + CONF_ITEM_TABLE(device_class, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(feature_set, 0, marlin3_pskey, 16), + CONF_ITEM_TABLE(device_addr, 0, marlin3_pskey, 6), + CONF_ITEM_TABLE(comp_id, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(g_sys_uart0_communication_supported, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(cp2_log_mode, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(LogLevel, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(g_central_or_perpheral, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(Log_BitMask, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(super_ssp_enable, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(common_rfu_b3, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(common_rfu_w, 0, marlin3_pskey, 2), + CONF_ITEM_TABLE(le_rfu_w, 0, marlin3_pskey, 2), + CONF_ITEM_TABLE(lmp_rfu_w, 0, marlin3_pskey, 2), + CONF_ITEM_TABLE(lc_rfu_w, 0, marlin3_pskey, 2), + CONF_ITEM_TABLE(g_wbs_nv_117, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(g_wbs_nv_118, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(g_nbv_nv_117, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(g_nbv_nv_118, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(g_sys_sco_transmit_mode, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(audio_rfu_b1, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(audio_rfu_b2, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(audio_rfu_b3, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(audio_rfu_w, 0, marlin3_pskey, 2), + CONF_ITEM_TABLE(g_sys_sleep_in_standby_supported, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(g_sys_sleep_master_supported, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(g_sys_sleep_slave_supported, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(power_rfu_b1, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(power_rfu_w, 0, marlin3_pskey, 2), + CONF_ITEM_TABLE(win_ext, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(edr_tx_edr_delay, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(edr_rx_edr_delay, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(tx_delay, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(rx_delay, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(bb_rfu_w, 0, marlin3_pskey, 2), + CONF_ITEM_TABLE(agc_mode, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(diff_or_eq, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(ramp_mode, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(modem_rfu_b1, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(modem_rfu_w, 0, marlin3_pskey, 2), + CONF_ITEM_TABLE(BQB_BitMask_1, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(BQB_BitMask_2, 0, marlin3_pskey, 1), + CONF_ITEM_TABLE(bt_coex_threshold, 0, marlin3_pskey, 8), + CONF_ITEM_TABLE(other_rfu_w, 0, marlin3_pskey, 6), + {0, 0, 0, 0, 0} +}; + +static const conf_entry_t marlin3_rf_table[] = { + CONF_ITEM_TABLE(g_GainValue_A, 0, marlin3_rf_config, 6), + CONF_ITEM_TABLE(g_ClassicPowerValue_A, 0, marlin3_rf_config, 10), + CONF_ITEM_TABLE(g_LEPowerValue_A, 0, marlin3_rf_config, 16), + CONF_ITEM_TABLE(g_BRChannelpwrvalue_A, 0, marlin3_rf_config, 8), + CONF_ITEM_TABLE(g_EDRChannelpwrvalue_A, 0, marlin3_rf_config, 8), + CONF_ITEM_TABLE(g_LEChannelpwrvalue_A, 0, marlin3_rf_config, 8), + CONF_ITEM_TABLE(g_GainValue_B, 0, marlin3_rf_config, 6), + CONF_ITEM_TABLE(g_ClassicPowerValue_B, 0, marlin3_rf_config, 10), + CONF_ITEM_TABLE(g_LEPowerValue_B, 0, marlin3_rf_config, 16), + CONF_ITEM_TABLE(g_BRChannelpwrvalue_B, 0, marlin3_rf_config, 8), + CONF_ITEM_TABLE(g_EDRChannelpwrvalue_B, 0, marlin3_rf_config, 8), + CONF_ITEM_TABLE(g_LEChannelpwrvalue_B, 0, marlin3_rf_config, 8), + CONF_ITEM_TABLE(LE_fix_powerword, 0, marlin3_rf_config, 1), + CONF_ITEM_TABLE(Classic_pc_by_channel, 0, marlin3_rf_config, 1), + CONF_ITEM_TABLE(LE_pc_by_channel, 0, marlin3_rf_config, 1), + CONF_ITEM_TABLE(RF_switch_mode, 0, marlin3_rf_config, 1), + CONF_ITEM_TABLE(Data_Capture_Mode, 0, marlin3_rf_config, 1), + CONF_ITEM_TABLE(Analog_IQ_Debug_Mode, 0, marlin3_rf_config, 1), + CONF_ITEM_TABLE(RF_common_rfu_b3, 0, marlin3_rf_config, 1), + CONF_ITEM_TABLE(RF_common_rfu_w, 0, marlin3_rf_config, 5), + {0, 0, 0, 0, 0} +}; + +static void log_bin_to_hexstr(uint8_t *bin, uint8_t binsz, const char *log_tag) +{ + SPRD_DBG("%s", log_tag); + SPRD_DUMP(bin, binsz); +} + +static void parse_number(char *p_conf_name, char *p_conf_value, void *buf, int len, int size) +{ + uint8_t *dest = (uint8_t *)buf; + char *sub_value, *p; + uint32_t value; + (void)p_conf_name; + sub_value = strtok_r(p_conf_value, CONF_VALUES_PARTITION, &p); + do { + if (sub_value == NULL) + break; + + if (sub_value[0] == '0' && (sub_value[1] == 'x' || sub_value[1] == 'X')) + value = strtoul(sub_value, 0, 16) & 0xFFFFFFFF; + else + value = strtoul(sub_value, 0, 10) & 0xFFFFFFFF; + + switch (size) { + case sizeof(uint8_t): + *dest = value & 0xFF; + dest += size; + break; + + case sizeof(uint16_t): + *((uint16_t *)dest) = value & 0xFFFF; + dest += size; + break; + + case sizeof(uint32_t): + *((uint32_t *)dest) = value & 0xFFFFFFFF; + dest += size; + break; + + default: + break; + } + sub_value = strtok_r(NULL, CONF_VALUES_PARTITION, &p); + } while (--len); +} + +static void set_mac_address(uint8_t *addr) +{ + int i = 0; + SPRD_DBG("%s", __func__); + for (i = 0; i < 6; i++) + addr[5-i] = (unsigned char)local_bdaddr[i]; +} + +static void vnd_load_configure(const char *p_path, const conf_entry_t *entry) +{ + FILE *p_file; + char *p_name, *p_value, *p; + conf_entry_t *p_entry; + char line[CONF_MAX_LINE_LEN + 1]; /* add 1 for \0 char */ + + SPRD_DBG("Attempt to load conf from %s", p_path); + + if ((p_file = fopen(p_path, "r")) != NULL) { + /* read line by line */ + while (fgets(line, CONF_MAX_LINE_LEN + 1, p_file) != NULL) { + if (line[0] == CONF_COMMENT) continue; + + p_name = strtok_r(line, CONF_DELIMITERS, &p); + + if (NULL == p_name) { + continue; + } + + p_value = strtok_r(NULL, CONF_VALUES_DELIMITERS, &p); + + if (NULL == p_value) { + SPRD_DBG("vnd_load_conf: missing value for name: %s", p_name); + continue; + } + + p_entry = (conf_entry_t*)entry; + + while (p_entry->conf_entry != NULL) { + if (strcmp(p_entry->conf_entry, (const char *)p_name) == 0) { + if (p_entry->p_action) { + p_entry->p_action(p_name, p_value, p_entry->buf, p_entry->len, + p_entry->size); + } else { + SPRD_DBG("%s -> %s", p_name, p_value); + parse_number(p_name, p_value, p_entry->buf, p_entry->len, + p_entry->size); + } + break; + } + + p_entry++; + } + } + + fclose(p_file); + } else { + SPRD_DBG("vnd_load_conf file >%s< not found", p_path); + } +} + +static size_t H4Protocol_Send(uint8_t type, const uint8_t* data, size_t length) +{ + struct iovec iov[] = { + {&type, sizeof(type)}, + {(uint8_t *)data, length}}; + + ssize_t ret = 0; + do { + ret = writev(s_bt_fd, iov, sizeof(iov) / sizeof(iov[0])); + } while (-1 == ret && EAGAIN == errno); + + if (ret == -1) { + SPRD_ERR("%s error writing to UART (%s)", __func__, strerror(errno)); + } else if (ret < length + 1) { + SPRD_ERR("%s: %d / %d bytes written - something went wrong...", __func__, ret, length + 1); + } + + return ret; +} + +static void *bt_vendor_alloc(int size) +{ + void *p = (uint8_t *)malloc(size); + return p; +} + +static void bt_vendor_free(void *buffer) +{ + free(buffer); +} + +static uint8_t bt_vendor_xmit(uint16_t opcode, void* buffer, hci_cback callback) +{ + uint8_t type = HCI_PACKET_TYPE_COMMAND; + (void)opcode; + HC_BT_HDR* bt_hdr = (HC_BT_HDR *)buffer; + H4Protocol_Send(type, bt_hdr->data, bt_hdr->len); + return BT_VND_OP_RESULT_SUCCESS; +} + +static uint8_t sprd_vnd_send_hci_vsc(uint16_t cmd, uint8_t *payload, uint8_t len, hci_cback cback) +{ + HC_BT_HDR *p_buf; + uint8_t *p, ret; + + p_buf = (HC_BT_HDR *)bt_vendor_alloc( + BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + len); + 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 + len; + p = (uint8_t *)(p_buf + 1); + + UINT16_TO_STREAM(p, cmd); + *p++ = len; + memcpy(p, payload, len); + log_bin_to_hexstr((uint8_t *)(p_buf + 1), HCI_CMD_PREAMBLE_SIZE + len, __FUNCTION__); + ret = bt_vendor_xmit(cmd, p_buf, cback); + bt_vendor_free(p_buf); + return ret; + } + return BT_VND_OP_RESULT_FAIL; +} + +static void hw_core_cback(void *p_mem) +{ + uint8_t *p_evt_buf = (uint8_t *)p_mem; + uint8_t *p, status; + uint16_t opcode, mode; + + p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE; + STREAM_TO_UINT16(opcode,p); + STREAM_TO_UINT16(mode,p); + STREAM_TO_UINT8(status,p); + SPRD_DBG("%s hw_core_cback response: [0x%04X, 0x%04X, 0x%02X]", __func__, opcode, mode, status); + bt_vendor_free(p_evt_buf); +} + +static void hw_core_enable(unsigned char enable) +{ + uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; + p = msg_req; + UINT16_TO_STREAM(p, DUAL_MODE); + UINT8_TO_STREAM(p, enable ? ENABLE_BT : DISABLE_BT); + sprd_vnd_send_hci_vsc(HCI_VSC_ENABLE_COMMMAND, msg_req, (uint8_t)(p - msg_req), NULL); +} + +static void hw_rf_cback(void *p_mem) +{ + uint8_t *p_evt_buf = (uint8_t *)p_mem, len; + uint8_t *p, status; + uint16_t opcode, mode = 0; + + p = (uint8_t *)(p_evt_buf + 1) + 1; + STREAM_TO_UINT8(len, p); + + p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE; + STREAM_TO_UINT16(opcode, p); + if (len == 6) + STREAM_TO_UINT16(mode, p); + + STREAM_TO_UINT8(status, p); + + SPRD_DBG("%s hw_rf_cback response: [0x%04X, 0x%04X, 0x%02X]", __func__, opcode, mode, status); + /* Must free the RX event buffer */ + bt_vendor_free(p_evt_buf); +} + +static int marlin3_rf_preload() +{ + uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; + int i; + + SPRD_DBG("yujian.qin %s", __FUNCTION__); + p = msg_req; + + for (i = 0; i < 6; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_GainValue_A[i]); + + for (i = 0; i < 10; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_ClassicPowerValue_A[i]); + + for (i = 0; i < 16; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_LEPowerValue_A[i]); + + for (i = 0; i < 8; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_BRChannelpwrvalue_A[i]); + + for (i = 0; i < 8; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_EDRChannelpwrvalue_A[i]); + + for (i = 0; i < 8; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_LEChannelpwrvalue_A[i]); + + for (i = 0; i < 6; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_GainValue_B[i]); + + for (i = 0; i < 10; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_ClassicPowerValue_B[i]); + + for (i = 0; i < 16; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_LEPowerValue_B[i]); + + for (i = 0; i < 8; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_BRChannelpwrvalue_B[i]); + + for (i = 0; i < 8; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_EDRChannelpwrvalue_B[i]); + + for (i = 0; i < 8; i++) + UINT16_TO_STREAM(p, marlin3_rf_config.g_LEChannelpwrvalue_B[i]); + + UINT16_TO_STREAM(p, marlin3_rf_config.LE_fix_powerword); + + UINT8_TO_STREAM(p, marlin3_rf_config.Classic_pc_by_channel); + UINT8_TO_STREAM(p, marlin3_rf_config.LE_pc_by_channel); + UINT8_TO_STREAM(p, marlin3_rf_config.RF_switch_mode); + UINT8_TO_STREAM(p, marlin3_rf_config.Data_Capture_Mode); + UINT8_TO_STREAM(p, marlin3_rf_config.Analog_IQ_Debug_Mode); + UINT8_TO_STREAM(p, marlin3_rf_config.RF_common_rfu_b3); + + for (i = 0; i < 5; i++) + UINT32_TO_STREAM(p, marlin3_rf_config.RF_common_rfu_w[i]); + + sprd_vnd_send_hci_vsc(HCI_RF_PARA, msg_req, (uint8_t)(p - msg_req), NULL); + return 0; +} + +static void marlin3_pskey_cback(void *p_mem) +{ + uint8_t *p_evt_buf = (uint8_t *)p_mem; + + uint16_t opcode, node, year; + uint8_t *p, month, day; + (void)opcode; + + p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE; + STREAM_TO_UINT16(opcode, p); + + p = (uint8_t *)(p_evt_buf + 1) + FW_NODE_BYTE; + STREAM_TO_UINT16(node, p); + p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_Y_BYTE; + STREAM_TO_UINT16(year, p); + p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_M_BYTE; + STREAM_TO_UINT8(month, p); + p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_D_BYTE; + STREAM_TO_UINT8(day, p); + + SPRD_DBG("Bluetooth Firmware Node: %04X Date: %04x-%02x-%02x", node, year, month, day); + + /* Must free the RX event buffer */ + bt_vendor_free(p_evt_buf); +} + +static int marlin3_pskey_preload(void *arg) +{ + uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; + int i; + (void)arg; + + SPRD_DBG("%s", __FUNCTION__); + p = msg_req; + UINT32_TO_STREAM(p, marlin3_pskey.device_class); + + for (i = 0; i < 16; i++) + UINT8_TO_STREAM(p, marlin3_pskey.feature_set[i]); + + for (i = 0; i < 6; i++) + UINT8_TO_STREAM(p, marlin3_pskey.device_addr[i]); + + UINT16_TO_STREAM(p, marlin3_pskey.comp_id); + UINT8_TO_STREAM(p, marlin3_pskey.g_sys_uart0_communication_supported); + UINT8_TO_STREAM(p, marlin3_pskey.cp2_log_mode); + UINT8_TO_STREAM(p, marlin3_pskey.LogLevel); + UINT8_TO_STREAM(p, marlin3_pskey.g_central_or_perpheral); + + UINT16_TO_STREAM(p, marlin3_pskey.Log_BitMask); + UINT8_TO_STREAM(p, marlin3_pskey.super_ssp_enable); + UINT8_TO_STREAM(p, marlin3_pskey.common_rfu_b3); + + for (i = 0; i < 2; i++) + UINT32_TO_STREAM(p, marlin3_pskey.common_rfu_w[i]); + + for (i = 0; i < 2; i++) + UINT32_TO_STREAM(p, marlin3_pskey.le_rfu_w[i]); + + for (i = 0; i < 2; i++) + UINT32_TO_STREAM(p, marlin3_pskey.lmp_rfu_w[i]); + + for (i = 0; i < 2; i++) + UINT32_TO_STREAM(p, marlin3_pskey.lc_rfu_w[i]); + + UINT16_TO_STREAM(p, marlin3_pskey.g_wbs_nv_117); + UINT16_TO_STREAM(p, marlin3_pskey.g_wbs_nv_118); + UINT16_TO_STREAM(p, marlin3_pskey.g_nbv_nv_117); + UINT16_TO_STREAM(p, marlin3_pskey.g_nbv_nv_118); + + UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sco_transmit_mode); + UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b1); + UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b2); + UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b3); + + for (i = 0; i < 2; i++) + UINT32_TO_STREAM(p, marlin3_pskey.audio_rfu_w[i]); + + UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_in_standby_supported); + UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_master_supported); + UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_slave_supported); + UINT8_TO_STREAM(p, marlin3_pskey.power_rfu_b1); + + for (i = 0; i < 2; i++) + UINT32_TO_STREAM(p, marlin3_pskey.power_rfu_w[i]); + + UINT32_TO_STREAM(p, marlin3_pskey.win_ext); + + UINT8_TO_STREAM(p, marlin3_pskey.edr_tx_edr_delay); + UINT8_TO_STREAM(p, marlin3_pskey.edr_rx_edr_delay); + UINT8_TO_STREAM(p, marlin3_pskey.tx_delay); + UINT8_TO_STREAM(p, marlin3_pskey.rx_delay); + + for (i = 0; i < 2; i++) + UINT32_TO_STREAM(p, marlin3_pskey.bb_rfu_w[i]); + + UINT8_TO_STREAM(p, marlin3_pskey.agc_mode); + UINT8_TO_STREAM(p, marlin3_pskey.diff_or_eq); + UINT8_TO_STREAM(p, marlin3_pskey.ramp_mode); + UINT8_TO_STREAM(p, marlin3_pskey.modem_rfu_b1); + + for (i = 0; i < 2; i++) + UINT32_TO_STREAM(p, marlin3_pskey.modem_rfu_w[i]); + + UINT32_TO_STREAM(p, marlin3_pskey.BQB_BitMask_1); + UINT32_TO_STREAM(p, marlin3_pskey.BQB_BitMask_2); + for (i = 0; i < 8; i++) + UINT16_TO_STREAM(p, marlin3_pskey.bt_coex_threshold[i]); + + for (i = 0; i < 6; i++) + UINT32_TO_STREAM(p, marlin3_pskey.other_rfu_w[i]); + + sprd_vnd_send_hci_vsc(HCI_PSKEY, msg_req, (uint8_t)(p - msg_req), NULL); + return 0; +} + + +int sprd_config_init(int fd, struct uart_t *u, struct termios *ti) +{ + uint8_t *recv = NULL; + int len = 0; + + s_bt_fd = fd; + + memset(&marlin3_pskey, 0, sizeof(marlin3_pskey)); + memset(&marlin3_rf_config, 0, sizeof(marlin3_rf_config)); + vnd_load_configure(BT_CONFIG_PATH "/bt_configure_pskey.ini", &marlin3_pksey_table[0]); + vnd_load_configure(BT_CONFIG_PATH "/bt_configure_rf.ini", &marlin3_rf_table[0]); + set_mac_address(marlin3_pskey.device_addr); + + marlin3_pskey_preload(NULL); + recv = bt_vendor_alloc(RESPONSE_LENGTH); + len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH); + SPRD_DBG("Received event, len: %d", len); + SPRD_DUMP(recv, len); + marlin3_pskey_cback(recv); + + marlin3_rf_preload(); + recv = bt_vendor_alloc(RESPONSE_LENGTH); + len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH); + SPRD_DBG("Received event, len: %d", len); + SPRD_DUMP(recv, len); + hw_rf_cback(recv); + + hw_core_enable(1); + recv = bt_vendor_alloc(RESPONSE_LENGTH); + len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH); + SPRD_DBG("Received event, len: %d", len); + SPRD_DUMP(recv, len); + hw_core_cback(recv); + + return 0; +} + +int sprd_config_post(int fd, struct uart_t *u, struct termios *ti) +{ + SPRD_DBG("Done setting line discpline"); + return 0; +} + diff --git a/external/cache/sources/hcitools/hciattach_st.c b/external/cache/sources/hcitools/hciattach_st.c new file mode 100644 index 000000000000..dbb7c47b28cb --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_st.c @@ -0,0 +1,278 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hciattach.h" + +static int debug = 0; + +static int do_command(int fd, uint8_t ogf, uint16_t ocf, + uint8_t *cparam, int clen, uint8_t *rparam, int rlen) +{ + //uint16_t opcode = (uint16_t) ((ocf & 0x03ff) | (ogf << 10)); + unsigned char cp[260], rp[260]; + int len, size, offset = 3; + + cp[0] = 0x01; + cp[1] = ocf & 0xff; + cp[2] = ogf << 2 | ocf >> 8; + cp[3] = clen; + + if (clen > 0) + memcpy(cp + 4, cparam, clen); + + if (debug) { + int i; + printf("[<"); + for (i = 0; i < clen + 4; i++) + printf(" %02x", cp[i]); + printf("]\n"); + } + + if (write(fd, cp, clen + 4) < 0) + return -1; + + do { + if (read(fd, rp, 1) < 1) + return -1; + } while (rp[0] != 0x04); + + if (read(fd, rp + 1, 2) < 2) + return -1; + + do { + len = read(fd, rp + offset, sizeof(rp) - offset); + offset += len; + } while (offset < rp[2] + 3); + + if (debug) { + int i; + printf("[>"); + for (i = 0; i < offset; i++) + printf(" %02x", rp[i]); + printf("]\n"); + } + + if (rp[0] != 0x04) { + errno = EIO; + return -1; + } + + switch (rp[1]) { + case 0x0e: /* command complete */ + if (rp[6] != 0x00) + return -ENXIO; + offset = 3 + 4; + size = rp[2] - 4; + break; + case 0x0f: /* command status */ + /* fall through */ + default: + offset = 3; + size = rp[2]; + break; + } + + if (!rparam || rlen < size) + return -ENXIO; + + memcpy(rparam, rp + offset, size); + + return size; +} + +static int load_file(int dd, uint16_t version, const char *suffix) +{ + DIR *dir; + struct dirent *d; + char pathname[PATH_MAX], filename[NAME_MAX], prefix[20]; + unsigned char cmd[256]; + unsigned char buf[256]; + uint8_t seqnum = 0; + int fd, size, len, found_fw_file; + + memset(filename, 0, sizeof(filename)); + + snprintf(prefix, sizeof(prefix), "STLC2500_R%d_%02d_", + version >> 8, version & 0xff); + + strcpy(pathname, "/lib/firmware"); + dir = opendir(pathname); + if (!dir) { + strcpy(pathname, "."); + dir = opendir(pathname); + if (!dir) + return -errno; + } + + found_fw_file = 0; + while (1) { + d = readdir(dir); + if (!d) + break; + + if (strncmp(d->d_name + strlen(d->d_name) - strlen(suffix), + suffix, strlen(suffix))) + continue; + + if (strncmp(d->d_name, prefix, strlen(prefix))) + continue; + + snprintf(filename, sizeof(filename), "%s/%s", + pathname, d->d_name); + found_fw_file = 1; + } + + closedir(dir); + + if (!found_fw_file) + return -ENOENT; + + printf("Loading file %s\n", filename); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror("Can't open firmware file"); + return -errno; + } + + while (1) { + size = read(fd, cmd + 1, 254); + if (size <= 0) + break; + + cmd[0] = seqnum; + + len = do_command(dd, 0xff, 0x002e, cmd, size + 1, buf, sizeof(buf)); + if (len < 1) + break; + + if (buf[0] != seqnum) { + fprintf(stderr, "Sequence number mismatch\n"); + break; + } + + seqnum++; + } + + close(fd); + + return 0; +} + +int stlc2500_init(int dd, bdaddr_t *bdaddr) +{ + unsigned char cmd[16]; + unsigned char buf[254]; + uint16_t version; + int len; + int err; + + /* Hci_Cmd_Ericsson_Read_Revision_Information */ + len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf)); + if (len < 0) + return -1; + + printf("%s\n", buf); + + /* HCI_Read_Local_Version_Information */ + len = do_command(dd, 0x04, 0x0001, NULL, 0, buf, sizeof(buf)); + if (len < 0) + return -1; + + version = buf[2] << 8 | buf[1]; + + err = load_file(dd, version, ".ptc"); + if (err < 0) { + if (err == -ENOENT) + fprintf(stderr, "No ROM patch file loaded.\n"); + else + return -1; + } + + err = load_file(dd, buf[2] << 8 | buf[1], ".ssf"); + if (err < 0) { + if (err == -ENOENT) + fprintf(stderr, "No static settings file loaded.\n"); + else + return -1; + } + + cmd[0] = 0xfe; + cmd[1] = 0x06; + bacpy((bdaddr_t *) (cmd + 2), bdaddr); + + /* Hci_Cmd_ST_Store_In_NVDS */ + len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf)); + if (len < 0) + return -1; + + /* HCI_Reset : applies parameters*/ + len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf)); + if (len < 0) + return -1; + + return 0; +} + +int bgb2xx_init(int dd, bdaddr_t *bdaddr) +{ + unsigned char cmd[16]; + unsigned char buf[254]; + int len; + + len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf)); + if (len < 0) + return -1; + + printf("%s\n", buf); + + cmd[0] = 0xfe; + cmd[1] = 0x06; + bacpy((bdaddr_t *) (cmd + 2), bdaddr); + + len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf)); + if (len < 0) + return -1; + + len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf)); + if (len < 0) + return -1; + + return 0; +} diff --git a/external/cache/sources/hcitools/hciattach_ti.c b/external/cache/sources/hcitools/hciattach_ti.c new file mode 100644 index 000000000000..8322b45733f4 --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_ti.c @@ -0,0 +1,533 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2007-2008 Texas Instruments, Inc. + * Copyright (C) 2005-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hciattach.h" + +#ifdef HCIATTACH_DEBUG +#define DPRINTF(x...) printf(x) +#else +#define DPRINTF(x...) +#endif + +#define HCIUARTGETDEVICE _IOR('U', 202, int) + +#define MAKEWORD(a, b) ((uint16_t)(((uint8_t)(a)) | ((uint16_t)((uint8_t)(b))) << 8)) + +#define TI_MANUFACTURER_ID 13 + +#define FIRMWARE_DIRECTORY "/lib/firmware/ti-connectivity/" + +#define ACTION_SEND_COMMAND 1 +#define ACTION_WAIT_EVENT 2 +#define ACTION_SERIAL 3 +#define ACTION_DELAY 4 +#define ACTION_RUN_SCRIPT 5 +#define ACTION_REMARKS 6 + +#define BRF_DEEP_SLEEP_OPCODE_BYTE_1 0x0c +#define BRF_DEEP_SLEEP_OPCODE_BYTE_2 0xfd +#define BRF_DEEP_SLEEP_OPCODE \ + (BRF_DEEP_SLEEP_OPCODE_BYTE_1 | (BRF_DEEP_SLEEP_OPCODE_BYTE_2 << 8)) + +#define FILE_HEADER_MAGIC 0x42535442 + +/* + * BRF Firmware header + */ +struct bts_header { + uint32_t magic; + uint32_t version; + uint8_t future[24]; + uint8_t actions[0]; +}__attribute__ ((packed)); + +/* + * BRF Actions structure + */ +struct bts_action { + uint16_t type; + uint16_t size; + uint8_t data[0]; +} __attribute__ ((packed)); + +struct bts_action_send { + uint8_t data[0]; +} __attribute__ ((packed)); + +struct bts_action_wait { + uint32_t msec; + uint32_t size; + uint8_t data[0]; +}__attribute__ ((packed)); + +struct bts_action_delay { + uint32_t msec; +}__attribute__ ((packed)); + +struct bts_action_serial { + uint32_t baud; + uint32_t flow_control; +}__attribute__ ((packed)); + +static FILE *bts_load_script(const char *file_name, uint32_t *version) +{ + struct bts_header header; + FILE *fp; + + fp = fopen(file_name, "rb"); + if (!fp) { + perror("can't open firmware file"); + return NULL; + } + + if (1 != fread(&header, sizeof(struct bts_header), 1, fp)) { + perror("can't read firmware file"); + goto errclose; + } + + if (header.magic != FILE_HEADER_MAGIC) { + fprintf(stderr, "%s not a legal TI firmware file\n", file_name); + goto errclose; + } + + if (NULL != version) + *version = header.version; + + return fp; + +errclose: + fclose(fp); + + return NULL; +} + +static unsigned long bts_fetch_action(FILE *fp, unsigned char *action_buf, + unsigned long buf_size, uint16_t *action_type) +{ + struct bts_action action_hdr; + unsigned long nread; + + if (!fp) + return 0; + + if (1 != fread(&action_hdr, sizeof(struct bts_action), 1, fp)) + return 0; + + if (action_hdr.size > buf_size) { + fprintf(stderr, "bts_next_action: not enough space to read next action\n"); + return 0; + } + + nread = fread(action_buf, sizeof(uint8_t), action_hdr.size, fp); + if (nread != (action_hdr.size)) { + fprintf(stderr, "bts_next_action: fread failed to read next action\n"); + return 0; + } + + *action_type = action_hdr.type; + + return nread * sizeof(uint8_t); +} + +static void bts_unload_script(FILE *fp) +{ + if (fp) + fclose(fp); +} + +static int is_it_texas(const uint8_t *respond) +{ + uint16_t manufacturer_id; + + manufacturer_id = MAKEWORD(respond[11], respond[12]); + + return TI_MANUFACTURER_ID == manufacturer_id ? 1 : 0; +} + +static const char *get_firmware_name(const uint8_t *respond) +{ + static char firmware_file_name[PATH_MAX] = {0}; + uint16_t version = 0, chip = 0, min_ver = 0, maj_ver = 0; + + version = MAKEWORD(respond[13], respond[14]); + chip = (version & 0x7C00) >> 10; + min_ver = (version & 0x007F); + maj_ver = (version & 0x0380) >> 7; + + if (version & 0x8000) + maj_ver |= 0x0008; + + sprintf(firmware_file_name, FIRMWARE_DIRECTORY "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver); + + return firmware_file_name; +} + +static void brf_delay(struct bts_action_delay *delay) +{ + usleep(1000 * delay->msec); +} + +static int brf_set_serial_params(struct bts_action_serial *serial_action, + int fd, int *speed, struct termios *ti) +{ + fprintf(stderr, "texas: changing baud rate to %u, flow control to %u\n", + serial_action->baud, serial_action->flow_control ); + tcflush(fd, TCIOFLUSH); + + if (serial_action->flow_control) + ti->c_cflag |= CRTSCTS; + else + ti->c_cflag &= ~CRTSCTS; + + if (tcsetattr(fd, TCSANOW, ti) < 0) { + perror("Can't set port settings"); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (set_speed(fd, ti, serial_action->baud) < 0) { + perror("Can't set baud rate"); + return -1; + } + + if (speed) + *speed = serial_action->baud; + + return 0; +} + +static int brf_send_command_socket(int fd, struct bts_action_send *send_action) +{ + char response[1024] = {0}; + hci_command_hdr *cmd = (hci_command_hdr *) send_action->data; + uint16_t opcode = cmd->opcode; + + struct hci_request rq; + memset(&rq, 0, sizeof(rq)); + rq.ogf = cmd_opcode_ogf(opcode); + rq.ocf = cmd_opcode_ocf(opcode); + rq.event = EVT_CMD_COMPLETE; + rq.cparam = &send_action->data[3]; + rq.clen = send_action->data[2]; + rq.rparam = response; + rq.rlen = sizeof(response); + + if (hci_send_req(fd, &rq, 15) < 0) { + perror("Cannot send hci command to socket"); + return -1; + } + + /* verify success */ + if (response[0]) { + errno = EIO; + return -1; + } + + return 0; +} + +static int brf_send_command_file(int fd, struct bts_action_send *send_action, + long size) +{ + unsigned char response[1024] = {0}; + long ret = 0; + + /* send command */ + if (size != write(fd, send_action, size)) { + perror("Texas: Failed to write action command"); + return -1; + } + + /* read response */ + ret = read_hci_event(fd, response, sizeof(response)); + if (ret < 0) { + perror("texas: failed to read command response"); + return -1; + } + + /* verify success */ + if (ret < 7 || 0 != response[6]) { + fprintf( stderr, "TI init command failed.\n" ); + errno = EIO; + return -1; + } + + return 0; +} + + +static int brf_send_command(int fd, struct bts_action_send *send_action, + long size, int hcill_installed) +{ + int ret = 0; + char *fixed_action; + + /* remove packet type when giving to socket API */ + if (hcill_installed) { + fixed_action = ((char *) send_action) + 1; + ret = brf_send_command_socket(fd, (struct bts_action_send *) fixed_action); + } else { + ret = brf_send_command_file(fd, send_action, size); + } + + return ret; +} + +static int brf_do_action(uint16_t brf_type, uint8_t *brf_action, long brf_size, + int fd, int *speed, struct termios *ti, int hcill_installed) +{ + int ret = 0; + + switch (brf_type) { + case ACTION_SEND_COMMAND: + DPRINTF("W"); + ret = brf_send_command(fd, + (struct bts_action_send *) brf_action, + brf_size, hcill_installed); + break; + case ACTION_WAIT_EVENT: + DPRINTF("R"); + break; + case ACTION_SERIAL: + DPRINTF("S"); + ret = brf_set_serial_params((struct bts_action_serial *) brf_action, fd, speed, ti); + break; + case ACTION_DELAY: + DPRINTF("D"); + brf_delay((struct bts_action_delay *) brf_action); + break; + case ACTION_REMARKS: + DPRINTF("C"); + break; + default: + fprintf(stderr, "brf_init: unknown firmware action type (%d)\n", brf_type); + break; + } + + return ret; +} + +/* + * tests whether a given brf action is a HCI_VS_Sleep_Mode_Configurations cmd + */ +static int brf_action_is_deep_sleep(uint8_t *brf_action, long brf_size, + uint16_t brf_type) +{ + uint16_t opcode; + + if (brf_type != ACTION_SEND_COMMAND) + return 0; + + if (brf_size < 3) + return 0; + + if (brf_action[0] != HCI_COMMAND_PKT) + return 0; + + /* HCI data is little endian */ + opcode = brf_action[1] | (brf_action[2] << 8); + + if (opcode != BRF_DEEP_SLEEP_OPCODE) + return 0; + + /* action is deep sleep configuration command ! */ + return 1; +} + +/* + * This function is called twice. + * The first time it is called, it loads the brf script, and executes its + * commands until it reaches a deep sleep command (or its end). + * The second time it is called, it assumes HCILL protocol is set up, + * and sends rest of brf script via the supplied socket. + */ +static int brf_do_script(int fd, int *speed, struct termios *ti, const char *bts_file) +{ + int ret = 0, hcill_installed = bts_file ? 0 : 1; + uint32_t vers; + static FILE *brf_script_file = NULL; + static uint8_t brf_action[512]; + static long brf_size; + static uint16_t brf_type; + + /* is it the first time we are called ? */ + if (0 == hcill_installed) { + DPRINTF("Sending script to serial device\n"); + brf_script_file = bts_load_script(bts_file, &vers ); + if (!brf_script_file) { + fprintf(stderr, "Warning: cannot find BTS file: %s\n", + bts_file); + return 0; + } + + fprintf( stderr, "Loaded BTS script version %u\n", vers ); + + brf_size = bts_fetch_action(brf_script_file, brf_action, + sizeof(brf_action), &brf_type); + if (brf_size == 0) { + fprintf(stderr, "Warning: BTS file is empty !"); + return 0; + } + } + else { + DPRINTF("Sending script to bluetooth socket\n"); + } + + /* execute current action and continue to parse brf script file */ + while (brf_size != 0) { + ret = brf_do_action(brf_type, brf_action, brf_size, + fd, speed, ti, hcill_installed); + if (ret == -1) + break; + + brf_size = bts_fetch_action(brf_script_file, brf_action, + sizeof(brf_action), &brf_type); + + /* if this is the first time we run (no HCILL yet) */ + /* and a deep sleep command is encountered */ + /* we exit */ + if (!hcill_installed && + brf_action_is_deep_sleep(brf_action, + brf_size, brf_type)) + return 0; + } + + bts_unload_script(brf_script_file); + brf_script_file = NULL; + DPRINTF("\n"); + + return ret; +} + +int texas_init(int fd, int *speed, struct termios *ti) +{ + struct timespec tm = {0, 50000}; + char cmd[4]; + unsigned char resp[100]; /* Response */ + const char *bts_file; + int n; + + memset(resp,'\0', 100); + + /* It is possible to get software version with manufacturer specific + HCI command HCI_VS_TI_Version_Number. But the only thing you get more + is if this is point-to-point or point-to-multipoint module */ + + /* Get Manufacturer and LMP version */ + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x01; + cmd[2] = 0x10; + cmd[3] = 0x00; + + do { + n = write(fd, cmd, 4); + if (n < 0) { + perror("Failed to write init command (READ_LOCAL_VERSION_INFORMATION)"); + return -1; + } + if (n < 4) { + fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n); + return -1; + } + + /* Read reply. */ + if (read_hci_event(fd, resp, 100) < 0) { + perror("Failed to read init response (READ_LOCAL_VERSION_INFORMATION)"); + return -1; + } + + /* Wait for command complete event for our Opcode */ + } while (resp[4] != cmd[1] && resp[5] != cmd[2]); + + /* Verify manufacturer */ + if (! is_it_texas(resp)) { + fprintf(stderr,"ERROR: module's manufacturer is not Texas Instruments\n"); + return -1; + } + + fprintf(stderr, "Found a Texas Instruments' chip!\n"); + + bts_file = get_firmware_name(resp); + fprintf(stderr, "Firmware file : %s\n", bts_file); + + n = brf_do_script(fd, speed, ti, bts_file); + + nanosleep(&tm, NULL); + + return n; +} + +int texas_post(int fd, struct termios *ti) +{ + int dev_id, dd, ret = 0; + + sleep(1); + + dev_id = ioctl(fd, HCIUARTGETDEVICE, 0); + if (dev_id < 0) { + perror("cannot get device id"); + return -1; + } + + DPRINTF("\nAdded device hci%d\n", dev_id); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + return -1; + } + + if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) { + fprintf(stderr, "Can't init device hci%d: %s (%d)", dev_id, + strerror(errno), errno); + hci_close_dev(dd); + return -1; + } + + ret = brf_do_script(dd, NULL, ti, NULL); + + hci_close_dev(dd); + + return ret; +} diff --git a/external/cache/sources/hcitools/hciattach_tialt.c b/external/cache/sources/hcitools/hciattach_tialt.c new file mode 100644 index 000000000000..c3caa4922d48 --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_tialt.c @@ -0,0 +1,242 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hciattach.h" + +#define FAILIF(x, args...) do { \ + if (x) { \ + fprintf(stderr, ##args); \ + return -1; \ + } \ +} while(0) + +typedef struct { + uint8_t uart_prefix; + hci_event_hdr hci_hdr; + evt_cmd_complete cmd_complete; + uint8_t status; + uint8_t data[16]; +} __attribute__((packed)) command_complete_t; + +static int read_command_complete(int fd, unsigned short opcode, unsigned char len) { + command_complete_t resp; + /* Read reply. */ + FAILIF(read_hci_event(fd, (unsigned char *)&resp, sizeof(resp)) < 0, + "Failed to read response"); + + /* Parse speed-change reply */ + FAILIF(resp.uart_prefix != HCI_EVENT_PKT, + "Error in response: not an event packet, but 0x%02x!\n", + resp.uart_prefix); + + FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE, /* event must be event-complete */ + "Error in response: not a cmd-complete event, " + "but 0x%02x!\n", resp.hci_hdr.evt); + + FAILIF(resp.hci_hdr.plen < 4, /* plen >= 4 for EVT_CMD_COMPLETE */ + "Error in response: plen is not >= 4, but 0x%02x!\n", + resp.hci_hdr.plen); + + /* cmd-complete event: opcode */ + FAILIF(resp.cmd_complete.opcode != (uint16_t)opcode, + "Error in response: opcode is 0x%04x, not 0x%04x!", + resp.cmd_complete.opcode, opcode); + + return resp.status == 0 ? 0 : -1; +} + +typedef struct { + uint8_t uart_prefix; + hci_command_hdr hci_hdr; + uint32_t speed; +} __attribute__((packed)) texas_speed_change_cmd_t; + +static int texas_change_speed(int fd, uint32_t speed) +{ + return 0; +} + +static int texas_load_firmware(int fd, const char *firmware) { + + int fw = open(firmware, O_RDONLY); + + fprintf(stdout, "Opening firmware file: %s\n", firmware); + + FAILIF(fw < 0, + "Could not open firmware file %s: %s (%d).\n", + firmware, strerror(errno), errno); + + fprintf(stdout, "Uploading firmware...\n"); + do { + /* Read each command and wait for a response. */ + unsigned char data[1024]; + unsigned char cmdp[1 + sizeof(hci_command_hdr)]; + hci_command_hdr *cmd = (hci_command_hdr *)(cmdp + 1); + int nr; + nr = read(fw, cmdp, sizeof(cmdp)); + if (!nr) + break; + FAILIF(nr != sizeof(cmdp), "Could not read H4 + HCI header!\n"); + FAILIF(*cmdp != HCI_COMMAND_PKT, "Command is not an H4 command packet!\n"); + + FAILIF(read(fw, data, cmd->plen) != cmd->plen, + "Could not read %d bytes of data for command with opcode %04x!\n", + cmd->plen, + cmd->opcode); + + { + int nw; +#if 0 + fprintf(stdout, "\topcode 0x%04x (%d bytes of data).\n", + cmd->opcode, + cmd->plen); +#endif + struct iovec iov_cmd[2]; + iov_cmd[0].iov_base = cmdp; + iov_cmd[0].iov_len = sizeof(cmdp); + iov_cmd[1].iov_base = data; + iov_cmd[1].iov_len = cmd->plen; + nw = writev(fd, iov_cmd, 2); + FAILIF(nw != (int) sizeof(cmd) + cmd->plen, + "Could not send entire command (sent only %d bytes)!\n", + nw); + } + + /* Wait for response */ + if (read_command_complete(fd, + cmd->opcode, + cmd->plen) < 0) { + return -1; + } + + } while(1); + fprintf(stdout, "Firmware upload successful.\n"); + + close(fw); + return 0; +} + +int texasalt_init(int fd, int speed, struct termios *ti) +{ + struct timespec tm = {0, 50000}; + char cmd[4]; + unsigned char resp[100]; /* Response */ + int n; + + memset(resp,'\0', 100); + + /* It is possible to get software version with manufacturer specific + HCI command HCI_VS_TI_Version_Number. But the only thing you get more + is if this is point-to-point or point-to-multipoint module */ + + /* Get Manufacturer and LMP version */ + cmd[0] = HCI_COMMAND_PKT; + cmd[1] = 0x01; + cmd[2] = 0x10; + cmd[3] = 0x00; + + do { + n = write(fd, cmd, 4); + if (n < 0) { + perror("Failed to write init command (READ_LOCAL_VERSION_INFORMATION)"); + return -1; + } + if (n < 4) { + fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n); + return -1; + } + + /* Read reply. */ + if (read_hci_event(fd, resp, 100) < 0) { + perror("Failed to read init response (READ_LOCAL_VERSION_INFORMATION)"); + return -1; + } + + /* Wait for command complete event for our Opcode */ + } while (resp[4] != cmd[1] && resp[5] != cmd[2]); + + /* Verify manufacturer */ + if ((resp[11] & 0xFF) != 0x0d) + fprintf(stderr,"WARNING : module's manufacturer is not Texas Instrument\n"); + + /* Print LMP version */ + fprintf(stderr, "Texas module LMP version : 0x%02x\n", resp[10] & 0xFF); + + /* Print LMP subversion */ + { + unsigned short lmp_subv = resp[13] | (resp[14] << 8); + unsigned short brf_chip = (lmp_subv & 0x7c00) >> 10; + static const char *c_brf_chip[8] = { + "unknown", + "unknown", + "brf6100", + "brf6150", + "brf6300", + "brf6350", + "unknown", + "wl1271" + }; + char fw[100]; + + fprintf(stderr, "Texas module LMP sub-version : 0x%04x\n", lmp_subv); + + fprintf(stderr, + "\tinternal version freeze: %d\n" + "\tsoftware version: %d\n" + "\tchip: %s (%d)\n", + lmp_subv & 0x7f, + ((lmp_subv & 0x8000) >> (15-3)) | ((lmp_subv & 0x380) >> 7), + ((brf_chip > 7) ? "unknown" : c_brf_chip[brf_chip]), + brf_chip); + + sprintf(fw, "/etc/firmware/%s.bin", c_brf_chip[brf_chip]); + texas_load_firmware(fd, fw); + + texas_change_speed(fd, speed); + } + nanosleep(&tm, NULL); + return 0; +} diff --git a/external/cache/sources/hcitools/hciattach_xr.c b/external/cache/sources/hcitools/hciattach_xr.c new file mode 100644 index 000000000000..c42b0099f9ea --- /dev/null +++ b/external/cache/sources/hcitools/hciattach_xr.c @@ -0,0 +1,557 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hciattach.h" + +/****************************************************************************** +** Constants & Macros +******************************************************************************/ +#define LOG_STR "XRADIO Bluetooth" +#define DBG_ON 1 + +#define XR_DBG(fmt, arg...) \ + do { \ + if (DBG_ON) \ + fprintf(stderr, "%s: " fmt "\n" , LOG_STR, ##arg); \ + } while(0) + +#define XR_ERR(fmt, arg...) \ + do { \ + fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg);\ + perror(LOG_STR" ERROR reason"); \ + } while(0) + +#define XR_DUMP(buffer, len) \ + fprintf(stderr, "%s: ", LOG_STR); \ + do { \ + for (int i = 0; i < len; i++) { \ + if (i && !(i % 16)) { \ + fprintf(stderr, "\n"); \ + fprintf(stderr, "%s: ", LOG_STR); \ + } \ + fprintf(stderr, "%02x ", buffer[i]); \ + } \ + fprintf(stderr, "\n"); \ + } while (0) + +#define BT_FW_PATH_NAME "/system/vendor/etc/firmware/fw_xr829_bt.bin" +#define BT_FW_LOAD_ADDR 0x0000 +#define BT_FW_JUMP_ADDR 0x0000 +#define AW1722 1 +#define AW1732 2 +#define CHIP_NAME AW1722 + +#define SZ_1K (0x00000400U ) +#define SZ_16K (0x00004000U ) + +#define SWAP16(d) (((d & 0xff) << 8) | ((d & 0xff00) >> 8)) +#define SWAP32(d) (((d & 0xff) << 24) | ((d & 0xff00) << 8) \ + | ((d & 0xff0000) >> 8) | ((d & 0xff000000) >> 24)) + +#define CMD_ID(group, key) (((group) << 3) | (key)) + +/*----------------------------*/ +/* COMMANDS FORM PC TO MCU */ +/*----------------------------*/ +#define CMD_ID_MEMRW 0x00 +#define CMD_ID_SEQRQ 0x01 +#define CMD_ID_SYSCTL 0x02 +#define CMD_ID_FLASH 0x03 + +#define CMD_ID_SEQRD CMD_ID(CMD_ID_SEQRQ, 0) +#define CMD_ID_SEQWR CMD_ID(CMD_ID_SEQRQ, 1) +/* uart commands */ +#define CMD_ID_SETUART CMD_ID(CMD_ID_SYSCTL, 0) +#define CMD_ID_SETPC CMD_ID(CMD_ID_SYSCTL, 3) + +#define CMD_WRITEN 0 +#define CMD_WRITESEQ 1 +#define CMD_SETBAUD 2 +#define CMD_SETPC 3 +#define DATA_RAW 4 + +/****************************************************************************** +** Type definitions +******************************************************************************/ + +/* vendor serial control block */ +typedef struct +{ + int fd; /* fd to Bluetooth device */ + struct termios *ti; /* serial terminal of BT port */ +} vnd_userial_cb_t; + +#pragma pack(1) +/* command header + * + * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 -7 byte 8-11 + * ___________________________________________________________________________________________________ + * | | | | | | | | | + * | 'B' | 'R' | 'O' | 'M' | Flags |Reserved | Checksum | Playload Length | + * |_________|_________|_________|_________|_________|_________|__________ ________|___________________| + */ +typedef struct { + uint8_t magic[4]; // magic "BROM" + #define CMD_BROM_MAGIC "BROM" + uint8_t flags; + #define CMD_HFLAG_ERROR (0x1U << 0) + #define CMD_HFLAG_ACK (0x1U << 1) + #define CMD_HFLAG_CHECK (0x1U << 2) + #define CMD_HFLAG_RETRY (0x1U << 3) + #define CMD_HFLAG_EXE (0x1U << 4) + uint8_t version:4; + uint8_t reserved:4; + uint16_t checksum; + uint32_t payload_len; +} __attribute__((packed)) cmd_header_t; +#define MB_CMD_HEADER_SIZE (sizeof(cmd_header_t)) + +/* acknownledge structure */ +typedef struct { + cmd_header_t h; + uint8_t err; +} __attribute__((packed)) cmd_ack_t; + +/* sequence read/write command structure */ +typedef struct { + cmd_header_t h; + uint8_t cmdid; + uint32_t addr; + uint32_t dlen; + uint16_t dcs; +} __attribute__((packed)) cmd_seq_wr_t; + +/* io change command structure */ +typedef struct { + cmd_header_t h; + uint8_t cmdid; + uint32_t val; +} __attribute__((packed)) cmd_sys_t; + +typedef struct { + cmd_header_t h; + uint8_t cmdid; + uint32_t lcr; +} __attribute__((packed)) cmd_sys_setuart_t; + +#pragma pack() + +static const uint8_t hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 }; +static const uint8_t hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x04, 0x60, 0xE3, 0x16, 0x00}; +static vnd_userial_cb_t vnd_userial; + +static int32_t cmd_sync_uart(void); +static int32_t cmd_sync_baud(uint32_t lcr); +static int32_t cmd_write_seq(uint32_t addr, uint32_t len, uint8_t *data); +static int32_t cmd_set_pc(uint32_t pc); +static void userial_set_hw_fctrl(uint8_t hw_fctrl); +static uint32_t userial_read(uint8_t *p_buffer, uint32_t len, uint32_t timeout); +static uint32_t userial_write(const uint8_t *p_data, uint32_t len); + +/****************************************************************************** +** Functions +******************************************************************************/ +static uint16_t CheckSum16(uint8_t *data, uint32_t len) +{ + uint16_t cs = 0; + uint16_t *p = (uint16_t *)data; + + while(len > 1) { + cs += *p++; + len -= 2; + } + if (len) { + cs += *(uint8_t *)p; + } + return cs; +} + +static uint64_t time_gettimeofday_us(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec; +} + +static uint8_t *memsearch(uint8_t *haystack, uint32_t hlen, uint8_t *needle, uint32_t nlen) +{ + while (hlen-- >= nlen) { + if (!memcmp(haystack, needle, nlen)) { + return haystack; + } + haystack++; + } + return NULL; +} + +static int32_t xr_raw_write(int type, uint8_t *data, uint32_t len) +{ + uint8_t buffer[MB_CMD_HEADER_SIZE + 13] = {'B', 'R', 'O', 'M', 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t *psend = data; + uint32_t lsend = len; + cmd_header_t *hdr = (cmd_header_t *)buffer;; + cmd_ack_t *ack = (cmd_ack_t *)buffer; + + if (type != DATA_RAW) { + psend = buffer; + lsend = MB_CMD_HEADER_SIZE + len; + memcpy(buffer + MB_CMD_HEADER_SIZE, data, len); + hdr->payload_len = len; +#if ENABLE_DCS + hdr->flags = CMD_HFLAG_CHECK; +#endif + hdr->checksum = ~CheckSum16(buffer, MB_CMD_HEADER_SIZE + len); + hdr->payload_len = SWAP32(hdr->payload_len); + hdr->checksum = SWAP16(hdr->checksum); + switch (type) { + case CMD_WRITESEQ: + { + cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)buffer; + cmd->addr = SWAP32(cmd->addr); + cmd->dlen = SWAP32(cmd->dlen); + cmd->dcs = SWAP16(cmd->dcs); + } + break; + case CMD_SETBAUD: + { + cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)buffer; + cmd->lcr = SWAP32(cmd->lcr); + } + break; + case CMD_SETPC: + { + cmd_sys_t *cmd = (cmd_sys_t*)buffer; + cmd->val = SWAP32(cmd->val); + } + break; + default: + XR_ERR("%s: Unsupport type %d", __func__, type); + return -1; + } + } + + ssize_t ret_w, ret_r; + uint64_t t0, t1, t2, t3; + + tcflush(vnd_userial.fd, TCIOFLUSH); + + t0 = time_gettimeofday_us(); + ret_w = userial_write(psend, lsend); + t1 = time_gettimeofday_us(); + + memset(buffer, 0, MB_CMD_HEADER_SIZE + 1); + + t2 = time_gettimeofday_us(); + ret_r = userial_read(buffer, MB_CMD_HEADER_SIZE, 100000); + t3 = time_gettimeofday_us(); + + XR_DBG("%s, type: %d, write len: %5d, ret: %5d, time: %6lluus, read len: %2d, ret: %2d, %6lluus", + __func__, type, lsend, ret_w, t1 - t0, MB_CMD_HEADER_SIZE, ret_r, t3 - t2); + + uint8_t *p = (uint8_t *)memsearch(buffer, MB_CMD_HEADER_SIZE, (uint8_t *)"BROM", 4); + if (p != buffer) { + if (p == NULL) { + XR_ERR("%s: invalid response", __func__); + return -1; + } + uint32_t nowread = buffer + MB_CMD_HEADER_SIZE - p; + uint32_t needread = p - buffer; + XR_DBG("%s: Index error, re-find header magic", __func__); + memcpy(buffer, p, nowread); + memset(buffer + nowread, 0x0, needread); + userial_read(buffer + nowread, needread, 100000); + } + + /* check response */ + if (ack->h.flags & CMD_HFLAG_ERROR) { + userial_read(buffer + MB_CMD_HEADER_SIZE, 1, 100000); + XR_ERR("%s: resp error flag, type %d", __func__, ack->err); + return -ack->err; + } + + if (ack->h.flags & CMD_HFLAG_ACK) { + /* convert network byte order to host byte order */ + ack->h.payload_len = SWAP32(ack->h.payload_len); + ack->h.checksum = SWAP16(ack->h.checksum); + if (ack->h.payload_len != 0) { + XR_ERR("%s: data payload len %d != 0", __func__, ack->h.payload_len); + return -1; + } + } + + if (ack->h.flags & CMD_HFLAG_CHECK) { + if (CheckSum16(buffer, MB_CMD_HEADER_SIZE) != 0xffff) { + XR_ERR("%s: write data response 0 checksum error", __func__); + return -1; + } + } + return 0; +} + +static int32_t cmd_sync_uart(void) +{ + uint8_t sync = 0x55; + uint8_t ack[3] = {0}; + ssize_t ret = -1; + uint32_t cnt = 0; + + do { + XR_DBG("uart sync count:%d.", cnt); + tcflush(vnd_userial.fd, TCIOFLUSH); + userial_write(&sync, 1); + ret = userial_read(ack, 2, 2000); + if (ret == 2 && ((ack[0] == 'O' && ack[1] == 'K') || (ack[0] == 'K' && ack[1] == 'O'))) { + XR_DBG("Receive %s, uart Sync done.", ack); + return 0; + } + } while (cnt++ < 50); + + XR_DBG("uart sync fail."); + return -1; +} + +static int32_t cmd_sync_baud(uint32_t lcr) +{ + uint8_t buffer[MB_CMD_HEADER_SIZE + 5]; + cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)buffer; + + cmd->cmdid = CMD_ID_SETUART; + cmd->lcr = lcr; + + uint8_t cnt = 0; + int ret = -1; + + do { + XR_DBG("%s count:%d.", __func__, cnt); + ret = xr_raw_write(CMD_SETBAUD, buffer + MB_CMD_HEADER_SIZE, 5); + if (ret == 0) { + set_speed(vnd_userial.fd, vnd_userial.ti, lcr & 0xffffff); + return cmd_sync_uart(); + } + } while (cnt++ < 3); + + XR_DBG("cmd_sync_baud fail."); + return -1; +} + +static int32_t cmd_write_seq(uint32_t addr, uint32_t len, uint8_t *data) +{ + int ret = -1; + uint8_t buffer[MB_CMD_HEADER_SIZE + 13]; + cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)buffer; + + cmd->cmdid = CMD_ID_SEQWR; + cmd->addr = addr; + cmd->dlen = len; +#if ENABLE_DCS + cmd->dcs = ~CheckSum16(data, len); +#endif + + ret = xr_raw_write(CMD_WRITESEQ, buffer + MB_CMD_HEADER_SIZE, 11); + if (ret == 0) { + return xr_raw_write(DATA_RAW, data, len); + } + return ret; +} + +static int32_t cmd_set_pc(uint32_t pc) +{ + uint8_t buffer[MB_CMD_HEADER_SIZE + 5]; + cmd_sys_t *cmd = (cmd_sys_t*)buffer; + + cmd->cmdid = CMD_ID_SETPC; + cmd->val = pc; + XR_DBG("set pc %x, val %x", pc, cmd->val); + + return xr_raw_write(CMD_SETPC, buffer + MB_CMD_HEADER_SIZE, 5); +} + +static void userial_set_hw_fctrl(uint8_t hw_fctrl) +{ + if (vnd_userial.fd == -1) { + XR_ERR("vnd_userial.fd is -1"); + return; + } + + if (hw_fctrl) { + XR_DBG("Set HW FlowControl On"); + vnd_userial.ti->c_cflag |= CRTSCTS; + } else { + XR_DBG("Set HW FlowControl Off"); + vnd_userial.ti->c_cflag &= ~CRTSCTS; + } + tcsetattr(vnd_userial.fd, TCSANOW, vnd_userial.ti); + tcflush(vnd_userial.fd, TCIOFLUSH); +} + +static uint32_t userial_read(uint8_t *buffer, uint32_t len, uint32_t timeout) +{ + fd_set set; + struct timeval tv; + int rv; + + FD_ZERO(&set); /* clear the set */ + FD_SET(vnd_userial.fd, &set); /* add our file descriptor to the set */ + + /* there was data to read */ + ssize_t r; + uint8_t *pos = (uint8_t*)buffer; + + while (len > 0) { + tv.tv_sec = 0; + tv.tv_usec = timeout; + + rv = select(vnd_userial.fd + 1, &set, NULL, NULL, &tv); + if(rv == -1) { + XR_ERR("select error"); /* an error accured */ + break; + } else if(rv == 0) { + XR_ERR("read timeout"); /* a timeout occured */ + break; + } + + r = read(vnd_userial.fd, pos, len); + if (r < 1) + break; + + len -= r; + pos += r; + } + + return pos - buffer; +} + +static uint32_t userial_write(const uint8_t *buffer, uint32_t len) +{ + ssize_t r; + uint8_t *pos = (uint8_t*)buffer; + + while (len > 0) { + r = write(vnd_userial.fd, pos, len); + if (r < 1) + break; + + len -= r; + pos += r; + } + + return pos - buffer; +} + +static int32_t load_btfirmware(void) +{ + FILE *fwfile_fd = NULL; + uint32_t len; + uint8_t *data = NULL; + uint32_t addr = BT_FW_LOAD_ADDR; + uint32_t section = SZ_16K; + + fwfile_fd = fopen(BT_FW_PATH_NAME, "rb"); + XR_DBG("BT firmware: %s", BT_FW_PATH_NAME); + if(!fwfile_fd) { + XR_ERR("Unable to open BT firmware %s", BT_FW_PATH_NAME); + return -1; + } + + data = (uint8_t*)malloc(section); + if (data == NULL) { + XR_DBG("failed to alloc %d byte memory.", section); + fclose(fwfile_fd); + return -1; + } + + XR_DBG("load bt firmware starting."); + while ((len = fread(data, 1, section, fwfile_fd)) > 0) { + cmd_write_seq(addr, len, data); + addr += len; + } + + free(data); + fclose(fwfile_fd); + XR_DBG("load firmware done."); + + XR_DBG("Firmware run from address 0x%08X", BT_FW_JUMP_ADDR); + cmd_set_pc(BT_FW_JUMP_ADDR); + + if (CHIP_NAME == AW1732) { + XR_DBG("second time sync starting...."); + if (cmd_sync_uart() < 0) + return -1; + cmd_set_pc(BT_FW_JUMP_ADDR); + } + return addr; +} + +static int hci_cmd_handle(const uint8_t *cmd, uint32_t cmd_len, uint32_t event_len) +{ + uint8_t buffer[256]; + + XR_DBG("send hci command"); + userial_write(cmd, cmd_len); + XR_DUMP(cmd, cmd_len); + + if (read_hci_event(vnd_userial.fd, buffer, event_len) != event_len) { + XR_ERR("Event read error"); + return -1; + } + XR_DBG("Received event"); + XR_DUMP(buffer, event_len); + return 0; +} + +int xr_init(int fd, struct uart_t *u, struct termios *ti) +{ + vnd_userial.fd = fd; + vnd_userial.ti = ti; + + XR_DBG("uart sync starting...."); + if (cmd_sync_uart() < 0) + goto END; + XR_DBG("set bandrate to %d.", u->speed); + if (cmd_sync_baud(((u->speed) | (3<<24))) < 0) + goto END; + if (load_btfirmware() < 0) + goto END; + XR_DBG("bt firmware is running...."); + + XR_DBG("set baudrate to %d", u->init_speed); + set_speed(vnd_userial.fd, vnd_userial.ti, u->init_speed); + userial_set_hw_fctrl(1); + usleep(50000); + + XR_DBG("process hci reset..."); + if (hci_cmd_handle(hci_reset, sizeof(hci_reset), 7) < 0) + goto END; + + XR_DBG("process hci update baud..."); + if (hci_cmd_handle(hci_update_baud_rate, sizeof(hci_update_baud_rate), 7) < 0) + goto END; + + usleep(100000); + + return 0; + +END: + XR_DBG("device fd = %d close", fd); + close(vnd_userial.fd); + vnd_userial.fd = -1; + vnd_userial.ti = NULL; + + return -1; +} + +int xr_post(int fd, struct uart_t *u, struct termios *ti) +{ + XR_DBG("Done setting line discpline"); + return 0; +} + diff --git a/external/cache/sources/hcitools/hciconfig.c b/external/cache/sources/hcitools/hciconfig.c new file mode 100644 index 000000000000..ec83139997cb --- /dev/null +++ b/external/cache/sources/hcitools/hciconfig.c @@ -0,0 +1,2052 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2002-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "textfile.h" +#include "csr.h" + +static struct hci_dev_info di; +static int all; + +static void print_dev_hdr(struct hci_dev_info *di); +static void print_dev_info(int ctl, struct hci_dev_info *di); + +static void print_dev_list(int ctl, int flags) +{ + struct hci_dev_list_req *dl; + struct hci_dev_req *dr; + int i; + + if (!(dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + + sizeof(uint16_t)))) { + perror("Can't allocate memory"); + exit(1); + } + dl->dev_num = HCI_MAX_DEV; + dr = dl->dev_req; + + if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) { + perror("Can't get device list"); + if(dl) { + free(dl); + dl = NULL; + } + exit(1); + } + + for (i = 0; i< dl->dev_num; i++) { + di.dev_id = (dr+i)->dev_id; + if (ioctl(ctl, HCIGETDEVINFO, (void *) &di) < 0) + continue; + if (hci_test_bit(HCI_RAW, &di.flags) && + !bacmp(&di.bdaddr, BDADDR_ANY)) { + int dd = hci_open_dev(di.dev_id); + hci_read_bd_addr(dd, &di.bdaddr, 1000); + hci_close_dev(dd); + } + print_dev_info(ctl, &di); + } + if(dl) { + free(dl); + dl = NULL; + } +} + +static void print_pkt_type(struct hci_dev_info *di) +{ + char *str; + str = hci_ptypetostr(di->pkt_type); + printf("\tPacket type: %s\n", str); + bt_free(str); +} + +static void print_link_policy(struct hci_dev_info *di) +{ + printf("\tLink policy: %s\n", hci_lptostr(di->link_policy)); +} + +static void print_link_mode(struct hci_dev_info *di) +{ + char *str; + str = hci_lmtostr(di->link_mode); + printf("\tLink mode: %s\n", str); + bt_free(str); +} + +static void print_dev_features(struct hci_dev_info *di, int format) +{ + printf("\tFeatures: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x " + "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", + di->features[0], di->features[1], di->features[2], + di->features[3], di->features[4], di->features[5], + di->features[6], di->features[7]); + + if (format) { + char *tmp = lmp_featurestostr(di->features, "\t\t", 63); + printf("%s\n", tmp); + bt_free(tmp); + } +} + +static void print_le_states(uint64_t states) +{ + int i; + const char *le_states[] = { + "Non-connectable Advertising State" , + "Scannable Advertising State", + "Connectable Advertising State", + "Directed Advertising State", + "Passive Scanning State", + "Active Scanning State", + "Initiating State/Connection State in Master Role", + "Connection State in the Slave Role", + "Non-connectable Advertising State and Passive Scanning State combination", + "Scannable Advertising State and Passive Scanning State combination", + "Connectable Advertising State and Passive Scanning State combination", + "Directed Advertising State and Passive Scanning State combination", + "Non-connectable Advertising State and Active Scanning State combination", + "Scannable Advertising State and Active Scanning State combination", + "Connectable Advertising State and Active Scanning State combination", + "Directed Advertising State and Active Scanning State combination", + "Non-connectable Advertising State and Initiating State combination", + "Scannable Advertising State and Initiating State combination", + "Non-connectable Advertising State and Master Role combination", + "Scannable Advertising State and Master Role combination", + "Non-connectable Advertising State and Slave Role combination", + "Scannable Advertising State and Slave Role combination", + "Passive Scanning State and Initiating State combination", + "Active Scanning State and Initiating State combination", + "Passive Scanning State and Master Role combination", + "Active Scanning State and Master Role combination", + "Passive Scanning State and Slave Role combination", + "Active Scanning State and Slave Role combination", + "Initiating State and Master Role combination/Master Role and Master Role combination", + NULL + }; + + printf("Supported link layer states:\n"); + for (i = 0; le_states[i]; i++) { + const char *status; + + status = states & (1 << i) ? "YES" : "NO "; + printf("\t%s %s\n", status, le_states[i]); + } +} + +static void cmd_rstat(int ctl, int hdev, char *opt) +{ + /* Reset HCI device stat counters */ + if (ioctl(ctl, HCIDEVRESTAT, hdev) < 0) { + fprintf(stderr, "Can't reset stats counters hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +} + +static void cmd_scan(int ctl, int hdev, char *opt) +{ + struct hci_dev_req dr; + + dr.dev_id = hdev; + dr.dev_opt = SCAN_DISABLED; + if (!strcmp(opt, "iscan")) + dr.dev_opt = SCAN_INQUIRY; + else if (!strcmp(opt, "pscan")) + dr.dev_opt = SCAN_PAGE; + else if (!strcmp(opt, "piscan")) + dr.dev_opt = SCAN_PAGE | SCAN_INQUIRY; + + if (ioctl(ctl, HCISETSCAN, (unsigned long) &dr) < 0) { + fprintf(stderr, "Can't set scan mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +} + +static void cmd_le_addr(int ctl, int hdev, char *opt) +{ + struct hci_request rq; + le_set_random_address_cp cp; + uint8_t status; + int dd, err, ret; + + if (!opt) + return; + + if (hdev < 0) + hdev = hci_get_route(NULL); + + dd = hci_open_dev(hdev); + if (dd < 0) { + err = -errno; + fprintf(stderr, "Could not open device: %s(%d)\n", + strerror(-err), -err); + exit(1); + } + + memset(&cp, 0, sizeof(cp)); + + str2ba(opt, &cp.bdaddr); + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_SET_RANDOM_ADDRESS; + rq.cparam = &cp; + rq.clen = LE_SET_RANDOM_ADDRESS_CP_SIZE; + rq.rparam = &status; + rq.rlen = 1; + + ret = hci_send_req(dd, &rq, 1000); + if (status || ret < 0) { + err = -errno; + fprintf(stderr, "Can't set random address for hci%d: " + "%s (%d)\n", hdev, strerror(-err), -err); + } + + hci_close_dev(dd); +} + +static void cmd_le_adv(int ctl, int hdev, char *opt) +{ + struct hci_request rq; + le_set_advertise_enable_cp advertise_cp; + le_set_advertising_parameters_cp adv_params_cp; + uint8_t status; + int dd, ret; + + if (hdev < 0) + hdev = hci_get_route(NULL); + + dd = hci_open_dev(hdev); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + memset(&adv_params_cp, 0, sizeof(adv_params_cp)); + adv_params_cp.min_interval = htobs(0x0800); + adv_params_cp.max_interval = htobs(0x0800); + if (opt) + adv_params_cp.advtype = atoi(opt); + adv_params_cp.chan_map = 7; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_SET_ADVERTISING_PARAMETERS; + rq.cparam = &adv_params_cp; + rq.clen = LE_SET_ADVERTISING_PARAMETERS_CP_SIZE; + rq.rparam = &status; + rq.rlen = 1; + + ret = hci_send_req(dd, &rq, 1000); + if (ret < 0) + goto done; + + memset(&advertise_cp, 0, sizeof(advertise_cp)); + advertise_cp.enable = 0x01; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE; + rq.cparam = &advertise_cp; + rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE; + rq.rparam = &status; + rq.rlen = 1; + + ret = hci_send_req(dd, &rq, 1000); + +done: + hci_close_dev(dd); + + if (ret < 0) { + fprintf(stderr, "Can't set advertise mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (status) { + fprintf(stderr, + "LE set advertise enable on hci%d returned status %d\n", + hdev, status); + exit(1); + } +} + +static void cmd_no_le_adv(int ctl, int hdev, char *opt) +{ + struct hci_request rq; + le_set_advertise_enable_cp advertise_cp; + uint8_t status; + int dd, ret; + + if (hdev < 0) + hdev = hci_get_route(NULL); + + dd = hci_open_dev(hdev); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + memset(&advertise_cp, 0, sizeof(advertise_cp)); + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE; + rq.cparam = &advertise_cp; + rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE; + rq.rparam = &status; + rq.rlen = 1; + + ret = hci_send_req(dd, &rq, 1000); + + hci_close_dev(dd); + + if (ret < 0) { + fprintf(stderr, "Can't set advertise mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (status) { + fprintf(stderr, "LE set advertise enable on hci%d returned status %d\n", + hdev, status); + exit(1); + } +} + +static void cmd_le_states(int ctl, int hdev, char *opt) +{ + le_read_supported_states_rp rp; + struct hci_request rq; + int err, dd; + + if (hdev < 0) + hdev = hci_get_route(NULL); + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + memset(&rp, 0, sizeof(rp)); + memset(&rq, 0, sizeof(rq)); + + rq.ogf = OGF_LE_CTL; + rq.ocf = OCF_LE_READ_SUPPORTED_STATES; + rq.rparam = &rp; + rq.rlen = LE_READ_SUPPORTED_STATES_RP_SIZE; + + err = hci_send_req(dd, &rq, 1000); + + hci_close_dev(dd); + + if (err < 0) { + fprintf(stderr, "Can't read LE supported states on hci%d:" + " %s(%d)\n", hdev, strerror(errno), errno); + exit(1); + } + + if (rp.status) { + fprintf(stderr, "Read LE supported states on hci%d" + " returned status %d\n", hdev, rp.status); + exit(1); + } + + print_le_states(rp.states); +} + +static void cmd_iac(int ctl, int hdev, char *opt) +{ + int s = hci_open_dev(hdev); + + if (s < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + if (opt) { + int l = strtoul(opt, 0, 16); + uint8_t lap[3]; + if (!strcasecmp(opt, "giac")) { + l = 0x9e8b33; + } else if (!strcasecmp(opt, "liac")) { + l = 0x9e8b00; + } else if (l < 0x9e8b00 || l > 0x9e8b3f) { + printf("Invalid access code 0x%x\n", l); + exit(1); + } + lap[0] = (l & 0xff); + lap[1] = (l >> 8) & 0xff; + lap[2] = (l >> 16) & 0xff; + if (hci_write_current_iac_lap(s, 1, lap, 1000) < 0) { + printf("Failed to set IAC on hci%d: %s\n", hdev, strerror(errno)); + exit(1); + } + } else { + uint8_t lap[3 * MAX_IAC_LAP]; + int i, j; + uint8_t n; + if (hci_read_current_iac_lap(s, &n, lap, 1000) < 0) { + printf("Failed to read IAC from hci%d: %s\n", hdev, strerror(errno)); + exit(1); + } + print_dev_hdr(&di); + printf("\tIAC: "); + for (i = 0; i < n; i++) { + printf("0x"); + for (j = 3; j--; ) + printf("%02x", lap[j + 3 * i]); + if (i < n - 1) + printf(", "); + } + printf("\n"); + } + close(s); +} + +static void cmd_auth(int ctl, int hdev, char *opt) +{ + struct hci_dev_req dr; + + dr.dev_id = hdev; + if (!strcmp(opt, "auth")) + dr.dev_opt = AUTH_ENABLED; + else + dr.dev_opt = AUTH_DISABLED; + + if (ioctl(ctl, HCISETAUTH, (unsigned long) &dr) < 0) { + fprintf(stderr, "Can't set auth on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +} + +static void cmd_encrypt(int ctl, int hdev, char *opt) +{ + struct hci_dev_req dr; + + dr.dev_id = hdev; + if (!strcmp(opt, "encrypt")) + dr.dev_opt = ENCRYPT_P2P; + else + dr.dev_opt = ENCRYPT_DISABLED; + + if (ioctl(ctl, HCISETENCRYPT, (unsigned long) &dr) < 0) { + fprintf(stderr, "Can't set encrypt on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +} + +static void cmd_up(int ctl, int hdev, char *opt) +{ + /* Start HCI device */ + if (ioctl(ctl, HCIDEVUP, hdev) < 0) { + if (errno == EALREADY) + return; + fprintf(stderr, "Can't init device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +} + +static void cmd_down(int ctl, int hdev, char *opt) +{ + /* Stop HCI device */ + if (ioctl(ctl, HCIDEVDOWN, hdev) < 0) { + fprintf(stderr, "Can't down device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +} + +static void cmd_reset(int ctl, int hdev, char *opt) +{ + /* Reset HCI device */ +#if 0 + if (ioctl(ctl, HCIDEVRESET, hdev) < 0 ){ + fprintf(stderr, "Reset failed for device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +#endif + cmd_down(ctl, hdev, "down"); + cmd_up(ctl, hdev, "up"); +} + +static void cmd_ptype(int ctl, int hdev, char *opt) +{ + struct hci_dev_req dr; + + dr.dev_id = hdev; + + if (hci_strtoptype(opt, &dr.dev_opt)) { + if (ioctl(ctl, HCISETPTYPE, (unsigned long) &dr) < 0) { + fprintf(stderr, "Can't set pkttype on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + print_dev_hdr(&di); + print_pkt_type(&di); + } +} + +static void cmd_lp(int ctl, int hdev, char *opt) +{ + struct hci_dev_req dr; + + dr.dev_id = hdev; + + if (hci_strtolp(opt, &dr.dev_opt)) { + if (ioctl(ctl, HCISETLINKPOL, (unsigned long) &dr) < 0) { + fprintf(stderr, "Can't set link policy on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + print_dev_hdr(&di); + print_link_policy(&di); + } +} + +static void cmd_lm(int ctl, int hdev, char *opt) +{ + struct hci_dev_req dr; + + dr.dev_id = hdev; + + if (hci_strtolm(opt, &dr.dev_opt)) { + if (ioctl(ctl, HCISETLINKMODE, (unsigned long) &dr) < 0) { + fprintf(stderr, "Can't set default link mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + print_dev_hdr(&di); + print_link_mode(&di); + } +} + +static void cmd_aclmtu(int ctl, int hdev, char *opt) +{ + struct hci_dev_req dr = { .dev_id = hdev }; + uint16_t mtu, mpkt; + + if (!opt) + return; + + if (sscanf(opt, "%4hu:%4hu", &mtu, &mpkt) != 2) + return; + + dr.dev_opt = htobl(htobs(mpkt) | (htobs(mtu) << 16)); + + if (ioctl(ctl, HCISETACLMTU, (unsigned long) &dr) < 0) { + fprintf(stderr, "Can't set ACL mtu on hci%d: %s(%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +} + +static void cmd_scomtu(int ctl, int hdev, char *opt) +{ + struct hci_dev_req dr = { .dev_id = hdev }; + uint16_t mtu, mpkt; + + if (!opt) + return; + + if (sscanf(opt, "%4hu:%4hu", &mtu, &mpkt) != 2) + return; + + dr.dev_opt = htobl(htobs(mpkt) | (htobs(mtu) << 16)); + + if (ioctl(ctl, HCISETSCOMTU, (unsigned long) &dr) < 0) { + fprintf(stderr, "Can't set SCO mtu on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } +} + +static void cmd_features(int ctl, int hdev, char *opt) +{ + uint8_t features[8], max_page = 0; + char *tmp; + int i, dd; + + if (!(di.features[7] & LMP_EXT_FEAT)) { + print_dev_hdr(&di); + print_dev_features(&di, 1); + return; + } + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (hci_read_local_ext_features(dd, 0, &max_page, features, 1000) < 0) { + fprintf(stderr, "Can't read extended features hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x " + "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", + (max_page > 0) ? " page 0" : "", + features[0], features[1], features[2], features[3], + features[4], features[5], features[6], features[7]); + + tmp = lmp_featurestostr(di.features, "\t\t", 63); + printf("%s\n", tmp); + bt_free(tmp); + + for (i = 1; i <= max_page; i++) { + if (hci_read_local_ext_features(dd, i, NULL, + features, 1000) < 0) + continue; + + printf("\tFeatures page %d: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x " + "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", i, + features[0], features[1], features[2], features[3], + features[4], features[5], features[6], features[7]); + } + + hci_close_dev(dd); +} + +static void cmd_name(int ctl, int hdev, char *opt) +{ + int dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (opt) { + if (hci_write_local_name(dd, opt, 2000) < 0) { + fprintf(stderr, "Can't change local name on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + char name[249]; + int i; + + if (hci_read_local_name(dd, sizeof(name), name, 1000) < 0) { + fprintf(stderr, "Can't read local name on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + for (i = 0; i < 248 && name[i]; i++) { + if ((unsigned char) name[i] < 32 || name[i] == 127) + name[i] = '.'; + } + + name[248] = '\0'; + + print_dev_hdr(&di); + printf("\tName: '%s'\n", name); + } + + hci_close_dev(dd); +} + +/* + * see http://www.bluetooth.org/assigned-numbers/baseband.htm --- all + * strings are reproduced verbatim + */ +static char *get_minor_device_name(int major, int minor) +{ + switch (major) { + case 0: /* misc */ + return ""; + case 1: /* computer */ + switch (minor) { + case 0: + return "Uncategorized"; + case 1: + return "Desktop workstation"; + case 2: + return "Server"; + case 3: + return "Laptop"; + case 4: + return "Handheld"; + case 5: + return "Palm"; + case 6: + return "Wearable"; + } + break; + case 2: /* phone */ + switch (minor) { + case 0: + return "Uncategorized"; + case 1: + return "Cellular"; + case 2: + return "Cordless"; + case 3: + return "Smart phone"; + case 4: + return "Wired modem or voice gateway"; + case 5: + return "Common ISDN Access"; + case 6: + return "Sim Card Reader"; + } + break; + case 3: /* lan access */ + if (minor == 0) + return "Uncategorized"; + switch (minor / 8) { + case 0: + return "Fully available"; + case 1: + return "1-17% utilized"; + case 2: + return "17-33% utilized"; + case 3: + return "33-50% utilized"; + case 4: + return "50-67% utilized"; + case 5: + return "67-83% utilized"; + case 6: + return "83-99% utilized"; + case 7: + return "No service available"; + } + break; + case 4: /* audio/video */ + switch (minor) { + case 0: + return "Uncategorized"; + case 1: + return "Device conforms to the Headset profile"; + case 2: + return "Hands-free"; + /* 3 is reserved */ + case 4: + return "Microphone"; + case 5: + return "Loudspeaker"; + case 6: + return "Headphones"; + case 7: + return "Portable Audio"; + case 8: + return "Car Audio"; + case 9: + return "Set-top box"; + case 10: + return "HiFi Audio Device"; + case 11: + return "VCR"; + case 12: + return "Video Camera"; + case 13: + return "Camcorder"; + case 14: + return "Video Monitor"; + case 15: + return "Video Display and Loudspeaker"; + case 16: + return "Video Conferencing"; + /* 17 is reserved */ + case 18: + return "Gaming/Toy"; + } + break; + case 5: /* peripheral */ { + static char cls_str[48]; + + cls_str[0] = '\0'; + + switch (minor & 48) { + case 16: + strncpy(cls_str, "Keyboard", sizeof(cls_str)); + break; + case 32: + strncpy(cls_str, "Pointing device", sizeof(cls_str)); + break; + case 48: + strncpy(cls_str, "Combo keyboard/pointing device", sizeof(cls_str)); + break; + } + if ((minor & 15) && (strlen(cls_str) > 0)) + strcat(cls_str, "/"); + + switch (minor & 15) { + case 0: + break; + case 1: + strncat(cls_str, "Joystick", sizeof(cls_str) - strlen(cls_str)); + break; + case 2: + strncat(cls_str, "Gamepad", sizeof(cls_str) - strlen(cls_str)); + break; + case 3: + strncat(cls_str, "Remote control", sizeof(cls_str) - strlen(cls_str)); + break; + case 4: + strncat(cls_str, "Sensing device", sizeof(cls_str) - strlen(cls_str)); + break; + case 5: + strncat(cls_str, "Digitizer tablet", sizeof(cls_str) - strlen(cls_str)); + break; + case 6: + strncat(cls_str, "Card reader", sizeof(cls_str) - strlen(cls_str)); + break; + default: + strncat(cls_str, "(reserved)", sizeof(cls_str) - strlen(cls_str)); + break; + } + if (strlen(cls_str) > 0) + return cls_str; + } + case 6: /* imaging */ + if (minor & 4) + return "Display"; + if (minor & 8) + return "Camera"; + if (minor & 16) + return "Scanner"; + if (minor & 32) + return "Printer"; + break; + case 7: /* wearable */ + switch (minor) { + case 1: + return "Wrist Watch"; + case 2: + return "Pager"; + case 3: + return "Jacket"; + case 4: + return "Helmet"; + case 5: + return "Glasses"; + } + break; + case 8: /* toy */ + switch (minor) { + case 1: + return "Robot"; + case 2: + return "Vehicle"; + case 3: + return "Doll / Action Figure"; + case 4: + return "Controller"; + case 5: + return "Game"; + } + break; + case 63: /* uncategorised */ + return ""; + } + return "Unknown (reserved) minor device class"; +} + +static void cmd_class(int ctl, int hdev, char *opt) +{ + static const char *services[] = { "Positioning", + "Networking", + "Rendering", + "Capturing", + "Object Transfer", + "Audio", + "Telephony", + "Information" }; + static const char *major_devices[] = { "Miscellaneous", + "Computer", + "Phone", + "LAN Access", + "Audio/Video", + "Peripheral", + "Imaging", + "Uncategorized" }; + int s = hci_open_dev(hdev); + + if (s < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + if (opt) { + uint32_t cod = strtoul(opt, NULL, 16); + if (hci_write_class_of_dev(s, cod, 2000) < 0) { + fprintf(stderr, "Can't write local class of device on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint8_t cls[3]; + if (hci_read_class_of_dev(s, cls, 1000) < 0) { + fprintf(stderr, "Can't read class of device on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + print_dev_hdr(&di); + printf("\tClass: 0x%02x%02x%02x\n", cls[2], cls[1], cls[0]); + printf("\tService Classes: "); + if (cls[2]) { + unsigned int i; + int first = 1; + for (i = 0; i < (sizeof(services) / sizeof(*services)); i++) + if (cls[2] & (1 << i)) { + if (!first) + printf(", "); + printf("%s", services[i]); + first = 0; + } + } else + printf("Unspecified"); + printf("\n\tDevice Class: "); + if ((cls[1] & 0x1f) >= sizeof(major_devices) / sizeof(*major_devices)) + printf("Invalid Device Class!\n"); + else + printf("%s, %s\n", major_devices[cls[1] & 0x1f], + get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2)); + } +} + +static void cmd_voice(int ctl, int hdev, char *opt) +{ + static char *icf[] = { "Linear", + "u-Law", + "A-Law", + "Reserved" }; + + static char *idf[] = { "1's complement", + "2's complement", + "Sign-Magnitude", + "Reserved" }; + + static char *iss[] = { "8 bit", + "16 bit" }; + + static char *acf[] = { "CVSD", + "u-Law", + "A-Law", + "Reserved" }; + + int s = hci_open_dev(hdev); + + if (s < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + if (opt) { + uint16_t vs = htobs(strtoul(opt, NULL, 16)); + if (hci_write_voice_setting(s, vs, 2000) < 0) { + fprintf(stderr, "Can't write voice setting on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint16_t vs; + uint8_t ic; + if (hci_read_voice_setting(s, &vs, 1000) < 0) { + fprintf(stderr, "Can't read voice setting on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + vs = htobs(vs); + ic = (vs & 0x0300) >> 8; + print_dev_hdr(&di); + printf("\tVoice setting: 0x%04x%s\n", vs, + ((vs & 0x03fc) == 0x0060) ? " (Default Condition)" : ""); + printf("\tInput Coding: %s\n", icf[ic]); + printf("\tInput Data Format: %s\n", idf[(vs & 0xc0) >> 6]); + + if (!ic) { + printf("\tInput Sample Size: %s\n", + iss[(vs & 0x20) >> 5]); + printf("\t# of bits padding at MSB: %d\n", + (vs & 0x1c) >> 2); + } + printf("\tAir Coding Format: %s\n", acf[vs & 0x03]); + } +} + +static void cmd_delkey(int ctl, int hdev, char *opt) +{ + bdaddr_t bdaddr; + uint8_t all; + int dd; + + if (!opt) + return; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (!strcasecmp(opt, "all")) { + bacpy(&bdaddr, BDADDR_ANY); + all = 1; + } else { + str2ba(opt, &bdaddr); + all = 0; + } + + if (hci_delete_stored_link_key(dd, &bdaddr, all, 1000) < 0) { + fprintf(stderr, "Can't delete stored link key on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + hci_close_dev(dd); +} + +static void cmd_oob_data(int ctl, int hdev, char *opt) +{ + uint8_t hash[16], randomizer[16]; + int i, dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (hci_read_local_oob_data(dd, hash, randomizer, 1000) < 0) { + fprintf(stderr, "Can't read local OOB data on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + printf("\tOOB Hash: "); + for (i = 0; i < 16; i++) + printf(" %02x", hash[i]); + printf("\n\tRandomizer:"); + for (i = 0; i < 16; i++) + printf(" %02x", randomizer[i]); + printf("\n"); + + hci_close_dev(dd); +} + +static void cmd_commands(int ctl, int hdev, char *opt) +{ + uint8_t cmds[64]; + char *str; + int i, n, dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (hci_read_local_commands(dd, cmds, 1000) < 0) { + fprintf(stderr, "Can't read support commands on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + for (i = 0; i < 64; i++) { + if (!cmds[i]) + continue; + + printf("%s Octet %-2d = 0x%02x (Bit", + i ? "\t\t ": "\tCommands:", i, cmds[i]); + for (n = 0; n < 8; n++) + if (cmds[i] & (1 << n)) + printf(" %d", n); + printf(")\n"); + } + + str = hci_commandstostr(cmds, "\t", 71); + printf("%s\n", str); + bt_free(str); + + hci_close_dev(dd); +} + +static void cmd_version(int ctl, int hdev, char *opt) +{ + struct hci_version ver; + char *hciver, *lmpver; + int dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (hci_read_local_version(dd, &ver, 1000) < 0) { + fprintf(stderr, "Can't read version info hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + hciver = hci_vertostr(ver.hci_ver); + if (((di.type & 0x30) >> 4) == HCI_BREDR) + lmpver = lmp_vertostr(ver.lmp_ver); + else + lmpver = pal_vertostr(ver.lmp_ver); + + print_dev_hdr(&di); + printf("\tHCI Version: %s (0x%x) Revision: 0x%x\n" + "\t%s Version: %s (0x%x) Subversion: 0x%x\n" + "\tManufacturer: %s (%d)\n", + hciver ? hciver : "n/a", ver.hci_ver, ver.hci_rev, + (((di.type & 0x30) >> 4) == HCI_BREDR) ? "LMP" : "PAL", + lmpver ? lmpver : "n/a", ver.lmp_ver, ver.lmp_subver, + bt_compidtostr(ver.manufacturer), ver.manufacturer); + + if (hciver) + bt_free(hciver); + if (lmpver) + bt_free(lmpver); + + hci_close_dev(dd); +} + +static void cmd_inq_tpl(int ctl, int hdev, char *opt) +{ + int dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (opt) { + int8_t level = atoi(opt); + + if (hci_write_inquiry_transmit_power_level(dd, level, 2000) < 0) { + fprintf(stderr, "Can't set inquiry transmit power level on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + int8_t level; + + if (hci_read_inq_response_tx_power_level(dd, &level, 1000) < 0) { + fprintf(stderr, "Can't read inquiry transmit power level on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + printf("\tInquiry transmit power level: %d\n", level); + } + + hci_close_dev(dd); +} + +static void cmd_inq_mode(int ctl, int hdev, char *opt) +{ + int dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (opt) { + uint8_t mode = atoi(opt); + + if (hci_write_inquiry_mode(dd, mode, 2000) < 0) { + fprintf(stderr, "Can't set inquiry mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint8_t mode; + + if (hci_read_inquiry_mode(dd, &mode, 1000) < 0) { + fprintf(stderr, "Can't read inquiry mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + printf("\tInquiry mode: "); + switch (mode) { + case 0: + printf("Standard Inquiry\n"); + break; + case 1: + printf("Inquiry with RSSI\n"); + break; + case 2: + printf("Inquiry with RSSI or Extended Inquiry\n"); + break; + default: + printf("Unknown (0x%02x)\n", mode); + break; + } + } + + hci_close_dev(dd); +} + +static void cmd_inq_data(int ctl, int hdev, char *opt) +{ + int i, dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (opt) { + uint8_t fec = 0, data[HCI_MAX_EIR_LENGTH]; + char tmp[3]; + int i, size; + + memset(data, 0, sizeof(data)); + + memset(tmp, 0, sizeof(tmp)); + size = (strlen(opt) + 1) / 2; + if (size > HCI_MAX_EIR_LENGTH) + size = HCI_MAX_EIR_LENGTH; + + for (i = 0; i < size; i++) { + memcpy(tmp, opt + (i * 2), 2); + data[i] = strtol(tmp, NULL, 16); + } + + if (hci_write_ext_inquiry_response(dd, fec, data, 2000) < 0) { + fprintf(stderr, "Can't set extended inquiry response on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint8_t fec, data[HCI_MAX_EIR_LENGTH], len, type, *ptr; + char *str; + + if (hci_read_ext_inquiry_response(dd, &fec, data, 1000) < 0) { + fprintf(stderr, "Can't read extended inquiry response on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + printf("\tFEC %s\n\t\t", fec ? "enabled" : "disabled"); + for (i = 0; i < HCI_MAX_EIR_LENGTH; i++) + printf("%02x%s%s", data[i], (i + 1) % 8 ? "" : " ", + (i + 1) % 16 ? " " : (i < 239 ? "\n\t\t" : "\n")); + + ptr = data; + while (*ptr) { + len = *ptr++; + type = *ptr++; + switch (type) { + case 0x01: + printf("\tFlags:"); + for (i = 0; i < len - 1; i++) + printf(" 0x%2.2x", *((uint8_t *) (ptr + i))); + printf("\n"); + break; + case 0x02: + case 0x03: + printf("\t%s service classes:", + type == 0x02 ? "Shortened" : "Complete"); + for (i = 0; i < (len - 1) / 2; i++) { + uint16_t val = bt_get_le16((ptr + (i * 2))); + printf(" 0x%4.4x", val); + } + printf("\n"); + break; + case 0x08: + case 0x09: + str = malloc(len); + if (str) { + snprintf(str, len, "%s", ptr); + for (i = 0; i < len - 1; i++) { + if ((unsigned char) str[i] < 32 || str[i] == 127) + str[i] = '.'; + } + printf("\t%s local name: \'%s\'\n", + type == 0x08 ? "Shortened" : "Complete", str); + free(str); + } + break; + case 0x0a: + printf("\tTX power level: %d\n", *((int8_t *) ptr)); + break; + case 0x10: + printf("\tDevice ID with %d bytes data\n", + len - 1); + break; + default: + printf("\tUnknown type 0x%02x with %d bytes data\n", + type, len - 1); + break; + } + + ptr += (len - 1); + } + + printf("\n"); + } + + hci_close_dev(dd); +} + +static void cmd_inq_type(int ctl, int hdev, char *opt) +{ + int dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (opt) { + uint8_t type = atoi(opt); + + if (hci_write_inquiry_scan_type(dd, type, 2000) < 0) { + fprintf(stderr, "Can't set inquiry scan type on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint8_t type; + + if (hci_read_inquiry_scan_type(dd, &type, 1000) < 0) { + fprintf(stderr, "Can't read inquiry scan type on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + printf("\tInquiry scan type: %s\n", + type == 1 ? "Interlaced Inquiry Scan" : "Standard Inquiry Scan"); + } + + hci_close_dev(dd); +} + +static void cmd_inq_parms(int ctl, int hdev, char *opt) +{ + struct hci_request rq; + int s; + + if ((s = hci_open_dev(hdev)) < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + memset(&rq, 0, sizeof(rq)); + + if (opt) { + unsigned int window, interval; + write_inq_activity_cp cp; + + if (sscanf(opt,"%4u:%4u", &window, &interval) != 2) { + printf("Invalid argument format\n"); + exit(1); + } + + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_WRITE_INQ_ACTIVITY; + rq.cparam = &cp; + rq.clen = WRITE_INQ_ACTIVITY_CP_SIZE; + + cp.window = htobs((uint16_t) window); + cp.interval = htobs((uint16_t) interval); + + if (window < 0x12 || window > 0x1000) + printf("Warning: inquiry window out of range!\n"); + + if (interval < 0x12 || interval > 0x1000) + printf("Warning: inquiry interval out of range!\n"); + + if (hci_send_req(s, &rq, 2000) < 0) { + fprintf(stderr, "Can't set inquiry parameters name on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint16_t window, interval; + read_inq_activity_rp rp; + + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_READ_INQ_ACTIVITY; + rq.rparam = &rp; + rq.rlen = READ_INQ_ACTIVITY_RP_SIZE; + + if (hci_send_req(s, &rq, 1000) < 0) { + fprintf(stderr, "Can't read inquiry parameters on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + if (rp.status) { + printf("Read inquiry parameters on hci%d returned status %d\n", + hdev, rp.status); + exit(1); + } + print_dev_hdr(&di); + + window = btohs(rp.window); + interval = btohs(rp.interval); + printf("\tInquiry interval: %u slots (%.2f ms), window: %u slots (%.2f ms)\n", + interval, (float)interval * 0.625, window, (float)window * 0.625); + } +} + +static void cmd_page_parms(int ctl, int hdev, char *opt) +{ + struct hci_request rq; + int s; + + if ((s = hci_open_dev(hdev)) < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + memset(&rq, 0, sizeof(rq)); + + if (opt) { + unsigned int window, interval; + write_page_activity_cp cp; + + if (sscanf(opt,"%4u:%4u", &window, &interval) != 2) { + printf("Invalid argument format\n"); + exit(1); + } + + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_WRITE_PAGE_ACTIVITY; + rq.cparam = &cp; + rq.clen = WRITE_PAGE_ACTIVITY_CP_SIZE; + + cp.window = htobs((uint16_t) window); + cp.interval = htobs((uint16_t) interval); + + if (window < 0x12 || window > 0x1000) + printf("Warning: page window out of range!\n"); + + if (interval < 0x12 || interval > 0x1000) + printf("Warning: page interval out of range!\n"); + + if (hci_send_req(s, &rq, 2000) < 0) { + fprintf(stderr, "Can't set page parameters name on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint16_t window, interval; + read_page_activity_rp rp; + + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_READ_PAGE_ACTIVITY; + rq.rparam = &rp; + rq.rlen = READ_PAGE_ACTIVITY_RP_SIZE; + + if (hci_send_req(s, &rq, 1000) < 0) { + fprintf(stderr, "Can't read page parameters on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + if (rp.status) { + printf("Read page parameters on hci%d returned status %d\n", + hdev, rp.status); + exit(1); + } + print_dev_hdr(&di); + + window = btohs(rp.window); + interval = btohs(rp.interval); + printf("\tPage interval: %u slots (%.2f ms), " + "window: %u slots (%.2f ms)\n", + interval, (float)interval * 0.625, + window, (float)window * 0.625); + } +} + +static void cmd_page_to(int ctl, int hdev, char *opt) +{ + struct hci_request rq; + int s; + + if ((s = hci_open_dev(hdev)) < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + memset(&rq, 0, sizeof(rq)); + + if (opt) { + unsigned int timeout; + write_page_timeout_cp cp; + + if (sscanf(opt,"%5u", &timeout) != 1) { + printf("Invalid argument format\n"); + exit(1); + } + + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_WRITE_PAGE_TIMEOUT; + rq.cparam = &cp; + rq.clen = WRITE_PAGE_TIMEOUT_CP_SIZE; + + cp.timeout = htobs((uint16_t) timeout); + + if (timeout < 0x01 || timeout > 0xFFFF) + printf("Warning: page timeout out of range!\n"); + + if (hci_send_req(s, &rq, 2000) < 0) { + fprintf(stderr, "Can't set page timeout on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint16_t timeout; + read_page_timeout_rp rp; + + rq.ogf = OGF_HOST_CTL; + rq.ocf = OCF_READ_PAGE_TIMEOUT; + rq.rparam = &rp; + rq.rlen = READ_PAGE_TIMEOUT_RP_SIZE; + + if (hci_send_req(s, &rq, 1000) < 0) { + fprintf(stderr, "Can't read page timeout on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + if (rp.status) { + printf("Read page timeout on hci%d returned status %d\n", + hdev, rp.status); + exit(1); + } + print_dev_hdr(&di); + + timeout = btohs(rp.timeout); + printf("\tPage timeout: %u slots (%.2f ms)\n", + timeout, (float)timeout * 0.625); + } +} + +static void cmd_afh_mode(int ctl, int hdev, char *opt) +{ + int dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (opt) { + uint8_t mode = atoi(opt); + + if (hci_write_afh_mode(dd, mode, 2000) < 0) { + fprintf(stderr, "Can't set AFH mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint8_t mode; + + if (hci_read_afh_mode(dd, &mode, 1000) < 0) { + fprintf(stderr, "Can't read AFH mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + printf("\tAFH mode: %s\n", mode == 1 ? "Enabled" : "Disabled"); + } +} + +static void cmd_ssp_mode(int ctl, int hdev, char *opt) +{ + int dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (opt) { + uint8_t mode = atoi(opt); + + if (hci_write_simple_pairing_mode(dd, mode, 2000) < 0) { + fprintf(stderr, "Can't set Simple Pairing mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + } else { + uint8_t mode; + + if (hci_read_simple_pairing_mode(dd, &mode, 1000) < 0) { + fprintf(stderr, "Can't read Simple Pairing mode on hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + print_dev_hdr(&di); + printf("\tSimple Pairing mode: %s\n", + mode == 1 ? "Enabled" : "Disabled"); + } +} + +static void print_rev_ericsson(int dd) +{ + struct hci_request rq; + unsigned char buf[102]; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x000f; + rq.cparam = NULL; + rq.clen = 0; + rq.rparam = &buf; + rq.rlen = sizeof(buf); + + if (hci_send_req(dd, &rq, 1000) < 0) { + printf("\nCan't read revision info: %s (%d)\n", + strerror(errno), errno); + return; + } + + printf("\t%s\n", buf + 1); +} + +static void print_rev_csr(int dd, uint16_t rev) +{ + uint16_t buildid, chipver, chiprev, maxkeylen, mapsco; + + if (csr_read_varid_uint16(dd, 0, CSR_VARID_BUILDID, &buildid) < 0) { + printf("\t%s\n", csr_buildidtostr(rev)); + return; + } + + printf("\t%s\n", csr_buildidtostr(buildid)); + + if (!csr_read_varid_uint16(dd, 1, CSR_VARID_CHIPVER, &chipver)) { + if (csr_read_varid_uint16(dd, 2, CSR_VARID_CHIPREV, &chiprev) < 0) + chiprev = 0; + printf("\tChip version: %s\n", csr_chipvertostr(chipver, chiprev)); + } + + if (!csr_read_varid_uint16(dd, 3, CSR_VARID_MAX_CRYPT_KEY_LENGTH, &maxkeylen)) + printf("\tMax key size: %d bit\n", maxkeylen * 8); + + if (!csr_read_pskey_uint16(dd, 4, CSR_PSKEY_HOSTIO_MAP_SCO_PCM, 0x0000, &mapsco)) + printf("\tSCO mapping: %s\n", mapsco ? "PCM" : "HCI"); +} + +static void print_rev_digianswer(int dd) +{ + struct hci_request rq; + unsigned char req[] = { 0x07 }; + unsigned char buf[102]; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_VENDOR_CMD; + rq.ocf = 0x000e; + rq.cparam = req; + rq.clen = sizeof(req); + rq.rparam = &buf; + rq.rlen = sizeof(buf); + + if (hci_send_req(dd, &rq, 1000) < 0) { + printf("\nCan't read revision info: %s (%d)\n", + strerror(errno), errno); + return; + } + + printf("\t%s\n", buf + 1); +} + +static void print_rev_broadcom(uint16_t hci_rev, uint16_t lmp_subver) +{ + printf("\tFirmware %d.%d / %d\n", + hci_rev & 0xff, lmp_subver >> 8, lmp_subver & 0xff); +} + +static void print_rev_avm(uint16_t hci_rev, uint16_t lmp_subver) +{ + if (lmp_subver == 0x01) + printf("\tFirmware 03.%d.%d\n", hci_rev >> 8, hci_rev & 0xff); + else + printf("\tUnknown type\n"); +} + +static void cmd_revision(int ctl, int hdev, char *opt) +{ + struct hci_version ver; + int dd; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + return; + } + + if (hci_read_local_version(dd, &ver, 1000) < 0) { + fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + return; + } + + print_dev_hdr(&di); + switch (ver.manufacturer) { + case 0: + case 37: + case 48: + print_rev_ericsson(dd); + break; + case 10: + print_rev_csr(dd, ver.hci_rev); + break; + case 12: + print_rev_digianswer(dd); + break; + case 15: + print_rev_broadcom(ver.hci_rev, ver.lmp_subver); + break; + case 31: + print_rev_avm(ver.hci_rev, ver.lmp_subver); + break; + default: + printf("\tUnsupported manufacturer\n"); + break; + } + return; +} + +static void cmd_block(int ctl, int hdev, char *opt) +{ + bdaddr_t bdaddr; + int dd; + + if (!opt) + return; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + str2ba(opt, &bdaddr); + + if (ioctl(dd, HCIBLOCKADDR, &bdaddr) < 0) { + perror("ioctl(HCIBLOCKADDR)"); + exit(1); + } + + hci_close_dev(dd); +} + +static void cmd_unblock(int ctl, int hdev, char *opt) +{ + bdaddr_t bdaddr; + int dd; + + if (!opt) + return; + + dd = hci_open_dev(hdev); + if (dd < 0) { + fprintf(stderr, "Can't open device hci%d: %s (%d)\n", + hdev, strerror(errno), errno); + exit(1); + } + + if (!strcasecmp(opt, "all")) + bacpy(&bdaddr, BDADDR_ANY); + else + str2ba(opt, &bdaddr); + + if (ioctl(dd, HCIUNBLOCKADDR, &bdaddr) < 0) { + perror("ioctl(HCIUNBLOCKADDR)"); + exit(1); + } + + hci_close_dev(dd); +} + +static void print_dev_hdr(struct hci_dev_info *di) +{ + static int hdr = -1; + char addr[18]; + + if (hdr == di->dev_id) + return; + hdr = di->dev_id; + + ba2str(&di->bdaddr, addr); + + printf("%s:\tType: %s Bus: %s\n", di->name, + hci_typetostr((di->type & 0x30) >> 4), + hci_bustostr(di->type & 0x0f)); + printf("\tBD Address: %s ACL MTU: %d:%d SCO MTU: %d:%d\n", + addr, di->acl_mtu, di->acl_pkts, + di->sco_mtu, di->sco_pkts); +} + +static void print_dev_info(int ctl, struct hci_dev_info *di) +{ + struct hci_dev_stats *st = &di->stat; + char *str; + + print_dev_hdr(di); + + str = hci_dflagstostr(di->flags); + printf("\t%s\n", str); + bt_free(str); + + printf("\tRX bytes:%d acl:%d sco:%d events:%d errors:%d\n", + st->byte_rx, st->acl_rx, st->sco_rx, st->evt_rx, st->err_rx); + + printf("\tTX bytes:%d acl:%d sco:%d commands:%d errors:%d\n", + st->byte_tx, st->acl_tx, st->sco_tx, st->cmd_tx, st->err_tx); + + if (all && !hci_test_bit(HCI_RAW, &di->flags)) { + print_dev_features(di, 0); + + if (((di->type & 0x30) >> 4) == HCI_BREDR) { + print_pkt_type(di); + print_link_policy(di); + print_link_mode(di); + + if (hci_test_bit(HCI_UP, &di->flags)) { + cmd_name(ctl, di->dev_id, NULL); + cmd_class(ctl, di->dev_id, NULL); + } + } + + if (hci_test_bit(HCI_UP, &di->flags)) + cmd_version(ctl, di->dev_id, NULL); + } + + printf("\n"); +} + +static struct { + char *cmd; + void (*func)(int ctl, int hdev, char *opt); + char *opt; + char *doc; +} command[] = { + { "up", cmd_up, 0, "Open and initialize HCI device" }, + { "down", cmd_down, 0, "Close HCI device" }, + { "reset", cmd_reset, 0, "Reset HCI device" }, + { "rstat", cmd_rstat, 0, "Reset statistic counters" }, + { "auth", cmd_auth, 0, "Enable Authentication" }, + { "noauth", cmd_auth, 0, "Disable Authentication" }, + { "encrypt", cmd_encrypt, 0, "Enable Encryption" }, + { "noencrypt", cmd_encrypt, 0, "Disable Encryption" }, + { "piscan", cmd_scan, 0, "Enable Page and Inquiry scan" }, + { "noscan", cmd_scan, 0, "Disable scan" }, + { "iscan", cmd_scan, 0, "Enable Inquiry scan" }, + { "pscan", cmd_scan, 0, "Enable Page scan" }, + { "ptype", cmd_ptype, "[type]", "Get/Set default packet type" }, + { "lm", cmd_lm, "[mode]", "Get/Set default link mode" }, + { "lp", cmd_lp, "[policy]", "Get/Set default link policy" }, + { "name", cmd_name, "[name]", "Get/Set local name" }, + { "class", cmd_class, "[class]", "Get/Set class of device" }, + { "voice", cmd_voice, "[voice]", "Get/Set voice setting" }, + { "iac", cmd_iac, "[iac]", "Get/Set inquiry access code" }, + { "inqtpl", cmd_inq_tpl, "[level]", "Get/Set inquiry transmit power level" }, + { "inqmode", cmd_inq_mode, "[mode]", "Get/Set inquiry mode" }, + { "inqdata", cmd_inq_data, "[data]", "Get/Set inquiry data" }, + { "inqtype", cmd_inq_type, "[type]", "Get/Set inquiry scan type" }, + { "inqparms", cmd_inq_parms, "[win:int]", "Get/Set inquiry scan window and interval" }, + { "pageparms", cmd_page_parms, "[win:int]", "Get/Set page scan window and interval" }, + { "pageto", cmd_page_to, "[to]", "Get/Set page timeout" }, + { "afhmode", cmd_afh_mode, "[mode]", "Get/Set AFH mode" }, + { "sspmode", cmd_ssp_mode, "[mode]", "Get/Set Simple Pairing Mode" }, + { "aclmtu", cmd_aclmtu, "", "Set ACL MTU and number of packets" }, + { "scomtu", cmd_scomtu, "", "Set SCO MTU and number of packets" }, + { "delkey", cmd_delkey, "", "Delete link key from the device" }, + { "oobdata", cmd_oob_data, 0, "Get local OOB data" }, + { "commands", cmd_commands, 0, "Display supported commands" }, + { "features", cmd_features, 0, "Display device features" }, + { "version", cmd_version, 0, "Display version information" }, + { "revision", cmd_revision, 0, "Display revision information" }, + { "block", cmd_block, "", "Add a device to the blacklist" }, + { "unblock", cmd_unblock, "", "Remove a device from the blacklist" }, + { "lerandaddr", cmd_le_addr, "", "Set LE Random Address" }, + { "leadv", cmd_le_adv, "[type]", "Enable LE advertising" + "\n\t\t\t0 - Connectable undirected advertising (default)" + "\n\t\t\t3 - Non connectable undirected advertising"}, + { "noleadv", cmd_no_le_adv, 0, "Disable LE advertising" }, + { "lestates", cmd_le_states, 0, "Display the supported LE states" }, + { NULL, NULL, 0 } +}; + +static void usage(void) +{ + int i; + + printf("hciconfig - HCI device configuration utility\n"); + printf("Usage:\n" + "\thciconfig\n" + "\thciconfig [-a] hciX [command ...]\n"); + printf("Commands:\n"); + for (i = 0; command[i].cmd; i++) + printf("\t%-10s %-8s\t%s\n", command[i].cmd, + command[i].opt ? command[i].opt : " ", + command[i].doc); +} + +static struct option main_options[] = { + { "help", 0, 0, 'h' }, + { "all", 0, 0, 'a' }, + { 0, 0, 0, 0 } +}; + +int main(int argc, char *argv[]) +{ + int opt, ctl, i, cmd = 0; + + while ((opt = getopt_long(argc, argv, "ah", main_options, NULL)) != -1) { + switch (opt) { + case 'a': + all = 1; + break; + + case 'h': + default: + usage(); + exit(0); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + /* Open HCI socket */ + if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) { + perror("Can't open HCI socket."); + exit(1); + } + + if (argc < 1) { + print_dev_list(ctl, 0); + exit(0); + } + + di.dev_id = atoi(argv[0] + 3); + argc--; argv++; + + if (ioctl(ctl, HCIGETDEVINFO, (void *) &di)) { + perror("Can't get device info"); + exit(1); + } + + if (hci_test_bit(HCI_RAW, &di.flags) && + !bacmp(&di.bdaddr, BDADDR_ANY)) { + int dd = hci_open_dev(di.dev_id); + hci_read_bd_addr(dd, &di.bdaddr, 1000); + hci_close_dev(dd); + } + + while (argc > 0) { + for (i = 0; command[i].cmd; i++) { + if (strncmp(command[i].cmd, + *argv, strlen(command[i].cmd))) + continue; + + if (command[i].opt) { + argc--; argv++; + } + + command[i].func(ctl, di.dev_id, *argv); + cmd = 1; + break; + } + + if (command[i].cmd == 0) + fprintf(stderr, "Warning: unknown command - \"%s\"\n", + *argv); + + argc--; argv++; + } + + if (!cmd) + print_dev_info(ctl, &di); + + close(ctl); + return 0; +} diff --git a/external/cache/sources/hcitools/hcitool.c b/external/cache/sources/hcitools/hcitool.c new file mode 100644 index 000000000000..aa58efc15956 --- /dev/null +++ b/external/cache/sources/hcitools/hcitool.c @@ -0,0 +1,3122 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2002-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include + +#include +#include +#include + +/* Unofficial value, might still change */ +#define LE_LINK 0x03 + +#define FLAGS_AD_TYPE 0x01 +#define FLAGS_LIMITED_MODE_BIT 0x01 +#define FLAGS_GENERAL_MODE_BIT 0x02 + +#define EIR_FLAGS 0x01 /* flags */ +#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ +#define EIR_NAME_SHORT 0x08 /* shortened local name */ +#define EIR_NAME_COMPLETE 0x09 /* complete local name */ +#define EIR_TX_POWER 0x0A /* transmit power level */ +#define EIR_DEVICE_ID 0x10 /* device ID */ + +#define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, NULL)) != -1) + +static volatile int signal_received = 0; + +static void usage(void); + +static char *batocomp(const bdaddr_t *ba) +{ + return NULL; +} + +static int dev_info(int s, int dev_id, long arg) +{ + struct hci_dev_info di = { .dev_id = dev_id }; + char addr[18]; + + if (ioctl(s, HCIGETDEVINFO, (void *) &di)) + return 0; + + ba2str(&di.bdaddr, addr); + printf("\t%s\t%s\n", di.name, addr); + return 0; +} + +static void helper_arg(int min_num_arg, int max_num_arg, int *argc, + char ***argv, const char *usage) +{ + *argc -= optind; + /* too many arguments, but when "max_num_arg < min_num_arg" then no + limiting (prefer "max_num_arg=-1" to gen infinity) + */ + if ( (*argc > max_num_arg) && (max_num_arg >= min_num_arg ) ) { + fprintf(stderr, "%s: too many arguments (maximal: %i)\n", + *argv[0], max_num_arg); + printf("%s", usage); + exit(1); + } + + /* print usage */ + if (*argc < min_num_arg) { + fprintf(stderr, "%s: too few arguments (minimal: %i)\n", + *argv[0], min_num_arg); + printf("%s", usage); + exit(0); + } + + *argv += optind; +} + +static char *type2str(uint8_t type) +{ + switch (type) { + case SCO_LINK: + return "SCO"; + case ACL_LINK: + return "ACL"; + case ESCO_LINK: + return "eSCO"; + case LE_LINK: + return "LE"; + default: + return "Unknown"; + } +} + +static int conn_list(int s, int dev_id, long arg) +{ + struct hci_conn_list_req *cl; + struct hci_conn_info *ci; + int id = arg; + int i; + + if (id != -1 && dev_id != id) + return 0; + + if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) { + perror("Can't allocate memory"); + exit(1); + } + cl->dev_id = dev_id; + cl->conn_num = 10; + ci = cl->conn_info; + + if (ioctl(s, HCIGETCONNLIST, (void *) cl)) { + perror("Can't get connection list"); + exit(1); + } + + for (i = 0; i < cl->conn_num; i++, ci++) { + char addr[18]; + char *str; + ba2str(&ci->bdaddr, addr); + str = hci_lmtostr(ci->link_mode); + printf("\t%s %s %s handle %d state %d lm %s\n", + ci->out ? "<" : ">", type2str(ci->type), + addr, ci->handle, ci->state, str); + bt_free(str); + } + + free(cl); + return 0; +} + +static int find_conn(int s, int dev_id, long arg) +{ + struct hci_conn_list_req *cl; + struct hci_conn_info *ci; + int i; + + if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl)))) { + perror("Can't allocate memory"); + exit(1); + } + cl->dev_id = dev_id; + cl->conn_num = 10; + ci = cl->conn_info; + + if (ioctl(s, HCIGETCONNLIST, (void *) cl)) { + perror("Can't get connection list"); + exit(1); + } + + for (i = 0; i < cl->conn_num; i++, ci++) + if (!bacmp((bdaddr_t *) arg, &ci->bdaddr)) { + free(cl); + return 1; + } + + free(cl); + return 0; +} + +static void hex_dump(char *pref, int width, unsigned char *buf, int len) +{ + register int i,n; + + for (i = 0, n = 1; i < len; i++, n++) { + if (n == 1) + printf("%s", pref); + printf("%2.2X ", buf[i]); + if (n == width) { + printf("\n"); + n = 0; + } + } + if (i && n!=1) + printf("\n"); +} + +static char *get_minor_device_name(int major, int minor) +{ + switch (major) { + case 0: /* misc */ + return ""; + case 1: /* computer */ + switch (minor) { + case 0: + return "Uncategorized"; + case 1: + return "Desktop workstation"; + case 2: + return "Server"; + case 3: + return "Laptop"; + case 4: + return "Handheld"; + case 5: + return "Palm"; + case 6: + return "Wearable"; + } + break; + case 2: /* phone */ + switch (minor) { + case 0: + return "Uncategorized"; + case 1: + return "Cellular"; + case 2: + return "Cordless"; + case 3: + return "Smart phone"; + case 4: + return "Wired modem or voice gateway"; + case 5: + return "Common ISDN Access"; + case 6: + return "Sim Card Reader"; + } + break; + case 3: /* lan access */ + if (minor == 0) + return "Uncategorized"; + switch (minor / 8) { + case 0: + return "Fully available"; + case 1: + return "1-17% utilized"; + case 2: + return "17-33% utilized"; + case 3: + return "33-50% utilized"; + case 4: + return "50-67% utilized"; + case 5: + return "67-83% utilized"; + case 6: + return "83-99% utilized"; + case 7: + return "No service available"; + } + break; + case 4: /* audio/video */ + switch (minor) { + case 0: + return "Uncategorized"; + case 1: + return "Device conforms to the Headset profile"; + case 2: + return "Hands-free"; + /* 3 is reserved */ + case 4: + return "Microphone"; + case 5: + return "Loudspeaker"; + case 6: + return "Headphones"; + case 7: + return "Portable Audio"; + case 8: + return "Car Audio"; + case 9: + return "Set-top box"; + case 10: + return "HiFi Audio Device"; + case 11: + return "VCR"; + case 12: + return "Video Camera"; + case 13: + return "Camcorder"; + case 14: + return "Video Monitor"; + case 15: + return "Video Display and Loudspeaker"; + case 16: + return "Video Conferencing"; + /* 17 is reserved */ + case 18: + return "Gaming/Toy"; + } + break; + case 5: /* peripheral */ { + static char cls_str[48]; cls_str[0] = 0; + + switch (minor & 48) { + case 16: + strncpy(cls_str, "Keyboard", sizeof(cls_str)); + break; + case 32: + strncpy(cls_str, "Pointing device", sizeof(cls_str)); + break; + case 48: + strncpy(cls_str, "Combo keyboard/pointing device", sizeof(cls_str)); + break; + } + if ((minor & 15) && (strlen(cls_str) > 0)) + strcat(cls_str, "/"); + + switch (minor & 15) { + case 0: + break; + case 1: + strncat(cls_str, "Joystick", sizeof(cls_str) - strlen(cls_str)); + break; + case 2: + strncat(cls_str, "Gamepad", sizeof(cls_str) - strlen(cls_str)); + break; + case 3: + strncat(cls_str, "Remote control", sizeof(cls_str) - strlen(cls_str)); + break; + case 4: + strncat(cls_str, "Sensing device", sizeof(cls_str) - strlen(cls_str)); + break; + case 5: + strncat(cls_str, "Digitizer tablet", sizeof(cls_str) - strlen(cls_str)); + break; + case 6: + strncat(cls_str, "Card reader", sizeof(cls_str) - strlen(cls_str)); + break; + default: + strncat(cls_str, "(reserved)", sizeof(cls_str) - strlen(cls_str)); + break; + } + if (strlen(cls_str) > 0) + return cls_str; + } + case 6: /* imaging */ + if (minor & 4) + return "Display"; + if (minor & 8) + return "Camera"; + if (minor & 16) + return "Scanner"; + if (minor & 32) + return "Printer"; + break; + case 7: /* wearable */ + switch (minor) { + case 1: + return "Wrist Watch"; + case 2: + return "Pager"; + case 3: + return "Jacket"; + case 4: + return "Helmet"; + case 5: + return "Glasses"; + } + break; + case 8: /* toy */ + switch (minor) { + case 1: + return "Robot"; + case 2: + return "Vehicle"; + case 3: + return "Doll / Action Figure"; + case 4: + return "Controller"; + case 5: + return "Game"; + } + break; + case 63: /* uncategorised */ + return ""; + } + return "Unknown (reserved) minor device class"; +} + +static char *major_classes[] = { + "Miscellaneous", "Computer", "Phone", "LAN Access", + "Audio/Video", "Peripheral", "Imaging", "Uncategorized" +}; + +static char *get_device_name(const bdaddr_t *local, const bdaddr_t *peer) +{ +#if 0 + char filename[PATH_MAX + 1]; + char local_addr[18], peer_addr[18]; + GKeyFile *key_file; + char *str = NULL; + int len; + + ba2str(local, local_addr); + ba2str(peer, peer_addr); + + snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local_addr, + peer_addr); + filename[PATH_MAX] = '\0'; + key_file = g_key_file_new(); + + if (g_key_file_load_from_file(key_file, filename, 0, NULL)) { + str = g_key_file_get_string(key_file, "General", "Name", NULL); + if (str) { + len = strlen(str); + if (len > HCI_MAX_NAME_LENGTH) + str[HCI_MAX_NAME_LENGTH] = '\0'; + } + } + + g_key_file_free(key_file); + + return str; +#endif + return NULL; +} + +/* Display local devices */ + +static struct option dev_options[] = { + { "help", 0, 0, 'h' }, + {0, 0, 0, 0 } +}; + +static const char *dev_help = + "Usage:\n" + "\tdev\n"; + +static void cmd_dev(int dev_id, int argc, char **argv) +{ + int opt; + + for_each_opt(opt, dev_options, NULL) { + switch (opt) { + default: + printf("%s", dev_help); + return; + } + } + helper_arg(0, 0, &argc, &argv, dev_help); + + printf("Devices:\n"); + + hci_for_each_dev(HCI_UP, dev_info, 0); +} + +/* Inquiry */ + +static struct option inq_options[] = { + { "help", 0, 0, 'h' }, + { "length", 1, 0, 'l' }, + { "numrsp", 1, 0, 'n' }, + { "iac", 1, 0, 'i' }, + { "flush", 0, 0, 'f' }, + { 0, 0, 0, 0 } +}; + +static const char *inq_help = + "Usage:\n" + "\tinq [--length=N] maximum inquiry duration in 1.28 s units\n" + "\t [--numrsp=N] specify maximum number of inquiry responses\n" + "\t [--iac=lap] specify the inquiry access code\n" + "\t [--flush] flush the inquiry cache\n"; + +static void cmd_inq(int dev_id, int argc, char **argv) +{ + inquiry_info *info = NULL; + uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; + int num_rsp, length, flags; + char addr[18]; + int i, l, opt; + + length = 8; /* ~10 seconds */ + num_rsp = 0; + flags = 0; + + for_each_opt(opt, inq_options, NULL) { + switch (opt) { + case 'l': + length = atoi(optarg); + break; + + case 'n': + num_rsp = atoi(optarg); + break; + + case 'i': + l = strtoul(optarg, 0, 16); + if (!strcasecmp(optarg, "giac")) { + l = 0x9e8b33; + } else if (!strcasecmp(optarg, "liac")) { + l = 0x9e8b00; + } if (l < 0x9e8b00 || l > 0x9e8b3f) { + printf("Invalid access code 0x%x\n", l); + exit(1); + } + lap[0] = (l & 0xff); + lap[1] = (l >> 8) & 0xff; + lap[2] = (l >> 16) & 0xff; + break; + + case 'f': + flags |= IREQ_CACHE_FLUSH; + break; + + default: + printf("%s", inq_help); + return; + } + } + helper_arg(0, 0, &argc, &argv, inq_help); + + printf("Inquiring ...\n"); + + num_rsp = hci_inquiry(dev_id, length, num_rsp, lap, &info, flags); + if (num_rsp < 0) { + perror("Inquiry failed."); + exit(1); + } + + for (i = 0; i < num_rsp; i++) { + ba2str(&(info+i)->bdaddr, addr); + printf("\t%s\tclock offset: 0x%4.4x\tclass: 0x%2.2x%2.2x%2.2x\n", + addr, btohs((info+i)->clock_offset), + (info+i)->dev_class[2], + (info+i)->dev_class[1], + (info+i)->dev_class[0]); + } + + bt_free(info); +} + +/* Device scanning */ + +static struct option scan_options[] = { + { "help", 0, 0, 'h' }, + { "length", 1, 0, 'l' }, + { "numrsp", 1, 0, 'n' }, + { "iac", 1, 0, 'i' }, + { "flush", 0, 0, 'f' }, + { "refresh", 0, 0, 'r' }, + { "class", 0, 0, 'C' }, + { "info", 0, 0, 'I' }, + { "oui", 0, 0, 'O' }, + { "all", 0, 0, 'A' }, + { "ext", 0, 0, 'A' }, + { 0, 0, 0, 0 } +}; + +static const char *scan_help = + "Usage:\n" + "\tscan [--length=N] [--numrsp=N] [--iac=lap] [--flush] [--class] [--info] [--oui] [--refresh]\n"; + +static void cmd_scan(int dev_id, int argc, char **argv) +{ + inquiry_info *info = NULL; + uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; + int num_rsp, length, flags; + uint8_t cls[3], features[8]; + char addr[18], name[249], *comp, *tmp; + struct hci_version version; + struct hci_dev_info di; + struct hci_conn_info_req *cr; + int refresh = 0, extcls = 0, extinf = 0, extoui = 0; + int i, n, l, opt, dd, cc, nc; + + length = 8; /* ~10 seconds */ + num_rsp = 0; + flags = 0; + + for_each_opt(opt, scan_options, NULL) { + switch (opt) { + case 'l': + length = atoi(optarg); + break; + + case 'n': + num_rsp = atoi(optarg); + break; + + case 'i': + l = strtoul(optarg, 0, 16); + if (!strcasecmp(optarg, "giac")) { + l = 0x9e8b33; + } else if (!strcasecmp(optarg, "liac")) { + l = 0x9e8b00; + } else if (l < 0x9e8b00 || l > 0x9e8b3f) { + printf("Invalid access code 0x%x\n", l); + exit(1); + } + lap[0] = (l & 0xff); + lap[1] = (l >> 8) & 0xff; + lap[2] = (l >> 16) & 0xff; + break; + + case 'f': + flags |= IREQ_CACHE_FLUSH; + break; + + case 'r': + refresh = 1; + break; + + case 'C': + extcls = 1; + break; + + case 'I': + extinf = 1; + break; + + case 'O': + extoui = 1; + break; + + case 'A': + extcls = 1; + extinf = 1; + extoui = 1; + break; + + default: + printf("%s", scan_help); + return; + } + } + helper_arg(0, 0, &argc, &argv, scan_help); + + if (dev_id < 0) { + dev_id = hci_get_route(NULL); + if (dev_id < 0) { + perror("Device is not available"); + exit(1); + } + } + + if (hci_devinfo(dev_id, &di) < 0) { + perror("Can't get device info"); + exit(1); + } + + printf("Scanning ...\n"); + num_rsp = hci_inquiry(dev_id, length, num_rsp, lap, &info, flags); + if (num_rsp < 0) { + perror("Inquiry failed"); + exit(1); + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + free(info); + exit(1); + } + + if (extcls || extinf || extoui) + printf("\n"); + + for (i = 0; i < num_rsp; i++) { + uint16_t handle = 0; + + if (!refresh) { + memset(name, 0, sizeof(name)); + tmp = get_device_name(&di.bdaddr, &(info+i)->bdaddr); + if (tmp) { + strncpy(name, tmp, 249); + free(tmp); + nc = 1; + } else + nc = 0; + } else + nc = 0; + + if (!extcls && !extinf && !extoui) { + ba2str(&(info+i)->bdaddr, addr); + + if (nc) { + printf("\t%s\t%s\n", addr, name); + continue; + } + + if (hci_read_remote_name_with_clock_offset(dd, + &(info+i)->bdaddr, + (info+i)->pscan_rep_mode, + (info+i)->clock_offset | 0x8000, + sizeof(name), name, 100000) < 0) + strcpy(name, "n/a"); + + for (n = 0; n < 248 && name[n]; n++) { + if ((unsigned char) name[i] < 32 || name[i] == 127) + name[i] = '.'; + } + + name[248] = '\0'; + + printf("\t%s\t%s\n", addr, name); + continue; + } + + ba2str(&(info+i)->bdaddr, addr); + printf("BD Address:\t%s [mode %d, clkoffset 0x%4.4x]\n", addr, + (info+i)->pscan_rep_mode, btohs((info+i)->clock_offset)); + + if (extoui) { + comp = batocomp(&(info+i)->bdaddr); + if (comp) { + char oui[9]; + ba2oui(&(info+i)->bdaddr, oui); + printf("OUI company:\t%s (%s)\n", comp, oui); + free(comp); + } + } + + cc = 0; + + if (extinf) { + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (cr) { + bacpy(&cr->bdaddr, &(info+i)->bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + handle = 0; + cc = 1; + } else { + handle = htobs(cr->conn_info->handle); + cc = 0; + } + free(cr); + } + + if (cc) { + if (hci_create_connection(dd, &(info+i)->bdaddr, + htobs(di.pkt_type & ACL_PTYPE_MASK), + (info+i)->clock_offset | 0x8000, + 0x01, &handle, 25000) < 0) { + handle = 0; + cc = 0; + } + } + } + + if (handle > 0 || !nc) { + if (hci_read_remote_name_with_clock_offset(dd, + &(info+i)->bdaddr, + (info+i)->pscan_rep_mode, + (info+i)->clock_offset | 0x8000, + sizeof(name), name, 100000) < 0) { + if (!nc) + strcpy(name, "n/a"); + } else { + for (n = 0; n < 248 && name[n]; n++) { + if ((unsigned char) name[i] < 32 || name[i] == 127) + name[i] = '.'; + } + + name[248] = '\0'; + nc = 0; + } + } + + if (strlen(name) > 0) + printf("Device name:\t%s%s\n", name, nc ? " [cached]" : ""); + + if (extcls) { + memcpy(cls, (info+i)->dev_class, 3); + printf("Device class:\t"); + if ((cls[1] & 0x1f) > sizeof(major_classes) / sizeof(char *)) + printf("Invalid"); + else + printf("%s, %s", major_classes[cls[1] & 0x1f], + get_minor_device_name(cls[1] & 0x1f, cls[0] >> 2)); + printf(" (0x%2.2x%2.2x%2.2x)\n", cls[2], cls[1], cls[0]); + } + + if (extinf && handle > 0) { + if (hci_read_remote_version(dd, handle, &version, 20000) == 0) { + char *ver = lmp_vertostr(version.lmp_ver); + printf("Manufacturer:\t%s (%d)\n", + bt_compidtostr(version.manufacturer), + version.manufacturer); + printf("LMP version:\t%s (0x%x) [subver 0x%x]\n", + ver ? ver : "n/a", + version.lmp_ver, version.lmp_subver); + if (ver) + bt_free(ver); + } + + if (hci_read_remote_features(dd, handle, features, 20000) == 0) { + char *tmp = lmp_featurestostr(features, "\t\t", 63); + printf("LMP features:\t0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x" + " 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", + features[0], features[1], + features[2], features[3], + features[4], features[5], + features[6], features[7]); + printf("%s\n", tmp); + bt_free(tmp); + } + + if (cc) { + usleep(10000); + hci_disconnect(dd, handle, HCI_OE_USER_ENDED_CONNECTION, 10000); + } + } + + printf("\n"); + } + + bt_free(info); + + hci_close_dev(dd); +} + +/* Remote name */ + +static struct option name_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *name_help = + "Usage:\n" + "\tname \n"; + +static void cmd_name(int dev_id, int argc, char **argv) +{ + bdaddr_t bdaddr; + char name[248]; + int opt, dd; + + for_each_opt(opt, name_options, NULL) { + switch (opt) { + default: + printf("%s", name_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, name_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_get_route(&bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Device is not available.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + if (hci_read_remote_name(dd, &bdaddr, sizeof(name), name, 25000) == 0) + printf("%s\n", name); + + hci_close_dev(dd); +} + +/* Info about remote device */ + +static struct option info_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *info_help = + "Usage:\n" + "\tinfo \n"; + +static void cmd_info(int dev_id, int argc, char **argv) +{ + bdaddr_t bdaddr; + uint16_t handle; + uint8_t features[8], max_page = 0; + char name[249], *comp, *tmp; + struct hci_version version; + struct hci_dev_info di; + struct hci_conn_info_req *cr; + int i, opt, dd, cc = 0; + + for_each_opt(opt, info_options, NULL) { + switch (opt) { + default: + printf("%s", info_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, info_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + + if (dev_id < 0) + dev_id = hci_get_route(&bdaddr); + + if (dev_id < 0) { + fprintf(stderr, "Device is not available or not connected.\n"); + exit(1); + } + + if (hci_devinfo(dev_id, &di) < 0) { + perror("Can't get device info"); + exit(1); + } + + printf("Requesting information ...\n"); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't get connection info"); + close(dd); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + if (hci_create_connection(dd, &bdaddr, + htobs(di.pkt_type & ACL_PTYPE_MASK), + 0, 0x01, &handle, 25000) < 0) { + perror("Can't create connection"); + close(dd); + exit(1); + } + sleep(1); + cc = 1; + } else + handle = htobs(cr->conn_info->handle); + + printf("\tBD Address: %s\n", argv[0]); + + comp = batocomp(&bdaddr); + if (comp) { + char oui[9]; + ba2oui(&bdaddr, oui); + printf("\tOUI Company: %s (%s)\n", comp, oui); + free(comp); + } + + if (hci_read_remote_name(dd, &bdaddr, sizeof(name), name, 25000) == 0) + printf("\tDevice Name: %s\n", name); + + if (hci_read_remote_version(dd, handle, &version, 20000) == 0) { + char *ver = lmp_vertostr(version.lmp_ver); + printf("\tLMP Version: %s (0x%x) LMP Subversion: 0x%x\n" + "\tManufacturer: %s (%d)\n", + ver ? ver : "n/a", + version.lmp_ver, + version.lmp_subver, + bt_compidtostr(version.manufacturer), + version.manufacturer); + if (ver) + bt_free(ver); + } + + memset(features, 0, sizeof(features)); + hci_read_remote_features(dd, handle, features, 20000); + + if ((di.features[7] & LMP_EXT_FEAT) && (features[7] & LMP_EXT_FEAT)) + hci_read_remote_ext_features(dd, handle, 0, &max_page, + features, 20000); + + printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x " + "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", + (max_page > 0) ? " page 0" : "", + features[0], features[1], features[2], features[3], + features[4], features[5], features[6], features[7]); + + tmp = lmp_featurestostr(features, "\t\t", 63); + printf("%s\n", tmp); + bt_free(tmp); + + for (i = 1; i <= max_page; i++) { + if (hci_read_remote_ext_features(dd, handle, i, NULL, + features, 20000) < 0) + continue; + + printf("\tFeatures page %d: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x " + "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", i, + features[0], features[1], features[2], features[3], + features[4], features[5], features[6], features[7]); + } + + if (cc) { + usleep(10000); + hci_disconnect(dd, handle, HCI_OE_USER_ENDED_CONNECTION, 10000); + } + + hci_close_dev(dd); +} + +/* Start periodic inquiry */ + +static struct option spinq_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *spinq_help = + "Usage:\n" + "\tspinq\n"; + +static void cmd_spinq(int dev_id, int argc, char **argv) +{ + uint8_t lap[3] = { 0x33, 0x8b, 0x9e }; + struct hci_request rq; + periodic_inquiry_cp cp; + int opt, dd; + + for_each_opt(opt, spinq_options, NULL) { + switch (opt) { + default: + printf("%s", spinq_help); + return; + } + } + helper_arg(0, 0, &argc, &argv, spinq_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Device open failed"); + exit(EXIT_FAILURE); + } + + memset(&cp, 0, sizeof(cp)); + memcpy(cp.lap, lap, 3); + cp.max_period = htobs(16); + cp.min_period = htobs(10); + cp.length = 8; + cp.num_rsp = 0; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LINK_CTL; + rq.ocf = OCF_PERIODIC_INQUIRY; + rq.cparam = &cp; + rq.clen = PERIODIC_INQUIRY_CP_SIZE; + + if (hci_send_req(dd, &rq, 100) < 0) { + perror("Periodic inquiry failed"); + exit(EXIT_FAILURE); + } + + hci_close_dev(dd); +} + +/* Exit periodic inquiry */ + +static struct option epinq_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *epinq_help = + "Usage:\n" + "\tepinq\n"; + +static void cmd_epinq(int dev_id, int argc, char **argv) +{ + int opt, dd; + + for_each_opt(opt, epinq_options, NULL) { + switch (opt) { + default: + printf("%s", epinq_help); + return; + } + } + helper_arg(0, 0, &argc, &argv, epinq_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Device open failed"); + exit(EXIT_FAILURE); + } + + if (hci_send_cmd(dd, OGF_LINK_CTL, + OCF_EXIT_PERIODIC_INQUIRY, 0, NULL) < 0) { + perror("Exit periodic inquiry failed"); + exit(EXIT_FAILURE); + } + + hci_close_dev(dd); +} + +/* Send arbitrary HCI commands */ + +static struct option cmd_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *cmd_help = + "Usage:\n" + "\tcmd [parameters]\n" + "Example:\n" + "\tcmd 0x03 0x0013 0x41 0x42 0x43 0x44\n"; + +static void cmd_cmd(int dev_id, int argc, char **argv) +{ + unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf; + struct hci_filter flt; + hci_event_hdr *hdr; + int i, opt, len, dd; + uint16_t ocf; + uint8_t ogf; + + for_each_opt(opt, cmd_options, NULL) { + switch (opt) { + default: + printf("%s", cmd_help); + return; + } + } + helper_arg(2, -1, &argc, &argv, cmd_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + errno = 0; + ogf = strtol(argv[0], NULL, 16); + ocf = strtol(argv[1], NULL, 16); + if (errno == ERANGE || (ogf > 0x3f) || (ocf > 0x3ff)) { + printf("%s", cmd_help); + return; + } + + for (i = 2, len = 0; i < argc && len < (int) sizeof(buf); i++, len++) + *ptr++ = (uint8_t) strtol(argv[i], NULL, 16); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Device open failed"); + exit(EXIT_FAILURE); + } + + /* Setup filter */ + hci_filter_clear(&flt); + hci_filter_set_ptype(HCI_EVENT_PKT, &flt); + hci_filter_all_events(&flt); + if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { + perror("HCI filter setup failed"); + exit(EXIT_FAILURE); + } + + printf("< HCI Command: ogf 0x%02x, ocf 0x%04x, plen %d\n", ogf, ocf, len); + hex_dump(" ", 20, buf, len); fflush(stdout); + + if (hci_send_cmd(dd, ogf, ocf, len, buf) < 0) { + perror("Send failed"); + exit(EXIT_FAILURE); + } + + len = read(dd, buf, sizeof(buf)); + if (len < 0) { + perror("Read failed"); + exit(EXIT_FAILURE); + } + + hdr = (void *)(buf + 1); + ptr = buf + (1 + HCI_EVENT_HDR_SIZE); + len -= (1 + HCI_EVENT_HDR_SIZE); + + printf("> HCI Event: 0x%02x plen %d\n", hdr->evt, hdr->plen); + hex_dump(" ", 20, ptr, len); fflush(stdout); + + hci_close_dev(dd); +} + +/* Display active connections */ + +static struct option con_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *con_help = + "Usage:\n" + "\tcon\n"; + +static void cmd_con(int dev_id, int argc, char **argv) +{ + int opt; + + for_each_opt(opt, con_options, NULL) { + switch (opt) { + default: + printf("%s", con_help); + return; + } + } + helper_arg(0, 0, &argc, &argv, con_help); + + printf("Connections:\n"); + + hci_for_each_dev(HCI_UP, conn_list, dev_id); +} + +/* Create connection */ + +static struct option cc_options[] = { + { "help", 0, 0, 'h' }, + { "role", 1, 0, 'r' }, + { "ptype", 1, 0, 'p' }, + { 0, 0, 0, 0 } +}; + +static const char *cc_help = + "Usage:\n" + "\tcc [--role=m|s] [--ptype=pkt_types] \n" + "Example:\n" + "\tcc --ptype=dm1,dh3,dh5 01:02:03:04:05:06\n" + "\tcc --role=m 01:02:03:04:05:06\n"; + +static void cmd_cc(int dev_id, int argc, char **argv) +{ + bdaddr_t bdaddr; + uint16_t handle; + uint8_t role; + unsigned int ptype; + int dd, opt; + + role = 0x01; + ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5; + + for_each_opt(opt, cc_options, NULL) { + switch (opt) { + case 'p': + hci_strtoptype(optarg, &ptype); + break; + + case 'r': + role = optarg[0] == 'm' ? 0 : 1; + break; + + default: + printf("%s", cc_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, cc_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_get_route(&bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Device is not available.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + if (hci_create_connection(dd, &bdaddr, htobs(ptype), + htobs(0x0000), role, &handle, 25000) < 0) + perror("Can't create connection"); + + hci_close_dev(dd); +} + +/* Close connection */ + +static struct option dc_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *dc_help = + "Usage:\n" + "\tdc [reason]\n"; + +static void cmd_dc(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint8_t reason; + int opt, dd; + + for_each_opt(opt, dc_options, NULL) { + switch (opt) { + default: + printf("%s", dc_help); + return; + } + } + helper_arg(1, 2, &argc, &argv, dc_help); + + str2ba(argv[0], &bdaddr); + reason = (argc > 1) ? atoi(argv[1]) : HCI_OE_USER_ENDED_CONNECTION; + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (hci_disconnect(dd, htobs(cr->conn_info->handle), + reason, 10000) < 0) + perror("Disconnect failed"); + + free(cr); + + hci_close_dev(dd); +} + +/* Role switch */ + +static struct option sr_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *sr_help = + "Usage:\n" + "\tsr \n"; + +static void cmd_sr(int dev_id, int argc, char **argv) +{ + bdaddr_t bdaddr; + uint8_t role; + int opt, dd; + + for_each_opt(opt, sr_options, NULL) { + switch (opt) { + default: + printf("%s", sr_help); + return; + } + } + helper_arg(2, 2, &argc, &argv, sr_help); + + str2ba(argv[0], &bdaddr); + switch (argv[1][0]) { + case 'm': + role = 0; + break; + case 's': + role = 1; + break; + default: + role = atoi(argv[1]); + break; + } + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + if (hci_switch_role(dd, &bdaddr, role, 10000) < 0) { + perror("Switch role request failed"); + exit(1); + } + + hci_close_dev(dd); +} + +/* Read RSSI */ + +static struct option rssi_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *rssi_help = + "Usage:\n" + "\trssi \n"; + +static void cmd_rssi(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + int8_t rssi; + int opt, dd; + + for_each_opt(opt, rssi_options, NULL) { + switch (opt) { + default: + printf("%s", rssi_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, rssi_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (hci_read_rssi(dd, htobs(cr->conn_info->handle), &rssi, 1000) < 0) { + perror("Read RSSI failed"); + exit(1); + } + + printf("RSSI return value: %d\n", rssi); + + free(cr); + + hci_close_dev(dd); +} + +/* Get link quality */ + +static struct option lq_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *lq_help = + "Usage:\n" + "\tlq \n"; + +static void cmd_lq(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint8_t lq; + int opt, dd; + + for_each_opt(opt, lq_options, NULL) { + switch (opt) { + default: + printf("%s", lq_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, lq_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (hci_read_link_quality(dd, htobs(cr->conn_info->handle), &lq, 1000) < 0) { + perror("HCI read_link_quality request failed"); + exit(1); + } + + printf("Link quality: %d\n", lq); + + free(cr); + + hci_close_dev(dd); +} + +/* Get transmit power level */ + +static struct option tpl_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *tpl_help = + "Usage:\n" + "\ttpl [type]\n"; + +static void cmd_tpl(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint8_t type; + int8_t level; + int opt, dd; + + for_each_opt(opt, tpl_options, NULL) { + switch (opt) { + default: + printf("%s", tpl_help); + return; + } + } + helper_arg(1, 2, &argc, &argv, tpl_help); + + str2ba(argv[0], &bdaddr); + type = (argc > 1) ? atoi(argv[1]) : 0; + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (hci_read_transmit_power_level(dd, htobs(cr->conn_info->handle), type, &level, 1000) < 0) { + perror("HCI read transmit power level request failed"); + exit(1); + } + + printf("%s transmit power level: %d\n", + (type == 0) ? "Current" : "Maximum", level); + + free(cr); + + hci_close_dev(dd); +} + +/* Get AFH channel map */ + +static struct option afh_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *afh_help = + "Usage:\n" + "\tafh \n"; + +static void cmd_afh(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint16_t handle; + uint8_t mode, map[10]; + int opt, dd; + + for_each_opt(opt, afh_options, NULL) { + switch (opt) { + default: + printf("%s", afh_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, afh_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + handle = htobs(cr->conn_info->handle); + + if (hci_read_afh_map(dd, handle, &mode, map, 1000) < 0) { + perror("HCI read AFH map request failed"); + exit(1); + } + + if (mode == 0x01) { + int i; + printf("AFH map: 0x"); + for (i = 0; i < 10; i++) + printf("%02x", map[i]); + printf("\n"); + } else + printf("AFH disabled\n"); + + free(cr); + + hci_close_dev(dd); +} + +/* Set connection packet type */ + +static struct option cpt_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *cpt_help = + "Usage:\n" + "\tcpt \n"; + +static void cmd_cpt(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + struct hci_request rq; + set_conn_ptype_cp cp; + evt_conn_ptype_changed rp; + bdaddr_t bdaddr; + unsigned int ptype; + int dd, opt; + + for_each_opt(opt, cpt_options, NULL) { + switch (opt) { + default: + printf("%s", cpt_help); + return; + } + } + helper_arg(2, 2, &argc, &argv, cpt_help); + + str2ba(argv[0], &bdaddr); + hci_strtoptype(argv[1], &ptype); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + cp.handle = htobs(cr->conn_info->handle); + cp.pkt_type = ptype; + + memset(&rq, 0, sizeof(rq)); + rq.ogf = OGF_LINK_CTL; + rq.ocf = OCF_SET_CONN_PTYPE; + rq.cparam = &cp; + rq.clen = SET_CONN_PTYPE_CP_SIZE; + rq.rparam = &rp; + rq.rlen = EVT_CONN_PTYPE_CHANGED_SIZE; + rq.event = EVT_CONN_PTYPE_CHANGED; + + if (hci_send_req(dd, &rq, 100) < 0) { + perror("Packet type change failed"); + exit(1); + } + + free(cr); + + hci_close_dev(dd); +} + +/* Get/Set link policy settings */ + +static struct option lp_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *lp_help = + "Usage:\n" + "\tlp [link policy]\n"; + +static void cmd_lp(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint16_t policy; + int opt, dd; + + for_each_opt(opt, lp_options, NULL) { + switch (opt) { + default: + printf("%s", lp_help); + return; + } + } + helper_arg(1, 2, &argc, &argv, lp_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (argc == 1) { + char *str; + if (hci_read_link_policy(dd, htobs(cr->conn_info->handle), + &policy, 1000) < 0) { + perror("HCI read_link_policy_settings request failed"); + exit(1); + } + + policy = btohs(policy); + str = hci_lptostr(policy); + if (str) { + printf("Link policy settings: %s\n", str); + bt_free(str); + } else { + fprintf(stderr, "Invalig settings\n"); + exit(1); + } + } else { + unsigned int val; + if (hci_strtolp(argv[1], &val) < 0) { + fprintf(stderr, "Invalig arguments\n"); + exit(1); + } + policy = val; + + if (hci_write_link_policy(dd, htobs(cr->conn_info->handle), + htobs(policy), 1000) < 0) { + perror("HCI write_link_policy_settings request failed"); + exit(1); + } + } + + free(cr); + + hci_close_dev(dd); +} + +/* Get/Set link supervision timeout */ + +static struct option lst_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *lst_help = + "Usage:\n" + "\tlst [new value in slots]\n"; + +static void cmd_lst(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint16_t timeout; + int opt, dd; + + for_each_opt(opt, lst_options, NULL) { + switch (opt) { + default: + printf("%s", lst_help); + return; + } + } + helper_arg(1, 2, &argc, &argv, lst_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (argc == 1) { + if (hci_read_link_supervision_timeout(dd, htobs(cr->conn_info->handle), + &timeout, 1000) < 0) { + perror("HCI read_link_supervision_timeout request failed"); + exit(1); + } + + timeout = btohs(timeout); + + if (timeout) + printf("Link supervision timeout: %u slots (%.2f msec)\n", + timeout, (float) timeout * 0.625); + else + printf("Link supervision timeout never expires\n"); + } else { + timeout = strtol(argv[1], NULL, 10); + + if (hci_write_link_supervision_timeout(dd, htobs(cr->conn_info->handle), + htobs(timeout), 1000) < 0) { + perror("HCI write_link_supervision_timeout request failed"); + exit(1); + } + } + + free(cr); + + hci_close_dev(dd); +} + +/* Request authentication */ + +static struct option auth_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *auth_help = + "Usage:\n" + "\tauth \n"; + +static void cmd_auth(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + int opt, dd; + + for_each_opt(opt, auth_options, NULL) { + switch (opt) { + default: + printf("%s", auth_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, auth_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000) < 0) { + perror("HCI authentication request failed"); + exit(1); + } + + free(cr); + + hci_close_dev(dd); +} + +/* Activate encryption */ + +static struct option enc_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *enc_help = + "Usage:\n" + "\tenc [encrypt enable]\n"; + +static void cmd_enc(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint8_t encrypt; + int opt, dd; + + for_each_opt(opt, enc_options, NULL) { + switch (opt) { + default: + printf("%s", enc_help); + return; + } + } + helper_arg(1, 2, &argc, &argv, enc_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + encrypt = (argc > 1) ? atoi(argv[1]) : 1; + + if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), encrypt, 25000) < 0) { + perror("HCI set encryption request failed"); + exit(1); + } + + free(cr); + + hci_close_dev(dd); +} + +/* Change connection link key */ + +static struct option key_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *key_help = + "Usage:\n" + "\tkey \n"; + +static void cmd_key(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + int opt, dd; + + for_each_opt(opt, key_options, NULL) { + switch (opt) { + default: + printf("%s", key_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, key_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (hci_change_link_key(dd, htobs(cr->conn_info->handle), 25000) < 0) { + perror("Changing link key failed"); + exit(1); + } + + free(cr); + + hci_close_dev(dd); +} + +/* Read clock offset */ + +static struct option clkoff_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *clkoff_help = + "Usage:\n" + "\tclkoff \n"; + +static void cmd_clkoff(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint16_t offset; + int opt, dd; + + for_each_opt(opt, clkoff_options, NULL) { + switch (opt) { + default: + printf("%s", clkoff_help); + return; + } + } + helper_arg(1, 1, &argc, &argv, clkoff_help); + + str2ba(argv[0], &bdaddr); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + exit(1); + } + + if (hci_read_clock_offset(dd, htobs(cr->conn_info->handle), &offset, 1000) < 0) { + perror("Reading clock offset failed"); + exit(1); + } + + printf("Clock offset: 0x%4.4x\n", btohs(offset)); + + free(cr); + + hci_close_dev(dd); +} + +/* Read clock */ + +static struct option clock_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *clock_help = + "Usage:\n" + "\tclock [bdaddr] [which clock]\n"; + +static void cmd_clock(int dev_id, int argc, char **argv) +{ + struct hci_conn_info_req *cr; + bdaddr_t bdaddr; + uint8_t which; + uint32_t handle, clock; + uint16_t accuracy; + int opt, dd; + + for_each_opt(opt, clock_options, NULL) { + switch (opt) { + default: + printf("%s", clock_help); + return; + } + } + helper_arg(0, 2, &argc, &argv, clock_help); + + if (argc > 0) + str2ba(argv[0], &bdaddr); + else + bacpy(&bdaddr, BDADDR_ANY); + + if (dev_id < 0 && !bacmp(&bdaddr, BDADDR_ANY)) + dev_id = hci_get_route(NULL); + + if (dev_id < 0) { + dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr); + if (dev_id < 0) { + fprintf(stderr, "Not connected.\n"); + exit(1); + } + } + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("HCI device open failed"); + exit(1); + } + + if (bacmp(&bdaddr, BDADDR_ANY)) { + cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); + if (!cr) { + perror("Can't allocate memory"); + exit(1); + } + + bacpy(&cr->bdaddr, &bdaddr); + cr->type = ACL_LINK; + if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) { + perror("Get connection info failed"); + free(cr); + exit(1); + } + + handle = htobs(cr->conn_info->handle); + which = (argc > 1) ? atoi(argv[1]) : 0x01; + + free(cr); + } else { + handle = 0x00; + which = 0x00; + } + + if (hci_read_clock(dd, handle, which, &clock, &accuracy, 1000) < 0) { + perror("Reading clock failed"); + exit(1); + } + + accuracy = btohs(accuracy); + + printf("Clock: 0x%4.4x\n", btohl(clock)); + printf("Accuracy: %.2f msec\n", (float) accuracy * 0.3125); + + hci_close_dev(dd); +} + +static int read_flags(uint8_t *flags, const uint8_t *data, size_t size) +{ + size_t offset; + + if (!flags || !data) + return -EINVAL; + + offset = 0; + while (offset < size) { + uint8_t len = data[offset]; + uint8_t type; + + /* Check if it is the end of the significant part */ + if (len == 0) + break; + + if (len + offset > size) + break; + + type = data[offset + 1]; + + if (type == FLAGS_AD_TYPE) { + *flags = data[offset + 2]; + return 0; + } + + offset += 1 + len; + } + + return -ENOENT; +} + +static int check_report_filter(uint8_t procedure, le_advertising_info *info) +{ + uint8_t flags; + + /* If no discovery procedure is set, all reports are treat as valid */ + if (procedure == 0) + return 1; + + /* Read flags AD type value from the advertising report if it exists */ + if (read_flags(&flags, info->data, info->length)) + return 0; + + switch (procedure) { + case 'l': /* Limited Discovery Procedure */ + if (flags & FLAGS_LIMITED_MODE_BIT) + return 1; + break; + case 'g': /* General Discovery Procedure */ + if (flags & (FLAGS_LIMITED_MODE_BIT | FLAGS_GENERAL_MODE_BIT)) + return 1; + break; + default: + fprintf(stderr, "Unknown discovery procedure\n"); + } + + return 0; +} + +static void sigint_handler(int sig) +{ + signal_received = sig; +} + +static void eir_parse_name(uint8_t *eir, size_t eir_len, + char *buf, size_t buf_len) +{ + size_t offset; + + offset = 0; + while (offset < eir_len) { + uint8_t field_len = eir[0]; + size_t name_len; + + /* Check for the end of EIR */ + if (field_len == 0) + break; + + if (offset + field_len > eir_len) + goto failed; + + switch (eir[1]) { + case EIR_NAME_SHORT: + case EIR_NAME_COMPLETE: + name_len = field_len - 1; + if (name_len > buf_len) + goto failed; + + memcpy(buf, &eir[2], name_len); + return; + } + + offset += field_len + 1; + eir += field_len + 1; + } + +failed: + snprintf(buf, buf_len, "(unknown)"); +} + +static int print_advertising_devices(int dd, uint8_t filter_type) +{ + unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr; + struct hci_filter nf, of; + struct sigaction sa; + socklen_t olen; + int len; + + olen = sizeof(of); + if (getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &olen) < 0) { + printf("Could not get socket options\n"); + return -1; + } + + hci_filter_clear(&nf); + hci_filter_set_ptype(HCI_EVENT_PKT, &nf); + hci_filter_set_event(EVT_LE_META_EVENT, &nf); + + if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) { + printf("Could not set socket options\n"); + return -1; + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = sigint_handler; + sigaction(SIGINT, &sa, NULL); + + while (1) { + evt_le_meta_event *meta; + le_advertising_info *info; + char addr[18]; + + while ((len = read(dd, buf, sizeof(buf))) < 0) { + if (errno == EINTR && signal_received == SIGINT) { + len = 0; + goto done; + } + + if (errno == EAGAIN || errno == EINTR) + continue; + goto done; + } + + ptr = buf + (1 + HCI_EVENT_HDR_SIZE); + len -= (1 + HCI_EVENT_HDR_SIZE); + + meta = (void *) ptr; + + if (meta->subevent != 0x02) + goto done; + + /* Ignoring multiple reports */ + info = (le_advertising_info *) (meta->data + 1); + if (check_report_filter(filter_type, info)) { + char name[30]; + + memset(name, 0, sizeof(name)); + + ba2str(&info->bdaddr, addr); + eir_parse_name(info->data, info->length, + name, sizeof(name) - 1); + + printf("%s %s\n", addr, name); + } + } + +done: + setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of)); + + if (len < 0) + return -1; + + return 0; +} + +static struct option lescan_options[] = { + { "help", 0, 0, 'h' }, + { "privacy", 0, 0, 'p' }, + { "passive", 0, 0, 'P' }, + { "whitelist", 0, 0, 'w' }, + { "discovery", 1, 0, 'd' }, + { "duplicates", 0, 0, 'D' }, + { 0, 0, 0, 0 } +}; + +static const char *lescan_help = + "Usage:\n" + "\tlescan [--privacy] enable privacy\n" + "\tlescan [--passive] set scan type passive (default active)\n" + "\tlescan [--whitelist] scan for address in the whitelist only\n" + "\tlescan [--discovery=g|l] enable general or limited discovery" + "procedure\n" + "\tlescan [--duplicates] don't filter duplicates\n"; + +static void cmd_lescan(int dev_id, int argc, char **argv) +{ + int err, opt, dd; + uint8_t own_type = 0x00; + uint8_t scan_type = 0x01; + uint8_t filter_type = 0; + uint8_t filter_policy = 0x00; + uint16_t interval = htobs(0x0010); + uint16_t window = htobs(0x0010); + uint8_t filter_dup = 1; + + for_each_opt(opt, lescan_options, NULL) { + switch (opt) { + case 'p': + own_type = 0x01; /* Random */ + break; + case 'P': + scan_type = 0x00; /* Passive */ + break; + case 'w': + filter_policy = 0x01; /* Whitelist */ + break; + case 'd': + filter_type = optarg[0]; + if (filter_type != 'g' && filter_type != 'l') { + fprintf(stderr, "Unknown discovery procedure\n"); + exit(1); + } + + interval = htobs(0x0012); + window = htobs(0x0012); + break; + case 'D': + filter_dup = 0x00; + break; + default: + printf("%s", lescan_help); + return; + } + } + helper_arg(0, 1, &argc, &argv, lescan_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + err = hci_le_set_scan_parameters(dd, scan_type, interval, window, + own_type, filter_policy, 1000); + if (err < 0) { + perror("Set scan parameters failed"); + exit(1); + } + + err = hci_le_set_scan_enable(dd, 0x01, filter_dup, 1000); + if (err < 0) { + perror("Enable scan failed"); + exit(1); + } + + printf("LE Scan ...\n"); + + err = print_advertising_devices(dd, filter_type); + if (err < 0) { + perror("Could not receive advertising events"); + exit(1); + } + + err = hci_le_set_scan_enable(dd, 0x00, filter_dup, 1000); + if (err < 0) { + perror("Disable scan failed"); + exit(1); + } + + hci_close_dev(dd); +} + +static struct option lecc_options[] = { + { "help", 0, 0, 'h' }, + { "random", 0, 0, 'r' }, + { "whitelist", 0, 0, 'w' }, + { 0, 0, 0, 0 } +}; + +static const char *lecc_help = + "Usage:\n" + "\tlecc [--random] \n" + "\tlecc --whitelist\n"; + +static void cmd_lecc(int dev_id, int argc, char **argv) +{ + int err, opt, dd; + bdaddr_t bdaddr; + uint16_t interval, latency, max_ce_length, max_interval, min_ce_length; + uint16_t min_interval, supervision_timeout, window, handle; + uint8_t initiator_filter, own_bdaddr_type, peer_bdaddr_type; + + peer_bdaddr_type = LE_PUBLIC_ADDRESS; + initiator_filter = 0; /* Use peer address */ + + for_each_opt(opt, lecc_options, NULL) { + switch (opt) { + case 'r': + peer_bdaddr_type = LE_RANDOM_ADDRESS; + break; + case 'w': + initiator_filter = 0x01; /* Use white list */ + break; + default: + printf("%s", lecc_help); + return; + } + } + helper_arg(0, 1, &argc, &argv, lecc_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + memset(&bdaddr, 0, sizeof(bdaddr_t)); + if (argv[0]) + str2ba(argv[0], &bdaddr); + + interval = htobs(0x0004); + window = htobs(0x0004); + own_bdaddr_type = 0x00; + min_interval = htobs(0x000F); + max_interval = htobs(0x000F); + latency = htobs(0x0000); + supervision_timeout = htobs(0x0C80); + min_ce_length = htobs(0x0001); + max_ce_length = htobs(0x0001); + + err = hci_le_create_conn(dd, interval, window, initiator_filter, + peer_bdaddr_type, bdaddr, own_bdaddr_type, min_interval, + max_interval, latency, supervision_timeout, + min_ce_length, max_ce_length, &handle, 25000); + if (err < 0) { + perror("Could not create connection"); + exit(1); + } + + printf("Connection handle %d\n", handle); + + hci_close_dev(dd); +} + +static struct option lewladd_options[] = { + { "help", 0, 0, 'h' }, + { "random", 0, 0, 'r' }, + { 0, 0, 0, 0 } +}; + +static const char *lewladd_help = + "Usage:\n" + "\tlewladd [--random] \n"; + +static void cmd_lewladd(int dev_id, int argc, char **argv) +{ + int err, opt, dd; + bdaddr_t bdaddr; + uint8_t bdaddr_type = LE_PUBLIC_ADDRESS; + + for_each_opt(opt, lewladd_options, NULL) { + switch (opt) { + case 'r': + bdaddr_type = LE_RANDOM_ADDRESS; + break; + default: + printf("%s", lewladd_help); + return; + } + } + + helper_arg(1, 1, &argc, &argv, lewladd_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + str2ba(argv[0], &bdaddr); + + err = hci_le_add_white_list(dd, &bdaddr, bdaddr_type, 1000); + hci_close_dev(dd); + + if (err < 0) { + err = -errno; + fprintf(stderr, "Can't add to white list: %s(%d)\n", + strerror(-err), -err); + exit(1); + } +} + +static struct option lewlrm_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *lewlrm_help = + "Usage:\n" + "\tlewlrm \n"; + +static void cmd_lewlrm(int dev_id, int argc, char **argv) +{ + int err, opt, dd; + bdaddr_t bdaddr; + + for_each_opt(opt, lewlrm_options, NULL) { + switch (opt) { + default: + printf("%s", lewlrm_help); + return; + } + } + + helper_arg(1, 1, &argc, &argv, lewlrm_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + str2ba(argv[0], &bdaddr); + + err = hci_le_rm_white_list(dd, &bdaddr, LE_PUBLIC_ADDRESS, 1000); + hci_close_dev(dd); + + if (err < 0) { + err = errno; + fprintf(stderr, "Can't remove from white list: %s(%d)\n", + strerror(err), err); + exit(1); + } +} + +static struct option lewlsz_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *lewlsz_help = + "Usage:\n" + "\tlewlsz\n"; + +static void cmd_lewlsz(int dev_id, int argc, char **argv) +{ + int err, dd, opt; + uint8_t size; + + for_each_opt(opt, lewlsz_options, NULL) { + switch (opt) { + default: + printf("%s", lewlsz_help); + return; + } + } + + helper_arg(0, 0, &argc, &argv, lewlsz_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + err = hci_le_read_white_list_size(dd, &size, 1000); + hci_close_dev(dd); + + if (err < 0) { + err = -errno; + fprintf(stderr, "Can't read white list size: %s(%d)\n", + strerror(-err), -err); + exit(1); + } + + printf("White list size: %d\n", size); +} + +static struct option lewlclr_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *lewlclr_help = + "Usage:\n" + "\tlewlclr\n"; + +static void cmd_lewlclr(int dev_id, int argc, char **argv) +{ + int err, dd, opt; + + for_each_opt(opt, lewlclr_options, NULL) { + switch (opt) { + default: + printf("%s", lewlclr_help); + return; + } + } + + helper_arg(0, 0, &argc, &argv, lewlclr_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + err = hci_le_clear_white_list(dd, 1000); + hci_close_dev(dd); + + if (err < 0) { + err = -errno; + fprintf(stderr, "Can't clear white list: %s(%d)\n", + strerror(-err), -err); + exit(1); + } +} + +static struct option ledc_options[] = { + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } +}; + +static const char *ledc_help = + "Usage:\n" + "\tledc [reason]\n"; + +static void cmd_ledc(int dev_id, int argc, char **argv) +{ + int err, opt, dd; + uint16_t handle; + uint8_t reason; + + for_each_opt(opt, ledc_options, NULL) { + switch (opt) { + default: + printf("%s", ledc_help); + return; + } + } + helper_arg(1, 2, &argc, &argv, ledc_help); + + if (dev_id < 0) + dev_id = hci_get_route(NULL); + + dd = hci_open_dev(dev_id); + if (dd < 0) { + perror("Could not open device"); + exit(1); + } + + handle = atoi(argv[0]); + + reason = (argc > 1) ? atoi(argv[1]) : HCI_OE_USER_ENDED_CONNECTION; + + err = hci_disconnect(dd, handle, reason, 10000); + if (err < 0) { + perror("Could not disconnect"); + exit(1); + } + + hci_close_dev(dd); +} + +static struct option lecup_options[] = { + { "help", 0, 0, 'h' }, + { "handle", 1, 0, 'H' }, + { "min", 1, 0, 'm' }, + { "max", 1, 0, 'M' }, + { "latency", 1, 0, 'l' }, + { "timeout", 1, 0, 't' }, + { 0, 0, 0, 0 } +}; + +static const char *lecup_help = + "Usage:\n" + "\tlecup \n" + "\tOptions:\n" + "\t -H, --handle <0xXXXX> LE connection handle\n" + "\t -m, --min Range: 0x0006 to 0x0C80\n" + "\t -M, --max Range: 0x0006 to 0x0C80\n" + "\t -l, --latency Slave latency. Range: 0x0000 to 0x03E8\n" + "\t -t, --timeout