summaryrefslogtreecommitdiff
path: root/emulator/usbpt
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/usbpt')
-rw-r--r--emulator/usbpt/BoardConfig.mk16
-rw-r--r--emulator/usbpt/bluetooth/BoardConfig.mk18
-rw-r--r--emulator/usbpt/bluetooth/bluetooth.mk32
-rw-r--r--emulator/usbpt/bluetooth/btusb/BoardConfig.mk24
-rw-r--r--emulator/usbpt/bluetooth/btusb/btusb.mk27
-rw-r--r--emulator/usbpt/bluetooth/btusb/hal/bdroid_buildcfg.h9
-rw-r--r--emulator/usbpt/bluetooth/btusb/init.btusb.rc5
-rw-r--r--emulator/usbpt/bluetooth/btusb/rtl_bt/Android.bp24
-rwxr-xr-xemulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_config.binbin0 -> 10 bytes
-rw-r--r--emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_fw.binbin0 -> 48816 bytes
-rw-r--r--emulator/usbpt/bluetooth/btusb/sepolicy/bluetooth.te2
-rw-r--r--emulator/usbpt/bluetooth/btusb/sepolicy/domain.te4
-rw-r--r--emulator/usbpt/bluetooth/btusb/sepolicy/file.te1
-rw-r--r--emulator/usbpt/bluetooth/btusb/sepolicy/file_contexts2
-rw-r--r--emulator/usbpt/bluetooth/btusb/sepolicy/property_contexts1
-rw-r--r--emulator/usbpt/bluetooth/modules.blocklist2
-rw-r--r--emulator/usbpt/bluetooth/usb_modeswitch/Android.bp47
-rw-r--r--emulator/usbpt/bluetooth/usb_modeswitch/LICENSE340
-rw-r--r--emulator/usbpt/bluetooth/usb_modeswitch/usb_modeswitch.c2119
-rw-r--r--emulator/usbpt/bluetooth/usb_modeswitch/usb_modeswitch.h116
-rw-r--r--emulator/usbpt/bluetooth/vendor.qemu.preferred.bt.service.rc3
-rw-r--r--emulator/usbpt/car_usbpt.mk21
-rw-r--r--emulator/usbpt/usbip-service/Android.bp63
-rw-r--r--emulator/usbpt/usbip-service/COPYING340
-rw-r--r--emulator/usbpt/usbip-service/README.md4
-rw-r--r--emulator/usbpt/usbip-service/TEST_MAPPING8
-rw-r--r--emulator/usbpt/usbip-service/UsbIpService.cpp55
-rw-r--r--emulator/usbpt/usbip-service/UsbIpTest.cpp101
-rw-r--r--emulator/usbpt/usbip-service/UsbIpUtils.cpp178
-rw-r--r--emulator/usbpt/usbip-service/UsbIpUtils.h25
-rw-r--r--emulator/usbpt/usbip-service/sepolicy/file_contexts4
-rw-r--r--emulator/usbpt/usbip-service/sepolicy/usbip_service.te16
-rw-r--r--emulator/usbpt/usbip-service/usbip-service.mk19
-rw-r--r--emulator/usbpt/usbip-service/usbip-service.rc2
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
new file mode 100755
index 0000000..76f62b8
--- /dev/null
+++ b/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_config.bin
Binary files differ
diff --git a/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_fw.bin b/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_fw.bin
new file mode 100644
index 0000000..ad31c94
--- /dev/null
+++ b/emulator/usbpt/bluetooth/btusb/rtl_bt/rtl8821c_fw.bin
Binary files differ
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