From 6742d0bd7c5ac56a2c0dfe82f6dcd23d0e66562c Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 21 Jul 2023 17:14:27 -0500 Subject: [PATCH] Add HIDAPI support not work with -m option. Add -hidapi option. Signed-off-by: Frank Li --- .gitmodules | 3 + README.md | 4 +- libuuu/CMakeLists.txt | 7 +- libuuu/cmd.h | 4 +- libuuu/config.h | 6 + libuuu/libuuu.h | 3 + libuuu/trans.cpp | 30 +++++ libuuu/usbhotplug.cpp | 220 +++++++++++++++++++++++++++++++++++- msvc/libuuu.vcxproj | 9 +- msvc/libuuu.vcxproj.filters | 3 + uuu/CMakeLists.txt | 13 ++- uuu/uuu.cpp | 14 +++ 12 files changed, 300 insertions(+), 16 deletions(-) diff --git a/.gitmodules b/.gitmodules index 1fb57d2c..10930d92 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "zstd"] path = zstd url = https://github.com/facebook/zstd.git +[submodule "hidapi"] + path = hidapi + url = https://github.com/libusb/hidapi.git diff --git a/README.md b/README.md index 66d7aed2..ad57e641 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Note that, since uuu is an OSI compliant Open Source project, you are entitled t ## Linux - `git clone https://github.com/nxp-imx/mfgtools.git` - `cd mfgtools` -- `sudo apt-get install libusb-1.0-0-dev libbz2-dev libzstd-dev pkg-config cmake libssl-dev g++` +- `sudo apt-get install libusb-1.0-0-dev libbz2-dev libzstd-dev libhid-dev pkg-config cmake libssl-dev g++` - `cmake . && make` The above commands build mfgtools in source. To build it out of source @@ -87,7 +87,7 @@ For cmake prior 3.13: ## macOS - `git clone https://github.com/nxp-imx/mfgtools.git` - `cd mfgtools` -- `brew install cmake libusb openssl pkg-config` +- `brew install cmake libusb openssl hidapi pkg-config` - `cmake -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl . && make` Note that we assume [brew](https://brew.sh) is installed and can be used to resolve dependencies as shown above. The remaining dependency `libbz2` can be resolved via the XCode supplied libraries. diff --git a/libuuu/CMakeLists.txt b/libuuu/CMakeLists.txt index 8dcb0f63..d43a3daf 100644 --- a/libuuu/CMakeLists.txt +++ b/libuuu/CMakeLists.txt @@ -6,6 +6,11 @@ set(CMAKE_SKIP_RPATH ON) find_package(BZip2 REQUIRED) find_package(PkgConfig REQUIRED) +if(APPLE) +pkg_check_modules(LIBHID REQUIRED hidapi) +else() +pkg_check_modules(LIBHID REQUIRED hidapi-libusb) +endif() pkg_check_modules(LIBUSB REQUIRED libusb-1.0>=1.0.16) pkg_check_modules(LIBZSTD REQUIRED libzstd) find_package(Threads) @@ -21,7 +26,7 @@ set(UUUSSL "-DUUUSSL") set(UUUOPENSLL_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR}) endif() -include_directories(${LIBUSB_INCLUDE_DIRS} ${LIBZSTD_INCLUDE_DIRS} ${UUUOPENSLL_INCLUDE_DIR} include) +include_directories(${LIBUSB_INCLUDE_DIRS} ${LIBZSTD_INCLUDE_DIRS} ${UUUOPENSLL_INCLUDE_DIR} ${LIBHID_INCLUDE_DIRS} include) set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wstrict-aliasing -Wextra ${UUUSSL}") diff --git a/libuuu/cmd.h b/libuuu/cmd.h index 96899454..f1ab9f4f 100644 --- a/libuuu/cmd.h +++ b/libuuu/cmd.h @@ -51,6 +51,7 @@ class CmdCtx ConfigItem *m_config_item = nullptr; void *m_dev = nullptr; short m_current_bcd; + bool m_bHIDAPI = false; }; class CmdUsbCtx : public CmdCtx @@ -219,4 +220,5 @@ int run_cmd(CmdCtx *pCtx, const char * cmd, int dry); int insert_env_variable(std::string key, std::string value); std::string get_env_variable(std::string key); int clear_env(); -bool is_evn_exist(std::string key); \ No newline at end of file +bool is_evn_exist(std::string key); +bool is_using_hidapi(); \ No newline at end of file diff --git a/libuuu/config.h b/libuuu/config.h index 6d87b2ec..c754f466 100644 --- a/libuuu/config.h +++ b/libuuu/config.h @@ -34,6 +34,7 @@ #include #include #include +#include class ConfigItem { @@ -48,6 +49,10 @@ class ConfigItem m_chip = chip; if (comp) m_compatible = comp; + + m_bHID = (strcmp(pro, "SDP:") == 0) + || (strcmp(pro, "SDPS:") == 0) + || (strcmp(pro, "SDPV:") == 0); } std::string m_protocol; std::string m_chip; @@ -56,6 +61,7 @@ class ConfigItem uint16_t m_vid = 0; uint16_t m_bcdVerMin = 0; uint16_t m_bcdVerMax = UINT16_MAX; + bool m_bHID; }; class Config :public std::vector diff --git a/libuuu/libuuu.h b/libuuu/libuuu.h index 1b011500..07bb8bb8 100644 --- a/libuuu/libuuu.h +++ b/libuuu/libuuu.h @@ -144,6 +144,9 @@ void uuu_set_debug_level(uint32_t mask); */ void uuu_set_small_mem(uint32_t val); + +void uuu_set_using_hidapi(uint32_t val); + #define MAX_USER_LEN 128 typedef int (*uuu_askpasswd)(char* prompt, char user[MAX_USER_LEN], char passwd[MAX_USER_LEN]); int uuu_set_askpasswd(uuu_askpasswd ask); diff --git a/libuuu/trans.cpp b/libuuu/trans.cpp index fa84ee19..f4391509 100644 --- a/libuuu/trans.cpp +++ b/libuuu/trans.cpp @@ -34,6 +34,8 @@ #include "liberror.h" #include "libusb.h" #include "zip.h" +#include "cmd.h" +#include "hidapi.h" extern "C" { @@ -105,6 +107,11 @@ int USBTrans::close() int HIDTrans::open(void *p) { + m_devhandle = p; + + if (is_using_hidapi()) + return 0; + if (USBTrans::open(p)) return -1; @@ -120,6 +127,16 @@ int HIDTrans::open(void *p) int HIDTrans::write(void *buff, size_t size) { int ret; + + if (is_using_hidapi()) + { + ret = hid_write((hid_device*)m_devhandle, (const unsigned char *)buff, size); + if (ret < 0) + set_last_err_string("hid_write() error"); + + return ret; + } + uint8_t *p = (uint8_t *)buff; int actual_size; @@ -163,6 +180,19 @@ int HIDTrans::write(void *buff, size_t size) int HIDTrans::read(void *buff, size_t size, size_t *rsize) { int ret; + + if (is_using_hidapi()) + { + ret = hid_read_timeout((hid_device*)m_devhandle, (unsigned char*)buff, size, m_timeout); + if (ret < 0) + { + set_last_err_string("hid_read() error"); + return ret; + } + *rsize = ret; + return 0; + } + int actual; ret = libusb_interrupt_transfer( (libusb_device_handle *)m_devhandle, diff --git a/libuuu/usbhotplug.cpp b/libuuu/usbhotplug.cpp index dd2f6d8d..d9c8359e 100644 --- a/libuuu/usbhotplug.cpp +++ b/libuuu/usbhotplug.cpp @@ -48,6 +48,7 @@ #include "libuuu.h" #include "vector" #include +#include "hidapi.h" using chrono::milliseconds; using chrono::operator ""ms; @@ -58,6 +59,12 @@ static atomic g_wait_usb_timeout{-1s}; static atomic g_usb_poll_period{200ms}; static atomic g_wait_next_usb_timeout{-1s}; +bool g_using_hidapi = true; + +#ifndef WIN32 +#define _strdup strdup +#endif + enum KnownDeviceState { NoKnownDevice, KnownDeviceToDo, @@ -73,10 +80,14 @@ class CAutoDeInit { if (libusb_init(nullptr) < 0) throw runtime_error{ "Call libusb_init failure" }; + + if (hid_init()) + throw runtime_error{ "Call hid_init failure" }; } ~CAutoDeInit() { libusb_exit(nullptr); + hid_exit(); } } g_autoDeInit; @@ -134,6 +145,45 @@ class CAutoList int m_rc = 0; }; +class CAutoHIDList +{ +public: + struct hid_device_info* m_list; + + CAutoHIDList(struct hid_device_info* list) + { + m_list = list; + } + + CAutoHIDList() + { + m_list = hid_enumerate(0, 0); + if (!m_list) + set_last_err_string("Failure get HID devices or failure at hid_enumerate()"); + } + ~CAutoHIDList() + { + if (m_list != nullptr) { + hid_free_enumeration(m_list); + } + } + + CAutoHIDList(CAutoHIDList&& other) + { + this->m_list = other.m_list; + other.m_list = nullptr; + } + + CAutoHIDList& operator=(CAutoHIDList&& other) + { + this->m_list = other.m_list; + return *this; + } + + CAutoHIDList& operator=(const CAutoHIDList&) = delete; // Prevent copy, allow move only + CAutoHIDList(const CAutoHIDList&) = delete; // Prevent copy, allow move only + +}; static struct { vector list; mutex lock; @@ -258,14 +308,18 @@ static int open_libusb(libusb_device *dev, void **usb_device_handle) thread start run_usb_cmds; libusb_free_list() */ -static int run_usb_cmds(ConfigItem *item, libusb_device *dev, short bcddevice) +static int run_usb_cmds(ConfigItem *item, void *dev, short bcddevice) { int ret; uuu_notify nt; nt.type = uuu_notify::NOTIFY_DEV_ATTACH; string str; - str = get_device_path(dev); + + if (is_using_hidapi() && item->m_bHID) + str = "HID"; + else + str = get_device_path((libusb_device*)dev); nt.str = (char*)str.c_str(); call_notify(nt); @@ -273,7 +327,19 @@ static int run_usb_cmds(ConfigItem *item, libusb_device *dev, short bcddevice) ctx.m_config_item = item; ctx.m_current_bcd = bcddevice; - if ((ret = open_libusb(dev, &(ctx.m_dev)))) + if (is_using_hidapi() && item->m_bHID) + { + ctx.m_dev = hid_open_path((char*)dev); + ctx.m_bHIDAPI = true; + if (!ctx.m_dev) + { + nt.status = -1; + call_notify(nt); + set_last_err_string("failure open HID devices"); + return -1; + } + } + else if ((ret = open_libusb((libusb_device*)dev, &(ctx.m_dev)))) { nt.type = uuu_notify::NOTIFY_CMD_END; nt.status = -1; @@ -287,7 +353,15 @@ static int run_usb_cmds(ConfigItem *item, libusb_device *dev, short bcddevice) nt.type = uuu_notify::NOTIFY_THREAD_EXIT; call_notify(nt); - libusb_unref_device(dev); //ref_device when start thread + if (ctx.m_bHIDAPI) + { + hid_close((hid_device*)ctx.m_dev); + free(dev); + } + else + { + libusb_unref_device((libusb_device*)dev); //ref_device when start thread + } clear_env(); return ret; } @@ -325,7 +399,27 @@ static int usb_add(libusb_device *dev) static int usb_remove(libusb_device * /*dev*/) { + return 0; +} +static int usb_hid_add(hid_device_info* info) +{ +#if HID_API_VERSION_MINOR >= 13 + if (info->bus_type != HID_API_BUS_USB) + return 0; +#endif + + ConfigItem* item = get_config()->find(info->vendor_id, info->product_id, info->release_number); + if (item) + { + g_known_device_state = KnownDeviceToDo; + std::thread(run_usb_cmds, item, _strdup(info->path), info->release_number).detach(); + } + return 0; +} + +static int usb_hid_remove(hid_device_info* info) +{ return 0; } @@ -371,6 +465,61 @@ void compare_list(libusb_device ** old, libusb_device **nw) } } +void compare_hid_list(struct hid_device_info* old_list, struct hid_device_info* nw_list) +{ + char* dev; + hid_device_info* old = old_list; + hid_device_info* nw = nw_list; + + if (old == nullptr) + { + while (nw) + { + dev = nw->path; + usb_hid_add(nw); + nw = nw->next; + } + return; + } + + while (nw) + { + hid_device_info* p = old_list; + dev = nw->path; + + while (p) + { + if (strcmp(p->path, dev) == 0) + break;//find it. + p = p->next; + }; + + if (!p) + usb_hid_add(nw); + + nw = nw->next; + } + + old = old_list; + + while (old) + { + nw = nw_list; + while (nw) + { + if (strcmp(nw->path, old->path) == 0) + break;//find it. + + nw = nw->next; + }; + + if (!nw) + usb_hid_remove(old); + + old = old->next; + } +} + static int check_usb_timeout(Timer& usb_timer) { auto known_device_state = g_known_device_state.load(); @@ -411,6 +560,7 @@ int polling_usb(std::atomic& bexit) Timer usb_timer; CAutoList oldlist(nullptr); + CAutoHIDList oldHIDList(nullptr); while(!bexit) { @@ -424,6 +574,13 @@ int polling_usb(std::atomic& bexit) std::swap(oldlist, newlist); + if (is_using_hidapi()) + { + CAutoHIDList newHIDList; + compare_hid_list(oldHIDList.m_list, newHIDList.m_list); + std::swap(oldHIDList, newHIDList); + } + this_thread::sleep_for(g_usb_poll_period.load()); if (check_usb_timeout(usb_timer)) @@ -437,7 +594,10 @@ CmdUsbCtx::~CmdUsbCtx() { if (m_dev) { - libusb_close((libusb_device_handle*)m_dev); + if (this->m_bHIDAPI) + hid_close((hid_device*)m_dev); + else + libusb_close((libusb_device_handle*)m_dev); m_dev = 0; } } @@ -474,6 +634,10 @@ int CmdUsbCtx::look_for_match_device(const char *pro) continue; ConfigItem *item = get_config()->find(desc.idVendor, desc.idProduct, desc.bcdDevice); + + if (is_using_hidapi() && item && item->m_bHID) + continue; + if (item && item->m_protocol == str_to_upper(pro)) { uuu_notify nt; @@ -492,6 +656,42 @@ int CmdUsbCtx::look_for_match_device(const char *pro) } } + //scan HID devices + if (is_using_hidapi()) + { + CAutoHIDList l; + hid_device_info* p = l.m_list; + while (p) + { +#if HID_API_VERSION_MINOR >= 13 + if (p->bus_type == HID_API_BUS_USB) +#endif + { + ConfigItem* item = get_config()->find(p->vendor_id, p->product_id, p->release_number); + + if (item && item->m_protocol == str_to_upper(pro)) + { + uuu_notify nt; + nt.type = uuu_notify::NOTIFY_DEV_ATTACH; + m_config_item = item; + m_current_bcd = p->release_number; + m_bHIDAPI = true; + m_dev = hid_open_path(p->path); + if (!m_dev) + { + set_last_err_string("open HID failure"); + return -1; + } + nt.str = (char*)"HID"; + call_notify(nt); + + return 0; + } + } + p = p->next; + } + } + this_thread::sleep_for(200ms); uuu_notify nt; @@ -561,3 +761,13 @@ int uuu_set_wait_next_timeout(int timeout_in_seconds) g_wait_next_usb_timeout = seconds{timeout_in_seconds}; return 0; } + +void uuu_set_using_hidapi(uint32_t val) +{ + g_using_hidapi = !!val; +} + +bool is_using_hidapi() +{ + return g_using_hidapi; +} diff --git a/msvc/libuuu.vcxproj b/msvc/libuuu.vcxproj index e1f99184..8e510541 100644 --- a/msvc/libuuu.vcxproj +++ b/msvc/libuuu.vcxproj @@ -19,6 +19,7 @@ + @@ -114,21 +115,21 @@ true $(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ - $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2;..\zstd\lib + $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2;..\zstd\lib;..\hidapi\hidapi true - $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2;..\zstd\lib + $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2;..\zstd\lib;..\hidapi\hidapi false $(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ - $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2;..\zstd\lib + $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2;..\zstd\lib;..\hidapi\hidapi false - $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2;..\zstd\lib + $(VC_IncludePath);$(WindowsSDK_IncludePath);..\zlib;..\libsparse\include;..\bzip2;..\zstd\lib;..\hidapi\hidapi diff --git a/msvc/libuuu.vcxproj.filters b/msvc/libuuu.vcxproj.filters index 9970701f..94173470 100644 --- a/msvc/libuuu.vcxproj.filters +++ b/msvc/libuuu.vcxproj.filters @@ -119,5 +119,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/uuu/CMakeLists.txt b/uuu/CMakeLists.txt index a2fb5ba8..38f54818 100644 --- a/uuu/CMakeLists.txt +++ b/uuu/CMakeLists.txt @@ -8,6 +8,11 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(LIBUSB REQUIRED libusb-1.0>=1.0.16) pkg_check_modules(LIBZ REQUIRED zlib) pkg_check_modules(LIBZSTD REQUIRED libzstd) +if(APPLE) +pkg_check_modules(LIBHID REQUIRED hidapi) +else() +pkg_check_modules(LIBHID REQUIRED hidapi-libusb) +endif() find_package(Threads) if (STATIC) @@ -35,7 +40,7 @@ set(LSTS nvme_burn_all.lst ) -link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libuuu ${LIBUSB_LIBRARY_DIRS} ${LIBZSTD_LIBRARY_DIRS} ${LIBZ_LIBRARY_DIRS}) +link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libuuu ${LIBUSB_LIBRARY_DIRS} ${LIBZSTD_LIBRARY_DIRS} ${LIBZ_LIBRARY_DIRS} ${LIBHID_LIBRARY_DIRS}) set(CLIST_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/gen_txt_include.sh) set(generated_files_dir "${CMAKE_BINARY_DIR}/uuu/gen") @@ -61,7 +66,7 @@ endfunction() preprocess_clst(CLSTS ${LSTS}) -include_directories(${generated_files_dir}) +include_directories(${HIDAPI_INC} ${generated_files_dir}) set(SOURCES uuu.cpp @@ -71,9 +76,11 @@ set(SOURCES ) add_executable(uuu ${SOURCES}) -target_link_libraries(uuu uuc_s ${OPENSSL_LIBRARIES} ${LIBUSB_LIBRARIES} ${LIBZ_LIBRARIES} ${LIBZSTD_LIBRARIES} dl bz2) + +target_link_libraries(uuu uuc_s ${OPENSSL_LIBRARIES} ${LIBUSB_LIBRARIES} ${LIBZ_LIBRARIES} ${LIBZSTD_LIBRARIES} ${LIBHID_LIBRARIES} dl bz2) install(TARGETS uuu DESTINATION bin) target_compile_definitions(uuu PRIVATE "TARGET_PATH=\"${CMAKE_INSTALL_PREFIX}/bin/uuu\"" ) + diff --git a/uuu/uuu.cpp b/uuu/uuu.cpp index 8018b338..7764bb9c 100644 --- a/uuu/uuu.cpp +++ b/uuu/uuu.cpp @@ -923,6 +923,8 @@ int main(int argc, char **argv) string cmd; int ret; int dryrun = 0; + int hidapi = 0; + int filter_port = 0; string cmd_script; @@ -972,6 +974,7 @@ int main(int argc, char **argv) else if (s == "-m") { i++; + filter_port = 1; uuu_add_usbpath_filter(argv[i]); g_usb_path_filter.push_back(argv[i]); } @@ -999,6 +1002,11 @@ int main(int argc, char **argv) { return set_ignore_serial_number(); } + else if (s == "-hidapi") + { + uuu_set_using_hidapi(1); + hidapi = 1; + } else if (s == "-e") { #ifndef WIN32 @@ -1089,6 +1097,12 @@ int main(int argc, char **argv) } } + if (filter_port && hidapi) + { + printf("-hidapi and -m can't use together\n"); + return -1; + } + signal(SIGINT, ctrl_c_handle); uuu_set_askpasswd(ask_passwd);