diff --git a/packages/electrum/0001-termux-unset-all-android-checks.patch b/packages/electrum/0001-termux-unset-all-android-checks.patch new file mode 100644 index 00000000000000..4e883e0a566afc --- /dev/null +++ b/packages/electrum/0001-termux-unset-all-android-checks.patch @@ -0,0 +1,208 @@ +From f63d200b667ac3438816479e82a69b5825201e4c Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Sun, 16 Feb 2025 20:48:02 +0100 +Subject: [PATCH] termux: unset all android checks + +Electrum expects android builds to be a "standard" java app. This will +not work in termux, as termux is more similar to a full linux +environment, so let's unset all the android checks. +--- + electrum/ecc_fast.py | 2 +- + electrum/electrum | 2 +- + electrum/gui/default_lang.py | 2 +- + electrum/gui/qml/qeapp.py | 4 ++-- + electrum/gui/qml/qeqrscanner.py | 6 +++--- + electrum/logging.py | 2 +- + electrum/qrreader/zbar.py | 2 +- + electrum/simple_config.py | 2 +- + electrum/util.py | 8 ++++---- + run_electrum | 2 +- + 10 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/electrum/ecc_fast.py b/electrum/ecc_fast.py +index a27e2114961f..b88d9acf7dc2 100644 +--- a/electrum/ecc_fast.py ++++ b/electrum/ecc_fast.py +@@ -47,7 +47,7 @@ def load_library(): + elif sys.platform in ('windows', 'win32'): + for v in tested_libversions: + libnames.append(f"libsecp256k1-{v}.dll") +- elif 'ANDROID_DATA' in os.environ: ++ elif False: + libnames = ['libsecp256k1.so', ] # don't care about version number. we built w/e is available. + else: # desktop Linux and similar + for v in tested_libversions: +diff --git a/electrum/electrum b/electrum/electrum +index dc997981c2f8..6d60af24bf00 100755 +--- a/electrum/electrum ++++ b/electrum/electrum +@@ -42,7 +42,7 @@ from typing import TYPE_CHECKING, Optional + + script_dir = os.path.dirname(os.path.realpath(__file__)) + is_pyinstaller = getattr(sys, 'frozen', False) +-is_android = 'ANDROID_DATA' in os.environ ++is_android = False + is_appimage = 'APPIMAGE' in os.environ + is_binary_distributable = is_pyinstaller or is_android or is_appimage + # is_local: unpacked tar.gz but not pip installed, or git clone +diff --git a/electrum/gui/default_lang.py b/electrum/gui/default_lang.py +index aacf8112f05e..c8c1d07afb74 100644 +--- a/electrum/gui/default_lang.py ++++ b/electrum/gui/default_lang.py +@@ -13,7 +13,7 @@ from electrum.i18n import languages + + + jLocale = None +-if "ANDROID_DATA" in os.environ: ++if False: + from jnius import autoclass, cast + jLocale = autoclass("java.util.Locale") + +diff --git a/electrum/gui/qml/qeapp.py b/electrum/gui/qml/qeapp.py +index 87f5ad7a6e17..4df3dee1faa2 100644 +--- a/electrum/gui/qml/qeapp.py ++++ b/electrum/gui/qml/qeapp.py +@@ -49,7 +49,7 @@ if TYPE_CHECKING: + from electrum.daemon import Daemon + from electrum.plugin import Plugins + +-if 'ANDROID_DATA' in os.environ: ++if False: + from jnius import autoclass, cast + from android import activity + +@@ -281,7 +281,7 @@ class QEAppController(BaseCrashReporter, QObject): + + @pyqtSlot(result=bool) + def isAndroid(self): +- return 'ANDROID_DATA' in os.environ ++ return False + + @pyqtSlot(result='QVariantMap') + def crashData(self): +diff --git a/electrum/gui/qml/qeqrscanner.py b/electrum/gui/qml/qeqrscanner.py +index a301cdaa93f5..712d5dadec88 100644 +--- a/electrum/gui/qml/qeqrscanner.py ++++ b/electrum/gui/qml/qeqrscanner.py +@@ -9,7 +9,7 @@ from electrum.logging import get_logger + from electrum.i18n import _ + + +-if 'ANDROID_DATA' in os.environ: ++if False: + from jnius import autoclass + from android import activity + +@@ -54,7 +54,7 @@ class QEQRScanner(QObject): + + @pyqtSlot() + def open(self): +- if 'ANDROID_DATA' not in os.environ: ++ if True: + self._scan_qr_non_android() + return + jSimpleScannerActivity = autoclass("org.electrum.qr.SimpleScannerActivity") +@@ -77,7 +77,7 @@ class QEQRScanner(QObject): + + @pyqtSlot() + def _unbind(self): +- if 'ANDROID_DATA' in os.environ: ++ if False: + activity.unbind(on_activity_result=self.on_qr_activity_result) + + def _scan_qr_non_android(self): +diff --git a/electrum/logging.py b/electrum/logging.py +index efe01f6c25cd..bf06d551f734 100644 +--- a/electrum/logging.py ++++ b/electrum/logging.py +@@ -359,7 +359,7 @@ def get_logfile_path() -> Optional[pathlib.Path]: + + + def describe_os_version() -> str: +- if 'ANDROID_DATA' in os.environ: ++ if False: + import jnius + bv = jnius.autoclass('android.os.Build$VERSION') + b = jnius.autoclass('android.os.Build') +diff --git a/electrum/qrreader/zbar.py b/electrum/qrreader/zbar.py +index 8a3ef54dfdf8..73144caf2366 100644 +--- a/electrum/qrreader/zbar.py ++++ b/electrum/qrreader/zbar.py +@@ -37,7 +37,7 @@ from .abstract_base import AbstractQrCodeReader, QrCodeResult + + _logger = get_logger(__name__) + +-if 'ANDROID_DATA' in os.environ: ++if False: + LIBNAME = 'libzbar.so' + elif sys.platform == 'darwin': + LIBNAME = 'libzbar.0.dylib' +diff --git a/electrum/simple_config.py b/electrum/simple_config.py +index 40ee656a5946..762fb447355d 100644 +--- a/electrum/simple_config.py ++++ b/electrum/simple_config.py +@@ -436,7 +436,7 @@ class SimpleConfig(Logger): + def get_backup_dir(self) -> Optional[str]: + # this is used to save wallet file backups (without active lightning channels) + # on Android, the export backup button uses android_backup_dir() +- if 'ANDROID_DATA' in os.environ: ++ if False: + return None + else: + return self.WALLET_BACKUP_DIRECTORY +diff --git a/electrum/util.py b/electrum/util.py +index a62abd86acac..597c061550b7 100644 +--- a/electrum/util.py ++++ b/electrum/util.py +@@ -420,7 +420,7 @@ class DaemonThread(threading.Thread, Logger): + self.wake_up_event.clear() + + def on_stop(self): +- if 'ANDROID_DATA' in os.environ: ++ if False: + import jnius + jnius.detach() + self.logger.info("jnius detach") +@@ -563,7 +563,7 @@ def get_new_wallet_name(wallet_folder: str) -> str: + + + def is_android_debug_apk() -> bool: +- is_android = 'ANDROID_DATA' in os.environ ++ is_android = False + if not is_android: + return False + from jnius import autoclass +@@ -573,7 +573,7 @@ def is_android_debug_apk() -> bool: + + + def get_android_package_name() -> str: +- is_android = 'ANDROID_DATA' in os.environ ++ is_android = False + assert is_android + from jnius import autoclass + from android.config import ACTIVITY_CLASS_NAME +@@ -637,7 +637,7 @@ def xor_bytes(a: bytes, b: bytes) -> bytes: + def user_dir(): + if "ELECTRUMDIR" in os.environ: + return os.environ["ELECTRUMDIR"] +- elif 'ANDROID_DATA' in os.environ: ++ elif False: + return android_data_dir() + elif os.name == 'posix': + return os.path.join(os.environ["HOME"], ".electrum") +diff --git a/run_electrum b/run_electrum +index dc997981c2f8..6d60af24bf00 100755 +--- a/run_electrum ++++ b/run_electrum +@@ -42,7 +42,7 @@ from typing import TYPE_CHECKING, Optional + + script_dir = os.path.dirname(os.path.realpath(__file__)) + is_pyinstaller = getattr(sys, 'frozen', False) +-is_android = 'ANDROID_DATA' in os.environ ++is_android = False + is_appimage = 'APPIMAGE' in os.environ + is_binary_distributable = is_pyinstaller or is_android or is_appimage + # is_local: unpacked tar.gz but not pip installed, or git clone +-- +2.49.0 + diff --git a/packages/electrum/only-text-gui.patch b/packages/electrum/0002-termux-set-text-gui-as-default.patch similarity index 50% rename from packages/electrum/only-text-gui.patch rename to packages/electrum/0002-termux-set-text-gui-as-default.patch index e4482d55be7e76..b13d496c22b3b9 100644 --- a/packages/electrum/only-text-gui.patch +++ b/packages/electrum/0002-termux-set-text-gui-as-default.patch @@ -1,6 +1,20 @@ +From ad45206125a21fc4324e9f4787fffeabe944df97 Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Sun, 16 Feb 2025 21:08:03 +0100 +Subject: [PATCH] termux: set text gui as default + +It is possible to run the other guis as well, with termux-x11 or vnc, +but default should be text gui in our terminal emulator. +--- + electrum/daemon.py | 2 +- + electrum/simple_config.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/electrum/daemon.py b/electrum/daemon.py +index ad7a81430271..6d8740307eb0 100644 --- a/electrum/daemon.py +++ b/electrum/daemon.py -@@ -606,7 +606,7 @@ +@@ -612,7 +612,7 @@ class Daemon(Logger): threading.current_thread().name = 'GUI' gui_name = self.config.GUI_NAME if gui_name in ['lite', 'classic']: @@ -9,9 +23,11 @@ self._plugins = Plugins(self.config, gui_name) # init plugins self.logger.info(f'launching GUI: {gui_name}') try: +diff --git a/electrum/simple_config.py b/electrum/simple_config.py +index 762fb447355d..d34e1ac21679 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py -@@ -1061,7 +1061,7 @@ +@@ -1080,7 +1080,7 @@ Warning: setting this to too low will result in lots of payment failures."""), RPC_SOCKET_TYPE = ConfigVar('rpcsock', default='auto', type_=str) RPC_SOCKET_FILEPATH = ConfigVar('rpcsockpath', default=None, type_=str) @@ -20,3 +36,6 @@ GUI_LAST_WALLET = ConfigVar('gui_last_wallet', default=None, type_=str) GUI_QT_COLOR_THEME = ConfigVar( +-- +2.49.0 + diff --git a/packages/electrum/0003-gui-text-init-window-max_pos-to-0.patch b/packages/electrum/0003-gui-text-init-window-max_pos-to-0.patch new file mode 100644 index 00000000000000..51f6c7ac9463b1 --- /dev/null +++ b/packages/electrum/0003-gui-text-init-window-max_pos-to-0.patch @@ -0,0 +1,45 @@ +From 7f497724258ab3efa567dcbd9fb424b22f5dc92a Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Sat, 15 Feb 2025 23:48:30 +0100 +Subject: [PATCH] gui: text: init window max_pos to 0 + +Otherwise running the text gui and directly pressing up or down +results in an error like: + + 2.45 | E | daemon.Daemon | GUI raised exception: AttributeError("'ElectrumGui' object has no attribute 'max_pos'"). shutting down. + 2.61 | E | __main__ | daemon.run_gui errored +Traceback (most recent call last): + File "/usr/bin/electrum", line 466, in handle_cmd + d.run_gui() + File "/usr/lib/python3.12/site-packages/electrum/daemon.py", line 598, in run_gui + self.gui_object.main() + File "/usr/lib/python3.12/site-packages/electrum/gui/text.py", line 537, in main + self.run_tab(0, self.print_history, self.run_history_tab) + File "/usr/lib/python3.12/site-packages/electrum/gui/text.py", line 473, in run_tab + c = self.main_command() + ^^^^^^^^^^^^^^^^^^^ + File "/usr/lib/python3.12/site-packages/electrum/gui/text.py", line 458, in main_command + self.increase_cursor(-1) + File "/usr/lib/python3.12/site-packages/electrum/gui/text.py", line 436, in increase_cursor + self.pos = min(self.pos, self.max_pos - 1) + ^^^^^^^^^^^^ +AttributeError: 'ElectrumGui' object has no attribute 'max_pos' +--- + electrum/gui/text.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/electrum/gui/text.py b/electrum/gui/text.py +index c5280f7a466b..73e374319ba0 100644 +--- a/electrum/gui/text.py ++++ b/electrum/gui/text.py +@@ -95,6 +95,7 @@ class ElectrumGui(BaseElectrumGui, EventListener): + self.lightning_invoice = None + self.tab = 0 + self.pos = 0 ++ self.max_pos = 0 + self.popup_pos = 0 + + self.str_recipient = "" +-- +2.49.0 + diff --git a/packages/electrum/0004-HACK-gui-text-set-fee_per_kb-to-0-if-it-is-None.patch b/packages/electrum/0004-HACK-gui-text-set-fee_per_kb-to-0-if-it-is-None.patch new file mode 100644 index 00000000000000..802d307154e85e --- /dev/null +++ b/packages/electrum/0004-HACK-gui-text-set-fee_per_kb-to-0-if-it-is-None.patch @@ -0,0 +1,45 @@ +From f7ef5d2aad1e7c3e9b4745bb50c6babf5faeca6b Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Sat, 15 Feb 2025 23:51:47 +0100 +Subject: [PATCH] HACK: gui: text: set fee_per_kb to 0 if it is None + +To fix crash when settings tab is opened in text gui: + + 2.25 | E | daemon.Daemon | GUI raised exception: TypeError('conversion from NoneType to Decimal is not supported'). shutting down. + 2.59 | E | __main__ | daemon.run_gui errored +Traceback (most recent call last): + File "/usr/bin/electrum", line 466, in handle_cmd + d.run_gui() + File "/usr/lib/python3.12/site-packages/electrum/daemon.py", line 598, in run_gui + self.gui_object.main() + File "/usr/lib/python3.12/site-packages/electrum/gui/text.py", line 537, in main + self.run_tab(0, self.print_history, self.run_history_tab) + File "/usr/lib/python3.12/site-packages/electrum/gui/text.py", line 473, in run_tab + c = self.main_command() + ^^^^^^^^^^^^^^^^^^^ + File "/usr/lib/python3.12/site-packages/electrum/gui/text.py", line 464, in main_command + self.settings_dialog() + File "/usr/lib/python3.12/site-packages/electrum/gui/text.py", line 763, in settings_dialog + fee = str(Decimal(self.config.fee_per_kb()) / COIN) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +TypeError: conversion from NoneType to Decimal is not supported +--- + electrum/gui/text.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/electrum/gui/text.py b/electrum/gui/text.py +index 73e374319ba0..cffc4230ebf2 100644 +--- a/electrum/gui/text.py ++++ b/electrum/gui/text.py +@@ -761,7 +761,7 @@ class ElectrumGui(BaseElectrumGui, EventListener): + self.network.run_from_another_thread(self.network.set_parameters(net_params)) + + def settings_dialog(self): +- fee = str(Decimal(self.config.fee_per_kb()) / COIN) ++ fee = str(Decimal(self.config.fee_per_kb() if self.config.fee_per_kb() else 0) / COIN) + out = self.run_dialog('Settings', [ + {'label':'Default fee', 'type':'satoshis', 'value': fee} + ], buttons = 1) +-- +2.49.0 + diff --git a/packages/electrum/0005-ecc_fast-look-for-libsecp256k1.so.patch b/packages/electrum/0005-ecc_fast-look-for-libsecp256k1.so.patch new file mode 100644 index 00000000000000..8bdcbd028b0295 --- /dev/null +++ b/packages/electrum/0005-ecc_fast-look-for-libsecp256k1.so.patch @@ -0,0 +1,27 @@ +From c6832bcf17376f9d3bac907db7342e8a7c3fff9a Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Thu, 3 Apr 2025 18:29:51 +0200 +Subject: [PATCH] ecc_fast: look for libsecp256k1.so + +Without .1 or .2 version suffix. Termux's libsecp256k1 library is +called just libsecp256k1.so. +--- + electrum/ecc_fast.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/electrum/ecc_fast.py b/electrum/ecc_fast.py +index b88d9acf7dc2..35b14aa62587 100644 +--- a/electrum/ecc_fast.py ++++ b/electrum/ecc_fast.py +@@ -47,7 +47,7 @@ def load_library(): + elif sys.platform in ('windows', 'win32'): + for v in tested_libversions: + libnames.append(f"libsecp256k1-{v}.dll") +- elif False: ++ elif True: + libnames = ['libsecp256k1.so', ] # don't care about version number. we built w/e is available. + else: # desktop Linux and similar + for v in tested_libversions: +-- +2.49.0 + diff --git a/packages/electrum/android.patch b/packages/electrum/android.patch deleted file mode 100644 index 03f4b0d44ad7a9..00000000000000 --- a/packages/electrum/android.patch +++ /dev/null @@ -1,82 +0,0 @@ ---- a/electrum/electrum -+++ b/electrum/electrum -@@ -42,7 +42,7 @@ - - script_dir = os.path.dirname(os.path.realpath(__file__)) - is_pyinstaller = getattr(sys, 'frozen', False) --is_android = 'ANDROID_DATA' in os.environ -+is_android = False - is_appimage = 'APPIMAGE' in os.environ - # is_local: unpacked tar.gz but not pip installed, or git clone - is_local = (not is_pyinstaller and not is_android and not is_appimage ---- a/electrum/logging.py -+++ b/electrum/logging.py -@@ -354,7 +354,7 @@ - - - def describe_os_version() -> str: -- if 'ANDROID_DATA' in os.environ: -+ if False: - import jnius - bv = jnius.autoclass('android.os.Build$VERSION') - b = jnius.autoclass('android.os.Build') ---- a/electrum/simple_config.py -+++ b/electrum/simple_config.py -@@ -280,7 +280,7 @@ - def get_backup_dir(self): - # this is used to save wallet file backups (without active lightning channels) - # on Android, the export backup button uses android_backup_dir() -- if 'ANDROID_DATA' in os.environ: -+ if False: - return None - else: - return self.get('backup_dir') ---- a/electrum/util.py -+++ b/electrum/util.py -@@ -386,7 +386,7 @@ - self.running = False - - def on_stop(self): -- if 'ANDROID_DATA' in os.environ: -+ if False: - import jnius - jnius.detach() - self.logger.info("jnius detach") -@@ -519,7 +519,7 @@ - - - def is_android_debug_apk() -> bool: -- is_android = 'ANDROID_DATA' in os.environ -+ is_android = False - if not is_android: - return False - from jnius import autoclass -@@ -529,7 +529,7 @@ - - - def get_android_package_name() -> str: -- is_android = 'ANDROID_DATA' in os.environ -+ is_android = False - assert is_android - from jnius import autoclass - from android.config import ACTIVITY_CLASS_NAME -@@ -604,7 +604,7 @@ - def user_dir(): - if "ELECTRUMDIR" in os.environ: - return os.environ["ELECTRUMDIR"] -- elif 'ANDROID_DATA' in os.environ: -+ elif False: - return android_data_dir() - elif os.name == 'posix': - return os.path.join(os.environ["HOME"], ".electrum") ---- a/run_electrum -+++ b/run_electrum -@@ -42,7 +42,7 @@ - - script_dir = os.path.dirname(os.path.realpath(__file__)) - is_pyinstaller = getattr(sys, 'frozen', False) --is_android = 'ANDROID_DATA' in os.environ -+is_android = False - is_appimage = 'APPIMAGE' in os.environ - # is_local: unpacked tar.gz but not pip installed, or git clone - is_local = (not is_pyinstaller and not is_android and not is_appimage diff --git a/packages/electrum/build.sh b/packages/electrum/build.sh index 4a00b7d6027b10..cfcd9f51a80b45 100644 --- a/packages/electrum/build.sh +++ b/packages/electrum/build.sh @@ -3,7 +3,7 @@ TERMUX_PKG_DESCRIPTION="Electrum is a lightweight Bitcoin wallet" TERMUX_PKG_LICENSE="MIT" TERMUX_PKG_MAINTAINER="@termux" TERMUX_PKG_VERSION="4.5.8" -TERMUX_PKG_REVISION=2 +TERMUX_PKG_REVISION=3 TERMUX_PKG_SRCURL=https://download.electrum.org/$TERMUX_PKG_VERSION/Electrum-$TERMUX_PKG_VERSION.tar.gz TERMUX_PKG_SHA256=dd8595a138132dee87cee76ce760a1d622fc2fd65d3b6ac7df7e53b7fb6ea7e8 # The python dependency list should be compared to @@ -11,7 +11,8 @@ TERMUX_PKG_SHA256=dd8595a138132dee87cee76ce760a1d622fc2fd65d3b6ac7df7e53b7fb6ea7 # update (or at least every major update). Disable auto updates for # now. TERMUX_PKG_AUTO_UPDATE=false -TERMUX_PKG_DEPENDS="python, libsecp256k1, python-pip, python-cryptography" +TERMUX_PKG_DEPENDS="libsecp256k1, python, python-cryptography, python-pip" +TERMUX_PKG_SUGGESTS="python-btchip, python-hidapi" TERMUX_PKG_PYTHON_TARGET_DEPS="'qrcode', 'protobuf<4,>=3.20', 'qdarkstyle>=2.7', 'aiorpcx<0.24,>=0.22.0', 'aiohttp<4.0.0,>=3.3.0', 'aiohttp_socks>=0.8.4', 'certifi', 'attrs>=20.1.0', 'jsonpatch', 'dnspython>=2.0'" TERMUX_PKG_BUILD_IN_SRC=true TERMUX_PKG_PLATFORM_INDEPENDENT=true diff --git a/packages/heimdall/0001-heimdall-use-termux_usb-functions-instead-of-some-li.patch b/packages/heimdall/0001-heimdall-use-termux_usb-functions-instead-of-some-li.patch new file mode 100644 index 00000000000000..2149703d111957 --- /dev/null +++ b/packages/heimdall/0001-heimdall-use-termux_usb-functions-instead-of-some-li.patch @@ -0,0 +1,201 @@ +From 9d56f62f268fde4c6a421cf5b1b3c5ba587fdd60 Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Wed, 26 Feb 2025 00:43:59 +0100 +Subject: [PATCH] heimdall: use termux_usb functions instead of (some) libusb + ones + +The functions are provided by libtermux-usb, which is part of +termux-api. +--- + heimdall/CMakeLists.txt | 5 +- + heimdall/source/BridgeManager.cpp | 79 ++++++++++++++++++++----------- + 2 files changed, 55 insertions(+), 29 deletions(-) + +diff --git a/heimdall/CMakeLists.txt b/heimdall/CMakeLists.txt +index 0cb0e2c0c42e..12c32dadb043 100644 +--- a/heimdall/CMakeLists.txt ++++ b/heimdall/CMakeLists.txt +@@ -37,7 +37,8 @@ set(HEIMDALL_SOURCE_FILES + source/main.cpp + source/PrintPitAction.cpp + source/Utility.cpp +- source/VersionAction.cpp) ++ source/VersionAction.cpp ++) + + include(CheckSymbolExists) + +@@ -74,7 +75,7 @@ add_executable(heimdall ${HEIMDALL_SOURCE_FILES}) + target_compile_features(heimdall PRIVATE cxx_std_11) + + target_link_libraries(heimdall PRIVATE pit) +-target_link_libraries(heimdall PRIVATE ${LIBUSB_LIBRARIES}) ++target_link_libraries(heimdall PRIVATE ${LIBUSB_LIBRARIES} termux-usb protobuf-c) + install (TARGETS heimdall + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) +diff --git a/heimdall/source/BridgeManager.cpp b/heimdall/source/BridgeManager.cpp +index f2ceee9e2cbe..45cdff8fb3f2 100644 +--- a/heimdall/source/BridgeManager.cpp ++++ b/heimdall/source/BridgeManager.cpp +@@ -25,6 +25,8 @@ + // libusb + #include + ++#include "termux-usb.h" ++ + // Heimdall + #include "BeginDumpPacket.h" + #include "BeginSessionPacket.h" +@@ -83,50 +85,64 @@ int BridgeManager::FindDeviceInterface(void) + else + Interface::Print("Detecting device...\n"); + +- struct libusb_device **devices; ++ struct termux_usb_device **devices; ++ char heimdallDeviceAddress[PATH_MAX] = {'\0'}; + unsigned int deviceCount, deviceIndex, i; +- libusb_device_descriptor descriptor; + while (true) + { +- deviceCount = libusb_get_device_list(libusbContext, &devices); ++ deviceCount = termux_usb_get_device_list(&devices); + + for (deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) + { +- libusb_get_device_descriptor(devices[deviceIndex], &descriptor); +- + for (i = 0; i < BridgeManager::kSupportedDeviceCount; i++) + { +- if (descriptor.idVendor == supportedDevices[i].vendorId && +- descriptor.idProduct == supportedDevices[i].productId) ++ if (devices[deviceIndex]->device_descriptor->idVendor == supportedDevices[i].vendorId && ++ devices[deviceIndex]->device_descriptor->idProduct == supportedDevices[i].productId) + { +- heimdallDevice = devices[deviceIndex]; +- libusb_ref_device(heimdallDevice); ++ strncpy(heimdallDeviceAddress, devices[deviceIndex]->device_address, PATH_MAX-1); ++ heimdallDeviceAddress[PATH_MAX-1] = '\0'; ++ Interface::Print("Found device\n"); + break; + } + } + } +- if (heimdallDevice) ++ if (heimdallDeviceAddress[0] != '\0') + break; + +- libusb_free_device_list(devices, deviceCount); ++ termux_usb_free_device_list(devices); + if (waitForDevice) + Sleep(1000); + else + break; + } + +- if (!heimdallDevice) ++ if (heimdallDeviceAddress[0] == '\0') + { + Interface::PrintDeviceDetectionFailed(); + return (BridgeManager::kInitialiseDeviceNotDetected); + } + +- int result = libusb_open(heimdallDevice, &deviceHandle); +- if (result != LIBUSB_SUCCESS) +- { +- Interface::PrintError("Failed to access device. libusb error: %d\n", result); ++ intptr_t fd = termux_usb_open_address(heimdallDeviceAddress); ++ if (fd <= 0) { ++ Interface::PrintError("termux_usb_open failed\n"); + return (BridgeManager::kInitialiseFailed); + } ++ int result = libusb_wrap_sys_device(libusbContext, fd, &deviceHandle); ++ if (result != LIBUSB_SUCCESS) { ++ Interface::PrintError("libusb_wrap_sys_device failed. libusb error: %d\n", result); ++ return (BridgeManager::kInitialiseFailed); ++ } else if (deviceHandle == NULL) { ++ Interface::PrintError("libusb_wrap_sys_device returned an invalid handle\n"); ++ return (BridgeManager::kInitialiseFailed); ++ } ++ heimdallDevice = libusb_get_device(deviceHandle); ++ libusb_ref_device(heimdallDevice); ++ ++ if (!heimdallDevice) ++ { ++ Interface::PrintDeviceDetectionFailed(); ++ return (BridgeManager::kInitialiseDeviceNotDetected); ++ } + + libusb_device_descriptor deviceDescriptor; + result = libusb_get_device_descriptor(heimdallDevice, &deviceDescriptor); +@@ -418,7 +434,13 @@ BridgeManager::~BridgeManager() + bool BridgeManager::DetectDevice(void) + { + // Initialise libusb +- int result = libusb_init(&libusbContext); ++ int result; ++ result = libusb_set_option(libusbContext, LIBUSB_OPTION_WEAK_AUTHORITY, NULL); ++ if (result != LIBUSB_SUCCESS) { ++ Interface::PrintError("libusb_set_option failed: %d\n", result); ++ return (false); ++ } ++ result = libusb_init(&libusbContext); + + if (result != LIBUSB_SUCCESS) + { +@@ -432,23 +454,20 @@ bool BridgeManager::DetectDevice(void) + // Set libusb log level. + SetUsbLogLevel(usbLogLevel); + +- struct libusb_device **devices; ++ struct termux_usb_device **devices; + unsigned int deviceCount, deviceIndex, i; +- libusb_device_descriptor descriptor; + while (true) + { +- deviceCount = libusb_get_device_list(libusbContext, &devices); ++ deviceCount = termux_usb_get_device_list(&devices); + + for (deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++) + { +- libusb_get_device_descriptor(devices[deviceIndex], &descriptor); +- + for (i = 0; i < BridgeManager::kSupportedDeviceCount; i++) + { +- if (descriptor.idVendor == supportedDevices[i].vendorId && +- descriptor.idProduct == supportedDevices[i].productId) ++ if (devices[deviceIndex]->device_descriptor->idVendor == supportedDevices[i].vendorId && ++ devices[deviceIndex]->device_descriptor->idProduct == supportedDevices[i].productId) + { +- libusb_free_device_list(devices, deviceCount); ++ termux_usb_free_device_list(devices); + + Interface::Print("Device detected\n"); + return (true); +@@ -456,7 +475,7 @@ bool BridgeManager::DetectDevice(void) + } + } + +- libusb_free_device_list(devices, deviceCount); ++ termux_usb_free_device_list(devices); + if (waitForDevice) + Sleep(1000); + else +@@ -471,7 +490,13 @@ int BridgeManager::Initialise(bool resume) + Interface::Print("Initialising connection...\n"); + + // Initialise libusb +- int result = libusb_init(&libusbContext); ++ int result; ++ result = libusb_set_option(libusbContext, LIBUSB_OPTION_WEAK_AUTHORITY, NULL); ++ if (result != LIBUSB_SUCCESS) { ++ Interface::PrintError("libusb_set_option failed: %d\n", result); ++ return (false); ++ } ++ result = libusb_init(&libusbContext); + + if (result != LIBUSB_SUCCESS) + { +-- +2.49.0 + diff --git a/packages/heimdall/build.sh b/packages/heimdall/build.sh new file mode 100644 index 00000000000000..02cbff93c344cc --- /dev/null +++ b/packages/heimdall/build.sh @@ -0,0 +1,13 @@ +TERMUX_PKG_HOMEPAGE=https://git.sr.ht/~grimler/Heimdall +TERMUX_PKG_DESCRIPTION="Tool for flashing firmware onto Samsung Galaxy devices" +TERMUX_PKG_LICENSE="MIT" +TERMUX_PKG_MAINTAINER="Henrik Grimler @grimler91" +TERMUX_PKG_VERSION=2.1.0 +TERMUX_PKG_SRCURL="https://git.sr.ht/~grimler/Heimdall/archive/v${TERMUX_PKG_VERSION}.tar.gz" +TERMUX_PKG_SHA256=51276d09acb14cdd7cfca4547ccfa059fa7a4d43fb741afd618c495996a50bfe +TERMUX_PKG_DEPENDS="libprotobuf-c, libusb, termux-api" +TERMUX_PKG_EXTRA_CONFIGURE_ARGS="-DDISABLE_FRONTEND=1" + +termux_step_pre_configure() { + termux_setup_protobuf +} diff --git a/packages/hidapi/0001-libusb-build-with-iconv-when-__TERMUX__-is-set.patch b/packages/hidapi/0001-libusb-build-with-iconv-when-__TERMUX__-is-set.patch new file mode 100644 index 00000000000000..21712877baaaae --- /dev/null +++ b/packages/hidapi/0001-libusb-build-with-iconv-when-__TERMUX__-is-set.patch @@ -0,0 +1,68 @@ +From aa18490ba5ce05a43b7046006ecc258633255c54 Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Tue, 4 Mar 2025 11:00:35 +0100 +Subject: [PATCH] libusb: build with iconv when __TERMUX__ is set + +Android does not have libiconv, but termux does, so add some +__TERMUX__ checks. +--- + libusb/CMakeLists.txt | 4 ---- + libusb/hid.c | 6 +++--- + 2 files changed, 3 insertions(+), 7 deletions(-) + +diff --git a/libusb/CMakeLists.txt b/libusb/CMakeLists.txt +index 6cd48c4f70f6..beba0a3fdb33 100644 +--- a/libusb/CMakeLists.txt ++++ b/libusb/CMakeLists.txt +@@ -22,7 +22,6 @@ target_link_libraries(hidapi_libusb PRIVATE Threads::Threads) + if(HIDAPI_NO_ICONV) + target_compile_definitions(hidapi_libusb PRIVATE NO_ICONV) + else() +- if(NOT ANDROID) + include(CheckCSourceCompiles) + + if(NOT CMAKE_VERSION VERSION_LESS 3.11) +@@ -77,9 +76,6 @@ else() + if(HIDAPI_ICONV_CONST) + target_compile_definitions(hidapi_libusb PRIVATE "ICONV_CONST=const") + endif() +- else() +- # On Android Iconv is disabled on the code level anyway, so no issue; +- endif() + endif() + + set_target_properties(hidapi_libusb +diff --git a/libusb/hid.c b/libusb/hid.c +index 188e536d537d..d3861f772673 100644 +--- a/libusb/hid.c ++++ b/libusb/hid.c +@@ -42,7 +42,7 @@ + + /* GNU / LibUSB */ + #include +-#if !defined(__ANDROID__) && !defined(NO_ICONV) ++#if (!defined(__ANDROID__) || defined(__TERMUX__)) && !defined(NO_ICONV) + #include + #ifndef ICONV_CONST + #define ICONV_CONST +@@ -406,7 +406,7 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) + int len; + wchar_t *str = NULL; + +-#if !defined(__ANDROID__) && !defined(NO_ICONV) /* we don't use iconv on Android, or when it is explicitly disabled */ ++#if (!defined(__ANDROID__) || defined(__TERMUX__)) && !defined(NO_ICONV) /* we don't use iconv on non-Termux Android, or when it is explicitly disabled */ + wchar_t wbuf[256]; + /* iconv variables */ + iconv_t ic; +@@ -432,7 +432,7 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) + if (len < 2) /* we always skip first 2 bytes */ + return NULL; + +-#if defined(__ANDROID__) || defined(NO_ICONV) ++#if (defined(__ANDROID__) || defined(NO_ICONV)) && !defined(__TERMUX__) + + /* Bionic does not have iconv support nor wcsdup() function, so it + has to be done manually. The following code will only work for +-- +2.49.0 + diff --git a/packages/hidapi/0002-libusb-replace-some-functions-with-termux_usb-varian.patch b/packages/hidapi/0002-libusb-replace-some-functions-with-termux_usb-varian.patch new file mode 100644 index 00000000000000..10f3b7b4874804 --- /dev/null +++ b/packages/hidapi/0002-libusb-replace-some-functions-with-termux_usb-varian.patch @@ -0,0 +1,322 @@ +From d4188925aa23cd25d9b46225a9d74f960e34febf Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Wed, 5 Mar 2025 07:07:09 +0100 +Subject: [PATCH] libusb: replace some functions with termux_usb variants + +On Android we cannot use libusb_get_device_list and libusb_open +directly. Instead we need to enumerate and open devices through the +Android API. In Termux we have termux-api for handling this +communication, so we can replace the libusb_.. functions with +termux_usb_.. variants. + +Also set LIBUSB_OPTION_NO_DEVICE_DISCOVERY, it is required on android +as libusb otherwise errors early when trying to scan for devices. +--- + libusb/CMakeLists.txt | 2 + + libusb/hid.c | 205 +++++++++++++++++++++++------------------- + 2 files changed, 113 insertions(+), 94 deletions(-) + +diff --git a/libusb/CMakeLists.txt b/libusb/CMakeLists.txt +index beba0a3fdb33..7888de064e4e 100644 +--- a/libusb/CMakeLists.txt ++++ b/libusb/CMakeLists.txt +@@ -8,6 +8,8 @@ add_library(hidapi_libusb + ) + target_link_libraries(hidapi_libusb PUBLIC hidapi_include) + ++target_link_libraries(hidapi_libusb PRIVATE protobuf-c termux-usb) ++ + if(TARGET usb-1.0) + target_link_libraries(hidapi_libusb PRIVATE usb-1.0) + else() +diff --git a/libusb/hid.c b/libusb/hid.c +index d3861f772673..8e866f32de41 100644 +--- a/libusb/hid.c ++++ b/libusb/hid.c +@@ -50,6 +50,7 @@ + #endif + + #include "hidapi_libusb.h" ++#include "termux-usb.h" + + #if defined(__ANDROID__) && __ANDROID_API__ < __ANDROID_API_N__ + +@@ -541,6 +542,8 @@ int HID_API_EXPORT hid_init(void) + if (!usb_context) { + const char *locale; + ++ libusb_set_option(usb_context, LIBUSB_OPTION_NO_DEVICE_DISCOVERY, NULL); ++ + /* Init Libusb */ + if (libusb_init(&usb_context)) + return -1; +@@ -741,8 +744,8 @@ static uint16_t get_report_descriptor_size_from_interface_descriptors(const stru + + struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) + { +- libusb_device **devs; +- libusb_device *dev; ++ struct termux_usb_device **devices; ++ struct termux_usb_device *device; + libusb_device_handle *handle = NULL; + ssize_t num_devs; + int i = 0; +@@ -752,99 +755,102 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, + + if(hid_init() < 0) + return NULL; +- +- num_devs = libusb_get_device_list(usb_context, &devs); ++ num_devs = termux_usb_get_device_list(&devices); + if (num_devs < 0) + return NULL; +- while ((dev = devs[i++]) != NULL) { ++ while ((device = devices[i++]) != NULL) { + struct libusb_device_descriptor desc; +- struct libusb_config_descriptor *conf_desc = NULL; +- int j, k; ++ struct termux_usb_config_descriptor *conf_desc = NULL; ++ int j; + +- int res = libusb_get_device_descriptor(dev, &desc); +- unsigned short dev_vid = desc.idVendor; +- unsigned short dev_pid = desc.idProduct; ++ unsigned short dev_vid = device->device_descriptor->idVendor; ++ unsigned short dev_pid = device->device_descriptor->idProduct; + + if ((vendor_id != 0x0 && vendor_id != dev_vid) || + (product_id != 0x0 && product_id != dev_pid)) { + continue; + } + +- res = libusb_get_active_config_descriptor(dev, &conf_desc); +- if (res < 0) +- libusb_get_config_descriptor(dev, 0, &conf_desc); ++ termux_usb_get_config_descriptor(device, 0, &conf_desc); + if (conf_desc) { + for (j = 0; j < conf_desc->bNumInterfaces; j++) { +- const struct libusb_interface *intf = &conf_desc->interface[j]; +- for (k = 0; k < intf->num_altsetting; k++) { +- const struct libusb_interface_descriptor *intf_desc; +- intf_desc = &intf->altsetting[k]; +- if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { +- struct hid_device_info *tmp; ++ const struct termux_usb_interface_descriptor *intf_desc = &conf_desc->interface[j]; ++ if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { ++ struct hid_device_info *tmp; + +- res = libusb_open(dev, &handle); ++ intptr_t fd = termux_usb_open(device); ++ if (fd <= 0) { ++ LOG("Failed to open device\n"); ++ continue; ++ } ++ int res = libusb_wrap_sys_device(usb_context, fd, &handle); ++ if (res != 0) { ++ LOG("Failed to wrap sys device: %d\n", res); ++ continue; ++ } ++ libusb_device *dev = libusb_get_device(handle); + + #ifdef __ANDROID__ +- if (handle) { +- /* There is (a potential) libusb Android backend, in which +- device descriptor is not accurate up until the device is opened. +- https://github.com/libusb/libusb/pull/874#discussion_r632801373 +- A workaround is to re-read the descriptor again. +- Even if it is not going to be accepted into libusb master, +- having it here won't do any harm, since reading the device descriptor +- is as cheap as copy 18 bytes of data. */ +- libusb_get_device_descriptor(dev, &desc); +- } ++ if (handle) { ++ /* There is (a potential) libusb Android backend, in which ++ device descriptor is not accurate up until the device is opened. ++ https://github.com/libusb/libusb/pull/874#discussion_r632801373 ++ A workaround is to re-read the descriptor again. ++ Even if it is not going to be accepted into libusb master, ++ having it here won't do any harm, since reading the device descriptor ++ is as cheap as copy 18 bytes of data. */ ++ libusb_get_device_descriptor(dev, &desc); ++ } + #endif + +- tmp = create_device_info_for_device(dev, handle, &desc, conf_desc->bConfigurationValue, intf_desc->bInterfaceNumber); +- if (tmp) { ++ tmp = create_device_info_for_device(dev, handle, &desc, conf_desc->bConfigurationValue, intf_desc->bInterfaceNumber); ++ if (tmp) { + #ifdef INVASIVE_GET_USAGE +- /* TODO: have a runtime check for this section. */ +- +- /* +- This section is removed because it is too +- invasive on the system. Getting a Usage Page +- and Usage requires parsing the HID Report +- descriptor. Getting a HID Report descriptor +- involves claiming the interface. Claiming the +- interface involves detaching the kernel driver. +- Detaching the kernel driver is hard on the system +- because it will unclaim interfaces (if another +- app has them claimed) and the re-attachment of +- the driver will sometimes change /dev entry names. +- It is for these reasons that this section is +- optional. For composite devices, use the interface +- field in the hid_device_info struct to distinguish +- between interfaces. */ +- if (handle) { +- uint16_t report_descriptor_size = get_report_descriptor_size_from_interface_descriptors(intf_desc); +- +- invasive_fill_device_info_usage(tmp, handle, intf_desc->bInterfaceNumber, report_descriptor_size); +- } +-#endif /* INVASIVE_GET_USAGE */ ++ /* TODO: have a runtime check for this section. */ ++ ++ /* ++ This section is removed because it is too ++ invasive on the system. Getting a Usage Page ++ and Usage requires parsing the HID Report ++ descriptor. Getting a HID Report descriptor ++ involves claiming the interface. Claiming the ++ interface involves detaching the kernel driver. ++ Detaching the kernel driver is hard on the system ++ because it will unclaim interfaces (if another ++ app has them claimed) and the re-attachment of ++ the driver will sometimes change /dev entry names. ++ It is for these reasons that this section is ++ optional. For composite devices, use the interface ++ field in the hid_device_info struct to distinguish ++ between interfaces. */ ++ if (handle) { ++ uint16_t report_descriptor_size = get_report_descriptor_size_from_interface_descriptors(intf_desc); + +- if (cur_dev) { +- cur_dev->next = tmp; +- } +- else { +- root = tmp; +- } +- cur_dev = tmp; ++ invasive_fill_device_info_usage(tmp, handle, intf_desc->bInterfaceNumber, report_descriptor_size); + } ++#endif /* INVASIVE_GET_USAGE */ + +- if (res >= 0) { +- libusb_close(handle); +- handle = NULL; ++ if (cur_dev) { ++ cur_dev->next = tmp; + } ++ else { ++ root = tmp; ++ } ++ cur_dev = tmp; + } +- } /* altsettings */ ++ ++ if (res >= 0) { ++ libusb_close(handle); ++ handle = NULL; ++ } ++ break; ++ } + } /* interfaces */ +- libusb_free_config_descriptor(conf_desc); ++ termux_usb_free_config_descriptor(conf_desc); + } + } + +- libusb_free_device_list(devs, 1); ++ termux_usb_free_device_list(devices); + + return root; + } +@@ -1140,8 +1146,8 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path) + { + hid_device *dev = NULL; + +- libusb_device **devs = NULL; +- libusb_device *usb_dev = NULL; ++ struct termux_usb_device **devs = NULL; ++ struct termux_usb_device *usb_dev = NULL; + int res = 0; + int d = 0; + int good_open = 0; +@@ -1151,40 +1157,51 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path) + + dev = new_hid_device(); + +- libusb_get_device_list(usb_context, &devs); ++ termux_usb_get_device_list(&devs); + while ((usb_dev = devs[d++]) != NULL && !good_open) { +- struct libusb_config_descriptor *conf_desc = NULL; +- int j,k; ++ struct termux_usb_config_descriptor *conf_desc = NULL; ++ int j, k, i; + +- if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0) +- continue; ++ termux_usb_get_config_descriptor(usb_dev, 0, &conf_desc); + for (j = 0; j < conf_desc->bNumInterfaces && !good_open; j++) { +- const struct libusb_interface *intf = &conf_desc->interface[j]; +- for (k = 0; k < intf->num_altsetting && !good_open; k++) { +- const struct libusb_interface_descriptor *intf_desc = &intf->altsetting[k]; +- if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { +- char dev_path[64]; +- get_path(&dev_path, usb_dev, conf_desc->bConfigurationValue, intf_desc->bInterfaceNumber); +- if (!strcmp(dev_path, path)) { +- /* Matched Paths. Open this device */ +- +- /* OPEN HERE */ +- res = libusb_open(usb_dev, &dev->device_handle); +- if (res < 0) { +- LOG("can't open device\n"); +- break; ++ const struct termux_usb_interface_descriptor *intf = &conf_desc->interface[j]; ++ if (intf->bInterfaceClass == LIBUSB_CLASS_HID) { ++ if (!strcmp(usb_dev->device_address, path)) { ++ /* Matched Paths. Open this device */ ++ ++ /* OPEN HERE */ ++ intptr_t fd = termux_usb_open(usb_dev); ++ if (fd <= 0) { ++ LOG("Failed to open device\n"); ++ continue; ++ } ++ int res = libusb_wrap_sys_device(usb_context, fd, &dev->device_handle); ++ if (res != 0) { ++ LOG("Failed to wrap sys device: %d\n", res); ++ continue; ++ } ++ libusb_device *device = libusb_get_device(dev->device_handle); ++ ++ /* Now we can check actually get conf_desc and check altsetting */ ++ struct libusb_config_descriptor *libusb_conf_desc = NULL; ++ libusb_get_active_config_descriptor(device, &libusb_conf_desc); ++ for (k = 0; k < libusb_conf_desc->bNumInterfaces && !good_open; k++) { ++ const struct libusb_interface *libusb_intf = &libusb_conf_desc->interface[k]; ++ for (i = 0; i < libusb_intf->num_altsetting && !good_open; i++) { ++ const struct libusb_interface_descriptor *libusb_intf_desc = &libusb_intf->altsetting[k]; ++ if (libusb_intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { ++ good_open = hidapi_initialize_device(dev, libusb_conf_desc->bConfigurationValue, libusb_intf_desc); ++ } + } +- good_open = hidapi_initialize_device(dev, conf_desc->bConfigurationValue, intf_desc); +- if (!good_open) +- libusb_close(dev->device_handle); + } ++ libusb_free_config_descriptor(libusb_conf_desc); + } + } + } +- libusb_free_config_descriptor(conf_desc); ++ termux_usb_free_config_descriptor(conf_desc); + } + +- libusb_free_device_list(devs, 1); ++ termux_usb_free_device_list(devs); + + /* If we have a good handle, return it. */ + if (good_open) { +-- +2.49.0 + diff --git a/packages/hidapi/0003-libusb-hid-set-path-to-device_address-from-termux-us.patch b/packages/hidapi/0003-libusb-hid-set-path-to-device_address-from-termux-us.patch new file mode 100644 index 00000000000000..4b1afd14ff4e70 --- /dev/null +++ b/packages/hidapi/0003-libusb-hid-set-path-to-device_address-from-termux-us.patch @@ -0,0 +1,48 @@ +From 36024a130df8bdbf64b7cb7f9c21dce4f8fe5530 Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Tue, 25 Mar 2025 14:16:01 +0100 +Subject: [PATCH] libusb: hid: set path to device_address from termux-usb + +The path normally comes from make_path/get_path, and is a string with +information about where/how device is connected and what configuration +and interface it uses. The information comes from +libusb_get_port_numbers, but that function does not seem to work on +android. Instead we can use the usbfs path to distinguish different +devices. + +This will likely break if a device has multiple configurations and +interfaces, and a program is suppose to use a specific one, but works +for simple devices and use-cases.. +--- + libusb/hid.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/libusb/hid.c b/libusb/hid.c +index 8e866f32de41..3f8d6a138448 100644 +--- a/libusb/hid.c ++++ b/libusb/hid.c +@@ -671,8 +671,6 @@ static struct hid_device_info * create_device_info_for_device(libusb_device *dev + + cur_dev->bus_type = HID_API_BUS_USB; + +- cur_dev->path = make_path(device, config_number, interface_num); +- + if (!handle) { + return cur_dev; + } +@@ -804,6 +802,12 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, + #endif + + tmp = create_device_info_for_device(dev, handle, &desc, conf_desc->bConfigurationValue, intf_desc->bInterfaceNumber); ++ /* path is suppose to come from make_path, but libusb_get_port_numbers ++ there does not seem to work on android. Instead pass and ++ distinguish devices based on the usbfs (/dev/bus/usb/001/001) ++ path. This likely has some drawbacks for devices with many ++ different configurations&interfaces.. */ ++ tmp->path = strdup(device->device_address); + if (tmp) { + #ifdef INVASIVE_GET_USAGE + /* TODO: have a runtime check for this section. */ +-- +2.49.0 + diff --git a/packages/hidapi/build.sh b/packages/hidapi/build.sh index 5a23cde2a98e7d..29c898b995f274 100644 --- a/packages/hidapi/build.sh +++ b/packages/hidapi/build.sh @@ -4,6 +4,11 @@ TERMUX_PKG_LICENSE="GPL-3.0, BSD 3-Clause, custom" TERMUX_PKG_LICENSE_FILE="LICENSE.txt, LICENSE-gpl3.txt, LICENSE-bsd.txt, LICENSE-orig.txt" TERMUX_PKG_MAINTAINER="@termux" TERMUX_PKG_VERSION=0.14.0 +TERMUX_PKG_REVISION=1 TERMUX_PKG_SRCURL="https://github.com/libusb/hidapi/archive/refs/tags/hidapi-${TERMUX_PKG_VERSION}.tar.gz" TERMUX_PKG_SHA256=a5714234abe6e1f53647dd8cba7d69f65f71c558b7896ed218864ffcf405bcbd -TERMUX_PKG_DEPENDS="libiconv, libusb" +TERMUX_PKG_DEPENDS="libiconv, libusb, libprotobuf-c, termux-api" + +termux_step_pre_configure() { + export CFLAGS+=" -DDEBUG_PRINTF=1" +} diff --git a/packages/hidapi/libusb-iconv-CMakeLists.txt.patch b/packages/hidapi/libusb-iconv-CMakeLists.txt.patch deleted file mode 100644 index 2a8261f04b22cb..00000000000000 --- a/packages/hidapi/libusb-iconv-CMakeLists.txt.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- ./libusb/CMakeLists.txt~ 2025-02-01 13:16:49.669029267 +0000 -+++ ./libusb/CMakeLists.txt 2025-02-01 13:18:12.309030989 +0000 -@@ -22,7 +22,6 @@ - if(HIDAPI_NO_ICONV) - target_compile_definitions(hidapi_libusb PRIVATE NO_ICONV) - else() -- if(NOT ANDROID) - include(CheckCSourceCompiles) - - if(NOT CMAKE_VERSION VERSION_LESS 3.11) -@@ -77,9 +76,6 @@ - if(HIDAPI_ICONV_CONST) - target_compile_definitions(hidapi_libusb PRIVATE "ICONV_CONST=const") - endif() -- else() -- # On Android Iconv is disabled on the code level anyway, so no issue; -- endif() - endif() - - set_target_properties(hidapi_libusb diff --git a/packages/hidapi/termux-iconv-hid.c.patch b/packages/hidapi/termux-iconv-hid.c.patch deleted file mode 100644 index 42091e982ea3eb..00000000000000 --- a/packages/hidapi/termux-iconv-hid.c.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- ./libusb/hid.c~ 2023-05-22 10:50:06.000000000 +0000 -+++ ./libusb/hid.c 2025-02-01 13:13:05.412357928 +0000 -@@ -42,7 +42,7 @@ - - /* GNU / LibUSB */ - #include --#if !defined(__ANDROID__) && !defined(NO_ICONV) -+#if (!defined(__ANDROID__) || defined(__TERMUX__)) && !defined(NO_ICONV) - #include - #ifndef ICONV_CONST - #define ICONV_CONST -@@ -406,7 +406,7 @@ - int len; - wchar_t *str = NULL; - --#if !defined(__ANDROID__) && !defined(NO_ICONV) /* we don't use iconv on Android, or when it is explicitly disabled */ -+#if (!defined(__ANDROID__) || defined(__TERMUX__)) && !defined(NO_ICONV) /* we don't use iconv on non-Termux Android, or when it is explicitly disabled */ - wchar_t wbuf[256]; - /* iconv variables */ - iconv_t ic; -@@ -432,7 +432,7 @@ - if (len < 2) /* we always skip first 2 bytes */ - return NULL; - --#if defined(__ANDROID__) || defined(NO_ICONV) -+#if (defined(__ANDROID__) || defined(NO_ICONV)) && !defined(__TERMUX__) - - /* Bionic does not have iconv support nor wcsdup() function, so it - has to be done manually. The following code will only work for diff --git a/packages/python-btchip/0001-setup.py-use-slightly-newer-dependency-for-python-py.patch b/packages/python-btchip/0001-setup.py-use-slightly-newer-dependency-for-python-py.patch new file mode 100644 index 00000000000000..3f1f9567791ee4 --- /dev/null +++ b/packages/python-btchip/0001-setup.py-use-slightly-newer-dependency-for-python-py.patch @@ -0,0 +1,31 @@ +From f1c4274af869265d07a520d527cce33a82e1a3b9 Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Sun, 16 Feb 2025 16:13:42 +0100 +Subject: [PATCH] setup.py: use (slightly) newer dependency for python-pyscard + +1.6.12-4build1 is not a valid version string, and gives an error in +modern python versions: + + error in btchip-python setup command: 'extras_require' must be a dictionary whose values are strings or lists of strings containing valid project/version requirement specifiers. + +Use the next available python-pyscard as min version. +--- + setup.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/setup.py b/setup.py +index accfe2485778..5be3c9ebc45b 100644 +--- a/setup.py ++++ b/setup.py +@@ -17,7 +17,7 @@ setup( + packages=find_packages(), + install_requires=['hidapi>=0.7.99', 'ecdsa>=0.9'], + extras_require = { +- 'smartcard': [ 'python-pyscard>=1.6.12-4build1' ] ++ 'smartcard': [ 'python-pyscard>=1.6.14' ] + }, + include_package_data=True, + zip_safe=False, +-- +2.48.1 + diff --git a/packages/python-btchip/build.sh b/packages/python-btchip/build.sh new file mode 100644 index 00000000000000..17fe87544771ee --- /dev/null +++ b/packages/python-btchip/build.sh @@ -0,0 +1,22 @@ +TERMUX_PKG_HOMEPAGE=https://github.com/LedgerHQ/btchip-python +TERMUX_PKG_DESCRIPTION="Ledger HW.1 Python API" +TERMUX_PKG_LICENSE="Apache-2.0" +TERMUX_PKG_MAINTAINER="@termux" +TERMUX_PKG_VERSION=0.1.32 +TERMUX_PKG_SRCURL="https://github.com/LedgerHQ/btchip-python/archive/refs/tags/${TERMUX_PKG_VERSION}.tar.gz" +TERMUX_PKG_SHA256=b5cce374072467d27267d5c4a9159e7e956a016543d8a0f00e20c9830061ec9b +# EOL, no need to check for updates +TERMUX_PKG_AUTO_UPDATE=false +TERMUX_PKG_DEPENDS="python, python-pip, python-hidapi" +TERMUX_PKG_PYTHON_COMMON_DEPS="wheel" +TERMUX_PKG_PYTHON_TARGET_DEPS="ecdsa" +TERMUX_PKG_PLATFORM_INDEPENDENT=true +TERMUX_PKG_BUILD_IN_SRC=true + +termux_step_create_debscripts() { + cat <<- EOF > ./postinst + #!$TERMUX_PREFIX/bin/sh + echo "Installing dependencies through pip..." + pip3 install ${TERMUX_PKG_PYTHON_TARGET_DEPS//, / } + EOF +} diff --git a/packages/python-hidapi/0001-setup.py-build-only-libusb-backend-even-on-linux.patch b/packages/python-hidapi/0001-setup.py-build-only-libusb-backend-even-on-linux.patch new file mode 100644 index 00000000000000..1808c4dd6af24d --- /dev/null +++ b/packages/python-hidapi/0001-setup.py-build-only-libusb-backend-even-on-linux.patch @@ -0,0 +1,64 @@ +From 79768217bb6bcd18e6f0dd00973ceff0d839798b Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Sun, 16 Feb 2025 19:43:58 +0100 +Subject: [PATCH] setup.py: build only libusb backend even on linux + +On android we cannot use hidraw, only libusb, so build only that +variant. +--- + setup.py | 18 +----------------- + 1 file changed, 1 insertion(+), 17 deletions(-) + +diff --git a/setup.py b/setup.py +index 7c79a38c7b8c..6e302ee12fd8 100755 +--- a/setup.py ++++ b/setup.py +@@ -137,7 +137,7 @@ def hid_from_embedded_hidapi(): + HIDAPI_WITH_LIBUSB = to_bool(os.getenv("HIDAPI_WITH_LIBUSB")) + + if HIDAPI_WITH_LIBUSB: +- hidraw_module = "hidraw" ++ hidraw_module = "hid" + modules.append( + pkgconfig_configure_extension( + Extension( +@@ -152,15 +152,6 @@ def hid_from_embedded_hidapi(): + hidraw_module = "hid" + check_deprecated_without_libusb() + +- modules.append( +- Extension( +- hidraw_module, +- sources=["hidraw.pyx", hidapi_src("linux")], +- include_dirs=[embedded_hidapi_include], +- libraries=["udev"], +- ) +- ) +- + else: + modules = [ + pkgconfig_configure_extension( +@@ -186,7 +177,6 @@ def hid_from_system_hidapi(): + HIDAPI_WITH_LIBUSB = to_bool(os.getenv("HIDAPI_WITH_LIBUSB")) + + if HIDAPI_WITH_LIBUSB: +- hidraw_module = "hidraw" + modules.append( + pkgconfig_configure_extension( + Extension("hid", sources=["hid.pyx"]), hidapi_libusb_pkgconfig +@@ -196,12 +186,6 @@ def hid_from_system_hidapi(): + hidraw_module = "hid" + check_deprecated_without_libusb() + +- modules.append( +- pkgconfig_configure_extension( +- Extension(hidraw_module, sources=["hidraw.pyx"]), +- hidapi_hidraw_pkgconfig, +- ) +- ) + else: + modules = [ + pkgconfig_configure_extension( +-- +2.49.0 + diff --git a/packages/python-hidapi/0002-termux-link-against-iconv-termux-usb-and-protobuf-c.patch b/packages/python-hidapi/0002-termux-link-against-iconv-termux-usb-and-protobuf-c.patch new file mode 100644 index 00000000000000..2961f34bd6c4a4 --- /dev/null +++ b/packages/python-hidapi/0002-termux-link-against-iconv-termux-usb-and-protobuf-c.patch @@ -0,0 +1,28 @@ +From 8390a9c52212a7df20987f4e39d05e7e44b638ef Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Sat, 8 Mar 2025 02:42:05 +0100 +Subject: [PATCH] termux: link against iconv, termux-usb and protobuf-c + +So that we can use termux-usb and termux-api's usb functions instead of (some of) +libusb's variants. +--- + setup.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/setup.py b/setup.py +index 6e302ee12fd8..ab6cf190ff41 100755 +--- a/setup.py ++++ b/setup.py +@@ -143,7 +143,8 @@ def hid_from_embedded_hidapi(): + Extension( + "hid", + sources=["hid.pyx", hidapi_src("libusb")], +- include_dirs=[embedded_hidapi_include], ++ include_dirs=[embedded_hidapi_include, "/data/data/com.termux/files/usr/include", "/data/data/com.termux/files/usr/include/libusb-1.0/"], ++ libraries=["iconv", "termux-usb", "protobuf-c"], + ), + libusb_pkgconfig, + ) +-- +2.49.0 + diff --git a/packages/python-hidapi/build.sh b/packages/python-hidapi/build.sh new file mode 100644 index 00000000000000..0fcb9ceca70cbc --- /dev/null +++ b/packages/python-hidapi/build.sh @@ -0,0 +1,17 @@ +TERMUX_PKG_HOMEPAGE=https://github.com/trezor/cython-hidapi +TERMUX_PKG_DESCRIPTION="Python wrapper for the HIDAPI" +TERMUX_PKG_LICENSE="GPL-3.0, BSD 3-Clause" +TERMUX_PKG_MAINTAINER="@termux" +TERMUX_PKG_VERSION=(0.14.0.post2 + 0.14.0) +TERMUX_PKG_SRCURL="https://github.com/trezor/cython-hidapi/archive/refs/tags/${TERMUX_PKG_VERSION}.tar.gz" +TERMUX_PKG_SHA256=72c51470f529f6e2f1b14a11c0220ed426af36efcd04dd1e58b97f3fb5702d74 +TERMUX_PKG_DEPENDS="hidapi, python, python-pip, termux-api, libprotobuf-c, libiconv" +TERMUX_PKG_PYTHON_COMMON_DEPS="Cython" +TERMUX_PKG_PLATFORM_INDEPENDENT=true +TERMUX_PKG_BUILD_IN_SRC=true + +termux_step_pre_configure() { + export HIDAPI_SYSTEM_HIDAPI=1 + export HIDAPI_WITH_LIBUSB=1 +} diff --git a/packages/termux-api/0001-Add-termux-usb-library.patch b/packages/termux-api/0001-Add-termux-usb-library.patch new file mode 100644 index 00000000000000..709276b2d00b1d --- /dev/null +++ b/packages/termux-api/0001-Add-termux-usb-library.patch @@ -0,0 +1,558 @@ +From 69db489ee69908afd7d52fe0f48b2f518cd43148 Mon Sep 17 00:00:00 2001 +From: Henrik Grimler +Date: Sun, 16 Mar 2025 09:53:35 +0100 +Subject: [PATCH] Add termux-usb library + +It contains the following functions: + +* termux_usb_get_device_list +* termux_usb_free_device_list +* termux_usb_open +* termux_usb_get_config_descriptor +* termux_usb_free_config_descriptor + +These functions are replacements for the corresponding libusb_* +functions, kind of. The termux variants uses structs like struct +termux_usb_device and struct termux_usb_config_descriptor that are +similar, but not identical, to libusb_device and +libusb_config_descriptor. They work by calling termux-api and get back +information about devices and configs as a protobuf stream. + +The free functions also frees all array elements, whereas the libusb +variants only frees elements that have a reference count of 1 or +less. For the termux variants where do not keep track of the reference +count, so information that should be kept around should be memcpy'ed +or similar before termux_usb_free_* is called. + +termux_usb_open requires user interaction. It calls termux-api which +opens the device through the android API, which shows a prompt to the +user to accept or deny opening the device. +--- + CMakeLists.txt | 2 + + usb/CMakeLists.txt | 33 ++++++ + usb/proto/UsbAPI.proto | 57 +++++++++ + usb/termux-usb.c | 259 +++++++++++++++++++++++++++++++++++++++++ + usb/termux-usb.h | 128 ++++++++++++++++++++ + 5 files changed, 479 insertions(+) + create mode 100644 usb/CMakeLists.txt + create mode 100644 usb/proto/UsbAPI.proto + create mode 100644 usb/termux-usb.c + create mode 100644 usb/termux-usb.h + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index c8b1f9e5995d..00f18a567e64 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -11,6 +11,8 @@ set_target_properties(termux-api-static PROPERTIES OUTPUT_NAME termux-api) + add_executable(termux-api-broadcast termux-api-broadcast.c) + target_link_libraries(termux-api-broadcast termux-api-static) + ++add_subdirectory(usb) ++ + # TODO: get list through regex or similar + set(script_files + scripts/termux-api-start +diff --git a/usb/CMakeLists.txt b/usb/CMakeLists.txt +new file mode 100644 +index 000000000000..d9d61419e7ea +--- /dev/null ++++ b/usb/CMakeLists.txt +@@ -0,0 +1,33 @@ ++cmake_minimum_required(VERSION 3.10.0) ++project(termux-usb) ++ ++find_package(PkgConfig REQUIRED) ++pkg_check_modules(libusb REQUIRED libusb-1.0) ++# For test building on Linux below needs to be changed to ++# find_package(Protobuf REQUIRED CONFIG) for some reason.. ++find_package(Protobuf REQUIRED) ++protobuf_generate( ++ LANGUAGE C ++ GENERATE_EXTENSIONS .pb-c.c ++ OUT_VAR PROTO_SRCS ++ PROTOS proto/UsbAPI.proto ++) ++add_library(termux-usb SHARED termux-usb.c termux-usb.h ${PROTO_SRCS} ${PROTO_HDRS}) ++ ++target_include_directories( ++ termux-usb ++ PUBLIC ${Protobuf_INCLUDE_DIRS} ${libusb_INCLUDE_DIRS} ++ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/proto ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} ++) ++target_link_libraries(termux-usb PUBLIC ${Protobuf_LIBRARIES} ${CMAKE_BINARY_DIR}/libtermux-api.so -lprotobuf-c ${libusb_LIBRARIES}) ++ ++install( ++ FILES ++ ${CMAKE_CURRENT_BINARY_DIR}/libtermux-usb.so ++ TYPE LIB ++) ++ ++install( ++ FILES ${CMAKE_CURRENT_SOURCE_DIR}/termux-usb.h ++ TYPE INCLUDE ++) +diff --git a/usb/proto/UsbAPI.proto b/usb/proto/UsbAPI.proto +new file mode 100644 +index 000000000000..5a1d89c5cb6a +--- /dev/null ++++ b/usb/proto/UsbAPI.proto +@@ -0,0 +1,57 @@ ++syntax = "proto3"; ++ ++package usbapi; ++ ++option java_package = "com.termux.api"; ++option java_outer_classname = "UsbAPIProto"; ++ ++/* Modelled after libusb's struct libusb_endpoint_descriptor */ ++message termuxUsbEndpointDescriptor { ++ int32 endpointAddress = 1; ++ int32 attributes = 2; ++ int32 maxPacketSize = 3; ++ int32 interval = 4; ++} ++ ++/* Modelled after libusb's struct libusb_interface_descriptor */ ++message termuxUsbInterfaceDescriptor { ++ int32 alternateSetting = 1; ++ int32 interfaceClass = 2; ++ int32 interfaceSubclass = 3; ++ int32 interfaceProtocol = 4; ++ string interface = 5; ++ repeated termuxUsbEndpointDescriptor endpoint = 6; ++} ++ ++/* Modelled after libusb's struct libusb_config_descriptor */ ++message termuxUsbConfigDescriptor { ++ int32 configurationValue = 1; ++ int32 maxPower = 2; ++ string configuration = 3; ++ repeated termuxUsbInterfaceDescriptor interface = 4; ++} ++ ++/* Modelled after libusb's struct libusb_device_descriptor */ ++message termuxUsbDeviceDescriptor { ++ int32 configurationCount = 1; ++ int32 deviceClass = 2; ++ int32 deviceProtocol = 3; ++ int32 deviceSubclass = 4; ++ int32 productId = 5; ++ int32 vendorId = 6; ++ string manufacturerName = 7; ++ string productName = 8; ++ string serialNumber = 9; ++} ++ ++/* Loosely modelled after libusb's internal struct libusb_device */ ++message termuxUsbDevice { ++ int32 busNumber = 1; ++ int32 portNumber = 2; ++ string deviceAddress = 3; ++ termuxUsbDeviceDescriptor device = 4; ++} ++ ++message termuxUsb { ++ repeated termuxUsbDevice device = 1; ++} +diff --git a/usb/termux-usb.c b/usb/termux-usb.c +new file mode 100644 +index 000000000000..4c55e2ae5032 +--- /dev/null ++++ b/usb/termux-usb.c +@@ -0,0 +1,259 @@ ++#include ++#include ++#include ++#include ++ ++#include "termux-api.h" ++#include "termux-usb.h" ++#include "UsbAPI.pb-c.h" ++ ++#define BUF_SIZE 1024 ++#define TERMUX_PREFIX "/data/data/com.termux/files/usr" ++ ++static size_t read_buffer (unsigned int buf_size, uint8_t *out, FILE *fp) ++{ ++ size_t cur_len = 0; ++ size_t nread; ++ while ((nread = fread(out + cur_len, 1, buf_size - cur_len, fp)) != 0) ++ { ++ cur_len += nread; ++ if (cur_len >= buf_size) ++ { ++ fprintf(stderr, "max message length exceeded\n"); ++ exit(EXIT_FAILURE); ++ } ++ } ++ return cur_len; ++} ++ ++ssize_t termux_usb_get_device_list(struct termux_usb_device ***list) ++{ ++ Usbapi__TermuxUsb *container; ++ struct termux_usb_device **ret; ++ uint8_t buf[BUF_SIZE]; ++ FILE *fp; ++ unsigned int num_devices; ++ ++ fp = popen(TERMUX_PREFIX "/libexec/termux-api Usb -a getDevices", "r"); ++ if (fp == NULL) { ++ perror("popen"); ++ exit(EXIT_FAILURE); ++ } ++ ++ size_t msg_len = read_buffer(BUF_SIZE, buf, fp); ++ if (pclose(fp)) { ++ fprintf(stderr, "Error closing protobuf stream\n"); ++ return -1; ++ } ++ ++ container = usbapi__termux_usb__unpack(NULL, msg_len, buf); ++ if (container == NULL) ++ { ++ fprintf(stderr, "Error unpacking incoming message\n"); ++ return -1; ++ } ++ ++ ret = (struct termux_usb_device **) calloc(container->n_device + 1, sizeof(struct termux_usb_device *)); ++ if (!ret) { ++ fprintf(stderr, "Failed to allocate memory\n"); ++ usbapi__termux_usb__free_unpacked(container, NULL); ++ return -1; ++ } ++ ++ ret[container->n_device] = NULL; ++ for (size_t i = 0; i < container->n_device; i++) { ++ Usbapi__TermuxUsbDevice *msg = container->device[i]; ++ Usbapi__TermuxUsbDeviceDescriptor *desc = msg->device; ++ struct termux_usb_device *dev = (struct termux_usb_device *) malloc(sizeof(struct termux_usb_device)); ++ struct termux_usb_device_descriptor *dev_desc = (struct termux_usb_device_descriptor *) malloc(sizeof(struct termux_usb_device_descriptor)); ++ ++ dev->bus_number = msg->busnumber; ++ dev->port_number = msg->portnumber; ++ ++ dev->device_address = (char *) malloc(strlen(msg->deviceaddress)+1); ++ strcpy(dev->device_address, msg->deviceaddress); ++ ++ dev_desc->bDeviceClass = desc->deviceclass; ++ dev_desc->bDeviceSubClass = desc->devicesubclass; ++ dev_desc->bDeviceProtocol = desc->deviceprotocol; ++ dev_desc->idVendor = desc->vendorid; ++ dev_desc->idProduct = desc->productid; ++ ++ dev_desc->manufacturer = (char *) malloc(strlen(desc->manufacturername)+1); ++ strcpy(dev_desc->manufacturer, desc->manufacturername); ++ ++ dev_desc->product = (char *) malloc(strlen(desc->productname)+1); ++ strcpy(dev_desc->product, desc->productname); ++ ++ dev_desc->serialNumber = (char *) malloc(strlen(desc->serialnumber)+1); ++ strcpy(dev_desc->serialNumber, desc->serialnumber); ++ ++ dev_desc->bNumConfigurations = desc->configurationcount; ++ ++ dev->device_descriptor = dev_desc; ++ ret[i] = dev; ++ } ++ *list = ret; ++ ++ num_devices = container->n_device; ++ usbapi__termux_usb__free_unpacked(container, NULL); ++ return num_devices; ++} ++ ++void termux_usb_free_device_list(struct termux_usb_device **list) ++{ ++ int i = 0; ++ struct termux_usb_device *dev; ++ while ((dev = list[i++]) != NULL) { ++ free(dev->device_descriptor->manufacturer); ++ free(dev->device_descriptor->product); ++ free(dev->device_descriptor->serialNumber); ++ free(dev->device_descriptor); ++ free(dev->device_address); ++ free(dev); ++ } ++ free(list); ++} ++ ++intptr_t termux_usb_open_address(char *address) ++{ ++ int argc = 10; ++ char *argv[argc]; ++ argv[0] = "termux-usb"; ++ argv[1] = "Usb"; ++ argv[2] = "-a"; ++ argv[3] = "open"; ++ argv[4] = "--ez"; ++ argv[5] = "request"; ++ argv[6] = "true"; ++ argv[7] = "--es"; ++ argv[8] = "device"; ++ argv[9] = address; ++ ++ int fd = run_api_command(argc, argv); ++ ++ return (intptr_t) fd; ++} ++ ++intptr_t termux_usb_open(struct termux_usb_device *dev) ++{ ++ return termux_usb_open_address(dev->device_address); ++} ++ ++int termux_usb_get_config_descriptor(struct termux_usb_device *dev, int config_index, ++ struct termux_usb_config_descriptor **conf_desc) ++{ ++ Usbapi__TermuxUsbConfigDescriptor *confDesc; ++ uint8_t buf[BUF_SIZE]; ++ FILE *fp; ++ ++ char cmd[256]; ++ char *base_cmd = TERMUX_PREFIX "/libexec/termux-api Usb -a getConfigDescriptor --es device %s --ei config %d"; ++ snprintf(cmd, sizeof(cmd)-1, base_cmd, dev->device_address, config_index); ++ fp = popen(cmd, "r"); ++ if (fp == NULL) { ++ perror("popen"); ++ return 1; ++ } ++ ++ size_t msg_len = read_buffer(BUF_SIZE, buf, fp); ++ if (pclose(fp)) { ++ fprintf(stderr, "Error closing protobuf stream\n"); ++ return -1; ++ } ++ ++ confDesc = usbapi__termux_usb_config_descriptor__unpack(NULL, msg_len, buf); ++ if (confDesc == NULL) { ++ fprintf(stderr, "Error unpacking incoming config descriptor message\n"); ++ return -1; ++ } ++ ++ struct termux_usb_config_descriptor *conf; ++ conf = (struct termux_usb_config_descriptor *) malloc(sizeof(struct termux_usb_config_descriptor)); ++ if (conf == NULL) { ++ fprintf(stderr, "Memory allocation failed\n"); ++ usbapi__termux_usb_config_descriptor__free_unpacked(confDesc, NULL); ++ return -1; ++ } ++ ++ conf->bConfigurationValue = confDesc->configurationvalue; ++ conf->configuration = (char *) malloc(strlen(confDesc->configuration)+1); ++ if (conf->configuration == NULL) { ++ fprintf(stderr, "Memory allocation failed\n"); ++ free(conf); ++ usbapi__termux_usb_config_descriptor__free_unpacked(confDesc, NULL); ++ return -1; ++ } ++ strcpy(conf->configuration, confDesc->configuration); ++ conf->MaxPower = confDesc->maxpower; ++ conf->bNumInterfaces = confDesc->n_interface; ++ ++ conf->interface = (struct termux_usb_interface_descriptor *) calloc(confDesc->n_interface, sizeof(struct termux_usb_interface_descriptor)); ++ if (conf->interface == NULL) { ++ fprintf(stderr, "Memory allocation failed\n"); ++ free(conf->configuration); ++ free(conf); ++ usbapi__termux_usb_config_descriptor__free_unpacked(confDesc, NULL); ++ return -1; ++ } ++ ++ for (size_t i = 0; i < confDesc->n_interface; i++) { ++ Usbapi__TermuxUsbInterfaceDescriptor *intfDesc = confDesc->interface[i]; ++ ++ conf->interface[i].bAlternateSetting = intfDesc->alternatesetting; ++ conf->interface[i].bNumEndpoints = intfDesc->n_endpoint; ++ conf->interface[i].bInterfaceClass = intfDesc->interfaceclass; ++ conf->interface[i].bInterfaceSubClass = intfDesc->interfacesubclass; ++ conf->interface[i].bInterfaceProtocol = intfDesc->interfaceprotocol; ++ conf->interface[i].interface = (char *) malloc(strlen(intfDesc->interface)+1); ++ if (conf->interface[i].interface == NULL) { ++ fprintf(stderr, "Memory allocation failed\n"); ++ for (size_t j = 0; j < i; i++) { ++ free(conf->interface[i].endpoint); ++ free(conf->interface[i].interface); ++ } ++ free(conf->interface); ++ free(conf->configuration); ++ free(conf); ++ usbapi__termux_usb_config_descriptor__free_unpacked(confDesc, NULL); ++ return -1; ++ } ++ strcpy(conf->interface[i].interface, intfDesc->interface); ++ ++ conf->interface[i].endpoint = (struct termux_usb_endpoint_descriptor *) calloc(intfDesc->n_endpoint, sizeof(struct termux_usb_endpoint_descriptor)); ++ if (conf->interface[i].endpoint == NULL) { ++ fprintf(stderr, "Memory allocation failed\n"); ++ for (size_t j = 0; j < i; i++) { ++ free(conf->interface[i].endpoint); ++ free(conf->interface[i].interface); ++ } ++ free(conf->interface); ++ free(conf->configuration); ++ free(conf); ++ usbapi__termux_usb_config_descriptor__free_unpacked(confDesc, NULL); ++ } ++ ++ for (size_t j = 0; j < intfDesc->n_endpoint; j++) { ++ Usbapi__TermuxUsbEndpointDescriptor *endpointDesc = intfDesc->endpoint[j]; ++ conf->interface[i].endpoint[j].bEndpointAddress = endpointDesc->endpointaddress; ++ conf->interface[i].endpoint[j].bmAttributes = endpointDesc->attributes; ++ conf->interface[i].endpoint[j].wMaxPacketSize = endpointDesc->maxpacketsize; ++ conf->interface[i].endpoint[j].bInterval = endpointDesc->interval; ++ } ++ } ++ *conf_desc = conf; ++ ++ usbapi__termux_usb_config_descriptor__free_unpacked(confDesc, NULL); ++ return 0; ++} ++ ++void termux_usb_free_config_descriptor(struct termux_usb_config_descriptor *conf_desc) ++{ ++ for (int i = 0; i < conf_desc->bNumInterfaces; i++) { ++ free(conf_desc->interface[i].endpoint); ++ free(conf_desc->interface[i].interface); ++ } ++ free(conf_desc->interface); ++ free(conf_desc->configuration); ++ free(conf_desc); ++} +diff --git a/usb/termux-usb.h b/usb/termux-usb.h +new file mode 100644 +index 000000000000..a59821dd4bcf +--- /dev/null ++++ b/usb/termux-usb.h +@@ -0,0 +1,128 @@ ++#include ++ ++#if defined(__cplusplus) ++extern "C" { ++#endif ++ ++struct termux_usb_device_descriptor { ++ /** USB-IF class code for the device. See \ref libusb_class_code. */ ++ uint8_t bDeviceClass; ++ ++ /** USB-IF subclass code for the device, qualified by the bDeviceClass ++ * value */ ++ uint8_t bDeviceSubClass; ++ ++ /** USB-IF protocol code for the device, qualified by the bDeviceClass and ++ * bDeviceSubClass values */ ++ uint8_t bDeviceProtocol; ++ ++ /** USB-IF vendor ID */ ++ uint16_t idVendor; ++ ++ /** USB-IF product ID */ ++ uint16_t idProduct; ++ ++ /** String describing manufacturer */ ++ char *manufacturer; ++ ++ /** String describing product */ ++ char *product; ++ ++ /** String containing device serial number */ ++ char *serialNumber; ++ ++ /** Number of possible configurations */ ++ uint8_t bNumConfigurations; ++}; ++ ++ ++struct termux_usb_device { ++ uint8_t bus_number; ++ uint8_t port_number; ++ char *device_address; ++ ++ struct termux_usb_device_descriptor *device_descriptor; ++}; ++ ++struct termux_usb_endpoint_descriptor { ++ /** The address of the endpoint described by this descriptor. Bits 0:3 are ++ * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, ++ * see \ref libusb_endpoint_direction. */ ++ uint8_t bEndpointAddress; ++ ++ /** Attributes which apply to the endpoint when it is configured using ++ * the bConfigurationValue. Bits 0:1 determine the transfer type and ++ * correspond to \ref libusb_endpoint_transfer_type. Bits 2:3 are only used ++ * for isochronous endpoints and correspond to \ref libusb_iso_sync_type. ++ * Bits 4:5 are also only used for isochronous endpoints and correspond to ++ * \ref libusb_iso_usage_type. Bits 6:7 are reserved. */ ++ uint8_t bmAttributes; ++ ++ /** Maximum packet size this endpoint is capable of sending/receiving. */ ++ uint16_t wMaxPacketSize; ++ ++ /** Interval for polling endpoint for data transfers. */ ++ uint8_t bInterval; ++}; ++ ++struct termux_usb_interface_descriptor { ++ /** Number of this interface */ ++ uint8_t bInterfaceNumber; ++ ++ /** Value used to select this alternate setting for this interface */ ++ uint8_t bAlternateSetting; ++ ++ /** Number of endpoints used by this interface (excluding the control ++ * endpoint). */ ++ uint8_t bNumEndpoints; ++ ++ /** USB-IF class code for this interface. See \ref libusb_class_code. */ ++ uint8_t bInterfaceClass; ++ ++ /** USB-IF subclass code for this interface, qualified by the ++ * bInterfaceClass value */ ++ uint8_t bInterfaceSubClass; ++ ++ /** USB-IF protocol code for this interface, qualified by the ++ * bInterfaceClass and bInterfaceSubClass values */ ++ uint8_t bInterfaceProtocol; ++ ++ /** String describing this interface */ ++ char *interface; ++ ++ /** Array of endpoint descriptors. This length of this array is determined ++ * by the bNumEndpoints field. */ ++ struct termux_usb_endpoint_descriptor *endpoint; ++}; ++ ++struct termux_usb_config_descriptor { ++ /** Number of interfaces supported by this configuration */ ++ uint8_t bNumInterfaces; ++ ++ /** Identifier value for this configuration */ ++ uint8_t bConfigurationValue; ++ ++ /** String describing this configuration */ ++ char *configuration; ++ ++ /** Maximum power consumption of the USB device from this bus in this ++ * configuration when the device is fully operation. Expressed in units ++ * of 2 mA when the device is operating in high-speed mode and in units ++ * of 8 mA when the device is operating in super-speed mode. */ ++ uint8_t MaxPower; ++ ++ /** Array of interfaces supported by this configuration. The length of ++ * this array is determined by the bNumInterfaces field. */ ++ struct termux_usb_interface_descriptor *interface; ++}; ++ ++ssize_t termux_usb_get_device_list(struct termux_usb_device ***); ++void termux_usb_free_device_list(struct termux_usb_device **); ++intptr_t termux_usb_open_address(char *); ++intptr_t termux_usb_open(struct termux_usb_device *); ++int termux_usb_get_config_descriptor(struct termux_usb_device *, int, ++ struct termux_usb_config_descriptor **); ++void termux_usb_free_config_descriptor(struct termux_usb_config_descriptor *); ++#if defined(__cplusplus) ++} ++#endif +-- +2.49.0 + diff --git a/packages/termux-api/build.sh b/packages/termux-api/build.sh index 8ca300f357f129..d9d419dcf339ca 100644 --- a/packages/termux-api/build.sh +++ b/packages/termux-api/build.sh @@ -3,7 +3,12 @@ TERMUX_PKG_DESCRIPTION="Termux API commands (install also the Termux:API app)" TERMUX_PKG_LICENSE="MIT" TERMUX_PKG_MAINTAINER="@termux" TERMUX_PKG_VERSION=0.59.1 +TERMUX_PKG_REVISION=1 TERMUX_PKG_SRCURL=https://github.com/termux/termux-api-package/archive/v${TERMUX_PKG_VERSION}.tar.gz TERMUX_PKG_SHA256=92c2da07991a0191735539428aabb793e0ddb8e33baac305bcf38d77aa1eda80 TERMUX_PKG_BUILD_IN_SRC=true -TERMUX_PKG_DEPENDS="bash, util-linux, termux-am (>= 0.8.0)" +TERMUX_PKG_DEPENDS="bash, libusb, libprotobuf-c, util-linux, termux-am (>= 0.8.0)" + +termux_step_pre_configure() { + termux_setup_protobuf +}