static int usb_std_io(usb_dev_handle * dev, int ep, char *bytes, int size, int timeout, int is_intr) { struct libusb20_transfer *xfer; uint32_t temp; uint32_t maxsize; uint32_t actlen; char *oldbytes; xfer = usb_get_transfer_by_ep_no(dev, ep); if (xfer == NULL) return (-1); if (libusb20_tr_pending(xfer)) { /* there is already a transfer ongoing */ return (-1); } maxsize = libusb20_tr_get_max_total_length(xfer); oldbytes = bytes; /* * We allow transferring zero bytes which is the same * equivalent to a zero length USB packet. */ do { temp = size; if (temp > maxsize) { /* find maximum possible length */ temp = maxsize; } if (is_intr) libusb20_tr_setup_intr(xfer, bytes, temp, timeout); else libusb20_tr_setup_bulk(xfer, bytes, temp, timeout); libusb20_tr_start(xfer); while (1) { if (libusb20_dev_process((void *)dev) != 0) { /* device detached */ return (-1); } if (libusb20_tr_pending(xfer) == 0) { /* transfer complete */ break; } /* wait for USB event from kernel */ libusb20_dev_wait_process((void *)dev, -1); } switch (libusb20_tr_get_status(xfer)) { case 0: /* success */ break; case LIBUSB20_TRANSFER_TIMED_OUT: /* transfer timeout */ return (-ETIMEDOUT); default: /* other transfer error */ return (-ENXIO); } actlen = libusb20_tr_get_actual_length(xfer); bytes += actlen; size -= actlen; if (actlen != temp) { /* short transfer */ break; } } while (size > 0); return (bytes - oldbytes); }
static void usb_modem_data_stress_test(struct modem *p, uint32_t duration) { struct timeval sub_tv; struct timeval ref_tv; struct timeval res_tv; time_t last_sec; uint8_t in_pending = 0; uint8_t in_ready = 0; uint8_t out_pending = 0; uint32_t id = 0; uint32_t in_max; uint32_t out_max; uint32_t io_max; uint8_t *in_buffer = 0; uint8_t *out_buffer = 0; gettimeofday(&ref_tv, 0); last_sec = ref_tv.tv_sec; printf("\n"); in_max = libusb20_tr_get_max_total_length(p->xfer_in); out_max = libusb20_tr_get_max_total_length(p->xfer_out); /* get the smallest buffer size and use that */ io_max = (in_max < out_max) ? in_max : out_max; if (in_max != out_max) printf("WARNING: Buffer sizes are un-equal: %u vs %u\n", in_max, out_max); in_buffer = malloc(io_max); if (in_buffer == NULL) goto fail; out_buffer = malloc(io_max); if (out_buffer == NULL) goto fail; while (1) { gettimeofday(&sub_tv, 0); if (last_sec != sub_tv.tv_sec) { printf("STATUS: ID=%u, RX=%u bytes/sec, TX=%u bytes/sec, ERR=%d\n", (int)id, (int)p->rx_bytes.bytes, (int)p->tx_bytes.bytes, (int)p->errors); p->rx_bytes.bytes = 0; p->tx_bytes.bytes = 0; fflush(stdout); last_sec = sub_tv.tv_sec; id++; } timersub(&sub_tv, &ref_tv, &res_tv); if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)duration)) break; libusb20_dev_process(p->usb_dev); if (!libusb20_tr_pending(p->xfer_in)) { if (in_pending) { if (libusb20_tr_get_status(p->xfer_in) == 0) { modem_read(in_buffer, libusb20_tr_get_length(p->xfer_in, 0)); } else { p->errors++; usleep(10000); } in_pending = 0; in_ready = 1; } if (p->loop_data == 0) { libusb20_tr_setup_bulk(p->xfer_in, in_buffer, io_max, 0); libusb20_tr_start(p->xfer_in); in_pending = 1; in_ready = 0; } } if (!libusb20_tr_pending(p->xfer_out)) { uint32_t len; uint32_t dly; if (out_pending) { if (libusb20_tr_get_status(p->xfer_out) != 0) { p->errors++; usleep(10000); } } if (p->random_tx_length) { len = ((uint32_t)usb_ts_rand_noise()) % ((uint32_t)io_max); } else { len = io_max; } if (p->random_tx_delay) { dly = ((uint32_t)usb_ts_rand_noise()) % 16000U; } else { dly = 0; } if (p->loop_data != 0) { if (in_ready != 0) { len = libusb20_tr_get_length(p->xfer_in, 0); memcpy(out_buffer, in_buffer, len); in_ready = 0; } else { len = io_max + 1; } if (!libusb20_tr_pending(p->xfer_in)) { libusb20_tr_setup_bulk(p->xfer_in, in_buffer, io_max, 0); libusb20_tr_start(p->xfer_in); in_pending = 1; } } else { modem_write(out_buffer, len); } if (len <= io_max) { libusb20_tr_setup_bulk(p->xfer_out, out_buffer, len, 0); if (dly != 0) usleep(dly); libusb20_tr_start(p->xfer_out); out_pending = 1; } } libusb20_dev_wait_process(p->usb_dev, 500); if (libusb20_dev_check_connected(p->usb_dev) != 0) { printf("Device disconnected\n"); break; } } libusb20_tr_stop(p->xfer_in); libusb20_tr_stop(p->xfer_out); printf("\nData stress test done!\n"); fail: if (in_buffer) free(in_buffer); if (out_buffer) free(out_buffer); }
uint8_t libusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer, void *pbuf, uint32_t length, uint32_t *pactlen, uint32_t timeout) { struct libusb20_device *pdev = xfer->pdev; uint32_t transfer_max; uint32_t transfer_act; uint8_t retval; /* set some sensible default value */ if (pactlen != NULL) *pactlen = 0; /* check for error condition */ if (libusb20_tr_pending(xfer)) return (LIBUSB20_ERROR_OTHER); do { /* compute maximum transfer length */ transfer_max = libusb20_tr_get_max_total_length(xfer); if (transfer_max > length) transfer_max = length; /* setup bulk or interrupt transfer */ libusb20_tr_setup_bulk(xfer, pbuf, transfer_max, timeout); /* start the transfer */ libusb20_tr_start(xfer); /* wait for transfer completion */ while (libusb20_dev_process(pdev) == 0) { if (libusb20_tr_pending(xfer) == 0) break; libusb20_dev_wait_process(pdev, -1); } transfer_act = libusb20_tr_get_actual_length(xfer); /* update actual length, if any */ if (pactlen != NULL) pactlen[0] += transfer_act; /* check transfer status */ retval = libusb20_tr_get_status(xfer); if (retval) break; /* check for short transfer */ if (transfer_act != transfer_max) break; /* update buffer pointer and length */ pbuf = ((uint8_t *)pbuf) + transfer_max; length = length - transfer_max; } while (length != 0); return (retval); }