aboutsummaryrefslogtreecommitdiff
path: root/tools/usb
diff options
context:
space:
mode:
Diffstat (limited to 'tools/usb')
-rw-r--r--tools/usb/Makefile14
-rw-r--r--tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c349
-rw-r--r--tools/usb/ffs-aio-example/multibuff/host_app/Makefile13
-rw-r--r--tools/usb/ffs-aio-example/multibuff/host_app/test.c146
-rw-r--r--tools/usb/ffs-aio-example/simple/device_app/aio_simple.c335
-rw-r--r--tools/usb/ffs-aio-example/simple/host_app/Makefile13
-rw-r--r--tools/usb/ffs-aio-example/simple/host_app/test.c148
-rw-r--r--tools/usb/ffs-test.c41
-rw-r--r--tools/usb/hcd-tests.sh275
-rw-r--r--tools/usb/testusb.c80
10 files changed, 1335 insertions, 79 deletions
diff --git a/tools/usb/Makefile b/tools/usb/Makefile
new file mode 100644
index 00000000000..acf2165c04e
--- /dev/null
+++ b/tools/usb/Makefile
@@ -0,0 +1,14 @@
+# Makefile for USB tools
+
+CC = $(CROSS_COMPILE)gcc
+PTHREAD_LIBS = -lpthread
+WARNINGS = -Wall -Wextra
+CFLAGS = $(WARNINGS) -g -I../include
+LDFLAGS = $(PTHREAD_LIBS)
+
+all: testusb ffs-test
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+clean:
+ $(RM) testusb ffs-test
diff --git a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
new file mode 100644
index 00000000000..87216a0c4a8
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
@@ -0,0 +1,349 @@
+#define _BSD_SOURCE /* for endian.h */
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <sys/eventfd.h>
+
+#include "libaio.h"
+#define IOCB_FLAG_RESFD (1 << 0)
+
+#include <linux/usb/functionfs.h>
+
+#define BUF_LEN 8192
+#define BUFS_MAX 128
+#define AIO_MAX (BUFS_MAX*2)
+
+/******************** Descriptors and Strings *******************************/
+
+static const struct {
+ struct usb_functionfs_descs_head header;
+ struct {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio bulk_sink;
+ struct usb_endpoint_descriptor_no_audio bulk_source;
+ } __attribute__ ((__packed__)) fs_descs, hs_descs;
+} __attribute__ ((__packed__)) descriptors = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(descriptors)),
+ .fs_count = 3,
+ .hs_count = 3,
+ },
+ .fs_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.fs_descs.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = 1,
+ },
+ .bulk_sink = {
+ .bLength = sizeof(descriptors.fs_descs.bulk_sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .bulk_source = {
+ .bLength = sizeof(descriptors.fs_descs.bulk_source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ },
+ .hs_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.hs_descs.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = 1,
+ },
+ .bulk_sink = {
+ .bLength = sizeof(descriptors.hs_descs.bulk_sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = htole16(512),
+ },
+ .bulk_source = {
+ .bLength = sizeof(descriptors.hs_descs.bulk_source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = htole16(512),
+ },
+ },
+};
+
+#define STR_INTERFACE "AIO Test"
+
+static const struct {
+ struct usb_functionfs_strings_head header;
+ struct {
+ __le16 code;
+ const char str1[sizeof(STR_INTERFACE)];
+ } __attribute__ ((__packed__)) lang0;
+} __attribute__ ((__packed__)) strings = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 = {
+ htole16(0x0409), /* en-us */
+ STR_INTERFACE,
+ },
+};
+
+/********************** Buffer structure *******************************/
+
+struct io_buffer {
+ struct iocb **iocb;
+ unsigned char **buf;
+ unsigned cnt;
+ unsigned len;
+ unsigned requested;
+};
+
+/******************** Endpoints handling *******************************/
+
+static void display_event(struct usb_functionfs_event *event)
+{
+ static const char *const names[] = {
+ [FUNCTIONFS_BIND] = "BIND",
+ [FUNCTIONFS_UNBIND] = "UNBIND",
+ [FUNCTIONFS_ENABLE] = "ENABLE",
+ [FUNCTIONFS_DISABLE] = "DISABLE",
+ [FUNCTIONFS_SETUP] = "SETUP",
+ [FUNCTIONFS_SUSPEND] = "SUSPEND",
+ [FUNCTIONFS_RESUME] = "RESUME",
+ };
+ switch (event->type) {
+ case FUNCTIONFS_BIND:
+ case FUNCTIONFS_UNBIND:
+ case FUNCTIONFS_ENABLE:
+ case FUNCTIONFS_DISABLE:
+ case FUNCTIONFS_SETUP:
+ case FUNCTIONFS_SUSPEND:
+ case FUNCTIONFS_RESUME:
+ printf("Event %s\n", names[event->type]);
+ }
+}
+
+static void handle_ep0(int ep0, bool *ready)
+{
+ int ret;
+ struct usb_functionfs_event event;
+
+ ret = read(ep0, &event, sizeof(event));
+ if (!ret) {
+ perror("unable to read event from ep0");
+ return;
+ }
+ display_event(&event);
+ switch (event.type) {
+ case FUNCTIONFS_SETUP:
+ if (event.u.setup.bRequestType & USB_DIR_IN)
+ write(ep0, NULL, 0);
+ else
+ read(ep0, NULL, 0);
+ break;
+
+ case FUNCTIONFS_ENABLE:
+ *ready = true;
+ break;
+
+ case FUNCTIONFS_DISABLE:
+ *ready = false;
+ break;
+
+ default:
+ break;
+ }
+}
+
+void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
+{
+ unsigned i;
+ iobuf->buf = malloc(n*sizeof(*iobuf->buf));
+ iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
+ iobuf->cnt = n;
+ iobuf->len = len;
+ iobuf->requested = 0;
+ for (i = 0; i < n; ++i) {
+ iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
+ iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
+ }
+ iobuf->cnt = n;
+}
+
+void delete_bufs(struct io_buffer *iobuf)
+{
+ unsigned i;
+ for (i = 0; i < iobuf->cnt; ++i) {
+ free(iobuf->buf[i]);
+ free(iobuf->iocb[i]);
+ }
+ free(iobuf->buf);
+ free(iobuf->iocb);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ unsigned i, j;
+ char *ep_path;
+
+ int ep0, ep1;
+
+ io_context_t ctx;
+
+ int evfd;
+ fd_set rfds;
+
+ struct io_buffer iobuf[2];
+ int actual = 0;
+ bool ready;
+
+ if (argc != 2) {
+ printf("ffs directory not specified!\n");
+ return 1;
+ }
+
+ ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
+ if (!ep_path) {
+ perror("malloc");
+ return 1;
+ }
+
+ /* open endpoint files */
+ sprintf(ep_path, "%s/ep0", argv[1]);
+ ep0 = open(ep_path, O_RDWR);
+ if (ep0 < 0) {
+ perror("unable to open ep0");
+ return 1;
+ }
+ if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
+ perror("unable do write descriptors");
+ return 1;
+ }
+ if (write(ep0, &strings, sizeof(strings)) < 0) {
+ perror("unable to write strings");
+ return 1;
+ }
+ sprintf(ep_path, "%s/ep1", argv[1]);
+ ep1 = open(ep_path, O_RDWR);
+ if (ep1 < 0) {
+ perror("unable to open ep1");
+ return 1;
+ }
+
+ free(ep_path);
+
+ memset(&ctx, 0, sizeof(ctx));
+ /* setup aio context to handle up to AIO_MAX requests */
+ if (io_setup(AIO_MAX, &ctx) < 0) {
+ perror("unable to setup aio");
+ return 1;
+ }
+
+ evfd = eventfd(0, 0);
+ if (evfd < 0) {
+ perror("unable to open eventfd");
+ return 1;
+ }
+
+ for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
+ init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
+
+ while (1) {
+ FD_ZERO(&rfds);
+ FD_SET(ep0, &rfds);
+ FD_SET(evfd, &rfds);
+
+ ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
+ &rfds, NULL, NULL, NULL);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("select");
+ break;
+ }
+
+ if (FD_ISSET(ep0, &rfds))
+ handle_ep0(ep0, &ready);
+
+ /* we are waiting for function ENABLE */
+ if (!ready)
+ continue;
+
+ /*
+ * when we're preparing new data to submit,
+ * second buffer being transmitted
+ */
+ for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
+ if (iobuf[i].requested)
+ continue;
+ /* prepare requests */
+ for (j = 0; j < iobuf[i].cnt; ++j) {
+ io_prep_pwrite(iobuf[i].iocb[j], ep1,
+ iobuf[i].buf[j],
+ iobuf[i].len, 0);
+ /* enable eventfd notification */
+ iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
+ iobuf[i].iocb[j]->u.c.resfd = evfd;
+ }
+ /* submit table of requests */
+ ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
+ if (ret >= 0) {
+ iobuf[i].requested = ret;
+ printf("submit: %d requests buf: %d\n", ret, i);
+ } else
+ perror("unable to submit reqests");
+ }
+
+ /* if event is ready to read */
+ if (!FD_ISSET(evfd, &rfds))
+ continue;
+
+ uint64_t ev_cnt;
+ ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
+ if (ret < 0) {
+ perror("unable to read eventfd");
+ break;
+ }
+
+ struct io_event e[BUFS_MAX];
+ /* we read aio events */
+ ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
+ if (ret > 0) /* if we got events */
+ iobuf[actual].requested -= ret;
+
+ /* if all req's from iocb completed */
+ if (!iobuf[actual].requested)
+ actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
+ }
+
+ /* free resources */
+
+ for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
+ delete_bufs(&iobuf[i]);
+ io_destroy(ctx);
+
+ close(ep1);
+ close(ep0);
+
+ return 0;
+}
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/Makefile b/tools/usb/ffs-aio-example/multibuff/host_app/Makefile
new file mode 100644
index 00000000000..8c4a6f0aa82
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/Makefile
@@ -0,0 +1,13 @@
+CC = gcc
+LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0)
+LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0)
+WARNINGS = -Wall -Wextra
+CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS)
+LDFLAGS = $(LIBUSB_LIBS)
+
+all: test
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+clean:
+ $(RM) test
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/test.c b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
new file mode 100644
index 00000000000..b0ad8747d03
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
@@ -0,0 +1,146 @@
+#include <libusb.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define VENDOR 0x1d6b
+#define PRODUCT 0x0105
+
+/* endpoints indexes */
+
+#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN)
+#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT)
+
+#define BUF_LEN 8192
+
+/*
+ * struct test_state - describes test program state
+ * @list: list of devices returned by libusb_get_device_list function
+ * @found: pointer to struct describing tested device
+ * @ctx: context, set to NULL
+ * @handle: handle of tested device
+ * @attached: indicates that device was attached to kernel, and has to be
+ * reattached at the end of test program
+ */
+
+struct test_state {
+ libusb_device *found;
+ libusb_context *ctx;
+ libusb_device_handle *handle;
+ int attached;
+};
+
+/*
+ * test_init - initialize test program
+ */
+
+int test_init(struct test_state *state)
+{
+ int i, ret;
+ ssize_t cnt;
+ libusb_device **list;
+
+ state->found = NULL;
+ state->ctx = NULL;
+ state->handle = NULL;
+ state->attached = 0;
+
+ ret = libusb_init(&state->ctx);
+ if (ret) {
+ printf("cannot init libusb: %s\n", libusb_error_name(ret));
+ return 1;
+ }
+
+ cnt = libusb_get_device_list(state->ctx, &list);
+ if (cnt <= 0) {
+ printf("no devices found\n");
+ goto error1;
+ }
+
+ for (i = 0; i < cnt; ++i) {
+ libusb_device *dev = list[i];
+ struct libusb_device_descriptor desc;
+ ret = libusb_get_device_descriptor(dev, &desc);
+ if (ret) {
+ printf("unable to get device descriptor: %s\n",
+ libusb_error_name(ret));
+ goto error2;
+ }
+ if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
+ state->found = dev;
+ break;
+ }
+ }
+
+ if (!state->found) {
+ printf("no devices found\n");
+ goto error2;
+ }
+
+ ret = libusb_open(state->found, &state->handle);
+ if (ret) {
+ printf("cannot open device: %s\n", libusb_error_name(ret));
+ goto error2;
+ }
+
+ if (libusb_claim_interface(state->handle, 0)) {
+ ret = libusb_detach_kernel_driver(state->handle, 0);
+ if (ret) {
+ printf("unable to detach kernel driver: %s\n",
+ libusb_error_name(ret));
+ goto error3;
+ }
+ state->attached = 1;
+ ret = libusb_claim_interface(state->handle, 0);
+ if (ret) {
+ printf("cannot claim interface: %s\n",
+ libusb_error_name(ret));
+ goto error4;
+ }
+ }
+
+ return 0;
+
+error4:
+ if (state->attached == 1)
+ libusb_attach_kernel_driver(state->handle, 0);
+
+error3:
+ libusb_close(state->handle);
+
+error2:
+ libusb_free_device_list(list, 1);
+
+error1:
+ libusb_exit(state->ctx);
+ return 1;
+}
+
+/*
+ * test_exit - cleanup test program
+ */
+
+void test_exit(struct test_state *state)
+{
+ libusb_release_interface(state->handle, 0);
+ if (state->attached == 1)
+ libusb_attach_kernel_driver(state->handle, 0);
+ libusb_close(state->handle);
+ libusb_exit(state->ctx);
+}
+
+int main(void)
+{
+ struct test_state state;
+
+ if (test_init(&state))
+ return 1;
+
+ while (1) {
+ static unsigned char buffer[BUF_LEN];
+ int bytes;
+ libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
+ &bytes, 500);
+ }
+ test_exit(&state);
+}
diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
new file mode 100644
index 00000000000..f558664a331
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
@@ -0,0 +1,335 @@
+#define _BSD_SOURCE /* for endian.h */
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <sys/eventfd.h>
+
+#include "libaio.h"
+#define IOCB_FLAG_RESFD (1 << 0)
+
+#include <linux/usb/functionfs.h>
+
+#define BUF_LEN 8192
+
+/******************** Descriptors and Strings *******************************/
+
+static const struct {
+ struct usb_functionfs_descs_head header;
+ struct {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio bulk_sink;
+ struct usb_endpoint_descriptor_no_audio bulk_source;
+ } __attribute__ ((__packed__)) fs_descs, hs_descs;
+} __attribute__ ((__packed__)) descriptors = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(descriptors)),
+ .fs_count = 3,
+ .hs_count = 3,
+ },
+ .fs_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.fs_descs.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = 1,
+ },
+ .bulk_sink = {
+ .bLength = sizeof(descriptors.fs_descs.bulk_sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .bulk_source = {
+ .bLength = sizeof(descriptors.fs_descs.bulk_source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ },
+ .hs_descs = {
+ .intf = {
+ .bLength = sizeof(descriptors.hs_descs.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = 1,
+ },
+ .bulk_sink = {
+ .bLength = sizeof(descriptors.hs_descs.bulk_sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .bulk_source = {
+ .bLength = sizeof(descriptors.hs_descs.bulk_source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ },
+};
+
+#define STR_INTERFACE "AIO Test"
+
+static const struct {
+ struct usb_functionfs_strings_head header;
+ struct {
+ __le16 code;
+ const char str1[sizeof(STR_INTERFACE)];
+ } __attribute__ ((__packed__)) lang0;
+} __attribute__ ((__packed__)) strings = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 = {
+ htole16(0x0409), /* en-us */
+ STR_INTERFACE,
+ },
+};
+
+/******************** Endpoints handling *******************************/
+
+static void display_event(struct usb_functionfs_event *event)
+{
+ static const char *const names[] = {
+ [FUNCTIONFS_BIND] = "BIND",
+ [FUNCTIONFS_UNBIND] = "UNBIND",
+ [FUNCTIONFS_ENABLE] = "ENABLE",
+ [FUNCTIONFS_DISABLE] = "DISABLE",
+ [FUNCTIONFS_SETUP] = "SETUP",
+ [FUNCTIONFS_SUSPEND] = "SUSPEND",
+ [FUNCTIONFS_RESUME] = "RESUME",
+ };
+ switch (event->type) {
+ case FUNCTIONFS_BIND:
+ case FUNCTIONFS_UNBIND:
+ case FUNCTIONFS_ENABLE:
+ case FUNCTIONFS_DISABLE:
+ case FUNCTIONFS_SETUP:
+ case FUNCTIONFS_SUSPEND:
+ case FUNCTIONFS_RESUME:
+ printf("Event %s\n", names[event->type]);
+ }
+}
+
+static void handle_ep0(int ep0, bool *ready)
+{
+ struct usb_functionfs_event event;
+ int ret;
+
+ struct pollfd pfds[1];
+ pfds[0].fd = ep0;
+ pfds[0].events = POLLIN;
+
+ ret = poll(pfds, 1, 0);
+
+ if (ret && (pfds[0].revents & POLLIN)) {
+ ret = read(ep0, &event, sizeof(event));
+ if (!ret) {
+ perror("unable to read event from ep0");
+ return;
+ }
+ display_event(&event);
+ switch (event.type) {
+ case FUNCTIONFS_SETUP:
+ if (event.u.setup.bRequestType & USB_DIR_IN)
+ write(ep0, NULL, 0);
+ else
+ read(ep0, NULL, 0);
+ break;
+
+ case FUNCTIONFS_ENABLE:
+ *ready = true;
+ break;
+
+ case FUNCTIONFS_DISABLE:
+ *ready = false;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i, ret;
+ char *ep_path;
+
+ int ep0;
+ int ep[2];
+
+ io_context_t ctx;
+
+ int evfd;
+ fd_set rfds;
+
+ char *buf_in, *buf_out;
+ struct iocb *iocb_in, *iocb_out;
+ int req_in = 0, req_out = 0;
+ bool ready;
+
+ if (argc != 2) {
+ printf("ffs directory not specified!\n");
+ return 1;
+ }
+
+ ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
+ if (!ep_path) {
+ perror("malloc");
+ return 1;
+ }
+
+ /* open endpoint files */
+ sprintf(ep_path, "%s/ep0", argv[1]);
+ ep0 = open(ep_path, O_RDWR);
+ if (ep0 < 0) {
+ perror("unable to open ep0");
+ return 1;
+ }
+ if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
+ perror("unable do write descriptors");
+ return 1;
+ }
+ if (write(ep0, &strings, sizeof(strings)) < 0) {
+ perror("unable to write strings");
+ return 1;
+ }
+ for (i = 0; i < 2; ++i) {
+ sprintf(ep_path, "%s/ep%d", argv[1], i+1);
+ ep[i] = open(ep_path, O_RDWR);
+ if (ep[i] < 0) {
+ printf("unable to open ep%d: %s\n", i+1,
+ strerror(errno));
+ return 1;
+ }
+ }
+
+ free(ep_path);
+
+ memset(&ctx, 0, sizeof(ctx));
+ /* setup aio context to handle up to 2 requests */
+ if (io_setup(2, &ctx) < 0) {
+ perror("unable to setup aio");
+ return 1;
+ }
+
+ evfd = eventfd(0, 0);
+ if (evfd < 0) {
+ perror("unable to open eventfd");
+ return 1;
+ }
+
+ /* alloc buffers and requests */
+ buf_in = malloc(BUF_LEN);
+ buf_out = malloc(BUF_LEN);
+ iocb_in = malloc(sizeof(*iocb_in));
+ iocb_out = malloc(sizeof(*iocb_out));
+
+ while (1) {
+ FD_ZERO(&rfds);
+ FD_SET(ep0, &rfds);
+ FD_SET(evfd, &rfds);
+
+ ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
+ &rfds, NULL, NULL, NULL);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("select");
+ break;
+ }
+
+ if (FD_ISSET(ep0, &rfds))
+ handle_ep0(ep0, &ready);
+
+ /* we are waiting for function ENABLE */
+ if (!ready)
+ continue;
+
+ /* if something was submitted we wait for event */
+ if (FD_ISSET(evfd, &rfds)) {
+ uint64_t ev_cnt;
+ ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
+ if (ret < 0) {
+ perror("unable to read eventfd");
+ break;
+ }
+
+ struct io_event e[2];
+ /* we wait for one event */
+ ret = io_getevents(ctx, 1, 2, e, NULL);
+ /* if we got event */
+ for (i = 0; i < ret; ++i) {
+ if (e[i].obj->aio_fildes == ep[0]) {
+ printf("ev=in; ret=%lu\n", e[i].res);
+ req_in = 0;
+ } else if (e[i].obj->aio_fildes == ep[1]) {
+ printf("ev=out; ret=%lu\n", e[i].res);
+ req_out = 0;
+ }
+ }
+ }
+
+ if (!req_in) { /* if IN transfer not requested*/
+ /* prepare write request */
+ io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0);
+ /* enable eventfd notification */
+ iocb_in->u.c.flags |= IOCB_FLAG_RESFD;
+ iocb_in->u.c.resfd = evfd;
+ /* submit table of requests */
+ ret = io_submit(ctx, 1, &iocb_in);
+ if (ret >= 0) { /* if ret > 0 request is queued */
+ req_in = 1;
+ printf("submit: in\n");
+ } else
+ perror("unable to submit request");
+ }
+ if (!req_out) { /* if OUT transfer not requested */
+ /* prepare read request */
+ io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0);
+ /* enable eventfs notification */
+ iocb_out->u.c.flags |= IOCB_FLAG_RESFD;
+ iocb_out->u.c.resfd = evfd;
+ /* submit table of requests */
+ ret = io_submit(ctx, 1, &iocb_out);
+ if (ret >= 0) { /* if ret > 0 request is queued */
+ req_out = 1;
+ printf("submit: out\n");
+ } else
+ perror("unable to submit request");
+ }
+ }
+
+ /* free resources */
+
+ io_destroy(ctx);
+
+ free(buf_in);
+ free(buf_out);
+ free(iocb_in);
+ free(iocb_out);
+
+ for (i = 0; i < 2; ++i)
+ close(ep[i]);
+ close(ep0);
+
+ return 0;
+}
diff --git a/tools/usb/ffs-aio-example/simple/host_app/Makefile b/tools/usb/ffs-aio-example/simple/host_app/Makefile
new file mode 100644
index 00000000000..8c4a6f0aa82
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/host_app/Makefile
@@ -0,0 +1,13 @@
+CC = gcc
+LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0)
+LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0)
+WARNINGS = -Wall -Wextra
+CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS)
+LDFLAGS = $(LIBUSB_LIBS)
+
+all: test
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+clean:
+ $(RM) test
diff --git a/tools/usb/ffs-aio-example/simple/host_app/test.c b/tools/usb/ffs-aio-example/simple/host_app/test.c
new file mode 100644
index 00000000000..64b6a57d8ca
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/host_app/test.c
@@ -0,0 +1,148 @@
+#include <libusb.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define VENDOR 0x1d6b
+#define PRODUCT 0x0105
+
+/* endpoints indexes */
+
+#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN)
+#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT)
+
+#define BUF_LEN 8192
+
+/*
+ * struct test_state - describes test program state
+ * @list: list of devices returned by libusb_get_device_list function
+ * @found: pointer to struct describing tested device
+ * @ctx: context, set to NULL
+ * @handle: handle of tested device
+ * @attached: indicates that device was attached to kernel, and has to be
+ * reattached at the end of test program
+ */
+
+struct test_state {
+ libusb_device *found;
+ libusb_context *ctx;
+ libusb_device_handle *handle;
+ int attached;
+};
+
+/*
+ * test_init - initialize test program
+ */
+
+int test_init(struct test_state *state)
+{
+ int i, ret;
+ ssize_t cnt;
+ libusb_device **list;
+
+ state->found = NULL;
+ state->ctx = NULL;
+ state->handle = NULL;
+ state->attached = 0;
+
+ ret = libusb_init(&state->ctx);
+ if (ret) {
+ printf("cannot init libusb: %s\n", libusb_error_name(ret));
+ return 1;
+ }
+
+ cnt = libusb_get_device_list(state->ctx, &list);
+ if (cnt <= 0) {
+ printf("no devices found\n");
+ goto error1;
+ }
+
+ for (i = 0; i < cnt; ++i) {
+ libusb_device *dev = list[i];
+ struct libusb_device_descriptor desc;
+ ret = libusb_get_device_descriptor(dev, &desc);
+ if (ret) {
+ printf("unable to get device descriptor: %s\n",
+ libusb_error_name(ret));
+ goto error2;
+ }
+ if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
+ state->found = dev;
+ break;
+ }
+ }
+
+ if (!state->found) {
+ printf("no devices found\n");
+ goto error2;
+ }
+
+ ret = libusb_open(state->found, &state->handle);
+ if (ret) {
+ printf("cannot open device: %s\n", libusb_error_name(ret));
+ goto error2;
+ }
+
+ if (libusb_claim_interface(state->handle, 0)) {
+ ret = libusb_detach_kernel_driver(state->handle, 0);
+ if (ret) {
+ printf("unable to detach kernel driver: %s\n",
+ libusb_error_name(ret));
+ goto error3;
+ }
+ state->attached = 1;
+ ret = libusb_claim_interface(state->handle, 0);
+ if (ret) {
+ printf("cannot claim interface: %s\n",
+ libusb_error_name(ret));
+ goto error4;
+ }
+ }
+
+ return 0;
+
+error4:
+ if (state->attached == 1)
+ libusb_attach_kernel_driver(state->handle, 0);
+
+error3:
+ libusb_close(state->handle);
+
+error2:
+ libusb_free_device_list(list, 1);
+
+error1:
+ libusb_exit(state->ctx);
+ return 1;
+}
+
+/*
+ * test_exit - cleanup test program
+ */
+
+void test_exit(struct test_state *state)
+{
+ libusb_release_interface(state->handle, 0);
+ if (state->attached == 1)
+ libusb_attach_kernel_driver(state->handle, 0);
+ libusb_close(state->handle);
+ libusb_exit(state->ctx);
+}
+
+int main(void)
+{
+ struct test_state state;
+
+ if (test_init(&state))
+ return 1;
+
+ while (1) {
+ static unsigned char buffer[BUF_LEN];
+ int bytes;
+ libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
+ &bytes, 500);
+ libusb_bulk_transfer(state.handle, EP_BULK_OUT, buffer, BUF_LEN,
+ &bytes, 500);
+ }
+ test_exit(&state);
+}
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index bbe2e3a2ea6..a87e99f37c5 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -2,7 +2,7 @@
* ffs-test.c.c -- user mode filesystem api for usb composite function
*
* Copyright (C) 2010 Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,8 +36,9 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include <tools/le_byteshift.h>
-#include <linux/usb/functionfs.h>
+#include "../../include/uapi/linux/usb/functionfs.h"
/******************** Little Endian Handling ********************************/
@@ -47,34 +48,6 @@
#define le32_to_cpu(x) le32toh(x)
#define le16_to_cpu(x) le16toh(x)
-static inline __u16 get_unaligned_le16(const void *_ptr)
-{
- const __u8 *ptr = _ptr;
- return ptr[0] | (ptr[1] << 8);
-}
-
-static inline __u32 get_unaligned_le32(const void *_ptr)
-{
- const __u8 *ptr = _ptr;
- return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
-}
-
-static inline void put_unaligned_le16(__u16 val, void *_ptr)
-{
- __u8 *ptr = _ptr;
- *ptr++ = val;
- *ptr++ = val >> 8;
-}
-
-static inline void put_unaligned_le32(__u32 val, void *_ptr)
-{
- __u8 *ptr = _ptr;
- *ptr++ = val;
- *ptr++ = val >> 8;
- *ptr++ = val >> 16;
- *ptr++ = val >> 24;
-}
-
/******************** Messages and Errors ***********************************/
@@ -143,8 +116,8 @@ static const struct {
.header = {
.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
.length = cpu_to_le32(sizeof descriptors),
- .fs_count = 3,
- .hs_count = 3,
+ .fs_count = cpu_to_le32(3),
+ .hs_count = cpu_to_le32(3),
},
.fs_descs = {
.intf = {
@@ -324,7 +297,7 @@ static void *start_thread_helper(void *arg)
ret = t->in(t, t->buf, t->buf_size);
if (ret > 0) {
- ret = t->out(t, t->buf, t->buf_size);
+ ret = t->out(t, t->buf, ret);
name = out_name;
op = "write";
} else {
@@ -450,7 +423,7 @@ invalid:
len, expected, *p);
for (p = buf, len = 0; len < nbytes; ++p, ++len) {
if (0 == (len % 32))
- fprintf(stderr, "%4d:", len);
+ fprintf(stderr, "%4zd:", len);
fprintf(stderr, " %02x", *p);
if (31 == (len % 32))
fprintf(stderr, "\n");
diff --git a/tools/usb/hcd-tests.sh b/tools/usb/hcd-tests.sh
new file mode 100644
index 00000000000..b30b3dc4c78
--- /dev/null
+++ b/tools/usb/hcd-tests.sh
@@ -0,0 +1,275 @@
+#!/bin/sh
+#
+# test types can be passed on the command line:
+#
+# - control: any device can do this
+# - out, in: out needs 'bulk sink' firmware, in needs 'bulk src'
+# - iso-out, iso-in: out needs 'iso sink' firmware, in needs 'iso src'
+# - halt: needs bulk sink+src, tests halt set/clear from host
+# - unlink: needs bulk sink and/or src, test HCD unlink processing
+# - loop: needs firmware that will buffer N transfers
+#
+# run it for hours, days, weeks.
+#
+
+#
+# this default provides a steady test load for a bulk device
+#
+TYPES='control out in'
+#TYPES='control out in halt'
+
+#
+# to test HCD code
+#
+# - include unlink tests
+# - add some ${RANDOM}ness
+# - connect several devices concurrently (same HC)
+# - keep HC's IRQ lines busy with unrelated traffic (IDE, net, ...)
+# - add other concurrent system loads
+#
+
+declare -i COUNT BUFLEN
+
+COUNT=50000
+BUFLEN=2048
+
+# NOTE: the 'in' and 'out' cases are usually bulk, but can be
+# set up to use interrupt transfers by 'usbtest' module options
+
+
+if [ "$DEVICE" = "" ]; then
+ echo "testing ALL recognized usbtest devices"
+ echo ""
+ TEST_ARGS="-a"
+else
+ TEST_ARGS=""
+fi
+
+do_test ()
+{
+ if ! ./testusb $TEST_ARGS -s $BUFLEN -c $COUNT $* 2>/dev/null
+ then
+ echo "FAIL"
+ exit 1
+ fi
+}
+
+ARGS="$*"
+
+if [ "$ARGS" = "" ];
+then
+ ARGS="$TYPES"
+fi
+
+# FIXME use /sys/bus/usb/device/$THIS/bConfigurationValue to
+# check and change configs
+
+CONFIG=''
+
+check_config ()
+{
+ if [ "$CONFIG" = "" ]; then
+ CONFIG=$1
+ echo "assuming $CONFIG configuration"
+ return
+ fi
+ if [ "$CONFIG" = $1 ]; then
+ return
+ fi
+
+ echo "** device must be in $1 config, but it's $CONFIG instead"
+ exit 1
+}
+
+
+echo "TESTING: $ARGS"
+
+while : true
+do
+ echo $(date)
+
+ for TYPE in $ARGS
+ do
+ # restore defaults
+ COUNT=5000
+ BUFLEN=2048
+
+ # FIXME automatically multiply COUNT by 10 when
+ # /sys/bus/usb/device/$THIS/speed == "480"
+
+# COUNT=50000
+
+ case $TYPE in
+ control)
+ # any device, in any configuration, can use this.
+ echo '** Control test cases:'
+
+ echo "test 9: ch9 postconfig"
+ do_test -t 9 -c 5000
+ echo "test 10: control queueing"
+ do_test -t 10 -c 5000
+
+ # this relies on some vendor-specific commands
+ echo "test 14: control writes"
+ do_test -t 14 -c 15000 -s 256 -v 1
+
+ echo "test 21: control writes, unaligned"
+ do_test -t 21 -c 100 -s 256 -v 1
+
+ ;;
+
+ out)
+ check_config sink-src
+ echo '** Host Write (OUT) test cases:'
+
+ echo "test 1: $COUNT transfers, same size"
+ do_test -t 1
+ echo "test 3: $COUNT transfers, variable/short size"
+ do_test -t 3 -v 421
+
+ COUNT=100
+ echo "test 17: $COUNT transfers, unaligned DMA map by core"
+ do_test -t 17
+
+ echo "test 19: $COUNT transfers, unaligned DMA map by usb_alloc_coherent"
+ do_test -t 19
+
+ COUNT=2000
+ echo "test 5: $COUNT scatterlists, same size entries"
+ do_test -t 5
+
+ # try to trigger short OUT processing bugs
+ echo "test 7a: $COUNT scatterlists, variable size/short entries"
+ do_test -t 7 -v 579
+ BUFLEN=4096
+ echo "test 7b: $COUNT scatterlists, variable size/bigger entries"
+ do_test -t 7 -v 41
+ BUFLEN=64
+ echo "test 7c: $COUNT scatterlists, variable size/micro entries"
+ do_test -t 7 -v 63
+ ;;
+
+ iso-out)
+ check_config sink-src
+ echo '** Host ISOCHRONOUS Write (OUT) test cases:'
+
+ # at peak iso transfer rates:
+ # - usb 2.0 high bandwidth, this is one frame.
+ # - usb 1.1, it's twenty-four frames.
+ BUFLEN=24500
+
+ COUNT=1000
+
+# COUNT=10000
+
+ echo "test 15: $COUNT transfers, same size"
+ # do_test -t 15 -g 3 -v 0
+ BUFLEN=32768
+ do_test -t 15 -g 8 -v 0
+
+ # FIXME it'd make sense to have an iso OUT test issuing
+ # short writes on more packets than the last one
+
+ COUNT=100
+ echo "test 22: $COUNT transfers, non aligned"
+ do_test -t 22 -g 8 -v 0
+
+ ;;
+
+ in)
+ check_config sink-src
+ echo '** Host Read (IN) test cases:'
+
+ # NOTE: these "variable size" reads are just multiples
+ # of 512 bytes, no EOVERFLOW testing is done yet
+
+ echo "test 2: $COUNT transfers, same size"
+ do_test -t 2
+ echo "test 4: $COUNT transfers, variable size"
+ do_test -t 4
+
+ COUNT=100
+ echo "test 18: $COUNT transfers, unaligned DMA map by core"
+ do_test -t 18
+
+ echo "test 20: $COUNT transfers, unaligned DMA map by usb_alloc_coherent"
+ do_test -t 20
+
+ COUNT=2000
+ echo "test 6: $COUNT scatterlists, same size entries"
+ do_test -t 6
+ echo "test 8: $COUNT scatterlists, variable size entries"
+ do_test -t 8
+ ;;
+
+ iso-in)
+ check_config sink-src
+ echo '** Host ISOCHRONOUS Read (IN) test cases:'
+
+ # at peak iso transfer rates:
+ # - usb 2.0 high bandwidth, this is one frame.
+ # - usb 1.1, it's twenty-four frames.
+ BUFLEN=24500
+
+ COUNT=1000
+
+# COUNT=10000
+
+ echo "test 16: $COUNT transfers, same size"
+ # do_test -t 16 -g 3 -v 0
+ BUFLEN=32768
+ do_test -t 16 -g 8 -v 0
+
+ # FIXME since iso expects faults, it'd make sense
+ # to have an iso IN test issuing short reads ...
+
+ COUNT=100
+ echo "test 23: $COUNT transfers, unaligned"
+ do_test -t 23 -g 8 -v 0
+
+ ;;
+
+ halt)
+ # NOTE: sometimes hardware doesn't cooperate well with halting
+ # endpoints from the host side. so long as mass-storage class
+ # firmware can halt them from the device, don't worry much if
+ # you can't make this test work on your device.
+ COUNT=2000
+ echo "test 13: $COUNT halt set/clear"
+ do_test -t 13
+ ;;
+
+ unlink)
+ COUNT=2000
+ echo "test 11: $COUNT read unlinks"
+ do_test -t 11
+
+ echo "test 12: $COUNT write unlinks"
+ do_test -t 12
+ ;;
+
+ loop)
+ # defaults need too much buffering for ez-usb devices
+ BUFLEN=2048
+ COUNT=32
+
+ # modprobe g_zero qlen=$COUNT buflen=$BUFLEN loopdefault
+ check_config loopback
+
+ # FIXME someone needs to write and merge a version of this
+
+ echo "write $COUNT buffers of $BUFLEN bytes, read them back"
+
+ echo "write $COUNT variable size buffers, read them back"
+
+ ;;
+
+ *)
+ echo "Don't understand test type $TYPE"
+ exit 1;
+ esac
+ echo ''
+ done
+done
+
+# vim: sw=4
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index f08e8946384..879f9870a6b 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -3,7 +3,7 @@
/*
* Copyright (c) 2002 by David Brownell
* Copyright (c) 2010 by Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -253,9 +253,6 @@ static int find_testdev(const char *name, const struct stat *sb, int flag)
if (flag != FTW_F)
return 0;
- /* ignore /proc/bus/usb/{devices,drivers} */
- if (strrchr(name, '/')[1] == 'd')
- return 0;
fd = fopen(name, "rb");
if (!fd) {
@@ -282,8 +279,7 @@ nomem:
entry->ifnum = ifnum;
- /* FIXME ask usbfs what speed; update USBDEVFS_CONNECTINFO so
- * it tells about high speed etc */
+ /* FIXME update USBDEVFS_CONNECTINFO so it tells about high speed etc */
fprintf(stderr, "%s speed\t%s\t%u\n",
speed(entry->speed), entry->name, entry->ifnum);
@@ -354,27 +350,12 @@ restart:
return arg;
}
-static const char *usbfs_dir_find(void)
+static const char *usb_dir_find(void)
{
- static char usbfs_path_0[] = "/dev/usb/devices";
- static char usbfs_path_1[] = "/proc/bus/usb/devices";
-
- static char *const usbfs_paths[] = {
- usbfs_path_0, usbfs_path_1
- };
-
- static char *const *
- end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths;
-
- char *const *it = usbfs_paths;
- do {
- int fd = open(*it, O_RDONLY);
- close(fd);
- if (fd >= 0) {
- strrchr(*it, '/')[0] = '\0';
- return *it;
- }
- } while (++it != end);
+ static char udev_usb_path[] = "/dev/bus/usb";
+
+ if (access(udev_usb_path, F_OK) == 0)
+ return udev_usb_path;
return NULL;
}
@@ -398,7 +379,7 @@ int main (int argc, char **argv)
int c;
struct testdev *entry;
char *device;
- const char *usbfs_dir = NULL;
+ const char *usb_dir = NULL;
int all = 0, forever = 0, not = 0;
int test = -1 /* all */;
struct usbtest_param param;
@@ -420,13 +401,13 @@ int main (int argc, char **argv)
/* for easy use when hotplugging */
device = getenv ("DEVICE");
- while ((c = getopt (argc, argv, "D:aA:c:g:hns:t:v:")) != EOF)
+ while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF)
switch (c) {
case 'D': /* device, if only one */
device = optarg;
continue;
- case 'A': /* use all devices with specified usbfs dir */
- usbfs_dir = optarg;
+ case 'A': /* use all devices with specified USB dir */
+ usb_dir = optarg;
/* FALL THROUGH */
case 'a': /* use all devices */
device = NULL;
@@ -463,32 +444,43 @@ int main (int argc, char **argv)
case 'h':
default:
usage:
- fprintf (stderr, "usage: %s [-n] [-D dev | -a | -A usbfs-dir]\n"
- "\t[-c iterations] [-t testnum]\n"
- "\t[-s packetsize] [-g sglen] [-v vary]\n",
- argv [0]);
+ fprintf (stderr,
+ "usage: %s [options]\n"
+ "Options:\n"
+ "\t-D dev only test specific device\n"
+ "\t-A usb-dir\n"
+ "\t-a test all recognized devices\n"
+ "\t-l loop forever(for stress test)\n"
+ "\t-t testnum only run specified case\n"
+ "\t-n no test running, show devices to be tested\n"
+ "Case arguments:\n"
+ "\t-c iterations default 1000\n"
+ "\t-s packetsize default 512\n"
+ "\t-g sglen default 32\n"
+ "\t-v vary default 512\n",
+ argv[0]);
return 1;
}
if (optind != argc)
goto usage;
if (!all && !device) {
fprintf (stderr, "must specify '-a' or '-D dev', "
- "or DEVICE=/proc/bus/usb/BBB/DDD in env\n");
+ "or DEVICE=/dev/bus/usb/BBB/DDD in env\n");
goto usage;
}
- /* Find usbfs mount point */
- if (!usbfs_dir) {
- usbfs_dir = usbfs_dir_find();
- if (!usbfs_dir) {
- fputs ("usbfs files are missing\n", stderr);
+ /* Find usb device subdirectory */
+ if (!usb_dir) {
+ usb_dir = usb_dir_find();
+ if (!usb_dir) {
+ fputs ("USB device files are missing\n", stderr);
return -1;
}
}
/* collect and list the test devices */
- if (ftw (usbfs_dir, find_testdev, 3) != 0) {
- fputs ("ftw failed; is usbfs missing?\n", stderr);
+ if (ftw (usb_dir, find_testdev, 3) != 0) {
+ fputs ("ftw failed; are USB device files missing?\n", stderr);
return -1;
}
@@ -514,10 +506,8 @@ usage:
return handle_testdev (entry) != entry;
}
status = pthread_create (&entry->thread, 0, handle_testdev, entry);
- if (status) {
+ if (status)
perror ("pthread_create");
- continue;
- }
}
if (device) {
struct testdev dev;