diff --git a/usbutils.c b/usbutils.c index 9a7cca69..99d1d4c4 100644 --- a/usbutils.c +++ b/usbutils.c @@ -1311,6 +1311,9 @@ static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb) free(cgusb->found); + if (cgusb->buffer) + free(cgusb->buffer); + free(cgusb); return NULL; @@ -2024,6 +2027,36 @@ static void rejected_inc(struct cgpu_info *cgpu, uint32_t mode) } #endif +static char *find_end(unsigned char *buf, unsigned char *ptr, int ptrlen, int tot, char *end, int endlen, bool first) +{ + unsigned char *search; + + if (endlen > tot) + return NULL; + + // If end is only 1 char - do a faster search + if (endlen == 1) { + if (first) + search = buf; + else + search = ptr; + + return strchr((char *)search, *end); + } else { + if (first) + search = buf; + else { + // must allow end to have been chopped in 2 + if ((tot - ptrlen) >= (endlen - 1)) + search = ptr - (endlen - 1); + else + search = ptr - (tot - ptrlen); + } + + return strstr((char *)search, end); + } +} + #define USB_MAX_READ 8192 int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, __maybe_unused enum usb_cmds cmd, bool readonce) @@ -2037,8 +2070,8 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro unsigned int initial_timeout; double max, done; int bufleft, err, got, tot; - __maybe_unused bool first = true; - unsigned char *search; + bool first = true; + char *search; int endlen; // We add 4: 1 for null, 2 for FTDI status and 1 to round to 4 bytes @@ -2064,19 +2097,34 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro timeout = usbdev->found->timeout; if (end == NULL) { - tot = 0; - ptr = usbbuf; - bufleft = bufsiz; + if (usbdev->buffer && usbdev->bufamt) { + tot = usbdev->bufamt; + bufleft = bufsiz - tot; + memcpy(usbbuf, usbdev->buffer, tot); + ptr = usbbuf + tot; + usbdev->bufamt = 0; + } else { + tot = 0; + bufleft = bufsiz; + ptr = usbbuf; + } + err = LIBUSB_SUCCESS; initial_timeout = timeout; max = ((double)timeout) / 1000.0; cgtime(&read_start); while (bufleft > 0) { - if (ftdi) - usbbufread = bufleft + 2; - else - usbbufread = bufleft; + // TODO: use (USB_MAX_READ - tot) always? + if (usbdev->buffer) + usbbufread = USB_MAX_READ - tot; + else { + if (ftdi) + usbbufread = bufleft + 2; + else + usbbufread = bufleft; + } got = 0; + STATS_TIMEVAL(&tv_start); err = libusb_bulk_transfer(usbdev->handle, usbdev->found->eps[ep].ep, @@ -2120,6 +2168,16 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro break; } + // N.B. usbdev->buffer was emptied before the while() loop + if (usbdev->buffer && tot > (int)bufsiz) { + usbdev->bufamt = tot - bufsiz; + memcpy(usbdev->buffer, ptr + bufsiz, usbdev->bufamt); + tot -= usbdev->bufamt; + usbbuf[tot] = '\0'; + applog(LOG_ERR, "USB: %s%i read1 buffering %d extra bytes", + cgpu->drv->name, cgpu->device_id, usbdev->bufamt); + } + *processed = tot; memcpy((char *)buf, (const char *)usbbuf, (tot < (int)bufsiz) ? tot + 1 : (int)bufsiz); @@ -2129,19 +2187,33 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro return err; } - tot = 0; - ptr = usbbuf; - bufleft = bufsiz; + if (usbdev->buffer && usbdev->bufamt) { + tot = usbdev->bufamt; + bufleft = bufsiz - tot; + memcpy(usbbuf, usbdev->buffer, tot); + ptr = usbbuf + tot; + usbdev->bufamt = 0; + } else { + tot = 0; + bufleft = bufsiz; + ptr = usbbuf; + } + endlen = strlen(end); err = LIBUSB_SUCCESS; initial_timeout = timeout; max = ((double)timeout) / 1000.0; cgtime(&read_start); while (bufleft > 0) { - if (ftdi) - usbbufread = bufleft + 2; - else - usbbufread = bufleft; + // TODO: use (USB_MAX_READ - tot) always? + if (usbdev->buffer) + usbbufread = USB_MAX_READ - tot; + else { + if (ftdi) + usbbufread = bufleft + 2; + else + usbbufread = bufleft; + } got = 0; STATS_TIMEVAL(&tv_start); err = libusb_bulk_transfer(usbdev->handle, @@ -2172,23 +2244,8 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro if (err || readonce) break; - // WARNING - this will return data past END ('if' there is extra data) - if (endlen <= tot) { - // If END is only 1 char - do a faster search - if (endlen == 1) { - if (strchr((char *)ptr, *end)) - break; - } else { - // must allow END to have been chopped in 2 transfers - if ((tot - got) >= (endlen - 1)) - search = ptr - (endlen - 1); - else - search = ptr - (tot - got); - - if (strstr((char *)search, end)) - break; - } - } + if (find_end(usbbuf, ptr, got, tot, (char *)end, endlen, first)) + break; ptr += got; bufleft -= got; @@ -2204,6 +2261,38 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro break; } + if (usbdev->buffer) { + bool dobuffer = false; + + if ((search = find_end(usbbuf, usbbuf, tot, tot, (char *)end, endlen, true))) { + // end finishes after bufsiz + if ((search + endlen - (char *)usbbuf) > (int)bufsiz) { + usbdev->bufamt = tot - bufsiz; + dobuffer = true; + } else { + // extra data after end + if (*(search + endlen)) { + usbdev->bufamt = tot - (search + endlen - (char *)usbbuf); + dobuffer = true; + } + } + } else { + // no end, but still bigger than bufsiz + if (tot > (int)bufsiz) { + usbdev->bufamt = tot - bufsiz; + dobuffer = true; + } + } + + if (dobuffer) { + tot -= usbdev->bufamt; + memcpy(usbdev->buffer, usbbuf + tot, usbdev->bufamt); + usbbuf[tot] = '\0'; + applog(LOG_ERR, "USB: %s%i read2 buffering %d extra bytes", + cgpu->drv->name, cgpu->device_id, usbdev->bufamt); + } + } + *processed = tot; memcpy((char *)buf, (const char *)usbbuf, (tot < (int)bufsiz) ? tot + 1 : (int)bufsiz); @@ -2400,6 +2489,45 @@ int usb_ftdi_cts(struct cgpu_info *cgpu) return (ret & FTDI_RS0_CTS); } +void usb_buffer_enable(struct cgpu_info *cgpu) +{ + struct cg_usb_device *cgusb = cgpu->usbdev; + + if (!cgusb->buffer) { + cgusb->bufamt = 0; + cgusb->buffer = malloc(USB_MAX_READ+1); + if (!cgusb->buffer) + quit(1, "Failed to malloc buffer for USB %s%i", + cgpu->drv->name, cgpu->device_id); + cgusb->bufsiz = USB_MAX_READ; + } +} + +void usb_buffer_disable(struct cgpu_info *cgpu) +{ + struct cg_usb_device *cgusb = cgpu->usbdev; + + if (cgusb->buffer) { + cgusb->bufamt = 0; + cgusb->bufsiz = 0; + free(cgusb->buffer); + } +} + +void usb_buffer_clear(struct cgpu_info *cgpu) +{ + struct cg_usb_device *cgusb = cgpu->usbdev; + + cgusb->bufamt = 0; +} + +uint32_t usb_buffer_size(struct cgpu_info *cgpu) +{ + struct cg_usb_device *cgusb = cgpu->usbdev; + + return cgusb->bufamt; +} + void usb_cleanup() { struct cgpu_info *cgpu; diff --git a/usbutils.h b/usbutils.h index 5ff90c22..71aa8fb6 100644 --- a/usbutils.h +++ b/usbutils.h @@ -167,6 +167,9 @@ struct cg_usb_device { char *serial_string; unsigned char fwVersion; // ?? unsigned char interfaceVersion; // ?? + char *buffer; + uint32_t bufsiz; + uint32_t bufamt; }; struct cg_usb_info { @@ -258,6 +261,10 @@ int usb_ftdi_ctw(struct cgpu_info *cgpu); int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds); int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, unsigned int timeout, enum usb_cmds cmd); int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd); +void usb_buffer_enable(struct cgpu_info *cgpu); +void usb_buffer_disable(struct cgpu_info *cgpu); +void usb_buffer_clear(struct cgpu_info *cgpu); +uint32_t usb_buffer_size(struct cgpu_info *cgpu); void usb_cleanup(); void usb_initialise(); void *usb_resource_thread(void *userdata);