Skip to content

Commit 9eefcfd

Browse files
committed
drivers/nutdrv_qx.c, drivers/blazer_usb.c: cypress_command()/phoenix_command(): clear endpoint halt and retry on LIBUSB_ERROR_OVERFLOW [#598]
Some firmware in the 0665:5161 Cypress USB-Serial bridge family (Salicru SPS ONE, Ippon, Belkin F6C1200-UNV, ViewPower, various Voltronic Power UPSes) occasionally emits an interrupt-IN frame larger than the declared wMaxPacketSize=8, mid-reply. The kernel xHCI driver flags this as LIBUSB_ERROR_OVERFLOW and discards the data; from that point on, every subsequent read on the endpoint also returns OVERFLOW until a USB-level reset is performed, which results in "Data stale" from upsd until the driver is restarted. Issue an immediate CLEAR_FEATURE(HALT) on EP 0x81 and retry the read once. CLEAR_FEATURE(HALT) unsticks the kernel-side endpoint state, and in the observed cases the firmware's TX FIFO state as well, so the next read returns a clean frame. If the retry also overflows, the existing error path is taken unchanged. Captured at byte level on a Salicru SPS 1500 ONE BL (Voltronic-QS H-protocol over 0665:5161, host xHCI on Linux 6.14): firmware emits chunks 3..6 of the QS reply collapsed into a single frame that exceeds wMaxPacketSize, kernel reports LIBUSB_ERROR_OVERFLOW, and all subsequent reads on EP 0x81 return OVERFLOW until a port reset. The same fix is applied to cypress_command() and phoenix_command() in both drivers because the read loops are byte-identical and the bug is at the USB transport layer, below either subdriver's protocol logic. Signed-off-by: Pedro Cunha <pedroagracio+nut@gmail.com>
1 parent 0d2c7a1 commit 9eefcfd

2 files changed

Lines changed: 80 additions & 0 deletions

File tree

drivers/blazer_usb.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,26 @@ static int cypress_command(const char *cmd, char *buf, size_t buflen)
128128
0x81,
129129
(usb_ctrl_charbuf)&buf[i], 8, 1000);
130130

