Skip to content

Commit

Permalink
Merge pull request #2331 from jimklimov/issue-2149
Browse files Browse the repository at this point in the history
Multiple USB-capable drivers: add ways to tune USB HID config, report, descriptor indexes and in/out endpoints
  • Loading branch information
jimklimov authored Mar 2, 2024
2 parents 72c6f4d + 66c4e10 commit 34c8a56
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 14 deletions.
7 changes: 7 additions & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ https://github.com/networkupstools/nut/milestone/10
* Driver programs with debug tracing support via `-D` CLI option and/or
the `NUT_DEBUG_LEVEL` environment variable now check those earlier in
their life-time, so that initialization routine can be debugged. [#2259]
* Multiple USB-capable drivers got options to customize `usb_config_index`
`usb_hid_rep_index`, `usb_hid_desc_index`, `usb_hid_ep_in` and
`usb_hid_ep_out` hardware connection settings via `ups.conf` options.
This is treated as experimental, not all code paths may be actually
using such values from `struct usb_communication_subdriver_t` rather
than hard-coded defaults. Discovery of correct values is up to the
user at the moment (using `lsusb`, internet search, luck...) [#2149]

- nut-driver-enumerator (NDE) service/script:
* The optional daemon mode (primarily useful for systems which monitor
Expand Down
9 changes: 9 additions & 0 deletions conf/ups.conf.sample
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@ maxretry = 3
# so it is not called by default. Yet others can be composite
# devices which use a non-zero interface to represent the UPS.
#
# usb_config_index=hexnum, usb_hid_rep_index=hexnum,
# usb_hid_desc_index=hexnum, usb_hid_ep_in=hexnum, usb_hid_ep_out=hexnum:
# OPTIONAL. Force use of specific interface, endpoint, descriptor
# index etc. numbers, rather than defaulting to 0 (rarely other
# values in certain drivers for some devices known to use non-zero
# numbers). As a rule of thumb for `usb_hid_desc_index` discovery,
# you can see larger `wDescriptorLength` values (roughly 600+ bytes)
# in reports of `lsusb` or similar tools.
#
# default.<variable>: OPTIONAL. Set a default value for <variable> which is
# used in case the UPS doesn't provide a value, but which will be
# overwritten if a value is available from the UPS, e.g.:
Expand Down
15 changes: 15 additions & 0 deletions docs/man/nut_usb_addvars.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,18 @@ If you must really know *which* one, it will not!
Force redundant call to `usb_set_altinterface()`, especially if needed
for devices serving multiple USB roles where the UPS is not represented
by the interface number `0` (default).

*usb_config_index*::
*usb_hid_rep_index*::
*usb_hid_desc_index*::
*usb_hid_ep_in*::
*usb_hid_ep_out*::

Force use of specific interface, endpoint, descriptor index etc. numbers,
rather than defaulting to 0 (rarely other values in certain drivers for
some devices known to use non-zero numbers). Specified as a hexadecimal
number.
+
As a rule of thumb for `usb_hid_desc_index` discovery, you can see larger
`wDescriptorLength` values (roughly 600+ bytes) in reports of `lsusb` or
similar tools.
15 changes: 15 additions & 0 deletions docs/man/ups.conf.txt
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,21 @@ certain UPSes from working on Mac OS X. If your UPS requires explicitly setting
the alternate interface, include this flag, and email the nut-upsdev list with
details about your UPS and operating system.

*usb_config_index*::
*usb_hid_rep_index*::
*usb_hid_desc_index*::
*usb_hid_ep_in*::
*usb_hid_ep_out*::

Optional. Force use of specific interface, endpoint, descriptor index etc.
numbers, rather than defaulting to 0 (rarely other values in certain drivers
for some devices known to use non-zero numbers). Specified as a hexadecimal
number.
+
As a rule of thumb for `usb_hid_desc_index` discovery, you can see larger
`wDescriptorLength` values (roughly 600+ bytes) in reports of `lsusb` or
similar tools.

*default.<variable>*::

Optional. Set a default value for <variable> which is used in case the UPS
Expand Down
4 changes: 3 additions & 1 deletion docs/nut.dict
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
personal_ws-1.1 en 3468 utf-8
personal_ws-1.1 en 3470 utf-8
AAC
AAS
ABI
Expand Down Expand Up @@ -2178,6 +2178,7 @@ hasFeature
hb
hcd
hcl
hexnum
hg
hh
hibernate's
Expand Down Expand Up @@ -2898,6 +2899,7 @@ relicensing
remoting
renderer
renderers
repindex
repo
reportId
reposurgeon
Expand Down
18 changes: 12 additions & 6 deletions drivers/arduino-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,24 @@ static int arduino_claim(HIDDevice_t *hd)
case POSSIBLY_SUPPORTED:
/* by default, reject, unless the productid option is given */
if (getval("productid")) {
usb->hid_ep_in=4;
usb->hid_ep_out=5;
usb->hid_rep_index = 2;
if (!getval("usb_hid_ep_in"))
usb->hid_ep_in=4;
if (!getval("usb_hid_ep_out"))
usb->hid_ep_out=5;
if (!getval("usb_hid_rep_index"))
usb->hid_rep_index = 2;
return 1;
}
possibly_supported("Arduino", hd);
return 0;

case SUPPORTED:
usb->hid_ep_in=4;
usb->hid_ep_out=5;
usb->hid_rep_index = 2;
if (!getval("usb_hid_ep_in"))
usb->hid_ep_in=4;
if (!getval("usb_hid_ep_out"))
usb->hid_ep_out=5;
if (!getval("usb_hid_rep_index"))
usb->hid_rep_index = 2;
return 1;

case NOT_SUPPORTED:
Expand Down
49 changes: 47 additions & 2 deletions drivers/libshut.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
#include "common.h" /* for xmalloc, upsdebugx prototypes */

#define SHUT_DRIVER_NAME "SHUT communication driver"
#define SHUT_DRIVER_VERSION "0.88"
#define SHUT_DRIVER_VERSION "0.89"

/* communication driver description structure */
upsdrv_info_t comm_upsdrv_info = {
Expand Down Expand Up @@ -394,6 +394,50 @@ static int libshut_open(
* version is at index 1 (in which case, bcdDevice == 0x0202) */
usb_ctrl_descindex hid_desc_index = 0;

#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) )
# pragma GCC diagnostic push
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE
# pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE
# pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE
# pragma GCC diagnostic ignored "-Wtautological-type-limit-compare"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE
#pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
/* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
#pragma clang diagnostic ignored "-Wtautological-compare"
#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
#endif
static int usb_hid_number_opts_parsed = 0;
if (!usb_hid_number_opts_parsed) {
const char *s;
unsigned short us = 0;
if ((s = getval("usb_hid_desc_index"))) {
if (!str_to_ushort(s, &us, 16) || (us > USB_CTRL_DESCINDEX_MAX)) {
fatalx(EXIT_FAILURE, "%s: could not parse usb_hid_desc_index", __func__);
}
hid_desc_index = (usb_ctrl_descindex)us;
}
usb_hid_number_opts_parsed = 1;
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) )
# pragma GCC diagnostic pop
#endif

if (!arg_device_path) {
fatalx(EXIT_FAILURE, "%s: arg_device_path=null", __func__);
}
Expand Down Expand Up @@ -537,7 +581,8 @@ static int libshut_open(
upsdebugx(2, "Device matches");

if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) {
upsdebugx(1, "Eaton device v2.02. Using full report descriptor");
upsdebugx(1, "Eaton device v2.02. Using full report descriptor");
if (!getval("usb_hid_desc_index"))
hid_desc_index = 1;
}

Expand Down
93 changes: 91 additions & 2 deletions drivers/libusb0.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#endif

#define USB_DRIVER_NAME "USB communication driver (libusb 0.1)"
#define USB_DRIVER_VERSION "0.45"
#define USB_DRIVER_VERSION "0.47"

/* driver description structure */
upsdrv_info_t comm_upsdrv_info = {
Expand Down Expand Up @@ -94,6 +94,12 @@ void nut_usb_addvars(void)

addvar(VAR_VALUE, "usb_set_altinterface", "Force redundant call to usb_set_altinterface() (value=bAlternateSetting; default=0)");

addvar(VAR_VALUE, "usb_config_index", "Deeper tuning of USB communications for complex devices");
addvar(VAR_VALUE, "usb_hid_rep_index", "Deeper tuning of USB communications for complex devices");
addvar(VAR_VALUE, "usb_hid_desc_index", "Deeper tuning of USB communications for complex devices");
addvar(VAR_VALUE, "usb_hid_ep_in", "Deeper tuning of USB communications for complex devices");
addvar(VAR_VALUE, "usb_hid_ep_out", "Deeper tuning of USB communications for complex devices");

dstate_setinfo("driver.version.usb", "libusb-0.1 (or compat)");

upsdebugx(1, "Using USB implementation: %s", dstate_getinfo("driver.version.usb"));
Expand Down Expand Up @@ -219,6 +225,76 @@ static int libusb_open(usb_dev_handle **udevp,

struct usb_bus *busses;

static int usb_hid_number_opts_parsed = 0;
if (!usb_hid_number_opts_parsed) {
const char *s;
unsigned short us = 0;

#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) )
# pragma GCC diagnostic push
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS
# pragma GCC diagnostic ignored "-Wtype-limits"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE
# pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE
# pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE
# pragma GCC diagnostic ignored "-Wtautological-type-limit-compare"
#endif
#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE
#pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
/* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
#pragma clang diagnostic ignored "-Wtautological-compare"
#pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
#endif
if ((s = getval("usb_config_index"))) {
if (!str_to_ushort(s, &us, 16) || (us > USB_CTRL_CFGINDEX_MAX)) {
fatalx(EXIT_FAILURE, "%s: could not parse usb_config_index", __func__);
}
usb_subdriver.usb_config_index = (usb_ctrl_cfgindex)us;
}
if ((s = getval("usb_hid_rep_index"))) {
if (!str_to_ushort(s, &us, 16) || (us > USB_CTRL_REPINDEX_MAX)) {
fatalx(EXIT_FAILURE, "%s: could not parse usb_hid_rep_index", __func__);
}
usb_subdriver.hid_rep_index = (usb_ctrl_repindex)us;
}
if ((s = getval("usb_hid_desc_index"))) {
if (!str_to_ushort(s, &us, 16) || (us > USB_CTRL_DESCINDEX_MAX)) {
fatalx(EXIT_FAILURE, "%s: could not parse usb_hid_desc_index", __func__);
}
usb_subdriver.hid_desc_index = (usb_ctrl_descindex)us;
}
if ((s = getval("usb_hid_ep_in"))) {
if (!str_to_ushort(s, &us, 16) || (us > USB_CTRL_ENDPOINT_MAX)) {
fatalx(EXIT_FAILURE, "%s: could not parse usb_hid_ep_in", __func__);
}
usb_subdriver.hid_ep_in = (usb_ctrl_endpoint)us;
}
if ((s = getval("usb_hid_ep_out"))) {
if (!str_to_ushort(s, &us, 16) || (us > USB_CTRL_ENDPOINT_MAX)) {
fatalx(EXIT_FAILURE, "%s: could not parse usb_hid_ep_out", __func__);
}
usb_subdriver.hid_ep_out = (usb_ctrl_endpoint)us;
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE) )
# pragma GCC diagnostic pop
#endif

usb_hid_number_opts_parsed = 1;
}

/* libusb base init */
usb_init();
usb_find_busses();
Expand Down Expand Up @@ -374,7 +450,8 @@ static int libusb_open(usb_dev_handle **udevp,

/* FIXME: extend to Eaton OEMs (HP, IBM, ...) */
if ((curDevice->VendorID == 0x463) && (curDevice->bcdDevice == 0x0202)) {
usb_subdriver.hid_desc_index = 1;
if (!getval("usb_hid_desc_index"))
usb_subdriver.hid_desc_index = 1;
}

upsdebugx(2, "Trying to match device");
Expand Down Expand Up @@ -618,6 +695,18 @@ static int libusb_open(usb_dev_handle **udevp,
"Report descriptor retrieved (Reportlen = %"
PRI_NUT_USB_CTRL_CHARBUFSIZE ")", rdlen);
upsdebugx(2, "Found HID device");

upsdebugx(3, "Using default, detected or customized USB HID numbers: "
"usb_config_index=%d usb_hid_rep_index=%d "
"usb_hid_desc_index=%d "
"usb_hid_ep_in=%d usb_hid_ep_out=%d",
usb_subdriver.usb_config_index,
usb_subdriver.hid_rep_index,
usb_subdriver.hid_desc_index,
usb_subdriver.hid_ep_in,
usb_subdriver.hid_ep_out
);

fflush(stdout);

return rdlen;
Expand Down
Loading

0 comments on commit 34c8a56

Please sign in to comment.