Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/macOS.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
fetch-depth: 0

- name: Set up environment
run: brew install libusb pkg-config zstd tinyxml2
run: brew install libusb hidapi pkg-config zstd tinyxml2

- name: Build
run: |
Expand Down
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,12 @@ For cmake prior 3.13:
## macOS
- `git clone https://github.com/nxp-imx/mfgtools.git`
- `cd mfgtools`
- `brew install cmake libusb openssl pkg-config tinyxml2`
- `brew install cmake libusb hidapi openssl pkg-config tinyxml2`
- `cmake -DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl . && make`

Note that we assume [homebrew](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.

Note if you meet "can't detach kernel driver" try to check libusb version.
```
brew info libusb
==> libusb: stable 1.0.26 (bottled), HEAD
```
On macOS, HID devices (SDP/SDPS boot ROM) are accessed through hidapi, so `sudo` is not needed to download images.

# Run environment
- Windows 10 64 bit
Expand Down
5 changes: 4 additions & 1 deletion libuuu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pkg_check_modules(LIBUSB REQUIRED libusb-1.0>=1.0.16)
pkg_check_modules(LIBZSTD REQUIRED libzstd)
find_package(Threads)
pkg_check_modules(TINYXML2 REQUIRED tinyxml2)
if (APPLE)
pkg_check_modules(HIDAPI REQUIRED hidapi)
endif()

if (STATIC)
set(OPENSSL_USE_STATIC_LIBS TRUE)
Expand All @@ -22,7 +25,7 @@ set(UUUSSL "-DUUUSSL")
set(UUUOPENSLL_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR})
endif()

include_directories(${LIBUSB_INCLUDE_DIRS} ${LIBZSTD_INCLUDE_DIRS} ${UUUOPENSLL_INCLUDE_DIR} ${TINYXML2_INCLUDE_DIRS} include)
include_directories(${LIBUSB_INCLUDE_DIRS} ${LIBZSTD_INCLUDE_DIRS} ${UUUOPENSLL_INCLUDE_DIR} ${TINYXML2_INCLUDE_DIRS} ${HIDAPI_INCLUDE_DIRS} include)


if (FORCE_OLD)
Expand Down
138 changes: 138 additions & 0 deletions libuuu/trans.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ extern "C"
#include "libusb.h"
}

#ifdef __APPLE__
#include <hidapi.h>
#include <hidapi_darwin.h>
#endif

using namespace std;

static bool g_force_hid_use_ctrl_ep = false;
Expand Down Expand Up @@ -186,8 +191,99 @@ int USBTrans::close()
return 0;
}

#ifdef __APPLE__
/*
* On macOS the HID interface is owned by the IOHIDFamily kernel driver.
* libusb can only detach it by re-enumerating the device with capture,
* which requires root, so claiming the interface fails with
* LIBUSB_ERROR_ACCESS for normal users. Talk to the device through the
* IOHIDFamily driver (hidapi) instead, which needs no extra privileges.
*/
static uint32_t get_darwin_location_id(libusb_device *dev)
{
uint8_t ports[7];
int n = libusb_get_port_numbers(dev, ports, sizeof(ports));
uint32_t location = (uint32_t)libusb_get_bus_number(dev) << 24;

for (int i = 0; i < n && i < 6; i++)
location |= (uint32_t)(ports[i] & 0xf) << (20 - 4 * i);

return location;
}

int HIDTrans::open_hidapi(TransHandle &usb)
{
if (usb.handle == nullptr) {
set_last_err_string("Invalid USB device handle");
return -1;
}

if (hid_init()) {
set_last_err_string("Call hid_init failure");
return -1;
}

m_devhandle = usb.handle;
libusb_device *dev = libusb_get_device((libusb_device_handle *)usb.handle);
libusb_device_descriptor desc;
if (libusb_get_device_descriptor(dev, &desc)) {
set_last_err_string("failure get device descriptor");
return -1;
}

const uint32_t location = get_darwin_location_id(dev);

hid_darwin_set_open_exclusive(0);

hid_device_info *list = hid_enumerate(desc.idVendor, desc.idProduct);
for (hid_device_info *info = list; info && !m_hid; info = info->next)
{
hid_device *hid = hid_open_path(info->path);
if (!hid)
continue;

uint32_t id = 0;
if (hid_darwin_get_location_id(hid, &id) == 0 && id == location)
m_hid = hid;
else
hid_close(hid);
}
hid_free_enumeration(list);

if (!m_hid) {
string_ex err;
err.format("Failure open HID device %04x:%04x at location 0x%08x",
desc.idVendor, desc.idProduct, location);
set_last_err_string(err);
return -1;
}

/*
* IOHIDFamily queues input reports received while the device is open.
* Drop anything stale so the next read returns the reply to our command.
*/
unsigned char flush[1025];
while (hid_read_timeout((hid_device *)m_hid, flush, sizeof(flush), 0) > 0)
;

return 0;
}

int HIDTrans::close()
{
if (m_hid) {
hid_close((hid_device *)m_hid);
m_hid = nullptr;
}
return 0;
}
#endif

int HIDTrans::open(TransHandle &p)
{
#ifdef __APPLE__
return open_hidapi(p);
#else
int ret;

if ((ret = USBTrans::open(p)))
Expand All @@ -200,12 +296,25 @@ int HIDTrans::open(TransHandle &p)
}

return 0;
#endif
}

