From owner-svn-ports-head@freebsd.org Sun Apr 5 11:55:55 2020 Return-Path: Delivered-To: svn-ports-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 8B1E62B42AC; Sun, 5 Apr 2020 11:55:55 +0000 (UTC) (envelope-from mr@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 48wBvY578Sz4d3c; Sun, 5 Apr 2020 11:55:53 +0000 (UTC) (envelope-from mr@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 11839C3A3; Sun, 5 Apr 2020 11:46:19 +0000 (UTC) (envelope-from mr@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 035BkIeP004384; Sun, 5 Apr 2020 11:46:18 GMT (envelope-from mr@FreeBSD.org) Received: (from mr@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 035BkHhx004377; Sun, 5 Apr 2020 11:46:17 GMT (envelope-from mr@FreeBSD.org) Message-Id: <202004051146.035BkHhx004377@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mr set sender to mr@FreeBSD.org using -f From: Michael Reifenberger Date: Sun, 5 Apr 2020 11:46:17 +0000 (UTC) To: ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org Subject: svn commit: r530770 - in head/cad/PrusaSlicer: . files X-SVN-Group: ports-head X-SVN-Commit-Author: mr X-SVN-Commit-Paths: in head/cad/PrusaSlicer: . files X-SVN-Commit-Revision: 530770 X-SVN-Commit-Repository: ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-ports-head@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the ports tree for head List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 05 Apr 2020 11:55:56 -0000 Author: mr Date: Sun Apr 5 11:46:17 2020 New Revision: 530770 URL: https://svnweb.freebsd.org/changeset/ports/530770 Log: Update to 2.2.0 PR: 245247 Submitted by: teodorsigaev@gmail.com Added: head/cad/PrusaSlicer/files/patch-CMakeLists.txt (contents, props changed) head/cad/PrusaSlicer/files/patch-src_avrdude_libavrdude.h (contents, props changed) head/cad/PrusaSlicer/files/patch-src_hidapi_CMakeLists.txt (contents, props changed) head/cad/PrusaSlicer/files/patch-src_hidapi_libusb_hid.c (contents, props changed) Deleted: head/cad/PrusaSlicer/files/patch-src-avrdude-libavrdude.h head/cad/PrusaSlicer/files/patch-src-slic3r-GUI-GUI_App.cpp head/cad/PrusaSlicer/files/patch-src-slic3r-GUI-GUI_Utils.cpp head/cad/PrusaSlicer/files/patch-src-slic3r-GUI-GUI_Utils.hpp Modified: head/cad/PrusaSlicer/Makefile head/cad/PrusaSlicer/distinfo head/cad/PrusaSlicer/pkg-plist Modified: head/cad/PrusaSlicer/Makefile ============================================================================== --- head/cad/PrusaSlicer/Makefile Sun Apr 5 11:26:52 2020 (r530769) +++ head/cad/PrusaSlicer/Makefile Sun Apr 5 11:46:17 2020 (r530770) @@ -2,9 +2,10 @@ PORTNAME= PrusaSlicer DISTVERSIONPREFIX= version_ -DISTVERSION= 2.1.1 -PORTREVISION= 1 +DISTVERSION= 2.2.0 CATEGORIES= cad +MASTER_SITES=https://github.com/CGAL/cgal/archive/releases/:cgal +DISTFILES=CGAL-5.0.2.tar.gz:cgal MAINTAINER= teodor@sigaev.ru COMMENT= Slicing application for 3D printers @@ -23,7 +24,10 @@ BUILD_DEPENDS= cereal>=1.2.2:devel/cereal \ boost-libs>=1.64:devel/boost-libs \ wx31-gtk3>=3.1:x11-toolkits/wxgtk31 \ cmake>=3.2:devel/cmake \ - ninja>=1.8.2:devel/ninja + ninja>=1.8.2:devel/ninja \ + openvdb>=6.1.0:misc/openvdb \ + gmp>=6.1.2:math/gmp \ + mpfr>=4.0.2:math/mpfr USES= cmake gettext @@ -33,5 +37,19 @@ CMAKE_INSTALL_PREFIX= ${PREFIX}/${PORTNAME} USE_GITHUB= yes USE_GL= glew GH_ACCOUNT= prusa3d + +post-patch: + ${REINPLACE_CMD} -e 's,%%WRKSRC%%,${WRKSRC},' \ + ${WRKSRC}/CMakeLists.txt + +pre-build: + cd ${WRKDIR}/cgal-releases-CGAL-5.0.2 && \ + ${CMAKE_BIN} -E remove CGALConfig-installation-dirs.cmake && \ + ${MKDIR} build && cd build && \ + ${CMAKE_BIN} -DCMAKE_INSTALL_PREFIX=${WRKSRC}/CGAL \ + -DCMAKE_PREFIX_PATH=${WRKSRC}/CGAL \ + -DCMAKE_MODULE_PATH=${WRKSRC}/cmake/modules \ + -DCMAKE_BUILD_TYPE=Release .. && \ + ${BSDMAKE} all install .include Modified: head/cad/PrusaSlicer/distinfo ============================================================================== --- head/cad/PrusaSlicer/distinfo Sun Apr 5 11:26:52 2020 (r530769) +++ head/cad/PrusaSlicer/distinfo Sun Apr 5 11:46:17 2020 (r530770) @@ -1,3 +1,5 @@ -TIMESTAMP = 1579717070 -SHA256 (prusa3d-PrusaSlicer-version_2.1.1_GH0.tar.gz) = 79d0681fbf3f4158cac25595522dcea330e0fa960934053ac929a15fa13c1072 -SIZE (prusa3d-PrusaSlicer-version_2.1.1_GH0.tar.gz) = 27551136 +TIMESTAMP = 1585766317 +SHA256 (prusa3d-PrusaSlicer-version_2.2.0_GH0.tar.gz) = e6e0c83bf92e448ec058fd3063b84caca69f58b8b419e48eace6e8ce534937c0 +SIZE (prusa3d-PrusaSlicer-version_2.2.0_GH0.tar.gz) = 30811929 +SHA256 (CGAL-5.0.2.tar.gz) = 7d824efce318fe901fd9d6f233a1f27e2d956d787602621df035a759b587c40c +SIZE (CGAL-5.0.2.tar.gz) = 146441795 Added: head/cad/PrusaSlicer/files/patch-CMakeLists.txt ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/cad/PrusaSlicer/files/patch-CMakeLists.txt Sun Apr 5 11:46:17 2020 (r530770) @@ -0,0 +1,11 @@ +--- CMakeLists.txt.orig 2020-03-21 10:55:51 UTC ++++ CMakeLists.txt +@@ -3,6 +3,8 @@ project(PrusaSlicer) + + include("version.inc") + include(GNUInstallDirs) ++include_directories(BEFORE SYSTEM "%%WRKSRC%%/CGAL/include") ++add_compile_options(-DNDEBUG) + + set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources") + file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN) Added: head/cad/PrusaSlicer/files/patch-src_avrdude_libavrdude.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/cad/PrusaSlicer/files/patch-src_avrdude_libavrdude.h Sun Apr 5 11:46:17 2020 (r530770) @@ -0,0 +1,11 @@ +--- src/avrdude/libavrdude.h.orig 2020-03-21 10:55:51 UTC ++++ src/avrdude/libavrdude.h +@@ -950,6 +950,8 @@ int read_config_builtin(); + // Header file for alloca() + #if defined(WIN32NATIVE) + # include ++#elif defined __FreeBSD__ ++# include + #else + # include + #endif Added: head/cad/PrusaSlicer/files/patch-src_hidapi_CMakeLists.txt ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/cad/PrusaSlicer/files/patch-src_hidapi_CMakeLists.txt Sun Apr 5 11:46:17 2020 (r530770) @@ -0,0 +1,20 @@ +--- src/hidapi/CMakeLists.txt.orig 2020-03-21 10:55:51 UTC ++++ src/hidapi/CMakeLists.txt +@@ -1,8 +1,9 @@ +- + if (WIN32) + set(HIDAPI_IMPL win/hid.c) + elseif (APPLE) + set(HIDAPI_IMPL mac/hid.c) ++elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ set(HIDAPI_IMPL libusb/hid.c) + else () + # Assume Linux or Unix other than Mac OS + set(HIDAPI_IMPL linux/hid.c) +@@ -16,4 +17,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + # Don't link the udev library, as there are two versions out there (libudev.so.0, libudev.so.1), so they are linked explicitely. + # target_link_libraries(hidapi udev) + target_link_libraries(hidapi dl) ++elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ++ target_link_libraries(hidapi usb iconv) + endif() Added: head/cad/PrusaSlicer/files/patch-src_hidapi_libusb_hid.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/cad/PrusaSlicer/files/patch-src_hidapi_libusb_hid.c Sun Apr 5 11:46:17 2020 (r530770) @@ -0,0 +1,1517 @@ +--- src/hidapi/libusb/hid.c.orig 2020-03-31 19:30:48 UTC ++++ src/hidapi/libusb/hid.c +@@ -0,0 +1,1514 @@ ++/******************************************************* ++ HIDAPI - Multi-Platform library for ++ communication with HID devices. ++ ++ Alan Ott ++ Signal 11 Software ++ ++ 8/22/2009 ++ Linux Version - 6/2/2010 ++ Libusb Version - 8/13/2010 ++ FreeBSD Version - 11/1/2011 ++ ++ Copyright 2009, All Rights Reserved. ++ ++ At the discretion of the user of this library, ++ this software may be licensed under the terms of the ++ GNU General Public License v3, a BSD-Style license, or the ++ original HIDAPI license as outlined in the LICENSE.txt, ++ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt ++ files located at the root of the source distribution. ++ These files may also be found in the public source ++ code repository located at: ++ http://github.com/signal11/hidapi . ++********************************************************/ ++ ++#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */ ++ ++/* C */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Unix */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* GNU / LibUSB */ ++#include ++#ifndef __ANDROID__ ++#include ++#endif ++ ++#include "hidapi.h" ++ ++#ifdef __ANDROID__ ++ ++/* Barrier implementation because Android/Bionic don't have pthread_barrier. ++ This implementation came from Brent Priddy and was posted on ++ StackOverflow. It is used with his permission. */ ++typedef int pthread_barrierattr_t; ++typedef struct pthread_barrier { ++ pthread_mutex_t mutex; ++ pthread_cond_t cond; ++ int count; ++ int trip_count; ++} pthread_barrier_t; ++ ++static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count) ++{ ++ if(count == 0) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ if(pthread_mutex_init(&barrier->mutex, 0) < 0) { ++ return -1; ++ } ++ if(pthread_cond_init(&barrier->cond, 0) < 0) { ++ pthread_mutex_destroy(&barrier->mutex); ++ return -1; ++ } ++ barrier->trip_count = count; ++ barrier->count = 0; ++ ++ return 0; ++} ++ ++static int pthread_barrier_destroy(pthread_barrier_t *barrier) ++{ ++ pthread_cond_destroy(&barrier->cond); ++ pthread_mutex_destroy(&barrier->mutex); ++ return 0; ++} ++ ++static int pthread_barrier_wait(pthread_barrier_t *barrier) ++{ ++ pthread_mutex_lock(&barrier->mutex); ++ ++(barrier->count); ++ if(barrier->count >= barrier->trip_count) ++ { ++ barrier->count = 0; ++ pthread_cond_broadcast(&barrier->cond); ++ pthread_mutex_unlock(&barrier->mutex); ++ return 1; ++ } ++ else ++ { ++ pthread_cond_wait(&barrier->cond, &(barrier->mutex)); ++ pthread_mutex_unlock(&barrier->mutex); ++ return 0; ++ } ++} ++ ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifdef DEBUG_PRINTF ++#define LOG(...) fprintf(stderr, __VA_ARGS__) ++#else ++#define LOG(...) do {} while (0) ++#endif ++ ++#ifndef __FreeBSD__ ++#define DETACH_KERNEL_DRIVER ++#endif ++ ++/* Uncomment to enable the retrieval of Usage and Usage Page in ++hid_enumerate(). Warning, on platforms different from FreeBSD ++this is very invasive as it requires the detach ++and re-attach of the kernel driver. See comments inside hid_enumerate(). ++libusb HIDAPI programs are encouraged to use the interface number ++instead to differentiate between interfaces on a composite HID device. */ ++/*#define INVASIVE_GET_USAGE*/ ++ ++/* Linked List of input reports received from the device. */ ++struct input_report { ++ uint8_t *data; ++ size_t len; ++ struct input_report *next; ++}; ++ ++ ++struct hid_device_ { ++ /* Handle to the actual device. */ ++ libusb_device_handle *device_handle; ++ ++ /* Endpoint information */ ++ int input_endpoint; ++ int output_endpoint; ++ int input_ep_max_packet_size; ++ ++ /* The interface number of the HID */ ++ int interface; ++ ++ /* Indexes of Strings */ ++ int manufacturer_index; ++ int product_index; ++ int serial_index; ++ ++ /* Whether blocking reads are used */ ++ int blocking; /* boolean */ ++ ++ /* Read thread objects */ ++ pthread_t thread; ++ pthread_mutex_t mutex; /* Protects input_reports */ ++ pthread_cond_t condition; ++ pthread_barrier_t barrier; /* Ensures correct startup sequence */ ++ int shutdown_thread; ++ int cancelled; ++ struct libusb_transfer *transfer; ++ ++ /* List of received input reports. */ ++ struct input_report *input_reports; ++}; ++ ++static libusb_context *usb_context = NULL; ++ ++uint16_t get_usb_code_for_current_locale(void); ++static int return_data(hid_device *dev, unsigned char *data, size_t length); ++ ++static hid_device *new_hid_device(void) ++{ ++ hid_device *dev = calloc(1, sizeof(hid_device)); ++ dev->blocking = 1; ++ ++ pthread_mutex_init(&dev->mutex, NULL); ++ pthread_cond_init(&dev->condition, NULL); ++ pthread_barrier_init(&dev->barrier, NULL, 2); ++ ++ return dev; ++} ++ ++static void free_hid_device(hid_device *dev) ++{ ++ /* Clean up the thread objects */ ++ pthread_barrier_destroy(&dev->barrier); ++ pthread_cond_destroy(&dev->condition); ++ pthread_mutex_destroy(&dev->mutex); ++ ++ /* Free the device itself */ ++ free(dev); ++} ++ ++#if 0 ++/*TODO: Implement this funciton on hidapi/libusb.. */ ++static void register_error(hid_device *dev, const char *op) ++{ ++ ++} ++#endif ++ ++#ifdef INVASIVE_GET_USAGE ++/* Get bytes from a HID Report Descriptor. ++ Only call with a num_bytes of 0, 1, 2, or 4. */ ++static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur) ++{ ++ /* Return if there aren't enough bytes. */ ++ if (cur + num_bytes >= len) ++ return 0; ++ ++ if (num_bytes == 0) ++ return 0; ++ else if (num_bytes == 1) { ++ return rpt[cur+1]; ++ } ++ else if (num_bytes == 2) { ++ return (rpt[cur+2] * 256 + rpt[cur+1]); ++ } ++ else if (num_bytes == 4) { ++ return (rpt[cur+4] * 0x01000000 + ++ rpt[cur+3] * 0x00010000 + ++ rpt[cur+2] * 0x00000100 + ++ rpt[cur+1] * 0x00000001); ++ } ++ else ++ return 0; ++} ++ ++/* Retrieves the device's Usage Page and Usage from the report ++ descriptor. The algorithm is simple, as it just returns the first ++ Usage and Usage Page that it finds in the descriptor. ++ The return value is 0 on success and -1 on failure. */ ++static int get_usage(uint8_t *report_descriptor, size_t size, ++ unsigned short *usage_page, unsigned short *usage) ++{ ++ unsigned int i = 0; ++ int size_code; ++ int data_len, key_size; ++ int usage_found = 0, usage_page_found = 0; ++ ++ while (i < size) { ++ int key = report_descriptor[i]; ++ int key_cmd = key & 0xfc; ++ ++ //printf("key: %02hhx\n", key); ++ ++ if ((key & 0xf0) == 0xf0) { ++ /* This is a Long Item. The next byte contains the ++ length of the data section (value) for this key. ++ See the HID specification, version 1.11, section ++ 6.2.2.3, titled "Long Items." */ ++ if (i+1 < size) ++ data_len = report_descriptor[i+1]; ++ else ++ data_len = 0; /* malformed report */ ++ key_size = 3; ++ } ++ else { ++ /* This is a Short Item. The bottom two bits of the ++ key contain the size code for the data section ++ (value) for this key. Refer to the HID ++ specification, version 1.11, section 6.2.2.2, ++ titled "Short Items." */ ++ size_code = key & 0x3; ++ switch (size_code) { ++ case 0: ++ case 1: ++ case 2: ++ data_len = size_code; ++ break; ++ case 3: ++ data_len = 4; ++ break; ++ default: ++ /* Can't ever happen since size_code is & 0x3 */ ++ data_len = 0; ++ break; ++ }; ++ key_size = 1; ++ } ++ ++ if (key_cmd == 0x4) { ++ *usage_page = get_bytes(report_descriptor, size, data_len, i); ++ usage_page_found = 1; ++ //printf("Usage Page: %x\n", (uint32_t)*usage_page); ++ } ++ if (key_cmd == 0x8) { ++ *usage = get_bytes(report_descriptor, size, data_len, i); ++ usage_found = 1; ++ //printf("Usage: %x\n", (uint32_t)*usage); ++ } ++ ++ if (usage_page_found && usage_found) ++ return 0; /* success */ ++ ++ /* Skip over this key and it's associated data */ ++ i += data_len + key_size; ++ } ++ ++ return -1; /* failure */ ++} ++#endif /* INVASIVE_GET_USAGE */ ++ ++#if defined(__FreeBSD__) && __FreeBSD__ < 10 ++/* The libusb version included in FreeBSD < 10 doesn't have this function. In ++ mainline libusb, it's inlined in libusb.h. This function will bear a striking ++ resemblance to that one, because there's about one way to code it. ++ ++ Note that the data parameter is Unicode in UTF-16LE encoding. ++ Return value is the number of bytes in data, or LIBUSB_ERROR_*. ++ */ ++static inline int libusb_get_string_descriptor(libusb_device_handle *dev, ++ uint8_t descriptor_index, uint16_t lang_id, ++ unsigned char *data, int length) ++{ ++ return libusb_control_transfer(dev, ++ LIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */ ++ LIBUSB_REQUEST_GET_DESCRIPTOR, ++ (LIBUSB_DT_STRING << 8) | descriptor_index, ++ lang_id, data, (uint16_t) length, 1000); ++} ++ ++#endif ++ ++ ++/* Get the first language the device says it reports. This comes from ++ USB string #0. */ ++static uint16_t get_first_language(libusb_device_handle *dev) ++{ ++ uint16_t buf[32]; ++ int len; ++ ++ /* Get the string from libusb. */ ++ len = libusb_get_string_descriptor(dev, ++ 0x0, /* String ID */ ++ 0x0, /* Language */ ++ (unsigned char*)buf, ++ sizeof(buf)); ++ if (len < 4) ++ return 0x0; ++ ++ return buf[1]; /* First two bytes are len and descriptor type. */ ++} ++ ++static int is_language_supported(libusb_device_handle *dev, uint16_t lang) ++{ ++ uint16_t buf[32]; ++ int len; ++ int i; ++ ++ /* Get the string from libusb. */ ++ len = libusb_get_string_descriptor(dev, ++ 0x0, /* String ID */ ++ 0x0, /* Language */ ++ (unsigned char*)buf, ++ sizeof(buf)); ++ if (len < 4) ++ return 0x0; ++ ++ ++ len /= 2; /* language IDs are two-bytes each. */ ++ /* Start at index 1 because there are two bytes of protocol data. */ ++ for (i = 1; i < len; i++) { ++ if (buf[i] == lang) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++/* This function returns a newly allocated wide string containing the USB ++ device string numbered by the index. The returned string must be freed ++ by using free(). */ ++static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) ++{ ++ char buf[512]; ++ int len; ++ wchar_t *str = NULL; ++ ++#ifndef __ANDROID__ /* we don't use iconv on Android */ ++ wchar_t wbuf[256]; ++ /* iconv variables */ ++ iconv_t ic; ++ size_t inbytes; ++ size_t outbytes; ++ size_t res; ++#ifdef __FreeBSD__ ++ const char *inptr; ++#else ++ char *inptr; ++#endif ++ char *outptr; ++#endif ++ ++ /* Determine which language to use. */ ++ uint16_t lang; ++ lang = get_usb_code_for_current_locale(); ++ if (!is_language_supported(dev, lang)) ++ lang = get_first_language(dev); ++ ++ /* Get the string from libusb. */ ++ len = libusb_get_string_descriptor(dev, ++ idx, ++ lang, ++ (unsigned char*)buf, ++ sizeof(buf)); ++ if (len < 0) ++ return NULL; ++ ++#ifdef __ANDROID__ ++ ++ /* Bionic does not have iconv support nor wcsdup() function, so it ++ has to be done manually. The following code will only work for ++ code points that can be represented as a single UTF-16 character, ++ and will incorrectly convert any code points which require more ++ than one UTF-16 character. ++ ++ Skip over the first character (2-bytes). */ ++ len -= 2; ++ str = malloc((len / 2 + 1) * sizeof(wchar_t)); ++ int i; ++ for (i = 0; i < len / 2; i++) { ++ str[i] = buf[i * 2 + 2] | (buf[i * 2 + 3] << 8); ++ } ++ str[len / 2] = 0x00000000; ++ ++#else ++ ++ /* buf does not need to be explicitly NULL-terminated because ++ it is only passed into iconv() which does not need it. */ ++ ++ /* Initialize iconv. */ ++ ic = iconv_open("WCHAR_T", "UTF-16LE"); ++ if (ic == (iconv_t)-1) { ++ LOG("iconv_open() failed\n"); ++ return NULL; ++ } ++ ++ /* Convert to native wchar_t (UTF-32 on glibc/BSD systems). ++ Skip the first character (2-bytes). */ ++ inptr = buf+2; ++ inbytes = len-2; ++ outptr = (char*) wbuf; ++ outbytes = sizeof(wbuf); ++ res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes); ++ if (res == (size_t)-1) { ++ LOG("iconv() failed\n"); ++ goto err; ++ } ++ ++ /* Write the terminating NULL. */ ++ wbuf[sizeof(wbuf)/sizeof(wbuf[0])-1] = 0x00000000; ++ if (outbytes >= sizeof(wbuf[0])) ++ *((wchar_t*)outptr) = 0x00000000; ++ ++ /* Allocate and copy the string. */ ++ str = wcsdup(wbuf); ++ ++err: ++ iconv_close(ic); ++ ++#endif ++ ++ return str; ++} ++ ++static char *make_path(libusb_device *dev, int interface_number) ++{ ++ char str[64]; ++ snprintf(str, sizeof(str), "%04x:%04x:%02x", ++ libusb_get_bus_number(dev), ++ libusb_get_device_address(dev), ++ interface_number); ++ str[sizeof(str)-1] = '\0'; ++ ++ return strdup(str); ++} ++ ++ ++int HID_API_EXPORT hid_init(void) ++{ ++ if (!usb_context) { ++ const char *locale; ++ ++ /* Init Libusb */ ++ if (libusb_init(&usb_context)) ++ return -1; ++ ++ /* Set the locale if it's not set. */ ++ locale = setlocale(LC_CTYPE, NULL); ++ if (!locale) ++ setlocale(LC_CTYPE, ""); ++ } ++ ++ return 0; ++} ++ ++int HID_API_EXPORT hid_exit(void) ++{ ++ if (usb_context) { ++ libusb_exit(usb_context); ++ usb_context = NULL; ++ } ++ ++ return 0; ++} ++ ++struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) ++{ ++ libusb_device **devs; ++ libusb_device *dev; ++ libusb_device_handle *handle; ++ ssize_t num_devs; ++ int i = 0; ++ ++ struct hid_device_info *root = NULL; /* return object */ ++ struct hid_device_info *cur_dev = NULL; ++ ++ if(hid_init() < 0) ++ return NULL; ++ ++ num_devs = libusb_get_device_list(usb_context, &devs); ++ if (num_devs < 0) ++ return NULL; ++ while ((dev = devs[i++]) != NULL) { ++ struct libusb_device_descriptor desc; ++ struct libusb_config_descriptor *conf_desc = NULL; ++ int j, k; ++ int interface_num = 0; ++ ++ int res = libusb_get_device_descriptor(dev, &desc); ++ unsigned short dev_vid = desc.idVendor; ++ unsigned short dev_pid = desc.idProduct; ++ ++ res = libusb_get_active_config_descriptor(dev, &conf_desc); ++ if (res < 0) ++ libusb_get_config_descriptor(dev, 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) { ++ interface_num = intf_desc->bInterfaceNumber; ++ ++ /* Check the VID/PID against the arguments */ ++ if ((vendor_id == 0x0 || vendor_id == dev_vid) && ++ (product_id == 0x0 || product_id == dev_pid)) { ++ struct hid_device_info *tmp; ++ ++ /* VID/PID match. Create the record. */ ++ tmp = calloc(1, sizeof(struct hid_device_info)); ++ if (cur_dev) { ++ cur_dev->next = tmp; ++ } ++ else { ++ root = tmp; ++ } ++ cur_dev = tmp; ++ ++ /* Fill out the record */ ++ cur_dev->next = NULL; ++ cur_dev->path = make_path(dev, interface_num); ++ ++ res = libusb_open(dev, &handle); ++ ++ if (res >= 0) { ++ /* Serial Number */ ++ if (desc.iSerialNumber > 0) ++ cur_dev->serial_number = ++ get_usb_string(handle, desc.iSerialNumber); ++ ++ /* Manufacturer and Product strings */ ++ if (desc.iManufacturer > 0) ++ cur_dev->manufacturer_string = ++ get_usb_string(handle, desc.iManufacturer); ++ if (desc.iProduct > 0) ++ cur_dev->product_string = ++ get_usb_string(handle, desc.iProduct); ++ ++#ifdef INVASIVE_GET_USAGE ++{ ++ /* ++ 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 ++ #if 0. For composite devices, use the interface ++ field in the hid_device_info struct to distinguish ++ between interfaces. */ ++ unsigned char data[256]; ++#ifdef DETACH_KERNEL_DRIVER ++ int detached = 0; ++ /* Usage Page and Usage */ ++ res = libusb_kernel_driver_active(handle, interface_num); ++ if (res == 1) { ++ res = libusb_detach_kernel_driver(handle, interface_num); ++ if (res < 0) ++ LOG("Couldn't detach kernel driver, even though a kernel driver was attached."); ++ else ++ detached = 1; ++ } ++#endif ++ res = libusb_claim_interface(handle, interface_num); ++ if (res >= 0) { ++ /* Get the HID Report Descriptor. */ ++ res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000); ++ if (res >= 0) { ++ unsigned short page=0, usage=0; ++ /* Parse the usage and usage page ++ out of the report descriptor. */ ++ get_usage(data, res, &page, &usage); ++ cur_dev->usage_page = page; ++ cur_dev->usage = usage; ++ } ++ else ++ LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res); ++ ++ /* Release the interface */ ++ res = libusb_release_interface(handle, interface_num); ++ if (res < 0) ++ LOG("Can't release the interface.\n"); ++ } ++ else ++ LOG("Can't claim interface %d\n", res); ++#ifdef DETACH_KERNEL_DRIVER ++ /* Re-attach kernel driver if necessary. */ ++ if (detached) { ++ res = libusb_attach_kernel_driver(handle, interface_num); ++ if (res < 0) ++ LOG("Couldn't re-attach kernel driver.\n"); ++ } ++#endif ++} ++#endif /* INVASIVE_GET_USAGE */ ++ ++ libusb_close(handle); ++ } ++ /* VID/PID */ ++ cur_dev->vendor_id = dev_vid; ++ cur_dev->product_id = dev_pid; ++ ++ /* Release Number */ ++ cur_dev->release_number = desc.bcdDevice; ++ ++ /* Interface Number */ ++ cur_dev->interface_number = interface_num; ++ } ++ } ++ } /* altsettings */ ++ } /* interfaces */ ++ libusb_free_config_descriptor(conf_desc); ++ } ++ } ++ ++ libusb_free_device_list(devs, 1); ++ ++ return root; ++} ++ ++void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) ++{ ++ struct hid_device_info *d = devs; ++ while (d) { ++ struct hid_device_info *next = d->next; ++ free(d->path); ++ free(d->serial_number); ++ free(d->manufacturer_string); ++ free(d->product_string); ++ free(d); ++ d = next; ++ } ++} ++ ++hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) ++{ ++ struct hid_device_info *devs, *cur_dev; ++ const char *path_to_open = NULL; ++ hid_device *handle = NULL; ++ ++ devs = hid_enumerate(vendor_id, product_id); ++ cur_dev = devs; ++ while (cur_dev) { ++ if (cur_dev->vendor_id == vendor_id && ++ cur_dev->product_id == product_id) { ++ if (serial_number) { ++ if (cur_dev->serial_number && ++ wcscmp(serial_number, cur_dev->serial_number) == 0) { ++ path_to_open = cur_dev->path; ++ break; ++ } ++ } ++ else { ++ path_to_open = cur_dev->path; ++ break; ++ } ++ } ++ cur_dev = cur_dev->next; ++ } ++ ++ if (path_to_open) { ++ /* Open the device */ ++ handle = hid_open_path(path_to_open); ++ } ++ ++ hid_free_enumeration(devs); ++ ++ return handle; ++} ++ ++static void read_callback(struct libusb_transfer *transfer) ++{ ++ hid_device *dev = transfer->user_data; ++ int res; ++ ++ if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { ++ ++ struct input_report *rpt = malloc(sizeof(*rpt)); ++ rpt->data = malloc(transfer->actual_length); ++ memcpy(rpt->data, transfer->buffer, transfer->actual_length); ++ rpt->len = transfer->actual_length; ++ rpt->next = NULL; ++ ++ pthread_mutex_lock(&dev->mutex); ++ ++ /* Attach the new report object to the end of the list. */ ++ if (dev->input_reports == NULL) { ++ /* The list is empty. Put it at the root. */ ++ dev->input_reports = rpt; ++ pthread_cond_signal(&dev->condition); ++ } ++ else { ++ /* Find the end of the list and attach. */ ++ struct input_report *cur = dev->input_reports; ++ int num_queued = 0; ++ while (cur->next != NULL) { ++ cur = cur->next; ++ num_queued++; ++ } ++ cur->next = rpt; ++ ++ /* Pop one off if we've reached 30 in the queue. This ++ way we don't grow forever if the user never reads ++ anything from the device. */ ++ if (num_queued > 30) { ++ return_data(dev, NULL, 0); ++ } ++ } ++ pthread_mutex_unlock(&dev->mutex); ++ } ++ else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { ++ dev->shutdown_thread = 1; ++ dev->cancelled = 1; ++ return; ++ } ++ else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { ++ dev->shutdown_thread = 1; ++ dev->cancelled = 1; ++ return; ++ } ++ else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) { ++ //LOG("Timeout (normal)\n"); ++ } ++ else { ++ LOG("Unknown transfer code: %d\n", transfer->status); ++ } ++ ++ /* Re-submit the transfer object. */ ++ res = libusb_submit_transfer(transfer); ++ if (res != 0) { ++ LOG("Unable to submit URB. libusb error code: %d\n", res); ++ dev->shutdown_thread = 1; ++ dev->cancelled = 1; ++ } ++} ++ ++ ++static void *read_thread(void *param) ++{ ++ hid_device *dev = param; ++ unsigned char *buf; ++ const size_t length = dev->input_ep_max_packet_size; ++ ++ /* Set up the transfer object. */ ++ buf = malloc(length); ++ dev->transfer = libusb_alloc_transfer(0); ++ libusb_fill_interrupt_transfer(dev->transfer, ++ dev->device_handle, ++ dev->input_endpoint, ++ buf, ++ length, ++ read_callback, ++ dev, ++ 5000/*timeout*/); ++ ++ /* Make the first submission. Further submissions are made ++ from inside read_callback() */ ++ libusb_submit_transfer(dev->transfer); ++ ++ /* Notify the main thread that the read thread is up and running. */ ++ pthread_barrier_wait(&dev->barrier); ++ ++ /* Handle all the events. */ ++ while (!dev->shutdown_thread) { ++ int res; ++ res = libusb_handle_events(usb_context); ++ if (res < 0) { ++ /* There was an error. */ ++ LOG("read_thread(): libusb reports error # %d\n", res); ++ ++ /* Break out of this loop only on fatal error.*/ ++ if (res != LIBUSB_ERROR_BUSY && ++ res != LIBUSB_ERROR_TIMEOUT && ++ res != LIBUSB_ERROR_OVERFLOW && ++ res != LIBUSB_ERROR_INTERRUPTED) { ++ break; ++ } ++ } ++ } ++ ++ /* Cancel any transfer that may be pending. This call will fail ++ if no transfers are pending, but that's OK. */ ++ libusb_cancel_transfer(dev->transfer); ++ ++ while (!dev->cancelled) ++ libusb_handle_events_completed(usb_context, &dev->cancelled); ++ ++ /* Now that the read thread is stopping, Wake any threads which are ++ waiting on data (in hid_read_timeout()). Do this under a mutex to ++ make sure that a thread which is about to go to sleep waiting on ++ the condition actually will go to sleep before the condition is ++ signaled. */ ++ pthread_mutex_lock(&dev->mutex); ++ pthread_cond_broadcast(&dev->condition); ++ pthread_mutex_unlock(&dev->mutex); ++ ++ /* The dev->transfer->buffer and dev->transfer objects are cleaned up ++ in hid_close(). They are not cleaned up here because this thread ++ could end either due to a disconnect or due to a user ++ call to hid_close(). In both cases the objects can be safely ++ cleaned up after the call to pthread_join() (in hid_close()), but ++ since hid_close() calls libusb_cancel_transfer(), on these objects, ++ they can not be cleaned up here. */ ++ ++ return NULL; ++} ++ ++ ++hid_device * HID_API_EXPORT hid_open_path(const char *path) ++{ ++ hid_device *dev = NULL; ++ ++ libusb_device **devs; ++ libusb_device *usb_dev; ++ int res; ++ int d = 0; ++ int good_open = 0; ++ ++ if(hid_init() < 0) ++ return NULL; ++ ++ dev = new_hid_device(); ++ ++ libusb_get_device_list(usb_context, &devs); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***