Browse Source

usbutils optional read buffering

nfactor-troky
Kano 12 years ago
parent
commit
4368a04fce
  1. 194
      usbutils.c
  2. 7
      usbutils.h

194
usbutils.c

@ -1311,6 +1311,9 @@ static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb)
free(cgusb->found); free(cgusb->found);
if (cgusb->buffer)
free(cgusb->buffer);
free(cgusb); free(cgusb);
return NULL; return NULL;
@ -2024,6 +2027,36 @@ static void rejected_inc(struct cgpu_info *cgpu, uint32_t mode)
} }
#endif #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 #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) 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; unsigned int initial_timeout;
double max, done; double max, done;
int bufleft, err, got, tot; int bufleft, err, got, tot;
__maybe_unused bool first = true; bool first = true;
unsigned char *search; char *search;
int endlen; int endlen;
// We add 4: 1 for null, 2 for FTDI status and 1 to round to 4 bytes // 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; timeout = usbdev->found->timeout;
if (end == NULL) { if (end == NULL) {
tot = 0; if (usbdev->buffer && usbdev->bufamt) {
ptr = usbbuf; tot = usbdev->bufamt;
bufleft = bufsiz; bufleft = bufsiz - tot;
memcpy(usbbuf, usbdev->buffer, tot);
ptr = usbbuf + tot;
usbdev->bufamt = 0;
} else {
tot = 0;
bufleft = bufsiz;
ptr = usbbuf;
}
err = LIBUSB_SUCCESS; err = LIBUSB_SUCCESS;
initial_timeout = timeout; initial_timeout = timeout;
max = ((double)timeout) / 1000.0; max = ((double)timeout) / 1000.0;
cgtime(&read_start); cgtime(&read_start);
while (bufleft > 0) { while (bufleft > 0) {
if (ftdi) // TODO: use (USB_MAX_READ - tot) always?
usbbufread = bufleft + 2; if (usbdev->buffer)
else usbbufread = USB_MAX_READ - tot;
usbbufread = bufleft; else {
if (ftdi)
usbbufread = bufleft + 2;
else
usbbufread = bufleft;
}
got = 0; got = 0;
STATS_TIMEVAL(&tv_start); STATS_TIMEVAL(&tv_start);
err = libusb_bulk_transfer(usbdev->handle, err = libusb_bulk_transfer(usbdev->handle,
usbdev->found->eps[ep].ep, 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; 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; *processed = tot;
memcpy((char *)buf, (const char *)usbbuf, (tot < (int)bufsiz) ? tot + 1 : (int)bufsiz); 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; return err;
} }
tot = 0; if (usbdev->buffer && usbdev->bufamt) {
ptr = usbbuf; tot = usbdev->bufamt;
bufleft = bufsiz; bufleft = bufsiz - tot;
memcpy(usbbuf, usbdev->buffer, tot);
ptr = usbbuf + tot;
usbdev->bufamt = 0;
} else {
tot = 0;
bufleft = bufsiz;
ptr = usbbuf;
}
endlen = strlen(end); endlen = strlen(end);
err = LIBUSB_SUCCESS; err = LIBUSB_SUCCESS;
initial_timeout = timeout; initial_timeout = timeout;
max = ((double)timeout) / 1000.0; max = ((double)timeout) / 1000.0;
cgtime(&read_start); cgtime(&read_start);
while (bufleft > 0) { while (bufleft > 0) {
if (ftdi) // TODO: use (USB_MAX_READ - tot) always?
usbbufread = bufleft + 2; if (usbdev->buffer)
else usbbufread = USB_MAX_READ - tot;
usbbufread = bufleft; else {
if (ftdi)
usbbufread = bufleft + 2;
else
usbbufread = bufleft;
}
got = 0; got = 0;
STATS_TIMEVAL(&tv_start); STATS_TIMEVAL(&tv_start);
err = libusb_bulk_transfer(usbdev->handle, 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) if (err || readonce)
break; break;
// WARNING - this will return data past END ('if' there is extra data) if (find_end(usbbuf, ptr, got, tot, (char *)end, endlen, first))
if (endlen <= tot) { break;
// 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;
}
}
ptr += got; ptr += got;
bufleft -= got; bufleft -= got;
@ -2204,6 +2261,38 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
break; 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; *processed = tot;
memcpy((char *)buf, (const char *)usbbuf, (tot < (int)bufsiz) ? tot + 1 : (int)bufsiz); 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); 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() void usb_cleanup()
{ {
struct cgpu_info *cgpu; struct cgpu_info *cgpu;

7
usbutils.h

@ -167,6 +167,9 @@ struct cg_usb_device {
char *serial_string; char *serial_string;
unsigned char fwVersion; // ?? unsigned char fwVersion; // ??
unsigned char interfaceVersion; // ?? unsigned char interfaceVersion; // ??
char *buffer;
uint32_t bufsiz;
uint32_t bufamt;
}; };
struct cg_usb_info { 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_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(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); 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_cleanup();
void usb_initialise(); void usb_initialise();
void *usb_resource_thread(void *userdata); void *usb_resource_thread(void *userdata);

Loading…
Cancel
Save