int HIDTrans::write_simple(void *buff, size_t size)
{
int ret;
uint8_t *p = (uint8_t *)buff;

#ifdef __APPLE__
ret = hid_write((hid_device *)m_hid, p, size);
if (ret < 0)
{
string_ex err;
err.format("HID(W): %ls", hid_error((hid_device *)m_hid));
set_last_err_string(err);
return LIBUSB_ERROR_IO;
}
return ret;
#else
int actual_size;

if (m_outEP && !g_force_hid_use_ctrl_ep)
Expand Down Expand Up @@ -242,11 +351,39 @@ int HIDTrans::write_simple(void *buff, size_t size)
}

return ret;
#endif
}

int HIDTrans::read_simple(void *buff, size_t size, size_t *rsize)
{
int ret;

#ifdef __APPLE__
/*
* hidapi returns whichever input report arrived first, while libusb
* callers pass the expected report ID in buff[0]. Skip reports with
* a different ID, e.g. ones left over from an earlier command.
*/
const uint8_t report_id = ((uint8_t *)buff)[0];
do {
ret = hid_read_timeout((hid_device *)m_hid, (unsigned char *)buff, size, m_timeout);
} while (ret > 0 && report_id && ((uint8_t *)buff)[0] != report_id);

if (ret < 0)
{
string_ex err;
err.format("HID(R): %ls", hid_error((hid_device *)m_hid));
set_last_err_string(err);
return LIBUSB_ERROR_IO;
}
if (ret == 0)
{
set_last_err_string("HID(R): LIBUSB_ERROR_TIMEOUT (-7)");
return LIBUSB_ERROR_TIMEOUT;
}
*rsize = ret;
return 0;
#else
int actual;
ret = libusb_interrupt_transfer(
(libusb_device_handle *)m_devhandle,
Expand All @@ -268,6 +405,7 @@ int HIDTrans::read_simple(void *buff, size_t size, size_t *rsize)
}

return 0;
#endif
}

int BulkTrans::write_simple(void *buff, size_t size)
Expand Down
7 changes: 7 additions & 0 deletions libuuu/trans.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,20 @@ class HIDTrans : public USBTrans
~HIDTrans() override { if (m_devhandle) close(); m_devhandle = nullptr; }

int open(TransHandle &p) override;
#ifdef __APPLE__
int close() override;
#endif
void set_hid_out_ep(int ep) noexcept { m_outEP = ep; }

protected:
int write_simple(void *buff, size_t size) override;
int read_simple(void *buff, size_t size, size_t *return_size) override;

private:
#ifdef __APPLE__
int open_hidapi(TransHandle &usb);
void *m_hid = nullptr;
#endif
int m_outEP = 0;
const int m_timeout = 1000;
int m_set_report = 9;
Expand Down
7 changes: 5 additions & 2 deletions uuu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pkg_check_modules(LIBZ REQUIRED zlib)
pkg_check_modules(LIBZSTD REQUIRED libzstd)
find_package(Threads)
pkg_check_modules(TINYXML2 REQUIRED tinyxml2)
if (APPLE)
pkg_check_modules(HIDAPI REQUIRED hidapi)
endif()

if (STATIC)
set(OPENSSL_USE_STATIC_LIBS TRUE)
Expand Down Expand Up @@ -39,7 +42,7 @@ set(LSTS
nvme_burn_all.lst
)

link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libuuu ${LIBUSB_LIBRARY_DIRS} ${LIBZSTD_LIBRARY_DIRS} ${LIBZ_LIBRARY_DIRS} ${TINYXML2_LIBRARY_DIRS})
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libuuu ${LIBUSB_LIBRARY_DIRS} ${LIBZSTD_LIBRARY_DIRS} ${LIBZ_LIBRARY_DIRS} ${TINYXML2_LIBRARY_DIRS} ${HIDAPI_LIBRARY_DIRS})

set(CLIST_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/gen_txt_include.sh)
set(generated_files_dir "${CMAKE_BINARY_DIR}/uuu/gen")
Expand Down Expand Up @@ -75,7 +78,7 @@ set(SOURCES
)

add_executable(uuu ${SOURCES})
target_link_libraries(uuu uuc_s ${OPENSSL_LIBRARIES} ${LIBUSB_LIBRARIES} ${LIBZ_LIBRARIES} ${LIBZSTD_LIBRARIES} ${TINYXML2_LIBRARIES} dl bz2)
target_link_libraries(uuu uuc_s ${OPENSSL_LIBRARIES} ${LIBUSB_LIBRARIES} ${LIBZ_LIBRARIES} ${LIBZSTD_LIBRARIES} ${TINYXML2_LIBRARIES} ${HIDAPI_LIBRARIES} dl bz2)

install(TARGETS uuu DESTINATION bin)
target_compile_definitions(uuu
Expand Down
6 changes: 6 additions & 0 deletions wrapper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ pkg_check_modules(bzip2 REQUIRED IMPORTED_TARGET bzip2)
pkg_check_modules(zstd REQUIRED IMPORTED_TARGET libzstd)
pkg_check_modules(openssl REQUIRED IMPORTED_TARGET openssl)
pkg_check_modules(zlib REQUIRED IMPORTED_TARGET zlib)
if (APPLE)
pkg_check_modules(hidapi REQUIRED IMPORTED_TARGET hidapi)
endif()


if (DARWIN)
Expand All @@ -114,3 +117,6 @@ endif(UNIX)


target_link_libraries(libuuu PkgConfig::libusb PkgConfig::tinyxml2 PkgConfig::bzip2 PkgConfig::zstd PkgConfig::zlib PkgConfig::openssl)
if (APPLE)
target_link_libraries(libuuu PkgConfig::hidapi)
endif()
6 changes: 5 additions & 1 deletion wrapper/vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"bzip2",
"zstd",
"zlib",
"openssl"
"openssl",
{
"name": "hidapi",
"platform": "osx"
}
]
}
Loading