131+
/* Some firmware in the 0665:5161 Cypress USB-Serial bridge family
132+
* (Salicru SPS ONE, Ippon, Belkin F6C1200-UNV, ViewPower, various
133+
* Voltronic Power UPSes) occasionally emits an interrupt-IN frame
134+
* larger than the declared wMaxPacketSize=8, mid-reply. The kernel
135+
* xHCI driver flags this as LIBUSB_ERROR_OVERFLOW and discards the
136+
* data; from that point on, every subsequent read on the endpoint
137+
* also returns OVERFLOW until a USB-level reset is performed.
138+
* Clear the endpoint halt and retry once: this issues CLEAR_FEATURE
139+
* (HALT) which unsticks the kernel-side endpoint state and in most
140+
* observed cases the firmware's TX-FIFO state as well. If the retry
141+
* also overflows, fall through to the normal error path below.
142+
* See NUT issue #598. */
143+
if (ret == LIBUSB_ERROR_OVERFLOW) {
144+
upsdebugx(2, "%s: LIBUSB_ERROR_OVERFLOW on EP 0x81, clearing halt and retrying", __func__);
145+
usb_clear_halt(udev, 0x81);
146+
ret = usb_interrupt_read(udev,
147+
0x81,
148+
(usb_ctrl_charbuf)&buf[i], 8, 1000);
149+
}
150+
131151
/*
132152
* Any errors here mean that we are unable to read a reply (which
133153
* will happen after successfully writing a command to the UPS)
@@ -212,6 +232,26 @@ static int phoenix_command(const char *cmd, char *buf, size_t buflen)
212232
0x81,
213233
(usb_ctrl_charbuf)&buf[i], 8, 1000);
214234

235+
/* Some firmware in the 0665:5161 Cypress USB-Serial bridge family
236+
* (Salicru SPS ONE, Ippon, Belkin F6C1200-UNV, ViewPower, various
237+
* Voltronic Power UPSes) occasionally emits an interrupt-IN frame
238+
* larger than the declared wMaxPacketSize=8, mid-reply. The kernel
239+
* xHCI driver flags this as LIBUSB_ERROR_OVERFLOW and discards the
240+
* data; from that point on, every subsequent read on the endpoint
241+
* also returns OVERFLOW until a USB-level reset is performed.
242+
* Clear the endpoint halt and retry once: this issues CLEAR_FEATURE
243+
* (HALT) which unsticks the kernel-side endpoint state and in most
244+
* observed cases the firmware's TX-FIFO state as well. If the retry
245+
* also overflows, fall through to the normal error path below.
246+
* See NUT issue #598. */
247+
if (ret == LIBUSB_ERROR_OVERFLOW) {
248+
upsdebugx(2, "%s: LIBUSB_ERROR_OVERFLOW on EP 0x81, clearing halt and retrying", __func__);
249+
usb_clear_halt(udev, 0x81);
250+
ret = usb_interrupt_read(udev,
251+
0x81,
252+
(usb_ctrl_charbuf)&buf[i], 8, 1000);
253+
}
254+
215255
/*
216256
* Any errors here mean that we are unable to read a reply (which
217257
* will happen after successfully writing a command to the UPS)

drivers/nutdrv_qx.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,26 @@ static int cypress_command(const char *cmd, size_t cmdlen, char *buf, size_t buf
778778
0x81,
779779
(usb_ctrl_charbuf)&buf[i], 8, 1000);
780780

781+
/* Some firmware in the 0665:5161 Cypress USB-Serial bridge family
782+
* (Salicru SPS ONE, Ippon, Belkin F6C1200-UNV, ViewPower, various
783+
* Voltronic Power UPSes) occasionally emits an interrupt-IN frame
784+
* larger than the declared wMaxPacketSize=8, mid-reply. The kernel
785+
* xHCI driver flags this as LIBUSB_ERROR_OVERFLOW and discards the
786+
* data; from that point on, every subsequent read on the endpoint
787+
* also returns OVERFLOW until a USB-level reset is performed.
788+
* Clear the endpoint halt and retry once: this issues CLEAR_FEATURE
789+
* (HALT) which unsticks the kernel-side endpoint state and in most
790+
* observed cases the firmware's TX-FIFO state as well. If the retry
791+
* also overflows, fall through to the normal error path below.
792+
* See NUT issue #598. */
793+
if (ret == LIBUSB_ERROR_OVERFLOW) {
794+
upsdebugx(2, "%s: LIBUSB_ERROR_OVERFLOW on EP 0x81, clearing halt and retrying", __func__);
795+
usb_clear_halt(udev, 0x81);
796+
ret = usb_interrupt_read(udev,
797+
0x81,
798+
(usb_ctrl_charbuf)&buf[i], 8, 1000);
799+
}
800+
781801
/* Any errors here mean that we are unable to read a reply
782802
* (which will happen after successfully writing a command
783803
* to the UPS) */
@@ -989,6 +1009,26 @@ static int phoenix_command(const char *cmd, size_t cmdlen, char *buf, size_t buf
9891009
0x81,
9901010
(usb_ctrl_charbuf)&buf[i], 8, 1000);
9911011

1012+
/* Some firmware in the 0665:5161 Cypress USB-Serial bridge family
1013+
* (Salicru SPS ONE, Ippon, Belkin F6C1200-UNV, ViewPower, various
1014+
* Voltronic Power UPSes) occasionally emits an interrupt-IN frame
1015+
* larger than the declared wMaxPacketSize=8, mid-reply. The kernel
1016+
* xHCI driver flags this as LIBUSB_ERROR_OVERFLOW and discards the
1017+
* data; from that point on, every subsequent read on the endpoint
1018+
* also returns OVERFLOW until a USB-level reset is performed.
1019+
* Clear the endpoint halt and retry once: this issues CLEAR_FEATURE
1020+
* (HALT) which unsticks the kernel-side endpoint state and in most
1021+
* observed cases the firmware's TX-FIFO state as well. If the retry
1022+
* also overflows, fall through to the normal error path below.
1023+
* See NUT issue #598. */
1024+
if (ret == LIBUSB_ERROR_OVERFLOW) {
1025+
upsdebugx(2, "%s: LIBUSB_ERROR_OVERFLOW on EP 0x81, clearing halt and retrying", __func__);
1026+
usb_clear_halt(udev, 0x81);
1027+
ret = usb_interrupt_read(udev,
1028+
0x81,
1029+
(usb_ctrl_charbuf)&buf[i], 8, 1000);
1030+
}
1031+
9921032
/* Any errors here mean that we are unable to read a reply
9931033
* (which will happen after successfully writing a command
9941034
* to the UPS) */

0 commit comments

Comments
 (0)