diff options
Diffstat (limited to 'emulator/usbpt')
34 files changed, 3628 insertions, 0 deletions
diff --git a/emulator/usbpt/BoardConfig.mk b/emulator/usbpt/BoardConfig.mk new file mode 100644 index 0000000..ea43a0b --- /dev/null +++ b/emulator/usbpt/BoardConfig.mk @@ -0,0 +1,16 @@ +# Copyright (C) 2022 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include device/generic/car/emulator/usbpt/bluetooth/BoardConfig.mk diff --git a/emulator/usbpt/bluetooth/BoardConfig.mk b/emulator/usbpt/bluetooth/BoardConfig.mk new file mode 100644 index 0000000..3c37ad4 --- /dev/null +++ b/emulator/usbpt/bluetooth/BoardConfig.mk @@ -0,0 +1,18 @@ +# Copyright (C) 2022 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +BOARD_HAVE_BLUETOOTH := true + +include device/generic/car/emulator/usbpt/bluetooth/btusb/BoardConfig.mk diff --git a/emulator/usbpt/bluetooth/bluetooth.mk b/emulator/usbpt/bluetooth/bluetooth.mk new file mode 100644 index 0000000..935097f --- /dev/null +++ b/emulator/usbpt/bluetooth/bluetooth.mk @@ -0,0 +1,32 @@ +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Enables btlinux when BT passthrough is enabled by starting the emulator with +# -prop vendor.qemu.preferred.bt.service=passthrough + +PRODUCT_PACKAGES += \ + android.hardware.bluetooth@1.1-service.btlinux \ + +PRODUCT_COPY_FILES += \ + device/generic/car/emulator/usbpt/bluetooth/vendor.qemu.preferred.bt.service.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/vendor.qemu.preferred.bt.service.rc \ + device/generic/car/emulator/usbpt/bluetooth/modules.blocklist:$(TARGET_COPY_OUT_VENDOR_RAMDISK)/lib/modules/modules.blocklist \ + +PRODUCT_SYSTEM_PROPERTIES += \ + persist.bluetooth.enablenewavrcp=false \ + +# USB Passthru +PRODUCT_PACKAGES += usb_modeswitch + +$(call inherit-product, device/generic/car/emulator/usbpt/bluetooth/btusb/btusb.mk) diff --git a/emulator/usbpt/bluetooth/btusb/BoardConfig.mk b/emulator/usbpt/bluetooth/btusb/BoardConfig.mk new file mode 100644 index 0000000..7011ee7 --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/BoardConfig.mk @@ -0,0 +1,24 @@ +# Copyright (C) 2022 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := device/generic/car/emulator/usbpt/bluetooth/btusb/hal + +TARGET_KERNEL_USE ?= 5.10 + +ifeq ($(TARGET_ARCH),x86_64) +BOARD_VENDOR_KERNEL_MODULES += kernel/prebuilts/common-modules/virtual-device/$(TARGET_KERNEL_USE)/x86-64/btusb.ko +else ifeq ($(TARGET_ARCH),arm64) +BOARD_VENDOR_KERNEL_MODULES += kernel/prebuilts/common-modules/virtual-device/$(TARGET_KERNEL_USE)/arm64/btusb.ko +endif diff --git a/emulator/usbpt/bluetooth/btusb/btusb.mk b/emulator/usbpt/bluetooth/btusb/btusb.mk new file mode 100644 index 0000000..6e21465 --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/btusb.mk @@ -0,0 +1,27 @@ +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Allow sepolicies to be excluded in GSI targets. +ifeq ($(DO_NOT_INCLUDE_BT_SEPOLICY),) +BOARD_SEPOLICY_DIRS += \ + device/generic/car/emulator/usbpt/bluetooth/btusb/sepolicy +endif + +# USB Passthru +PRODUCT_PACKAGES += rtl8821c_fw.bin.car \ + rtl8821c_config.bin.car + +PRODUCT_COPY_FILES += \ + device/generic/car/emulator/usbpt/bluetooth/btusb/init.btusb.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.btusb.rc \ diff --git a/emulator/usbpt/bluetooth/btusb/hal/bdroid_buildcfg.h b/emulator/usbpt/bluetooth/btusb/hal/bdroid_buildcfg.h new file mode 100644 index 0000000..132b683 --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/hal/bdroid_buildcfg.h @@ -0,0 +1,9 @@ +#ifndef _BDROID_BUILDCFG_H +#define _BDROID_BUILDCFG_H +#define BTM_DEF_LOCAL_NAME "gCar Emulator" +#define BTA_AV_SINK_INCLUDED TRUE +/* Handsfree device */ +#define BTA_DM_COD {0x26, 0x04, 0x08} +/* Workaround for error at connection. */ +#define BT_CLEAN_TURN_ON_DISABLED 1 +#endif diff --git a/emulator/usbpt/bluetooth/btusb/init.btusb.rc b/emulator/usbpt/bluetooth/btusb/init.btusb.rc new file mode 100644 index 0000000..4603f83 --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/init.btusb.rc @@ -0,0 +1,5 @@ +on early-init + write /sys/module/firmware_class/parameters/path /vendor/firmware/ + +on boot + exec u:r:vendor_modprobe:s0 -- /vendor/bin/modprobe -a -d /vendor/lib/modules btusb.ko diff --git a/emulator/usbpt/bluetooth/btusb/rtl_bt/Android.bp b/emulator/usbpt/bluetooth/btusb/rtl_bt/Android.bp new file mode 100644 index 0000000..ade064e --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/rtl_bt/Android.bp @@ -0,0 +1,24 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "device_generic_car_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["device_generic_car_license"], +} + +prebuilt_firmware { + name: "rtl8821c_fw.bin.car", + src: "rtl8821c_fw.bin", + sub_dir: "rtl_bt", + filename_from_src: true, + proprietary: true, +} + +prebuilt_firmware { + name: "rtl8821c_config.bin.car", + src: "rtl8821c_config.bin", + sub_dir: "rtl_bt", + filename_from_src: true, + proprietary: true, +} diff --git a/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_config.bin b/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_config.bin Binary files differnew file mode 100755 index 0000000..76f62b8 --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_config.bin diff --git a/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_fw.bin b/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_fw.bin Binary files differnew file mode 100644 index 0000000..ad31c94 --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_fw.bin diff --git a/emulator/usbpt/bluetooth/btusb/sepolicy/bluetooth.te b/emulator/usbpt/bluetooth/btusb/sepolicy/bluetooth.te new file mode 100644 index 0000000..dacbe8f --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/sepolicy/bluetooth.te @@ -0,0 +1,2 @@ +allow kernel vendor_fw_file:file {open read}; +allow kernel vendor_fw_file:dir search; diff --git a/emulator/usbpt/bluetooth/btusb/sepolicy/domain.te b/emulator/usbpt/bluetooth/btusb/sepolicy/domain.te new file mode 100644 index 0000000..448f1c3 --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/sepolicy/domain.te @@ -0,0 +1,4 @@ +allow domain qemu_device:chr_file rw_file_perms; + +get_prop(domain, vendor_qemu_prop) +get_prop(domain, vendor_build_prop) diff --git a/emulator/usbpt/bluetooth/btusb/sepolicy/file.te b/emulator/usbpt/bluetooth/btusb/sepolicy/file.te new file mode 100644 index 0000000..bfde7a6 --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/sepolicy/file.te @@ -0,0 +1 @@ +type vendor_fw_file, vendor_file_type, file_type; diff --git a/emulator/usbpt/bluetooth/btusb/sepolicy/file_contexts b/emulator/usbpt/bluetooth/btusb/sepolicy/file_contexts new file mode 100644 index 0000000..a4c28ba --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/sepolicy/file_contexts @@ -0,0 +1,2 @@ +# Vendor Firmwares +/(vendor|system/vendor)/firmware(/.*)? u:object_r:vendor_fw_file:s0 diff --git a/emulator/usbpt/bluetooth/btusb/sepolicy/property_contexts b/emulator/usbpt/bluetooth/btusb/sepolicy/property_contexts new file mode 100644 index 0000000..224ca7f --- /dev/null +++ b/emulator/usbpt/bluetooth/btusb/sepolicy/property_contexts @@ -0,0 +1 @@ +vendor.qemu.preferred.bt.service u:object_r:vendor_qemu_prop:s0 diff --git a/emulator/usbpt/bluetooth/modules.blocklist b/emulator/usbpt/bluetooth/modules.blocklist new file mode 100644 index 0000000..5816cd8 --- /dev/null +++ b/emulator/usbpt/bluetooth/modules.blocklist @@ -0,0 +1,2 @@ +# List of sub-device specific modules to not load automatically +blocklist btusb.ko diff --git a/emulator/usbpt/bluetooth/usb_modeswitch/Android.bp b/emulator/usbpt/bluetooth/usb_modeswitch/Android.bp new file mode 100644 index 0000000..8858908 --- /dev/null +++ b/emulator/usbpt/bluetooth/usb_modeswitch/Android.bp @@ -0,0 +1,47 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: [ + "device_generic_car_emulator_usb_modeswitch_license", + ], +} + +// See: http://go/android-license-faq +license { + name: "device_generic_car_emulator_usb_modeswitch_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-GPL-2.0+", + ], + license_text: [ + "LICENSE", + ], +} + +cc_binary { + name: "usb_modeswitch", + srcs: [ + "usb_modeswitch.c", + ], + shared_libs: [ + "libusb", + ], + cflags: [ + "-Wno-self-assign", + "-Wno-unused-parameter", + "-Wno-sometimes-uninitialized", + ], + vendor: true +} diff --git a/emulator/usbpt/bluetooth/usb_modeswitch/LICENSE b/emulator/usbpt/bluetooth/usb_modeswitch/LICENSE new file mode 100644 index 0000000..1f963da --- /dev/null +++ b/emulator/usbpt/bluetooth/usb_modeswitch/LICENSE @@ -0,0 +1,340 @@ + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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/emulator/usbpt/bluetooth/usb_modeswitch/usb_modeswitch.c b/emulator/usbpt/bluetooth/usb_modeswitch/usb_modeswitch.c new file mode 100644 index 0000000..3b7c48b --- /dev/null +++ b/emulator/usbpt/bluetooth/usb_modeswitch/usb_modeswitch.c @@ -0,0 +1,2119 @@ +/* + Mode switching tool for controlling mode of 'multi-state' USB devices + Version 2.6.0, 2019/11/28 + + Copyright (C) 2007 - 2019 Josua Dietze (mail to "usb_admin" at the domain + of the home page; or write a personal message through the forum to "Josh". + NO SUPPORT VIA E-MAIL - please use the forum for that) + + Major contributions: + + Command line parsing, decent usage/config output/handling, bugfixes and advanced + options added by: + Joakim Wennergren + + TargetClass parameter implementation to support new Option devices/firmware: + Paul Hardwick (http://www.pharscape.org) + + Created with initial help from: + "usbsnoop2libusb.pl" by Timo Lindfors (http://iki.fi/lindi/usb/usbsnoop2libusb.pl) + + Config file parsing code borrowed from: + Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html) + + Hexstr2bin function borrowed from: + Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c") + + Other contributions: see README + + Device information contributors are named in the "device_reference.txt" file. See + homepage. + + 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: + + http://www.gnu.org/licenses/gpl.txt + +*/ + +/* Recommended tab size: 4 */ + +#define VERSION "2.6.0" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <ctype.h> +#include <getopt.h> +#include <syslog.h> +#include <unistd.h> + +#include "usb_modeswitch.h" + + +// Little helpers + +int usb_bulk_io(struct libusb_device_handle *handle, int ep, unsigned char *bytes, + int size, int timeout) +{ + int actual_length; + int r; +// usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout); + r = libusb_bulk_transfer(handle, ep & 0xff, bytes, size, + &actual_length, timeout); + + /* if we timed out but did transfer some data, report as successful short + * read. FIXME: is this how libusb-0.1 works? */ + if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0)) + return actual_length; + + return r; +} + + +static int usb_interrupt_io(libusb_device_handle *handle, int ep, unsigned char *bytes, + int size, int timeout) +{ + int actual_length; + int r; +// usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout); + r = libusb_interrupt_transfer(handle, ep & 0xff, bytes, size, + &actual_length, timeout); + + /* if we timed out but did transfer some data, report as successful short + * read. FIXME: is this how libusb-0.1 works? */ + if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0)) + return actual_length; + + return (r); +} + + +#define LINE_DIM 1024 +#define MSG_DIM 11 +#define MAXLINES 50 +#define BUF_SIZE 4096 +#define DESCR_MAX 129 + +#define SEARCH_DEFAULT 0 +#define SEARCH_TARGET 1 +#define SEARCH_BUSDEV 2 + +#define SWITCH_CONFIG_MAXTRIES 5 + +#define SHOW_PROGRESS if (show_progress) fprintf + +char *TempPP=NULL; + +static struct libusb_context *ctx = NULL; +static struct libusb_device *dev = NULL; +static struct libusb_device_handle *devh = NULL; +static struct libusb_config_descriptor *active_config = NULL; + +int DefaultVendor=0, DefaultProduct=0, TargetVendor=0, TargetProduct=-1, TargetClass=0; +int MessageEndpoint=0, ResponseEndpoint=0, ReleaseDelay=0; +int targetDeviceCount=0, searchMode; +int devnum=-1, busnum=-1; + +unsigned int ModeMap = 0; +#define DETACHONLY_MODE 0x00000001 +#define HUAWEI_MODE 0x00000002 +#define SIERRA_MODE 0x00000004 +#define SONY_MODE 0x00000008 +#define GCT_MODE 0x00000010 +#define KOBIL_MODE 0x00000020 +#define SEQUANS_MODE 0x00000040 +#define MOBILEACTION_MODE 0x00000080 +#define CISCO_MODE 0x00000100 +#define QISDA_MODE 0x00000200 +#define QUANTA_MODE 0x00000400 +#define BLACKBERRY_MODE 0x00000800 +#define PANTECH_MODE 0x00001000 +#define HUAWEINEW_MODE 0x00002000 +#define OPTION_MODE 0x00004000 +#define HUAWEIALT_MODE 0x00008000 + + +int PantechMode=0; +char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0; +char NoDriverLoading=0, sysmode=0, mbim=0; +char StandardEject=0; + +char MessageContent[LINE_DIM]; +char MessageContent2[LINE_DIM]; +char MessageContent3[LINE_DIM]; +char TargetProductList[LINE_DIM]; +char DefaultProductList[5]; +unsigned char ByteString[LINE_DIM/2]; +unsigned char buffer[BUF_SIZE]; +char **Messages = NULL; + +FILE *output; + + +/* Settable interface, altsetting (for debugging mostly) and configuration */ +int Interface = -1, Configuration = 0, AltSetting = -1; + + +static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'e'}, + {"default-vendor", required_argument, 0, 'v'}, + {"default-product", required_argument, 0, 'p'}, + {"target-vendor", required_argument, 0, 'V'}, + {"target-product", required_argument, 0, 'P'}, + {"target-class", required_argument, 0, 'C'}, + {"message-endpoint", required_argument, 0, 'm'}, + {"message-content", required_argument, 0, 'M'}, + {"message-content2", required_argument, 0, '2'}, + {"message-content3", required_argument, 0, '3'}, + {"release-delay", required_argument, 0, 'w'}, + {"response-endpoint", required_argument, 0, 'r'}, + {"bus-num", required_argument, 0, 'b'}, + {"device-num", required_argument, 0, 'g'}, + {"detach-only", no_argument, 0, 'd'}, + {"huawei-mode", no_argument, 0, 'H'}, + {"huawei-new-mode", no_argument, 0, 'J'}, + {"huawei-alt-mode", no_argument, 0, 'X'}, + {"sierra-mode", no_argument, 0, 'S'}, + {"sony-mode", no_argument, 0, 'O'}, + {"qisda-mode", no_argument, 0, 'B'}, + {"quanta-mode", no_argument, 0, 'E'}, + {"kobil-mode", no_argument, 0, 'T'}, + {"gct-mode", no_argument, 0, 'G'}, + {"sequans-mode", no_argument, 0, 'N'}, + {"mobileaction-mode", no_argument, 0, 'A'}, + {"cisco-mode", no_argument, 0, 'L'}, + {"blackberry-mode", no_argument, 0, 'Z'}, + {"option-mode", no_argument, 0, 'U'}, + {"pantech-mode", required_argument, 0, 'F'}, + {"std-eject", no_argument, 0, 'K'}, + {"need-response", no_argument, 0, 'n'}, + {"reset-usb", no_argument, 0, 'R'}, + {"config-file", required_argument, 0, 'c'}, + {"verbose", no_argument, 0, 'W'}, + {"quiet", no_argument, 0, 'Q'}, + {"sysmode", no_argument, 0, 'D'}, + {"inquire", no_argument, 0, 'I'}, + {"stdinput", no_argument, 0, 't'}, + {"find-mbim", no_argument, 0, 'j'}, + {"long-config", required_argument, 0, 'f'}, + {"check-success", required_argument, 0, 's'}, + {"interface", required_argument, 0, 'i'}, + {"configuration", required_argument, 0, 'u'}, + {"altsetting", required_argument, 0, 'a'}, + {0, 0, 0, 0} +}; + + +void readConfigFile(const char *configFilename) +{ + ParseParamHex(configFilename, TargetVendor); + ParseParamHex(configFilename, TargetProduct); + ParseParamString(configFilename, TargetProductList); + ParseParamHex(configFilename, TargetClass); + ParseParamHex(configFilename, DefaultVendor); + ParseParamHex(configFilename, DefaultProduct); + ParseParamBoolMap(configFilename, DetachStorageOnly, ModeMap, DETACHONLY_MODE); + ParseParamBoolMap(configFilename, HuaweiMode, ModeMap, HUAWEI_MODE); + ParseParamBoolMap(configFilename, HuaweiNewMode, ModeMap, HUAWEINEW_MODE); + ParseParamBoolMap(configFilename, HuaweiAltMode, ModeMap, HUAWEIALT_MODE); + ParseParamBoolMap(configFilename, SierraMode, ModeMap, SIERRA_MODE); + ParseParamBoolMap(configFilename, SonyMode, ModeMap, SONY_MODE); + ParseParamBoolMap(configFilename, GCTMode, ModeMap, GCT_MODE); + ParseParamBoolMap(configFilename, KobilMode, ModeMap, KOBIL_MODE); + ParseParamBoolMap(configFilename, SequansMode, ModeMap, SEQUANS_MODE); + ParseParamBoolMap(configFilename, MobileActionMode, ModeMap, MOBILEACTION_MODE); + ParseParamBoolMap(configFilename, CiscoMode, ModeMap, CISCO_MODE); + ParseParamBoolMap(configFilename, QisdaMode, ModeMap, QISDA_MODE); + ParseParamBoolMap(configFilename, QuantaMode, ModeMap, QUANTA_MODE); + ParseParamBoolMap(configFilename, OptionMode, ModeMap, OPTION_MODE); + ParseParamBoolMap(configFilename, BlackberryMode, ModeMap, BLACKBERRY_MODE); + ParseParamInt(configFilename, PantechMode); + if (PantechMode) + ModeMap |= PANTECH_MODE; + ParseParamBool(configFilename, StandardEject); + ParseParamBool(configFilename, NoDriverLoading); + ParseParamHex(configFilename, MessageEndpoint); + ParseParamString(configFilename, MessageContent); + ParseParamString(configFilename, MessageContent2); + ParseParamString(configFilename, MessageContent3); + ParseParamInt(configFilename, ReleaseDelay); + ParseParamHex(configFilename, ResponseEndpoint); + ParseParamHex(configFilename, ResetUSB); + ParseParamInt(configFilename, CheckSuccess); + ParseParamHex(configFilename, Interface); + ParseParamHex(configFilename, Configuration); + ParseParamHex(configFilename, AltSetting); + + /* TargetProductList has priority over TargetProduct */ + if (TargetProduct != -1 && TargetProductList[0] != '\0') { + TargetProduct = -1; + SHOW_PROGRESS(output,"Warning: TargetProductList overrides TargetProduct!\n"); + } + + config_read = 1; +} + + +void printConfig() +{ + if ( DefaultVendor ) + fprintf (output,"DefaultVendor= 0x%04x\n", DefaultVendor); + if ( DefaultProduct ) + fprintf (output,"DefaultProduct= 0x%04x\n", DefaultProduct); + if ( TargetVendor ) + fprintf (output,"TargetVendor= 0x%04x\n", TargetVendor); + if ( TargetProduct > -1 ) + fprintf (output,"TargetProduct= 0x%04x\n", TargetProduct); + if ( TargetClass ) + fprintf (output,"TargetClass= 0x%02x\n", TargetClass); + if ( strlen(TargetProductList) ) + fprintf (output,"TargetProductList=\"%s\"\n", TargetProductList); + if (StandardEject) + fprintf (output,"\nStandardEject=1\n"); + if (ModeMap & DETACHONLY_MODE) + fprintf (output,"\nDetachStorageOnly=1\n"); + if (ModeMap & HUAWEI_MODE) + fprintf (output,"HuaweiMode=1\n"); + if (ModeMap & HUAWEINEW_MODE) + fprintf (output,"HuaweiNewMode=1\n"); + if (ModeMap & HUAWEIALT_MODE) + fprintf (output,"HuaweiAltMode=1\n"); + if (ModeMap & SIERRA_MODE) + fprintf (output,"SierraMode=1\n"); + if (ModeMap & SONY_MODE) + fprintf (output,"SonyMode=1\n"); + if (ModeMap & QISDA_MODE) + fprintf (output,"QisdaMode=1\n"); + if (ModeMap & QUANTA_MODE) + fprintf (output,"QuantaMode=1\n"); + if (ModeMap & GCT_MODE) + fprintf (output,"GCTMode=1\n"); + if (ModeMap & KOBIL_MODE) + fprintf (output,"KobilMode=1\n"); + if (ModeMap & SEQUANS_MODE) + fprintf (output,"SequansMode=1\n"); + if (ModeMap & MOBILEACTION_MODE) + fprintf (output,"MobileActionMode=1\n"); + if (ModeMap & CISCO_MODE) + fprintf (output,"CiscoMode=1\n"); + if (ModeMap & BLACKBERRY_MODE) + fprintf (output,"BlackberryMode=1\n"); + if (ModeMap & OPTION_MODE) + fprintf (output,"OptionMode=1\n"); + if (ModeMap & PANTECH_MODE) + fprintf (output,"PantechMode=1\n"); + if ( MessageEndpoint ) + fprintf (output,"MessageEndpoint=0x%02x\n", MessageEndpoint); + if ( strlen(MessageContent) ) + fprintf (output,"MessageContent=\"%s\"\n", MessageContent); + if ( strlen(MessageContent2) ) + fprintf (output,"MessageContent2=\"%s\"\n", MessageContent2); + if ( strlen(MessageContent3) ) + fprintf (output,"MessageContent3=\"%s\"\n", MessageContent3); + if ( ResponseEndpoint ) + fprintf (output,"ResponseEndpoint=0x%02x\n", ResponseEndpoint); + if ( Interface > -1 ) + fprintf (output,"Interface=0x%02x\n", Interface); + if ( Configuration > 0 ) + fprintf (output,"Configuration=0x%02x\n", Configuration); + if ( AltSetting > -1 ) + fprintf (output,"AltSetting=0x%02x\n", AltSetting); + if ( CheckSuccess ) + fprintf (output,"Success check enabled, max. wait time %d seconds\n", CheckSuccess); + if ( sysmode ) + fprintf (output,"System integration mode enabled\n"); +} + + +int readArguments(int argc, char **argv) +{ + int c, option_index = 0, count=0; + char *longConfig = NULL; + if (argc==1) + { + printHelp(); + printVersion(); + exit(1); + } + + while (1) + { + c = getopt_long (argc, argv, "hejWQDndKHJSOBEGTNALZUXF:RItv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:f:b:g:", + long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + count++; + switch (c) + { + case 'R': ResetUSB = 1; break; + case 'v': DefaultVendor = strtol(optarg, NULL, 16); break; + case 'p': DefaultProduct = strtol(optarg, NULL, 16); break; + case 'V': TargetVendor = strtol(optarg, NULL, 16); break; + case 'P': TargetProduct = strtol(optarg, NULL, 16); break; + case 'C': TargetClass = strtol(optarg, NULL, 16); break; + case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break; + case 'M': strncpy(MessageContent, optarg, LINE_DIM); break; + case '2': strncpy(MessageContent2, optarg, LINE_DIM); break; + case '3': strncpy(MessageContent3, optarg, LINE_DIM); break; + case 'w': ReleaseDelay = strtol(optarg, NULL, 10); break; + case 'n': break; + case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break; + case 'K': StandardEject = 1; break; + case 'd': ModeMap = ModeMap + DETACHONLY_MODE; break; + case 'H': ModeMap = ModeMap + HUAWEI_MODE; break; + case 'J': ModeMap = ModeMap + HUAWEINEW_MODE; break; + case 'X': ModeMap = ModeMap + HUAWEIALT_MODE; break; + case 'S': ModeMap = ModeMap + SIERRA_MODE; break; + case 'O': ModeMap = ModeMap + SONY_MODE; break;; break; + case 'B': ModeMap = ModeMap + QISDA_MODE; break; + case 'E': ModeMap = ModeMap + QUANTA_MODE; break; + case 'G': ModeMap = ModeMap + GCT_MODE; break; + case 'T': ModeMap = ModeMap + KOBIL_MODE; break; + case 'N': ModeMap = ModeMap + SEQUANS_MODE; break; + case 'A': ModeMap = ModeMap + MOBILEACTION_MODE; break; + case 'L': ModeMap = ModeMap + CISCO_MODE; break; + case 'Z': ModeMap = ModeMap + BLACKBERRY_MODE; break; + case 'U': ModeMap = ModeMap + OPTION_MODE; break; + case 'F': ModeMap = ModeMap + PANTECH_MODE; + PantechMode = strtol(optarg, NULL, 10); break; + case 'c': readConfigFile(optarg); break; + case 't': readConfigFile("stdin"); break; + case 'W': verbose = 1; show_progress = 1; count--; break; + case 'Q': show_progress = 0; verbose = 0; count--; break; + case 'D': sysmode = 1; count--; break; + case 's': CheckSuccess = strtol(optarg, NULL, 10); count--; break; + case 'I': break; + case 'b': busnum = strtol(optarg, NULL, 10); break; + case 'g': devnum = strtol(optarg, NULL, 10); break; + + case 'i': Interface = strtol(optarg, NULL, 16); break; + case 'u': Configuration = strtol(optarg, NULL, 16); break; + case 'a': AltSetting = strtol(optarg, NULL, 16); break; + case 'j': mbim = 1; break; + + case 'f': + longConfig = malloc(strlen(optarg)+5); + strcpy(longConfig,"##\n"); + strcat(longConfig,optarg); + strcat(longConfig,"\n"); + readConfigFile(longConfig); + free(longConfig); + break; + + case 'e': + printVersion(); + exit(0); + break; + case 'h': + printVersion(); + printHelp(); + exit(0); + break; + + default: /* Unsupported - error message has already been printed */ + fprintf (output,"\n"); + printHelp(); + exit(1); + } + } + return count; +} + + +int main(int argc, char **argv) +{ + int ret=0, numDefaults=0, sonySuccess=0, i; + int defaultClass=0, interfaceClass=0, currentConfigVal=0; + struct libusb_device_descriptor descriptor; + enum libusb_error libusbError; + + /* Make sure we have empty strings even if not set by config */ + TargetProductList[0] = '\0'; + MessageContent[0] = '\0'; + MessageContent2[0] = '\0'; + MessageContent3[0] = '\0'; + DefaultProductList[0] = '\0'; + + /* Useful for debugging during boot */ +// output=fopen("/dev/console", "w"); + output=stdout; + + signal(SIGTERM, release_usb_device); + + /* + * Parameter parsing, USB preparation/diagnosis, plausibility checks + */ + + /* Check command arguments, use params instead of config file when given */ + switch (readArguments(argc, argv)) { + case 0: /* no argument or -W, -q or -s */ + break; + default: /* one or more arguments except -W, -q or -s */ + if (!config_read) /* if arguments contain -c, the config file was already processed */ + if (verbose) fprintf(output,"Take all parameters from the command line\n\n"); + } + + if (verbose) { + printVersion(); + printConfig(); + fprintf(output,"\n"); + } + + /* Some validty checks. The default IDs are mandatory */ + if (!(DefaultVendor && DefaultProduct)) { + SHOW_PROGRESS(output,"No default vendor/product ID given. Abort\n\n"); + exit(1); + } + + if (strlen(MessageContent)) { + if (strlen(MessageContent) % 2 != 0) { + fprintf(stderr, "MessageContent hex string has uneven length. Abort\n\n"); + exit(1); + } + if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) { + fprintf(stderr, "MessageContent %s\n is not a hex string. Abort\n\n", + MessageContent); + + exit(1); + } + } + + if (devnum == -1) { + searchMode = SEARCH_DEFAULT; + } else { + SHOW_PROGRESS(output,"Use given bus/device number: %03d/%03d ...\n", busnum, devnum); + searchMode = SEARCH_BUSDEV; + } + + if (show_progress) + if (CheckSuccess && !(TargetVendor || TargetProduct > -1 || TargetProductList[0] != '\0') + && !TargetClass) + + fprintf(output,"Note: No target parameter given; success check limited\n"); + + if (TargetProduct > -1 && TargetProductList[0] == '\0') { + sprintf(TargetProductList,"%04x",TargetProduct); + TargetProduct = -1; + } + + /* libusb initialization */ + if ((libusbError = libusb_init(&ctx)) != LIBUSB_SUCCESS) { + fprintf(stderr, "Error: Failed to initialize libusb. %s (%d)\n\n", + libusb_error_name(libusbError), libusbError); + exit(1); + } + + if (verbose) + libusb_set_debug(ctx, 3); + + if (mbim) { + printf("%d\n", findMBIMConfig(DefaultVendor, DefaultProduct, searchMode) ); + exit(0); + } + + /* Count existing target devices, remember for success check */ + if (searchMode != SEARCH_BUSDEV && (TargetVendor || TargetClass)) { + SHOW_PROGRESS(output,"Look for target devices ...\n"); + search_devices(&targetDeviceCount, TargetVendor, TargetProductList, TargetClass, 0, + SEARCH_TARGET); + + if (targetDeviceCount) { + SHOW_PROGRESS(output," Found devices in target mode or class (%d)\n", targetDeviceCount); + } else + SHOW_PROGRESS(output," No devices in target mode or class found\n"); + } + + /* Count default devices, get the last one found */ + SHOW_PROGRESS(output,"Look for default devices ...\n"); + + sprintf(DefaultProductList,"%04x",DefaultProduct); + dev = search_devices(&numDefaults, DefaultVendor, DefaultProductList, TargetClass, + Configuration, searchMode); + + if (numDefaults) { + SHOW_PROGRESS(output," Found devices in default mode (%d)\n", numDefaults); + } else { + SHOW_PROGRESS(output," No devices in default mode found. Nothing to do. Bye!\n\n"); + close_all(); + exit(0); + } + + if (dev == NULL) { + SHOW_PROGRESS(output," No bus/device match. Is device connected? Abort\n\n"); + close_all(); + exit(0); + } else { + if (devnum == -1) { + devnum = libusb_get_device_address(dev); + busnum = libusb_get_bus_number(dev); + SHOW_PROGRESS(output,"Access device %03d on bus %03d\n", devnum, busnum); + } + libusb_open(dev, &devh); + if (devh == NULL) { + SHOW_PROGRESS(output,"Error opening the device. Abort\n\n"); + abortExit(); + } + } + + /* Get current configuration of default device, note value if Configuration + * parameter is set. Also sets active_config + */ + currentConfigVal = get_current_config_value(dev); + if (Configuration > -1) { + SHOW_PROGRESS(output,"Current configuration number is %d\n", currentConfigVal); + } else + currentConfigVal = 0; + + libusb_get_device_descriptor(dev, &descriptor); + defaultClass = descriptor.bDeviceClass; + if (Interface == -1) + Interface = active_config->interface[0].altsetting[0].bInterfaceNumber; + SHOW_PROGRESS(output,"Use interface number %d\n", Interface); + + /* Get class of default device/interface */ + interfaceClass = get_interface_class(); + + if (interfaceClass == -1) { + fprintf(stderr, "Error: Could not get class of interface %d. Does it exist? Abort\n\n",Interface); + abortExit(); + } else { + SHOW_PROGRESS(output," with class %d\n", interfaceClass); + } + + if (defaultClass == 0 || defaultClass == 0xef) + defaultClass = interfaceClass; + else + if (interfaceClass == LIBUSB_CLASS_MASS_STORAGE && defaultClass != LIBUSB_CLASS_MASS_STORAGE + && defaultClass != LIBUSB_CLASS_VENDOR_SPEC) { + + /* Unexpected default class combined with differing interface class */ + SHOW_PROGRESS(output,"Bogus Class/InterfaceClass: 0x%02x/0x08\n", defaultClass); + defaultClass = 8; + } + + if ((strlen(MessageContent) && strncmp("55534243",MessageContent,8) == 0) + || StandardEject || ModeMap & HUAWEINEW_MODE || ModeMap & HUAWEIALT_MODE + || ModeMap & CISCO_MODE || ModeMap & OPTION_MODE) + if (defaultClass != 8) { + fprintf(stderr, "Error: can't use storage command in MessageContent with interface %d; " + "interface class is %d, expected 8. Abort\n\n", Interface, defaultClass); + abortExit(); + } + + /* Check or get endpoints and alloc message list if needed*/ + if (strlen(MessageContent) || StandardEject || ModeMap & CISCO_MODE + || ModeMap & HUAWEINEW_MODE || ModeMap & HUAWEIALT_MODE + || ModeMap & OPTION_MODE) { + + Messages = (char**) calloc(MSG_DIM, sizeof(char*)); + for (i = 0; i < MSG_DIM; i++) { + Messages[i] = (char*) calloc(LINE_DIM, sizeof(char)); + Messages[i][0] = '\0'; + } + + if (!MessageEndpoint) + MessageEndpoint = find_first_bulk_endpoint(LIBUSB_ENDPOINT_OUT); + if (!ResponseEndpoint) + ResponseEndpoint = find_first_bulk_endpoint(LIBUSB_ENDPOINT_IN); + if (!MessageEndpoint) { + fprintf(stderr,"Error: message endpoint not given or found. Abort\n\n"); + abortExit(); + } + if (!ResponseEndpoint) { + fprintf(stderr,"Error: response endpoint not given or found. Abort\n\n"); + abortExit(); + } + SHOW_PROGRESS(output,"Use endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint, + ResponseEndpoint); + + } + + if (verbose) { + fprintf(output,"\nUSB description data (for identification)\n"); + deviceDescription(); + } + + /* Special modes are exclusive, so check for illegal combinations. + * More than one bit set? + */ + if ( ModeMap & (ModeMap-1) ) { + fprintf(output,"Multiple special modes selected; check configuration. Abort\n\n"); + abortExit(); + } + + if ((strlen(MessageContent) || StandardEject) && ModeMap ) { + MessageContent[0] = '\0'; + StandardEject = 0; + fprintf(output,"Warning: MessageContent/StandardEject ignored; can't combine with special mode\n"); + } + + if (StandardEject && (strlen(MessageContent2) || strlen(MessageContent3))) { + fprintf(output,"Warning: MessageContent2/3 ignored; only one allowed with StandardEject\n"); + } + + if ( !ModeMap && !strlen(MessageContent) && AltSetting == -1 && !Configuration && !StandardEject ) + SHOW_PROGRESS(output,"Warning: no switching method given. See documentation\n"); + + /* + * The switching actions + */ + + if (sysmode) { + openlog("usb_modeswitch", 0, LOG_SYSLOG); + syslog(LOG_NOTICE, "switch device %04x:%04x on %03d/%03d", DefaultVendor, DefaultProduct, + busnum, devnum); + + } + + if (ModeMap & DETACHONLY_MODE) { + SHOW_PROGRESS(output,"Detach storage driver as switching method ...\n"); + ret = detachDrivers(); + if (ret == 2) + SHOW_PROGRESS(output," You may want to remove the storage driver manually\n"); + } + + if(ModeMap & HUAWEI_MODE) { + switchHuaweiMode(); + } + if(ModeMap & SIERRA_MODE) { + switchSierraMode(); + } + if(ModeMap & GCT_MODE) { + detachDrivers(); + switchGCTMode(); + } + if(ModeMap & QISDA_MODE) { + switchQisdaMode(); + } + if(ModeMap & KOBIL_MODE) { + detachDrivers(); + switchKobilMode(); + } + if(ModeMap & QUANTA_MODE) { + switchQuantaMode(); + } + if(ModeMap & SEQUANS_MODE) { + switchSequansMode(); + } + if(ModeMap & MOBILEACTION_MODE) { + switchActionMode(); + } + if(ModeMap & CISCO_MODE) { + detachDrivers(); + switchCiscoMode(); + } + if(ModeMap & BLACKBERRY_MODE) { + detachDrivers(); + switchBlackberryMode(); + } + if(ModeMap & PANTECH_MODE) { + detachDrivers(); + if (PantechMode > 1) + switchPantechMode(); + else + SHOW_PROGRESS(output,"Waiting for auto-switch of Pantech modem ...\n"); + } + if(ModeMap & SONY_MODE) { + if (CheckSuccess) + SHOW_PROGRESS(output,"Note: CheckSuccess ignored; Sony mode does separate checks\n"); + CheckSuccess = 0; /* separate and implied success control */ + sonySuccess = switchSonyMode(); + } + + if (StandardEject) { + SHOW_PROGRESS(output,"Sending standard EJECT sequence\n"); + detachDrivers(); + + strcpy(Messages[0],"5553424387654321000000000000061e000000000000000000000000000000"); + strcpy(Messages[1],"5553424397654321000000000000061b000000020000000000000000000000"); + strcpy(Messages[2],"5553424387654321000000000001061e000000000000000000000000000000"); + strcpy(Messages[3],"5553424397654321000000000001061b000000020000000000000000000000"); + if (MessageContent[0] != '\0') + strcpy(Messages[4], MessageContent); + + switchSendMessage(); + } else if (ModeMap & HUAWEINEW_MODE) { + SHOW_PROGRESS(output,"Using standard Huawei switching message\n"); + detachDrivers(); + strcpy(Messages[0],"55534243123456780000000000000011062000000101000100000000000000"); + switchSendMessage(); + } else if (ModeMap & HUAWEIALT_MODE) { + SHOW_PROGRESS(output,"Using alternative Huawei switching message\n"); + detachDrivers(); + strcpy(Messages[0],"55534243123456780000000000000011063000000000010000000000000000"); + switchSendMessage(); + } else if (ModeMap & OPTION_MODE) { + SHOW_PROGRESS(output,"Using standard Option switching message\n"); + detachDrivers(); + strcpy(Messages[0],"55534243123456780000000000000601000000000000000000000000000000"); + switchSendMessage(); + } else if (strlen(MessageContent)) { + detachDrivers(); + strcpy(Messages[0],MessageContent); + if (MessageContent2[0] != '\0') + strcpy(Messages[1], MessageContent2); + if (MessageContent3[0] != '\0') + strcpy(Messages[2], MessageContent3); + switchSendMessage(); + } + + if (Configuration > 0) { + if (currentConfigVal != Configuration) { + if (switchConfiguration()) { + currentConfigVal = get_current_config_value(dev); + if (currentConfigVal == Configuration) { + SHOW_PROGRESS(output,"The configuration was set successfully\n"); + } else { + SHOW_PROGRESS(output,"Changing the configuration has failed\n"); + } + } + } else { + SHOW_PROGRESS(output,"Target configuration %d already active. Nothing to do. Bye!\n\n", currentConfigVal); + close_all(); + exit(0); + } + } + + if (AltSetting != -1) { + switchAltSetting(); + } + + /* No "removal" check if these are set */ + if ((Configuration > 0 || AltSetting > -1) && !ResetUSB) { + libusb_close(devh); + devh = NULL; + } + + if (ResetUSB) { + resetUSB(); + devh = NULL; + } + + if (searchMode == SEARCH_BUSDEV && sysmode) { + printf("ok:busdev\n"); + close_all(); + exit(0); + } + + if (CheckSuccess) { + if (checkSuccess()) { + if (sysmode) { + if (NoDriverLoading) + printf("ok:\n"); + else + if (TargetProduct < 1) + printf("ok:no_data\n"); + else + printf("ok:%04x:%04x\n", TargetVendor, TargetProduct); + } + } else + if (sysmode) + printf("fail:\n"); + } else { + if (ModeMap & SONY_MODE) + if (sonySuccess) { + if (sysmode) { + syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode"); + printf("ok:\n"); /* ACM device, no driver action */ + } + SHOW_PROGRESS(output,"-> device should be stable now. Bye!\n\n"); + } else { + if (sysmode) + printf("fail:\n"); + SHOW_PROGRESS(output,"-> switching was probably not completed. Bye!\n\n"); + } + else + SHOW_PROGRESS(output,"-> Run lsusb to note any changes. Bye!\n\n"); + } + close_all(); + exit(0); +} + + +/* Get descriptor strings if available (identification details) */ +void deviceDescription () +{ + char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX]; + int ret=0; + char* c; + memset (imanufact, ' ', DESCR_MAX); + memset (iproduct, ' ', DESCR_MAX); + memset (iserial, ' ', DESCR_MAX); + + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(dev, &descriptor); + + int iManufacturer = descriptor.iManufacturer; + int iProduct = descriptor.iProduct; + int iSerialNumber = descriptor.iSerialNumber; + + if (iManufacturer) { + ret = libusb_get_string_descriptor_ascii(devh, iManufacturer, (unsigned char *)imanufact, DESCR_MAX); + if (ret < 0) { + fprintf(stderr, "Error: could not get description string \"manufacturer\"\n"); + strcpy(imanufact, "read error"); + } + } else + strcpy(imanufact, "not provided"); + c = strstr(imanufact, " "); + if (c) + memset((void*)c, '\0', 1); + + if (iProduct) { + ret = libusb_get_string_descriptor_ascii(devh, iProduct, (unsigned char *)iproduct, DESCR_MAX); + if (ret < 0) { + fprintf(stderr, "Error: could not get description string \"product\"\n"); + strcpy(iproduct, "read error"); + } + } else + strcpy(iproduct, "not provided"); + c = strstr(iproduct, " "); + if (c) + memset((void*)c, '\0', 1); + + if (iSerialNumber) { + ret = libusb_get_string_descriptor_ascii(devh, iSerialNumber, (unsigned char *)iserial, DESCR_MAX); + if (ret < 0) { + fprintf(stderr, "Error: could not get description string \"serial number\"\n"); + strcpy(iserial, "read error"); + } + } else + strcpy(iserial, "not provided"); + c = strstr(iserial, " "); + if (c) + memset((void*)c, '\0', 1); + fprintf(output,"-------------------------\n"); + fprintf(output,"Manufacturer: %s\n", imanufact); + fprintf(output," Product: %s\n", iproduct); + fprintf(output," Serial No.: %s\n", iserial); + fprintf(output,"-------------------------\n"); +} + + +/* Auxiliary function used by the wrapper */ +int findMBIMConfig(int vendor, int product, int mode) +{ + struct libusb_device **devs; + int resultConfig=0; + int i=0, j; + + if (libusb_get_device_list(ctx, &devs) < 0) { + perror("Libusb could not access USB. Abort"); + return 0; + } + + SHOW_PROGRESS(output,"Search USB devices ...\n"); + while ((dev = devs[i++]) != NULL) { + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(dev, &descriptor); + + if (mode == SEARCH_BUSDEV) { + if ((libusb_get_bus_number(dev) != busnum) || + (libusb_get_device_address(dev) != devnum)) { + continue; + } else { + if (descriptor.idVendor != vendor) + continue; + if (product != descriptor.idProduct) + continue; + } + } + SHOW_PROGRESS(output,"Found device, search for MBIM configuration...\n"); + + // No check if there is only one configuration + if (descriptor.bNumConfigurations < 2) + return -1; + + // Checking all interfaces of all configurations + for (j=0; j<descriptor.bNumConfigurations; j++) { + struct libusb_config_descriptor *config; + + libusb_get_config_descriptor(dev, j, &config); + resultConfig = config->bConfigurationValue; + for (i=0; i<config->bNumInterfaces; i++) { + if ( config->interface[i].altsetting[0].bInterfaceClass == 2 ) + if ( config->interface[i].altsetting[0].bInterfaceSubClass == 0x0e ) { + // found MBIM interface in this configuration + libusb_free_config_descriptor(config); + return resultConfig; + } + } + libusb_free_config_descriptor(config); + } + return -1; + } + return 0; +} + + +void resetUSB () +{ + int success; + int bpoint = 0; + + if (!devh) { + fprintf(output,"Device handle empty, skip USB reset\n"); + return; + } + if (show_progress) { + fprintf(output,"Reset USB device "); + fflush(output); + } + sleep( 1 ); + do { + success = libusb_reset_device(devh); + if ( ((bpoint % 10) == 0) && show_progress ) { + fprintf(output,"."); + fflush(output); + } + bpoint++; + if (bpoint > 100) { + SHOW_PROGRESS(output," Reset USB device failed with error %d", success); + fprintf(stderr,"Reset USB device failed with error %d", success); + success = 1; + } + } while (success < 0); + + if ( success == 0 ) + SHOW_PROGRESS(output,"\n Device was reset\n"); +} + + +int switchSendMessage () +{ + const char* cmdHead = "55534243"; + int ret, i; + int retries = 1; +/* char* msg[3]; + msg[0] = MessageContent; + msg[1] = MessageContent2; + msg[2] = MessageContent3; +*/ + SHOW_PROGRESS(output,"Set up interface %d\n", Interface); + ret = libusb_claim_interface(devh, Interface); + if (ret != 0) { + SHOW_PROGRESS(output," Could not claim interface (error %d). Skip message sending\n", ret); + return 0; + } + + SHOW_PROGRESS(output,"Use endpoint 0x%02x for message sending ...\n", MessageEndpoint); + if (show_progress) + fflush(stdout); + +retry: + for (i=0; i<MSG_DIM; i++) { + if ( strlen(Messages[i]) == 0) + break; + + if ( sendMessage(Messages[i], i+1) ) + goto skip; + + if ( strstr(Messages[i],cmdHead) != NULL ) { + // UFI command + SHOW_PROGRESS(output,"Read the response to message %d (CSW) ...\n", i+1); + ret = read_bulk(ResponseEndpoint, ByteString, 13); + if (ret >= 0) { + SHOW_PROGRESS(output,", status %d",ByteString[12]); + } + } /* else { + // Other bulk transfer + SHOW_PROGRESS(output,"Read the response to message %d ...\n", i+1); + ret = read_bulk(ResponseEndpoint, ByteString, strlen(Messages[i])/2 ); + }*/ + SHOW_PROGRESS(output,"\n"); + if (ret == LIBUSB_TRANSFER_STALL && retries--) { + SHOW_PROGRESS(output,"Endpoint stalled. Resetting ...\n"); + libusb_clear_halt(devh, MessageEndpoint); + goto retry; + } + if (ret < 0) + goto skip; + } + + SHOW_PROGRESS(output,"Reset response endpoint 0x%02x\n", ResponseEndpoint); + ret = libusb_clear_halt(devh, ResponseEndpoint); + if (ret) + SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret); + SHOW_PROGRESS(output,"Reset message endpoint 0x%02x\n", MessageEndpoint); + ret = libusb_clear_halt(devh, MessageEndpoint); + if (ret) + SHOW_PROGRESS(output," Could not reset endpoint (probably harmless): %d\n", ret); + usleep(50000); + + if (ReleaseDelay) { + SHOW_PROGRESS(output,"Wait for %d ms before releasing interface ...\n", ReleaseDelay); + usleep(ReleaseDelay*1000); + } + ret = libusb_release_interface(devh, Interface); + if (ret) + goto skip; + return 1; + +skip: + SHOW_PROGRESS(output," Device is gone, skip any further commands\n"); + libusb_close(devh); + devh = NULL; + return 2; +} + + +int switchConfiguration () +{ + int ret; + + SHOW_PROGRESS(output,"Change configuration to %i ...\n", Configuration); + detachDrivers(); +// ret = libusb_set_configuration(devh, -1); + ret = libusb_set_configuration(devh, 0); + if (ret < 0) { + SHOW_PROGRESS(output," Resetting the configuration failed (error %d). Try to continue\n", ret); + } else { + SHOW_PROGRESS(output," Configuration was reset\n"); + } + /* Empirically tested wait period, improves reliability of configuration change */ + usleep(100000); + ret = libusb_set_configuration(devh, Configuration); + if (ret < 0) { + SHOW_PROGRESS(output," Changing the configuration failed (error %d). Try to continue\n", ret); + return 0; + } else { + SHOW_PROGRESS(output," OK, configuration set\n"); + return 1; + } +} + + +int switchAltSetting () +{ + int ret; + SHOW_PROGRESS(output,"Change to alt setting %i ...\n", AltSetting); + ret = libusb_claim_interface(devh, Interface); + if (ret < 0) { + SHOW_PROGRESS(output," Could not claim interface (error %d). Skip AltSetting\n", ret); + return 0; + } + ret = libusb_set_interface_alt_setting(devh, Interface, AltSetting); + libusb_release_interface(devh, Interface); + if (ret < 0) { + SHOW_PROGRESS(output," Change to alt setting returned error %d. Try to continue\n", ret); + return 0; + } else + return 1; +} + + +void switchHuaweiMode () +{ + int ret; + SHOW_PROGRESS(output,"Send old Huawei control message ...\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + LIBUSB_REQUEST_SET_FEATURE, 00000001, 0, buffer, 0, 1000); + + if (ret != 0) { + fprintf(stderr, "Error: Huawei control message failed (error %d). Abort\n\n", ret); + exit(0); + } +} + + +void switchSierraMode () +{ + int ret; + SHOW_PROGRESS(output,"Send Sierra control message\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + LIBUSB_REQUEST_SET_INTERFACE, 00000001, 0, buffer, 0, 1000); + if (ret == LIBUSB_ERROR_PIPE) { + SHOW_PROGRESS(output," communication with device stopped. May have switched modes anyway\n"); + return; + } + if (ret < 0) { + fprintf(stderr, "Error: Sierra control message failed (error %d). Abort\n\n", ret); + exit(0); + } +} + + +void switchGCTMode () +{ + int ret; + ret = libusb_claim_interface(devh, Interface); + if (ret != 0) { + SHOW_PROGRESS(output," Could not claim interface (error %d). Skip GCT sequence\n", ret); + return; + } + SHOW_PROGRESS(output,"Send GCT control message 1 ...\n type (should be 161/0xA1): %d", + LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN); + + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, + 0xa0, 0, Interface, buffer, 1, 1000); + + if (ret < 0) { + SHOW_PROGRESS(output," GCT control message 1 failed (error %d), continue anyway ...\n", ret); + } + SHOW_PROGRESS(output,"Send GCT control message 2 ...\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, + 0xfe, 0, Interface, buffer, 1, 1000); + + if (ret < 0) { + SHOW_PROGRESS(output," GCT control message 2 failed (error %d). Abort\n\n", ret); + } + libusb_release_interface(devh, Interface); + if (ret < 0) + exit(0); +} + + +void switchKobilMode() { + int ret; + SHOW_PROGRESS(output,"Send Kobil control message ...\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, + 0x88, 0, 0, buffer, 8, 1000); + + if (ret < 0) { + fprintf(stderr, "Error: Kobil control message failed (error %d). Abort\n\n", ret); + exit(0); + } +} + + +void switchQisdaMode () { + int ret; + SHOW_PROGRESS(output,"Sending Qisda control message ...\n"); + memcpy(buffer, "\x05\x8c\x04\x08\xa0\xee\x20\x00\x5c\x01\x04\x08\x98\xcd\xea\xbf", 16); + ret = libusb_control_transfer(devh, 0x40, 0x04, 0, 0, buffer, 16, 1000); + if (ret < 0) { + fprintf(stderr, "Error: Qisda control message failed (error %d). Abort\n\n", ret); + exit(0); + } +} + + +void switchQuantaMode() { + int ret; + SHOW_PROGRESS(output,"Send Quanta control message ...\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, + 0xff, 0, 0, buffer, 0, 1000); + + if (ret < 0) { + SHOW_PROGRESS(output,"Error: Quanta control message failed (error %d). Abort\n\n", ret); + exit(0); + } +} + + +void switchBlackberryMode () +{ + int ret; + SHOW_PROGRESS(output,"Send Blackberry control message 1 ...\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, + 0xb1, 0x0000, 0, buffer, 8, 1000); + + if (ret != 8) { + fprintf(stderr, "Error: Blackberry control message 1 failed (result %d)\n", ret); + } + SHOW_PROGRESS(output,"Send Blackberry control message 2 ...\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, + 0xa9, 0x000e, 0, buffer, 2, 1000); + + if (ret != 2) { + fprintf(stderr, "Error: Blackberry control message 2 failed (result %d). Abort\n\n", ret); + exit(0); + } +} + + +void switchPantechMode() +{ + int ret; + SHOW_PROGRESS(output,"Send Pantech control message, wValue %d ...\n", PantechMode); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + 0x70, PantechMode, 0, buffer, 0, 1000); + + if (ret < 0) { + SHOW_PROGRESS(output," Error: Pantech control message failed (error %d). Abort\n\n", ret); + exit(0); + } +} + + +#define EP_OUT 0x02 +#define EP_IN 0x81 +#define SIZE 0x08 + +#define MOBILE_ACTION_READLOOP1 63 +#define MOBILE_ACTION_READLOOP2 73 + +/* The code here is statically derived from sniffing (and confirmed working). + * However, I bet it could be simplified significantly. + */ + +void switchActionMode () +{ + int ret, i; + SHOW_PROGRESS(output,"Send MobileAction control sequence ...\n"); + memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE); + libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, + 0x09, 0x0300, 0, buffer, SIZE, 1000); + + memcpy(buffer, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE); + libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, + 0x09, 0x0300, 0, buffer, SIZE, 1000); + + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE); + usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000); + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE); + usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000); + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE); + usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000); + for (i=0; i < MOBILE_ACTION_READLOOP1; i++) { + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + } + memcpy(buffer, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE); + usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000); + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + memcpy(buffer, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE); + usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000); + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + memcpy(buffer, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE); + usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000); + for (i=0; i < MOBILE_ACTION_READLOOP2; i++) { + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + } + memcpy(buffer, "\x33\x04\xfe\x00\xf4\x6c\x1f\xf0", SIZE); + usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000); + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + memcpy(buffer, "\x32\x07\xfe\xf0\x29\xb9\x3a\xf0", SIZE); + ret = usb_interrupt_io(devh, EP_OUT, buffer, SIZE, 1000); + usb_interrupt_io(devh, EP_IN, buffer, SIZE, 1000); + if (ret < 0) { + SHOW_PROGRESS(output," MobileAction control sequence did not complete\n" + " Last error was %d\n",ret); + } else { + SHOW_PROGRESS(output," MobileAction control sequence complete\n"); + } +} + + +#define SQN_SET_DEVICE_MODE_REQUEST 0x0b +#define SQN_GET_DEVICE_MODE_REQUEST 0x0a + +#define SQN_DEFAULT_DEVICE_MODE 0x00 +#define SQN_MASS_STORAGE_MODE 0x01 +#define SQN_CUSTOM_DEVICE_MODE 0x02 + +void switchSequansMode() +{ + + int ret; + SHOW_PROGRESS(output,"Send Sequans control message\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE + | LIBUSB_ENDPOINT_OUT, SQN_SET_DEVICE_MODE_REQUEST, SQN_CUSTOM_DEVICE_MODE, + 0, buffer, 0, 1000); + + if (ret < 0) { + fprintf(stderr, "Error: Sequans request failed (error %d). Abort\n\n", ret); + exit(0); + } +} + + +void switchCiscoMode() +{ + int ret, i, j; + + strcpy(Messages[0],"55534243f83bcd810002000080000afd000000030000000100000000000000"); + strcpy(Messages[1],"55534243984300820002000080000afd000000070000000100000000000000"); + strcpy(Messages[2],"55534243984300820000000000000afd000100071000000000000000000000"); + strcpy(Messages[3],"55534243984300820002000080000afd000200230000000100000000000000"); + strcpy(Messages[4],"55534243984300820000000000000afd000300238200000000000000000000"); + strcpy(Messages[5],"55534243984300820002000080000afd000200260000000100000000000000"); + strcpy(Messages[6],"55534243984300820000000000000afd00030026c800000000000000000000"); + strcpy(Messages[7],"55534243d84c04820002000080000afd000010730000000100000000000000"); + strcpy(Messages[8],"55534243d84c04820002000080000afd000200240000000100000000000000"); + strcpy(Messages[9],"55534243d84c04820000000000000afd000300241300000000000000000000"); + strcpy(Messages[10],"55534243d84c04820000000000000afd000110732400000000000000000000"); + + SHOW_PROGRESS(output,"Set up Cisco interface %d\n", Interface); + ret = libusb_claim_interface(devh, Interface); + if (ret < 0) { + SHOW_PROGRESS(output," Could not claim interface (error %d). Abort\n", ret); + abortExit(); + } + if (show_progress) + fflush(output); + +// ret = read_bulk(ResponseEndpoint, ByteString, 13); +// SHOW_PROGRESS(output," Extra response (CSW) read, result %d\n",ret); + + for (i=0; i<11; i++) { + if ( sendMessage(Messages[i], i+1) ) + goto skip; + + for (j=1; j<4; j++) { + + SHOW_PROGRESS(output," Read the CSW for bulk message %d (attempt %d) ...\n",i+1,j); + ret = read_bulk(ResponseEndpoint, ByteString, 13); + SHOW_PROGRESS(output,"\n"); + + if (ret < 0) + goto skip; + if (ret == 13) + break; + } + } + libusb_clear_halt(devh, MessageEndpoint); + libusb_clear_halt(devh, ResponseEndpoint); + + ReleaseDelay = 2000; + SHOW_PROGRESS(output,"Wait for %d ms before releasing interface ...\n", ReleaseDelay); + usleep(ReleaseDelay*1000); + + ret = libusb_release_interface(devh, Interface); + if (ret < 0) + goto skip; + return; + +skip: + SHOW_PROGRESS(output,"Device returned error %d, skip further commands\n", ret); + libusb_close(devh); + devh = NULL; +} + + +int switchSonyMode () +{ + int ret, i, found; + detachDrivers(); + + if (CheckSuccess) { + CheckSuccess = 0; + } + + SHOW_PROGRESS(output,"Send Sony control message\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE + | LIBUSB_ENDPOINT_IN, 0x11, 2, 0, buffer, 3, 100); + + if (ret < 0) { + fprintf(stderr, "Error: Sony control message failed (error %d). Abort\n\n", ret); + exit(0); + } else + SHOW_PROGRESS(output," OK, control message sent, wait for device to return ...\n"); + + libusb_close(devh); + devh = NULL; + + /* Now waiting for the device to reappear */ + devnum=-1; + busnum=-1; + i=0; + dev = 0; + while ( dev == 0 && i < 30 ) { + if ( i > 5 ) { + dev = search_devices(&found, DefaultVendor, DefaultProductList, TargetClass, + 0, SEARCH_TARGET); + } + if ( dev != 0 ) + break; + sleep(1); + if (show_progress) { + fprintf(output,"#"); + fflush(stdout); + } + i++; + } + SHOW_PROGRESS(output,"\n After %d seconds:",i); + if ( dev ) { + SHOW_PROGRESS(output," device came back, proceed\n"); + libusb_open(dev, &devh); + if (devh == 0) { + fprintf(stderr, "Error: could not get handle on device\n"); + return 0; + } + } else { + SHOW_PROGRESS(output," device still gone, abort\n"); + return 0; + } + sleep(1); + + SHOW_PROGRESS(output,"Send Sony control message again ...\n"); + ret = libusb_control_transfer(devh, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE + | LIBUSB_ENDPOINT_IN, 0x11, 2, 0, buffer, 3, 100); + + if (ret < 0) { + fprintf(stderr, "Error: Sony control message (2) failed (error %d)\n", ret); + return 0; + } + SHOW_PROGRESS(output," OK, control message sent\n"); + return 1; +} + + +/* Detach driver + */ +int detachDrivers() +{ + int i, ret; + SHOW_PROGRESS(output,"Looking for active drivers ...\n"); + ret = libusb_kernel_driver_active(devh, 0); + if (ret == LIBUSB_ERROR_NOT_SUPPORTED) { + fprintf(output," Can't do driver detection on this platform.\n"); + return 2; + } + + struct libusb_config_descriptor *config; + libusb_get_active_config_descriptor(dev, &config); + + for (i=0; i<config->bNumInterfaces; i++) { + ret = libusb_kernel_driver_active(devh, i); + if (ret < 0) { + SHOW_PROGRESS(output," Failed to check driver status for interface %d (error %d)\n Try to continue\n",i,ret); + continue; + } + if (ret) { + ret = libusb_detach_kernel_driver(devh, i); + if (ret == LIBUSB_ERROR_NOT_SUPPORTED) { + fprintf(output," Can't do driver detaching on this platform.\n"); + return 2; + } + if (ret == 0) { + SHOW_PROGRESS(output," OK, driver detached\n"); + } else { + SHOW_PROGRESS(output," Driver detach failed for interface %d (error %d).\n Try to continue\n",i,ret); + continue; + } + } + } + libusb_free_config_descriptor(config); + return 1; +} + + +int sendMessage(char* message, int count) +{ + int ret, message_length; + + if (strlen(message) % 2 != 0) { + fprintf(stderr, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count); + return 1; + } + message_length = strlen(message) / 2; + if ( hexstr2bin(message, ByteString, message_length) == -1) { + fprintf(stderr, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n", + count, MessageContent); + + return 1; + } + SHOW_PROGRESS(output,"Trying to send message %d to endpoint 0x%02x ...\n", count, MessageEndpoint); + fflush(output); + ret = write_bulk(MessageEndpoint, ByteString, message_length); + if (ret == LIBUSB_ERROR_NO_DEVICE) + return 1; + + return 0; +} + + +int checkSuccess() +{ + int ret, i; + int newTargetCount, success=0; + + SHOW_PROGRESS(output,"\nCheck for mode switch (max. %d times, once per second) ...\n", CheckSuccess); + sleep(1); + + /* If target parameters are given, don't check for vanished device + * Changed for Cisco AM10 where a new device is added while the install + * storage device stays active + */ + if ((TargetVendor || TargetClass) && devh) { + libusb_close(devh); + devh = NULL; + } + + /* if target ID is not given but target class is, assign default as target; + * it will be needed for sysmode output + */ + if (!TargetVendor && TargetClass) { + TargetVendor = DefaultVendor; + TargetProduct = DefaultProduct; + } + + /* devh is 0 if device vanished during command transmission or if target params were given + */ + if (devh) + for (i=0; i < CheckSuccess; i++) { + + /* Test if default device still can be accessed; positive result does + * not necessarily mean failure + */ + SHOW_PROGRESS(output," Wait for original device to vanish ...\n"); + + ret = libusb_claim_interface(devh, Interface); + libusb_release_interface(devh, Interface); + if (ret < 0) { + SHOW_PROGRESS(output," Original device can't be accessed anymore. Good.\n"); + libusb_close(devh); + devh = NULL; + break; + } + if (i == CheckSuccess-1) { + SHOW_PROGRESS(output," Original device still present after the timeout\n\n" + "Mode switch most likely failed. Bye!\n\n"); + } else + sleep(1); + } + + if ( TargetVendor && (TargetProduct > -1 || TargetProductList[0] != '\0') ) { + + /* Recount target devices (compare with previous count) if target data is given. + * Target device on the same bus with higher device number is returned, + * description is read for syslog message + */ + // Wait counter passed on from previous loop + for (i=i; i < CheckSuccess; i++) { + SHOW_PROGRESS(output," Search for target devices ...\n"); + dev = search_devices(&newTargetCount, TargetVendor, TargetProductList, + TargetClass, 0, SEARCH_TARGET); + + if (dev && (newTargetCount > targetDeviceCount)) { + if (verbose) { + libusb_open(dev, &devh); + fprintf(output,"\nFound target device %03d on bus %03d\n", + libusb_get_device_address(dev), libusb_get_bus_number(dev)); + + fprintf(output,"\nTarget device description data\n"); + deviceDescription(); + libusb_close(devh); + devh = NULL; + } + SHOW_PROGRESS(output," Found correct target device\n\n" + "Mode switch succeeded. Bye!\n\n"); + + success = 2; + break; + } + if (i == CheckSuccess-1) { + SHOW_PROGRESS(output," No new devices in target mode or class found\n\n" + "Mode switch has failed. Bye!\n\n"); + } else + sleep(1); + } + } else + /* No target data given, rely on the vanished device */ + if (!devh) { + SHOW_PROGRESS(output," (For a better success check provide target IDs or class)\n"); + SHOW_PROGRESS(output," Original device vanished after switching\n\n" + "Mode switch most likely succeeded. Bye!\n\n"); + success = 1; + } + + switch (success) { + case 2: + if (sysmode) + syslog(LOG_NOTICE, "switched to %04x:%04x on %03d/%03d", TargetVendor, + TargetProduct, busnum, devnum); + + success = 1; + break; + case 1: + if (sysmode) + syslog(LOG_NOTICE, "device seems to have switched"); + default: + ; + } + if (sysmode) + closelog(); + + return success; + +} + + +int write_bulk(int endpoint, unsigned char *message, int length) +{ + int ret = usb_bulk_io(devh, endpoint, message, length, 3000); + if (ret >= 0 ) { + SHOW_PROGRESS(output," OK, message successfully sent\n"); + } else + if (ret == LIBUSB_ERROR_NO_DEVICE) { + SHOW_PROGRESS(output," Device seems to have vanished right after sending. Good.\n"); + } else + SHOW_PROGRESS(output," Sending the message returned error %d. Try to continue\n", ret); + return ret; +} + + +int read_bulk(int endpoint, unsigned char *buffer, int length) +{ + int ret = usb_bulk_io(devh, endpoint, buffer, length, 3000); + if (ret >= 0 ) { + SHOW_PROGRESS(output," Response successfully read (%d bytes)", ret); + } else + if (ret == LIBUSB_ERROR_NO_DEVICE) { + SHOW_PROGRESS(output," Device seems to have vanished after reading. Good."); + } else + SHOW_PROGRESS(output," Response reading failed (error %d)", ret); + return ret; +} + + +void release_usb_device(int __attribute__((unused)) placeholder) +{ + SHOW_PROGRESS(output,"Program cancelled by system. Bye!\n\n"); + if (devh) + libusb_release_interface(devh, Interface); + close_all(); + exit(0); +} + + +/* Iterates over buses and devices, counts the ones which match the given + * parameters and returns the last one of them +*/ +struct libusb_device* search_devices( int *numFound, int vendor, char* productList, + int targetClass, int configuration, int mode) +{ + char *listcopy=NULL, *token; + unsigned char buffer[2]; + int devClass, product; + struct libusb_device* right_dev = NULL; + struct libusb_device **devs; + int i=0; + + /* only target class given, target vendor and product assumed unchanged */ + if ( targetClass && !(vendor || strlen(productList)) ) { + vendor = DefaultVendor; + productList = DefaultProductList; + } + *numFound = 0; + + /* Validity check */ + if (!vendor || *productList == '\0') + return NULL; + + listcopy = malloc(strlen(productList)+1); + + if (libusb_get_device_list(ctx, &devs) < 0) { + perror("Libusb failed to get USB access!"); + return 0; + } + + while ((dev = devs[i++]) != NULL) { + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(dev, &descriptor); + + if (mode == SEARCH_BUSDEV) { + if ((libusb_get_bus_number(dev) != busnum) || + (libusb_get_device_address(dev) != devnum)) + continue; + else + SHOW_PROGRESS(output," bus/device number matched\n"); + } + + if (verbose) + fprintf (output," found USB ID %04x:%04x\n", + descriptor.idVendor, descriptor.idProduct); + if (descriptor.idVendor != vendor) + continue; + if (verbose) + fprintf (output," vendor ID matched\n"); + + strcpy(listcopy, productList); + token = strtok(listcopy, ","); + while (token != NULL) { + if (strlen(token) != 4) { + SHOW_PROGRESS(output,"Error: entry in product ID list has wrong length: %s. " + "Ignored\n", token); + + goto NextToken; + } + if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) { + SHOW_PROGRESS(output,"Error: entry in product ID list is not a hex string: %s. " + "Ignored\n", token); + + goto NextToken; + } + product = 0; + product += (unsigned char)buffer[0]; + product <<= 8; + product += (unsigned char)buffer[1]; + if (product == descriptor.idProduct) { + if (verbose) + fprintf(output," product ID matched\n"); + + if (targetClass != 0) { + /* TargetClass is set, check class of first interface */ + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(dev, &descriptor); + devClass = descriptor.bDeviceClass; + struct libusb_config_descriptor *config; + libusb_get_config_descriptor(dev, 0, &config); + int ifaceClass = config->interface[0].altsetting[0].bInterfaceClass; + libusb_free_config_descriptor(config); + if (devClass == 0) + devClass = ifaceClass; + else + /* Check for some quirky devices */ + if (devClass != ifaceClass) + devClass = ifaceClass; + if (devClass == targetClass) { + if (verbose) + fprintf (output," target class %02x matches\n", targetClass); + if (mode == SEARCH_TARGET) { + (*numFound)++; + right_dev = dev; + if (verbose) + fprintf (output," count device\n"); + } else + if (verbose) + fprintf (output," device not counted, target class reached\n"); + } else { + if (verbose) + fprintf (output," device class %02x not matching target\n", devClass); + if (mode == SEARCH_DEFAULT || mode == SEARCH_BUSDEV) { + (*numFound)++; + right_dev = dev; + if (verbose) + fprintf (output," count device\n"); + } + } + } else { + /* Neither TargetClass nor Configuration are set */ + (*numFound)++; + right_dev = dev; + if (mode == SEARCH_BUSDEV) + break; + } + } + + NextToken: + token = strtok(NULL, ","); + } + } + if (listcopy != NULL) + free(listcopy); + return right_dev; +} + + +/* Autodetect bulk endpoints (ab) */ + +int find_first_bulk_endpoint(int direction) +{ + int i, j; + const struct libusb_interface_descriptor *alt; + const struct libusb_endpoint_descriptor *ep; + + for (j=0; j < active_config->bNumInterfaces; j++) { + alt = &(active_config->interface[j].altsetting[0]); + if (alt->bInterfaceNumber == Interface) { + for (i=0; i < alt->bNumEndpoints; i++) { + ep = &(alt->endpoint[i]); + if ( ( (ep->bmAttributes & LIBUSB_ENDPOINT_ADDRESS_MASK) == LIBUSB_TRANSFER_TYPE_BULK) + && ( (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == direction ) ) { + + return ep->bEndpointAddress; + } + } + } + } + return 0; +} + + +int get_current_config_value() +{ + SHOW_PROGRESS(output,"Get the current device configuration ...\n"); + if (active_config != NULL) { + libusb_free_config_descriptor(active_config); + active_config = NULL; + } + int ret = libusb_get_active_config_descriptor(dev, &active_config); + if (ret < 0) { + SHOW_PROGRESS(output," Determining the active configuration failed (error %d). Abort\n", ret); + abortExit(); + } + return active_config->bConfigurationValue; +} + + +int get_interface_class() +{ + int i; + for (i=0; i < active_config->bNumInterfaces; i++) { + if (active_config->interface[i].altsetting[0].bInterfaceNumber == Interface) + return active_config->interface[i].altsetting[0].bInterfaceClass; + } + return -1; +} + + +/* Parameter parsing */ + +char* ReadParseParam(const char* FileName, char *VariableName) +{ + static int numLines = 0; + static char* ConfigBuffer[MAXLINES]; + char *VarName, *Comment=NULL, *Equal=NULL; + char *FirstQuote, *LastQuote, *P1, *P2; + int Line=0; + unsigned Len=0, Pos=0; + static char Str[LINE_DIM]; + char *token, *configPos; + FILE *file = NULL; + + // Reading and storing input during the first call + if (numLines==0) { + if (strncmp(FileName,"##",2) == 0) { + if (verbose) fprintf(output,"\nRead long config from command line\n"); + // "Embedded" configuration data + configPos = (char*)FileName; + token = strtok(configPos, "\n"); + strncpy(Str,token,LINE_DIM-1); + } else { + if (strcmp(FileName, "stdin")==0) { + if (verbose) fprintf(output,"\nRead long config from stdin\n"); + file = stdin; + } else { + if (verbose) fprintf(output,"\nRead config file: %s\n", FileName); + file=fopen(FileName, "r"); + } + if (file==NULL) { + fprintf(stderr, "Error: Could not find file %s. Abort\n\n", FileName); + abortExit(); + } else { + token = fgets(Str, LINE_DIM-1, file); + } + } + while (token != NULL && numLines < MAXLINES) { + Len=strlen(Str); + if (Len==0) + goto NextLine; + if (Str[Len-1]=='\n' or Str[Len-1]=='\r') + Str[--Len]='\0'; + Equal = strchr (Str, '='); // search for equal sign + Pos = strcspn (Str, ";#!"); // search for comment + Comment = (Pos==Len) ? NULL : Str+Pos; + if (Equal==NULL or ( Comment!=NULL and Comment<=Equal)) + goto NextLine; // Comment or irrelevant, don't save + Len=strlen(Str)+1; + ConfigBuffer[numLines] = malloc(Len*sizeof(char)); + strcpy(ConfigBuffer[numLines],Str); + numLines++; + NextLine: + if (file == NULL) { + token = strtok(NULL, "\n"); + if (token != NULL) + strncpy(Str,token,LINE_DIM-1); + } else + token = fgets(Str, LINE_DIM-1, file); + } + if (file != NULL) + fclose(file); + } + + // Now checking for parameters + Line=0; + while (Line < numLines) { + strcpy(Str,ConfigBuffer[Line]); + Equal = strchr (Str, '='); // search for equal sign + *Equal++ = '\0'; + + // String + FirstQuote=strchr (Equal, '"'); // search for double quote char + LastQuote=strrchr (Equal, '"'); + if (FirstQuote!=NULL) { + if (LastQuote==NULL) { + fprintf(stderr, "Error reading parameters from file %s - " + "Missing end quote:\n%s\n", FileName, Str); + + goto Next; + } + *FirstQuote=*LastQuote='\0'; + Equal=FirstQuote+1; + } + + // removes leading/trailing spaces + Pos=strspn (Str, " \t"); + if (Pos==strlen(Str)) { + fprintf(stderr, "Error reading parameters from file %s - " + "Missing variable name:\n%s\n", FileName, Str); + + goto Next; + } + while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL) + if (P1!=NULL) *P1='\0'; + else if (P2!=NULL) *P2='\0'; + VarName=Str+Pos; + + Pos=strspn (Equal, " \t"); + if (Pos==strlen(Equal)) { + fprintf(stderr, "Error reading parameter from file %s - " + "Missing value:\n%s\n", FileName, Str); + + goto Next; + } + Equal+=Pos; + + if (strcmp(VarName, VariableName)==0) { // Found it + return Equal; + } + Next: + Line++; + } + + return NULL; +} + + +int hex2num(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + + +int hex2byte(const char *hex) +{ + int a, b; + a = hex2num(*hex++); + if (a < 0) + return -1; + b = hex2num(*hex++); + if (b < 0) + return -1; + return (a << 4) | b; +} + + +int hexstr2bin(const char *hex, unsigned char *buffer, int len) +{ + int i; + int a; + const char *ipos = hex; + unsigned char *opos = buffer; + + for (i = 0; i < len; i++) { + a = hex2byte(ipos); + if (a < 0) + return -1; + *opos++ = (unsigned char) a; + ipos += 2; + } + return 0; +} + + +void close_all() +{ + int i; + if (Messages) { + for ( i = 0; i < MSG_DIM; i++ ) { + free(Messages[i]); + } + free(Messages); + } + if (active_config) + libusb_free_config_descriptor(active_config); + if (devh) + libusb_close(devh); + // libusb_exit will crash on Raspbian 7, crude protection +#ifndef __ARMEL__ + if (ctx) + libusb_exit(NULL); +#endif + if (sysmode) + closelog(); +} + + +void abortExit() +{ + fflush(output); + fflush(stderr); + close_all(); + exit(1); +} + + +void printVersion() +{ + char* version = VERSION; + fprintf(output,"\n * usb_modeswitch: handle USB devices with multiple modes\n" + " * Version %s (C) Josua Dietze 2017\n" + " * Based on libusb1/libusbx\n\n" + " ! PLEASE REPORT NEW CONFIGURATIONS !\n\n", version); +} + + +void printHelp() +{ + fprintf(output,"\nUsage: usb_modeswitch [<params>] [-c filename]\n\n" + " -h, --help this help\n" + " -e, --version print version information and exit\n" + " -j, --find-mbim return config no. with MBIM interface, exit\n\n" + " -v, --default-vendor NUM vendor ID of original mode (mandatory)\n" + " -p, --default-product NUM product ID of original mode (mandatory)\n" + " -V, --target-vendor NUM target mode vendor ID (optional)\n" + " -P, --target-product NUM target mode product ID (optional)\n" + " -C, --target-class NUM target mode device class (optional)\n" + " -b, --bus-num NUM system bus number of device (for hard ID)\n" + " -g, --device-num NUM system device number (for hard ID)\n" + " -m, --message-endpoint NUM direct the message transfer there (optional)\n" + " -M, --message-content <msg> message to send (hex number as string)\n" + " -2, --message-content2 <msg>\n" + " -3, --message-content3 <msg> additional messages to send if needed\n" + " -w, --release-delay <msecs> wait a while before releasing the interface\n" + " -n, --need-response obsolete, no effect (always on)\n" + " -r, --response-endpoint NUM read response from there (optional)\n" + " -K, --std-eject send standard EJECT sequence\n" + " -d, --detach-only detach the active driver, no further action\n" + " -H, --huawei-mode apply a special procedure\n" + " -J, --huawei-new-mode apply a special procedure\n" + " -X, --huawei-alt-mode apply a special procedure\n" + " -S, --sierra-mode apply a special procedure\n" + " -O, --sony-mode apply a special procedure\n" + " -G, --gct-mode apply a special procedure\n" + " -N, --sequans-mode apply a special procedure\n" + " -A, --mobileaction-mode apply a special procedure\n" + " -T, --kobil-mode apply a special procedure\n" + " -L, --cisco-mode apply a special procedure\n" + " -B, --qisda-mode apply a special procedure\n" + " -E, --quanta-mode apply a special procedure\n" + " -F, --pantech-mode NUM apply a special procedure, pass NUM through\n" + " -Z, --blackberry-mode apply a special procedure\n" + " -U, --option-mode apply a special procedure\n" + " -R, --reset-usb reset the device after all other actions\n" + " -Q, --quiet don't show progress or error messages\n" + " -W, --verbose print all settings and debug output\n" + " -D, --sysmode specific result and syslog message\n" + " -s, --check-success <seconds> check switching result, with timeout\n" + " -I, --inquire obsolete, no effect\n\n" + " -c, --config-file <filename> load long configuration from file\n\n" + " -t, --stdinput read long configuration from stdin\n\n" + " -f, --long-config <text> get long configuration from string\n\n" + " -i, --interface NUM select initial USB interface (default 0)\n" + " -u, --configuration NUM select USB configuration\n" + " -a, --altsetting NUM select alternative USB interface setting\n\n"); +} diff --git a/emulator/usbpt/bluetooth/usb_modeswitch/usb_modeswitch.h b/emulator/usbpt/bluetooth/usb_modeswitch/usb_modeswitch.h new file mode 100644 index 0000000..f407f95 --- /dev/null +++ b/emulator/usbpt/bluetooth/usb_modeswitch/usb_modeswitch.h @@ -0,0 +1,116 @@ +/* + This file is part of usb_modeswitch, a mode switching tool for controlling + the mode of 'multi-state' USB devices + + Version 2.6.0, 2019/11/28 + Copyright (C) 2007 - 2019 Josua Dietze + + Config file parsing stuff borrowed from Guillaume Dargaud + (http://www.gdargaud.net/Hack/SourceCode.html) + + 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: + + http://www.gnu.org/licenses/gpl.txt + +*/ + +#include <stdlib.h> +#include <libusb/libusb.h> + +void readConfigFile(const char *configFilename); +void printConfig(); +int switchSendMessage(); +int switchConfiguration(); +int switchAltSetting(); +void switchHuaweiMode(); + +void switchSierraMode(); +void switchGCTMode(); +void switchKobilMode(); +void switchQisdaMode(); +void switchQuantaMode(); +void switchSequansMode(); +void switchActionMode(); +void switchBlackberryMode(); +void switchPantechMode(); +void switchCiscoMode(); +int switchSonyMode(); +int detachDrivers(); +int checkSuccess(); +int sendMessage(char* message, int count); +int write_bulk(int endpoint, unsigned char *message, int length); +int read_bulk(int endpoint, unsigned char *buffer, int length); +void release_usb_device(int placeholder); +struct libusb_device* search_devices( int *numFound, int vendor, char* productList, + int targetClass, int configuration, int mode); +int find_first_bulk_endpoint(int direction); +int get_current_config_value(); +int get_interface_class(); +char* ReadParseParam(const char* FileName, char *VariableName); +int hex2num(char c); +int hex2byte(const char *hex); +int hexstr2bin(const char *hex, unsigned char *buffer, int len); +void printVersion(); +void printHelp(); +void close_all(); +void abortExit(); +int readArguments(int argc, char **argv); +void deviceDescription(); +void resetUSB(); +void release_usb_device(int placeholder); +int findMBIMConfig(int vendor, int product, int mode); + + +// Boolean +#define and && +#define or || +#define not ! + +// Bitwise +#define bitand & +#define bitor | +#define compl ~ +#define xor ^ + +// Equals +#define and_eq &= +#define not_eq != +#define or_eq |= +#define xor_eq ^= + +extern char* ReadParseParam(const char* FileName, char *VariableName); + +extern char *TempPP; + +#define ParseParamString(ParamFileName, Str) \ + if ((TempPP=ReadParseParam((ParamFileName), #Str))!=NULL) \ + strcpy(Str, TempPP); else Str[0]='\0' + +#define ParseParamInt(ParamFileName, Int) \ + if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) \ + Int=atoi(TempPP) + +#define ParseParamHex(ParamFileName, Int) \ + if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) \ + Int=strtol(TempPP, NULL, 16) + +#define ParseParamFloat(ParamFileName, Flt) \ + if ((TempPP=ReadParseParam((ParamFileName), #Flt))!=NULL) \ + Flt=atof(TempPP) + +#define ParseParamBool(ParamFileName, B) \ + if ((TempPP=ReadParseParam((ParamFileName), #B))!=NULL) \ + B=(toupper(TempPP[0])=='Y' || toupper(TempPP[0])=='T'|| TempPP[0]=='1'); else B=0 + +#define ParseParamBoolMap(ParamFileName, B, M, Const) \ + if ((TempPP=ReadParseParam((ParamFileName), #B))!=NULL) \ + if (toupper(TempPP[0])=='Y' || toupper(TempPP[0])=='T'|| TempPP[0]=='1') \ + M=M+Const diff --git a/emulator/usbpt/bluetooth/vendor.qemu.preferred.bt.service.rc b/emulator/usbpt/bluetooth/vendor.qemu.preferred.bt.service.rc new file mode 100644 index 0000000..acd158b --- /dev/null +++ b/emulator/usbpt/bluetooth/vendor.qemu.preferred.bt.service.rc @@ -0,0 +1,3 @@ +on property:vendor.qemu.preferred.bt.service=passthrough + stop vendor.bluetooth-1-1 + restart btlinux-1.1 diff --git a/emulator/usbpt/car_usbpt.mk b/emulator/usbpt/car_usbpt.mk new file mode 100644 index 0000000..d6dc800 --- /dev/null +++ b/emulator/usbpt/car_usbpt.mk @@ -0,0 +1,21 @@ +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +$(call inherit-product, device/generic/car/emulator/usbpt/bluetooth/bluetooth.mk) +$(call inherit-product, device/generic/car/emulator/usbpt/usbip-service/usbip-service.mk) + +# Required for USB passthrough +PRODUCT_COPY_FILES += \ + frameworks/native/data/etc/android.hardware.usb.host.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.usb.host.xml diff --git a/emulator/usbpt/usbip-service/Android.bp b/emulator/usbpt/usbip-service/Android.bp new file mode 100644 index 0000000..9ad8446 --- /dev/null +++ b/emulator/usbpt/usbip-service/Android.bp @@ -0,0 +1,63 @@ +package { + default_applicable_licenses: ["external_usbip-service_license"], +} + +license { + name: "external_usbip-service_license", + visibility: [":__subpackages__"], + license_kinds: ["SPDX-license-identifier-GPL-2.0"], + license_text: ["COPYING"], +} + +cc_defaults { + name: "usbip_defaults", + host_supported: true, + cflags: [ + "-Wall", + "-Werror", + ], + shared_libs: [ + "liblog", + "libutils", + "libcutils", + "libbase", + "libc++", + ], + product_specific: true, + stl: "none", +} + +cc_binary { + name: "usbip_service", + init_rc: ["usbip-service.rc"], + defaults: ["usbip_defaults"], + srcs: [ + "UsbIpService.cpp" + ], + static_libs: [ + "usbip_utils", + ], +} + +cc_library { + name: "usbip_utils", + defaults: ["usbip_defaults"], + srcs: [ + "UsbIpUtils.cpp" + ], + export_include_dirs: ["./"], +} + +cc_test { + name: "usbip_test", + defaults: ["usbip_defaults"], + srcs: ["UsbIpTest.cpp"], + test_suites: ["general-tests"], + + test_options: { + unit_test: false, + }, + shared_libs: [ + "usbip_utils", + ], +} diff --git a/emulator/usbpt/usbip-service/COPYING b/emulator/usbpt/usbip-service/COPYING new file mode 100644 index 0000000..c5611e4 --- /dev/null +++ b/emulator/usbpt/usbip-service/COPYING @@ -0,0 +1,340 @@ + 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 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 Library General +Public License instead of this License. diff --git a/emulator/usbpt/usbip-service/README.md b/emulator/usbpt/usbip-service/README.md new file mode 100644 index 0000000..693e86d --- /dev/null +++ b/emulator/usbpt/usbip-service/README.md @@ -0,0 +1,4 @@ +Implements a very basic version of usbip. + +GPLv2 license is maintained in this directory since it implements interfaces +provided by the usbip library. diff --git a/emulator/usbpt/usbip-service/TEST_MAPPING b/emulator/usbpt/usbip-service/TEST_MAPPING new file mode 100644 index 0000000..c977d11 --- /dev/null +++ b/emulator/usbpt/usbip-service/TEST_MAPPING @@ -0,0 +1,8 @@ +{ + "presubmit": [ + { + "name": "usbpip_test", + "host": true + } + ] +} diff --git a/emulator/usbpt/usbip-service/UsbIpService.cpp b/emulator/usbpt/usbip-service/UsbIpService.cpp new file mode 100644 index 0000000..26d2f3d --- /dev/null +++ b/emulator/usbpt/usbip-service/UsbIpService.cpp @@ -0,0 +1,55 @@ +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <log/log.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "UsbIpUtils.h" + +int main(int argc, char *argv[]) { + if (argc != 4) { + ALOGE("usage: 'usbip_service <ip_addr> <port> <dev_id>'\n"); + return -1; + } + ALOGD("IP: %s\nPort: %s\nDevId: %s\n", argv[1], argv[2], argv[3]); + + usbip_conn_info info; + if (!get_usbip_connection(argv[1], argv[2], argv[3], &info)) { + ALOGE("Couldn't retrieve socket connection\n"); + return -1; + } + + // Get free port. + FILE *file = fopen("/sys/devices/platform/vhci_hcd.0/status", "r"); + if (file == NULL) { + ALOGE("Couldn't open sysfs status file: %s\n", strerror(errno)); + close(info.sock_fd); + return -1; + } + int port_num = get_free_vhci_port(file, info.speed); + + // Pass socket to the kernel driver. + int fd = + openat(AT_FDCWD, "/sys/devices/platform/vhci_hcd.0/attach", O_WRONLY); + if (fd == -1) { + ALOGE("Couldn't open sysfs attach file: %s\n", strerror(errno)); + close(info.sock_fd); + return -1; + } + if (dprintf(fd, "%d %d %d %d", port_num, info.sock_fd, info.dev_id, + info.speed) < 0) { + ALOGE("Failed to attach socket to VHCI.\n"); + close(info.sock_fd); + close(fd); + return -1; + } + + close(info.sock_fd); + close(fd); + return 0; +} diff --git a/emulator/usbpt/usbip-service/UsbIpTest.cpp b/emulator/usbpt/usbip-service/UsbIpTest.cpp new file mode 100644 index 0000000..97ef09c --- /dev/null +++ b/emulator/usbpt/usbip-service/UsbIpTest.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <gtest/gtest.h> + +#include <cstdio> +#include <string> + +#include "UsbIpUtils.h" + +/* No virtual USB devices are attached. */ +static const std::string EMPTY_STATUS = + "hub port sta spd dev sockfd local_busid\n" + "hs 0000 004 000 00000000 000000 0-0\n" + "hs 0001 004 000 00000000 000000 0-0\n" + "hs 0002 004 000 00000000 000000 0-0\n" + "hs 0003 004 000 00000000 000000 0-0\n" + "ss 0004 004 000 00000000 000000 0-0\n" + "ss 0005 004 000 00000000 000000 0-0\n" + "ss 0006 004 000 00000000 000000 0-0\n" + "ss 0007 004 000 00000000 000000 0-0"; + +/* A single high speed an super speed device are attached. */ +static const std::string PORTS_ALLOCATED = + "hub port sta spd dev sockfd local_busid\n" + "hs 0000 006 003 00010003 000003 4-1\n" + "hs 0001 004 000 00000000 000000 0-0\n" + "hs 0002 004 000 00000000 000000 0-0\n" + "hs 0003 004 000 00000000 000000 0-0\n" + "ss 0004 006 004 00010004 000004 5-1\n" + "ss 0005 004 000 00000000 000000 0-0\n" + "ss 0006 004 000 00000000 000000 0-0\n" + "ss 0007 004 000 00000000 000000 0-0"; + +/* All USB device ports are allocated. */ +static const std::string NONE_AVAILABLE = + "hub port sta spd dev sockfd local_busid\n" + "hs 0000 006 003 00010001 000003 4-1\n" + "hs 0001 006 003 00010002 000004 4-2\n" + "hs 0002 006 003 00010003 000005 4-3\n" + "hs 0003 006 003 00010004 000006 4-4\n" + "ss 0004 006 004 00010005 000007 5-1\n" + "ss 0005 006 004 00010006 000008 5-2\n" + "ss 0006 006 004 00010007 000009 5-3\n" + "ss 0007 006 004 00010008 000010 5-4"; + +/* + * Returns a file pointer associated with a std::string. + * NOTE: User should call fclose on the pointer when done. + */ +static FILE *get_fp_from_string(const std::string &test_input) { + return fmemopen((void *)test_input.c_str(), test_input.size(), "r"); +} + +TEST(UsbIpTest, ReturnsFirstHighSpeedPort) { + FILE *file = get_fp_from_string(EMPTY_STATUS); + ASSERT_EQ(get_free_vhci_port(file, USBIP_SPEED_HIGH), 0); + fclose(file); +} + +TEST(UsbIpTest, ReturnsFirstSuperSpeedPort) { + FILE *file = get_fp_from_string(EMPTY_STATUS); + ASSERT_EQ(get_free_vhci_port(file, USBIP_SPEED_SUPER), 4); + fclose(file); +} + +TEST(UsbIpTest, ReturnsFirstFreeHighSpeedPort) { + FILE *file = get_fp_from_string(PORTS_ALLOCATED); + ASSERT_EQ(get_free_vhci_port(file, USBIP_SPEED_HIGH), 1); + fclose(file); +} + +TEST(UsbIpTest, ReturnsFirstFreeSuperSpeedPort) { + FILE *file = get_fp_from_string(PORTS_ALLOCATED); + ASSERT_EQ(get_free_vhci_port(file, USBIP_SPEED_SUPER), 5); + fclose(file); +} + +TEST(UsbIpTest, AllHighSpeedPortsAllocatted) { + FILE *file = get_fp_from_string(NONE_AVAILABLE); + ASSERT_EQ(get_free_vhci_port(file, USBIP_SPEED_HIGH), -1); + fclose(file); +} + +TEST(UsbIpTest, AllSuperSpeedPortsAllocated) { + FILE *file = get_fp_from_string(NONE_AVAILABLE); + ASSERT_EQ(get_free_vhci_port(file, USBIP_SPEED_SUPER), -1); + fclose(file); +} diff --git a/emulator/usbpt/usbip-service/UsbIpUtils.cpp b/emulator/usbpt/usbip-service/UsbIpUtils.cpp new file mode 100644 index 0000000..ce449f7 --- /dev/null +++ b/emulator/usbpt/usbip-service/UsbIpUtils.cpp @@ -0,0 +1,178 @@ +#include "UsbIpUtils.h" + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <log/log.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> + +constexpr uint16_t kIpVersion = 0x0111; + +constexpr uint16_t kOpRequest = 0x8003; +constexpr uint16_t kOpResponse = 0x0003; + +// Fields associated with all USBIP packets. +typedef struct op_req_common { + uint16_t ip_version; + uint16_t command_code; + uint32_t status; +} op_req_common; + +typedef struct op_req_import { + op_req_common common; + uint32_t busid[8]; +} op_req_import; + +typedef struct op_rep_import { + op_req_common common; +} op_rep_import; + +// Metadata fields only valid for successful status flag. +typedef struct op_rep_import_metadata { + uint32_t path[64]; + uint32_t bus_id[8]; + uint32_t bus_num; + uint32_t dev_num; + uint32_t speed; + uint16_t id_vendor; + uint16_t id_product; + uint16_t bcd_device; + uint8_t device_class; + uint8_t device_subclass; + uint8_t device_protocol; + uint8_t configuration_value; + uint8_t num_configurations; + uint8_t num_interfaces; +} op_rep_import_success; + +bool get_usbip_connection(const char *server, const char *port, + const char *dev_id, usbip_conn_info *info) { + struct sockaddr_in address; + + // Setup socket to the server. + if ((info->sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == 0) { + ALOGE("Opening socket failed: %s\n", strerror(errno)); + return false; + } + + int flags = 1; + if (setsockopt(info->sock_fd, SOL_SOCKET, SO_KEEPALIVE, &flags, + sizeof(flags)) == -1) { + ALOGE("Failed to enable keep alive: %s\n", strerror(errno)); + close(info->sock_fd); + return false; + } + if (setsockopt(info->sock_fd, SOL_TCP, TCP_NODELAY, &flags, + sizeof(flags)) == -1) { + ALOGE("Failed to enable no delay: %s\n", strerror(errno)); + close(info->sock_fd); + return false; + } + + address.sin_family = AF_INET; + if (inet_aton(server, &address.sin_addr) == 0) { + ALOGE("Failure to convert ip address %s\n", server); + close(info->sock_fd); + return false; + } + + errno = 0; + char *error; + address.sin_port = strtol(port, &error, 10); + if (address.sin_port == 0) { + ALOGE("Port is invalid %s\n", port); + close(info->sock_fd); + return false; + } + address.sin_port = htons(address.sin_port); + if (connect(info->sock_fd, (struct sockaddr *)&address, sizeof(address)) == + -1) { + ALOGE("Connection failed: %s\n", strerror(errno)); + close(info->sock_fd); + return false; + } + + // Fill in op request + op_req_import op_req; + op_req.common.ip_version = htons(kIpVersion); + op_req.common.command_code = htons(kOpRequest); + op_req.common.status = 0x0000; + strncpy((char *)op_req.busid, dev_id, sizeof(op_req.busid)); + + if (send(info->sock_fd, &op_req, sizeof(op_req), 0) == -1) { + ALOGE("Error sending op_req: %s\n", strerror(errno)); + close(info->sock_fd); + return false; + } + + // Read in op response. + op_rep_import op_rep; + if (recv(info->sock_fd, &op_rep, sizeof(op_rep), MSG_WAITALL) == -1) { + ALOGE("Error receiving op_rep: %s\n", strerror(errno)); + close(info->sock_fd); + return false; + } + + if (op_rep.common.status != 0) { + ALOGE("op_rep status is invalid.\n"); + close(info->sock_fd); + return false; + } + + uint16_t command = ntohs(op_rep.common.command_code); + if (command != kOpResponse) { + ALOGE("Invalid command expected: %d received: %d", command, kOpResponse); + close(info->sock_fd); + return false; + } + + op_rep_import_success data; + if (recv(info->sock_fd, &data, sizeof(data), MSG_WAITALL) == -1) { + ALOGE("Error receiving op_rep_data: %s\n", strerror(errno)); + close(info->sock_fd); + return false; + } + + int temp_bus_num = ntohl(data.bus_num); + int temp_dev_num = ntohl(data.dev_num); + info->speed = ntohl(data.speed); + info->dev_id = (temp_bus_num << 16) | temp_dev_num; + return true; +} + +int get_free_vhci_port(FILE *file, int speed) { + // Throw away the header line. + char *buf = NULL; + size_t length = 0; + if (getline(&buf, &length, file) == -1) { + ALOGE("Couldn't get the header line: %s\n", strerror(errno)); + free(buf); + return -1; + } + free(buf); + + char busid[32]; + char hub[3]; + int port = 0; + int status = 0; + int spd = 0; + int dev = 0; + int sockfd = 0; + const char *expected_hub = (speed == USBIP_SPEED_SUPER) ? "ss" : "hs"; + + // Scan status lines for a free USB port. + while (fscanf(file, "%2s %d %d %d %x %u %31s\n", hub, &port, &status, &spd, + &dev, &sockfd, busid) != EOF) { + if (strcmp(expected_hub, hub) == 0 && status == USBIP_VDEV_NULL) { + return port; + } + } + + return -1; +} diff --git a/emulator/usbpt/usbip-service/UsbIpUtils.h b/emulator/usbpt/usbip-service/UsbIpUtils.h new file mode 100644 index 0000000..c410ba0 --- /dev/null +++ b/emulator/usbpt/usbip-service/UsbIpUtils.h @@ -0,0 +1,25 @@ +#include <stdio.h> + +// Speed constants +inline constexpr int USBIP_SPEED_HIGH = 3; +inline constexpr int USBIP_SPEED_SUPER = 4; + +// Status Constants +inline constexpr int USBIP_VDEV_NULL = 4; + +// Connection information +typedef struct usbip_conn_info { + int sock_fd; + int speed; + int dev_id; +} usbip_conn_info; + +/* + * Connects to server and retrieves required info for connection. + * NOTE: User must close the sock_fd when they are done with it. + */ +bool get_usbip_connection(const char *server, const char *port, + const char *dev_id, usbip_conn_info *info); + +/* Returns free port number from vhci, -1 on failure. */ +int get_free_vhci_port(FILE *file, int speed); diff --git a/emulator/usbpt/usbip-service/sepolicy/file_contexts b/emulator/usbpt/usbip-service/sepolicy/file_contexts new file mode 100644 index 0000000..47fe583 --- /dev/null +++ b/emulator/usbpt/usbip-service/sepolicy/file_contexts @@ -0,0 +1,4 @@ +/product/bin/usbip_service u:object_r:usbip_service_exec:s0 +/sys/devices/platform/vhci_hcd.0/status u:object_r:sysfs_usbip:s0 +/sys/devices/platform/vhci_hcd.0/attach u:object_r:sysfs_usbip:s0 + diff --git a/emulator/usbpt/usbip-service/sepolicy/usbip_service.te b/emulator/usbpt/usbip-service/sepolicy/usbip_service.te new file mode 100644 index 0000000..b885493 --- /dev/null +++ b/emulator/usbpt/usbip-service/sepolicy/usbip_service.te @@ -0,0 +1,16 @@ +type usbip_service, domain; +type sysfs_usbip, sysfs_type, fs_type; +type usbip_service_exec, exec_type, system_file_type, file_type; + +net_domain(usbip_service); + +allow usbip_service netd:tcp_socket { read write }; + +allow kernel su:tcp_socket { read write }; +allow kernel shell:tcp_socket { read write }; + +allow init sysfs_usbip:file setattr; + +allow shell sysfs_usbip:dir { r_dir_perms }; +allow shell sysfs_usbip:file { rw_file_perms }; +allow shell usbip_service_exec:file { execute execute_no_trans getattr map open read }; diff --git a/emulator/usbpt/usbip-service/usbip-service.mk b/emulator/usbpt/usbip-service/usbip-service.mk new file mode 100644 index 0000000..46b2ef7 --- /dev/null +++ b/emulator/usbpt/usbip-service/usbip-service.mk @@ -0,0 +1,19 @@ +# +# Copyright (C) 2021 Google Inc. +# +# 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. +# + +PRODUCT_PACKAGES += usbip_service +BOARD_SEPOLICY_DIRS += device/generic/car/emulator/usbpt/usbip-service/sepolicy + diff --git a/emulator/usbpt/usbip-service/usbip-service.rc b/emulator/usbpt/usbip-service/usbip-service.rc new file mode 100644 index 0000000..7172bb7 --- /dev/null +++ b/emulator/usbpt/usbip-service/usbip-service.rc @@ -0,0 +1,2 @@ +on boot + chmod 222 /sys/bus/platform/devices/vhci_hcd.0/attach |