Skip to content

Commit dcd9e6e

Browse files
authored
Merge pull request #3259 from com6056/fix-cyberpower-eio-tolerance
usbhid-ups: improve handling of transient LIBUSB_ERROR_IO failures
2 parents 1151920 + f5c95d5 commit dcd9e6e

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

NEWS.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ https://github.com/networkupstools/nut/milestone/12
209209
if too few data points were seen. [#3082, #3095]
210210
* `openups-hid` had `nobattery` definition inverted, causing alarms -- now
211211
fixed to use the same mapping helper as other subdrivers. [issue #3246]
212+
* Improved handling of transient `LIBUSB_ERROR_IO` failures during polling.
213+
Some devices (CyberPower, etc.) have firmware bugs causing random I/O
214+
errors on certain HID reports. The driver now skips failing reports and
215+
continues polling rather than triggering expensive reconnection attempts.
216+
True disconnections are still detected via other error codes or when all
217+
polls fail. [issue #3116]
212218

213219
- `nut-scanner` tool updates:
214220
* Fixed `nut-scanner` search for "simulation devices" to not use only the

drivers/usbhid-ups.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,6 +2183,7 @@ static bool_t hid_ups_walk(walkmode_t mode)
21832183
hid_info_t *item;
21842184
double value;
21852185
int retcode;
2186+
int items_succeeded = 0; /* Track successful polls to detect total failure */
21862187

21872188
#if !((defined SHUT_MODE) && SHUT_MODE)
21882189
/* extract the VendorId for further testing */
@@ -2373,13 +2374,19 @@ static bool_t hid_ups_walk(walkmode_t mode)
23732374
return FALSE;
23742375

23752376
case LIBUSB_ERROR_IO: /* I/O error */
2376-
/* Uh oh, got to reconnect, with a special suggestion! */
2377-
dstate_setinfo("driver.state", "reconnect.trying");
2377+
/* Some devices have firmware bugs causing transient I/O errors
2378+
* on specific HID reports. Rather than triggering expensive
2379+
* reconnects, skip the failing report and continue. If device
2380+
* is truly disconnected, other error codes will catch it, or
2381+
* all polls fail and safety check below triggers reconnect. */
2382+
upsdebugx(3, "Got LIBUSB_ERROR_IO on item '%s' ReportID=0x%02x - skipping",
2383+
item->info_type ? item->info_type : "(null)",
2384+
item->hiddata ? item->hiddata->ReportID : 0xFFU);
23782385
interrupt_pipe_EIO_count++;
2379-
hd = NULL;
2380-
return FALSE;
2386+
continue;
23812387

23822388
case 1:
2389+
items_succeeded++; /* Count successful data retrieval */
23832390
break; /* Found! */
23842391

23852392
case 0:
@@ -2449,6 +2456,16 @@ static bool_t hid_ups_walk(walkmode_t mode)
24492456
}
24502457
}
24512458

2459+
/* Safety check: if we got zero successful polls during update,
2460+
* device may be truly disconnected (not just transient errors).
2461+
* Skip this check during INIT mode where failures are expected. */
2462+
if (items_succeeded == 0 && (mode == HU_WALKMODE_QUICK_UPDATE || mode == HU_WALKMODE_FULL_UPDATE)) {
2463+
upsdebugx(1, "Got zero successful data polls - device may be disconnected");
2464+
dstate_setinfo("driver.state", "reconnect.trying");
2465+
hd = NULL;
2466+
return FALSE;
2467+
}
2468+
24522469
return TRUE;
24532470
}
24542471

0 commit comments

Comments
 (0)