diff options
Diffstat (limited to 'ANDROID_3.4.5/tools/usb')
-rw-r--r-- | ANDROID_3.4.5/tools/usb/Makefile | 13 | ||||
-rw-r--r-- | ANDROID_3.4.5/tools/usb/ffs-test.c | 527 | ||||
-rw-r--r-- | ANDROID_3.4.5/tools/usb/hcd-tests.sh | 275 | ||||
-rw-r--r-- | ANDROID_3.4.5/tools/usb/testusb.c | 547 |
4 files changed, 0 insertions, 1362 deletions
diff --git a/ANDROID_3.4.5/tools/usb/Makefile b/ANDROID_3.4.5/tools/usb/Makefile deleted file mode 100644 index 396d6c44..00000000 --- a/ANDROID_3.4.5/tools/usb/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Makefile for USB tools - -CC = $(CROSS_COMPILE)gcc -PTHREAD_LIBS = -lpthread -WARNINGS = -Wall -Wextra -CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) -I../include - -all: testusb ffs-test -%: %.c - $(CC) $(CFLAGS) -o $@ $^ - -clean: - $(RM) testusb ffs-test diff --git a/ANDROID_3.4.5/tools/usb/ffs-test.c b/ANDROID_3.4.5/tools/usb/ffs-test.c deleted file mode 100644 index 8674b9ec..00000000 --- a/ANDROID_3.4.5/tools/usb/ffs-test.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * ffs-test.c.c -- user mode filesystem api for usb composite function - * - * Copyright (C) 2010 Samsung Electronics - * 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 Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $(CROSS_COMPILE)cc -Wall -Wextra -g -o ffs-test ffs-test.c -lpthread */ - - -#define _BSD_SOURCE /* for endian.h */ - -#include <endian.h> -#include <errno.h> -#include <fcntl.h> -#include <pthread.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 <unistd.h> -#include <tools/le_byteshift.h> - -#include "../../include/linux/usb/functionfs.h" - - -/******************** Little Endian Handling ********************************/ - -#define cpu_to_le16(x) htole16(x) -#define cpu_to_le32(x) htole32(x) -#define le32_to_cpu(x) le32toh(x) -#define le16_to_cpu(x) le16toh(x) - - -/******************** Messages and Errors ***********************************/ - -static const char argv0[] = "ffs-test"; - -static unsigned verbosity = 7; - -static void _msg(unsigned level, const char *fmt, ...) -{ - if (level < 2) - level = 2; - else if (level > 7) - level = 7; - - if (level <= verbosity) { - static const char levels[8][6] = { - [2] = "crit:", - [3] = "err: ", - [4] = "warn:", - [5] = "note:", - [6] = "info:", - [7] = "dbg: " - }; - - int _errno = errno; - va_list ap; - - fprintf(stderr, "%s: %s ", argv0, levels[level]); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - - if (fmt[strlen(fmt) - 1] != '\n') { - char buffer[128]; - strerror_r(_errno, buffer, sizeof buffer); - fprintf(stderr, ": (-%d) %s\n", _errno, buffer); - } - - fflush(stderr); - } -} - -#define die(...) (_msg(2, __VA_ARGS__), exit(1)) -#define err(...) _msg(3, __VA_ARGS__) -#define warn(...) _msg(4, __VA_ARGS__) -#define note(...) _msg(5, __VA_ARGS__) -#define info(...) _msg(6, __VA_ARGS__) -#define debug(...) _msg(7, __VA_ARGS__) - -#define die_on(cond, ...) do { \ - if (cond) \ - die(__VA_ARGS__); \ - } while (0) - - -/******************** Descriptors and Strings *******************************/ - -static const struct { - struct usb_functionfs_descs_head header; - struct { - struct usb_interface_descriptor intf; - struct usb_endpoint_descriptor_no_audio sink; - struct usb_endpoint_descriptor_no_audio source; - } __attribute__((packed)) fs_descs, hs_descs; -} __attribute__((packed)) descriptors = { - .header = { - .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), - .length = cpu_to_le32(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, - }, - .sink = { - .bLength = sizeof descriptors.fs_descs.sink, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - /* .wMaxPacketSize = autoconfiguration (kernel) */ - }, - .source = { - .bLength = sizeof descriptors.fs_descs.source, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - /* .wMaxPacketSize = autoconfiguration (kernel) */ - }, - }, - .hs_descs = { - .intf = { - .bLength = sizeof descriptors.fs_descs.intf, - .bDescriptorType = USB_DT_INTERFACE, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .iInterface = 1, - }, - .sink = { - .bLength = sizeof descriptors.hs_descs.sink, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 1 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), - }, - .source = { - .bLength = sizeof descriptors.hs_descs.source, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 2 | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), - .bInterval = 1, /* NAK every 1 uframe */ - }, - }, -}; - - -#define STR_INTERFACE_ "Source/Sink" - -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 = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC), - .length = cpu_to_le32(sizeof strings), - .str_count = cpu_to_le32(1), - .lang_count = cpu_to_le32(1), - }, - .lang0 = { - cpu_to_le16(0x0409), /* en-us */ - STR_INTERFACE_, - }, -}; - -#define STR_INTERFACE strings.lang0.str1 - - -/******************** Files and Threads Handling ****************************/ - -struct thread; - -static ssize_t read_wrap(struct thread *t, void *buf, size_t nbytes); -static ssize_t write_wrap(struct thread *t, const void *buf, size_t nbytes); -static ssize_t ep0_consume(struct thread *t, const void *buf, size_t nbytes); -static ssize_t fill_in_buf(struct thread *t, void *buf, size_t nbytes); -static ssize_t empty_out_buf(struct thread *t, const void *buf, size_t nbytes); - - -static struct thread { - const char *const filename; - size_t buf_size; - - ssize_t (*in)(struct thread *, void *, size_t); - const char *const in_name; - - ssize_t (*out)(struct thread *, const void *, size_t); - const char *const out_name; - - int fd; - pthread_t id; - void *buf; - ssize_t status; -} threads[] = { - { - "ep0", 4 * sizeof(struct usb_functionfs_event), - read_wrap, NULL, - ep0_consume, "<consume>", - 0, 0, NULL, 0 - }, - { - "ep1", 8 * 1024, - fill_in_buf, "<in>", - write_wrap, NULL, - 0, 0, NULL, 0 - }, - { - "ep2", 8 * 1024, - read_wrap, NULL, - empty_out_buf, "<out>", - 0, 0, NULL, 0 - }, -}; - - -static void init_thread(struct thread *t) -{ - t->buf = malloc(t->buf_size); - die_on(!t->buf, "malloc"); - - t->fd = open(t->filename, O_RDWR); - die_on(t->fd < 0, "%s", t->filename); -} - -static void cleanup_thread(void *arg) -{ - struct thread *t = arg; - int ret, fd; - - fd = t->fd; - if (t->fd < 0) - return; - t->fd = -1; - - /* test the FIFO ioctls (non-ep0 code paths) */ - if (t != threads) { - ret = ioctl(fd, FUNCTIONFS_FIFO_STATUS); - if (ret < 0) { - /* ENODEV reported after disconnect */ - if (errno != ENODEV) - err("%s: get fifo status", t->filename); - } else if (ret) { - warn("%s: unclaimed = %d\n", t->filename, ret); - if (ioctl(fd, FUNCTIONFS_FIFO_FLUSH) < 0) - err("%s: fifo flush", t->filename); - } - } - - if (close(fd) < 0) - err("%s: close", t->filename); - - free(t->buf); - t->buf = NULL; -} - -static void *start_thread_helper(void *arg) -{ - const char *name, *op, *in_name, *out_name; - struct thread *t = arg; - ssize_t ret; - - info("%s: starts\n", t->filename); - in_name = t->in_name ? t->in_name : t->filename; - out_name = t->out_name ? t->out_name : t->filename; - - pthread_cleanup_push(cleanup_thread, arg); - - for (;;) { - pthread_testcancel(); - - ret = t->in(t, t->buf, t->buf_size); - if (ret > 0) { - ret = t->out(t, t->buf, ret); - name = out_name; - op = "write"; - } else { - name = in_name; - op = "read"; - } - - if (ret > 0) { - /* nop */ - } else if (!ret) { - debug("%s: %s: EOF", name, op); - break; - } else if (errno == EINTR || errno == EAGAIN) { - debug("%s: %s", name, op); - } else { - warn("%s: %s", name, op); - break; - } - } - - pthread_cleanup_pop(1); - - t->status = ret; - info("%s: ends\n", t->filename); - return NULL; -} - -static void start_thread(struct thread *t) -{ - debug("%s: starting\n", t->filename); - - die_on(pthread_create(&t->id, NULL, start_thread_helper, t) < 0, - "pthread_create(%s)", t->filename); -} - -static void join_thread(struct thread *t) -{ - int ret = pthread_join(t->id, NULL); - - if (ret < 0) - err("%s: joining thread", t->filename); - else - debug("%s: joined\n", t->filename); -} - - -static ssize_t read_wrap(struct thread *t, void *buf, size_t nbytes) -{ - return read(t->fd, buf, nbytes); -} - -static ssize_t write_wrap(struct thread *t, const void *buf, size_t nbytes) -{ - return write(t->fd, buf, nbytes); -} - - -/******************** Empty/Fill buffer routines ****************************/ - -/* 0 -- stream of zeros, 1 -- i % 63, 2 -- pipe */ -enum pattern { PAT_ZERO, PAT_SEQ, PAT_PIPE }; -static enum pattern pattern; - -static ssize_t -fill_in_buf(struct thread *ignore, void *buf, size_t nbytes) -{ - size_t i; - __u8 *p; - - (void)ignore; - - switch (pattern) { - case PAT_ZERO: - memset(buf, 0, nbytes); - break; - - case PAT_SEQ: - for (p = buf, i = 0; i < nbytes; ++i, ++p) - *p = i % 63; - break; - - case PAT_PIPE: - return fread(buf, 1, nbytes, stdin); - } - - return nbytes; -} - -static ssize_t -empty_out_buf(struct thread *ignore, const void *buf, size_t nbytes) -{ - const __u8 *p; - __u8 expected; - ssize_t ret; - size_t len; - - (void)ignore; - - switch (pattern) { - case PAT_ZERO: - expected = 0; - for (p = buf, len = 0; len < nbytes; ++p, ++len) - if (*p) - goto invalid; - break; - - case PAT_SEQ: - for (p = buf, len = 0; len < nbytes; ++p, ++len) - if (*p != len % 63) { - expected = len % 63; - goto invalid; - } - break; - - case PAT_PIPE: - ret = fwrite(buf, nbytes, 1, stdout); - if (ret > 0) - fflush(stdout); - break; - -invalid: - err("bad OUT byte %zd, expected %02x got %02x\n", - len, expected, *p); - for (p = buf, len = 0; len < nbytes; ++p, ++len) { - if (0 == (len % 32)) - fprintf(stderr, "%4zd:", len); - fprintf(stderr, " %02x", *p); - if (31 == (len % 32)) - fprintf(stderr, "\n"); - } - fflush(stderr); - errno = EILSEQ; - return -1; - } - - return len; -} - - -/******************** Endpoints routines ************************************/ - -static void handle_setup(const struct usb_ctrlrequest *setup) -{ - printf("bRequestType = %d\n", setup->bRequestType); - printf("bRequest = %d\n", setup->bRequest); - printf("wValue = %d\n", le16_to_cpu(setup->wValue)); - printf("wIndex = %d\n", le16_to_cpu(setup->wIndex)); - printf("wLength = %d\n", le16_to_cpu(setup->wLength)); -} - -static ssize_t -ep0_consume(struct thread *ignore, const void *buf, size_t nbytes) -{ - 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", - }; - - const struct usb_functionfs_event *event = buf; - size_t n; - - (void)ignore; - - for (n = nbytes / sizeof *event; n; --n, ++event) - 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]); - if (event->type == FUNCTIONFS_SETUP) - handle_setup(&event->u.setup); - break; - - default: - printf("Event %03u (unknown)\n", event->type); - } - - return nbytes; -} - -static void ep0_init(struct thread *t) -{ - ssize_t ret; - - info("%s: writing descriptors\n", t->filename); - ret = write(t->fd, &descriptors, sizeof descriptors); - die_on(ret < 0, "%s: write: descriptors", t->filename); - - info("%s: writing strings\n", t->filename); - ret = write(t->fd, &strings, sizeof strings); - die_on(ret < 0, "%s: write: strings", t->filename); -} - - -/******************** Main **************************************************/ - -int main(void) -{ - unsigned i; - - /* XXX TODO: Argument parsing missing */ - - init_thread(threads); - ep0_init(threads); - - for (i = 1; i < sizeof threads / sizeof *threads; ++i) - init_thread(threads + i); - - for (i = 1; i < sizeof threads / sizeof *threads; ++i) - start_thread(threads + i); - - start_thread_helper(threads); - - for (i = 1; i < sizeof threads / sizeof *threads; ++i) - join_thread(threads + i); - - return 0; -} diff --git a/ANDROID_3.4.5/tools/usb/hcd-tests.sh b/ANDROID_3.4.5/tools/usb/hcd-tests.sh deleted file mode 100644 index b30b3dc4..00000000 --- a/ANDROID_3.4.5/tools/usb/hcd-tests.sh +++ /dev/null @@ -1,275 +0,0 @@ -#!/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/ANDROID_3.4.5/tools/usb/testusb.c b/ANDROID_3.4.5/tools/usb/testusb.c deleted file mode 100644 index 6e0f5670..00000000 --- a/ANDROID_3.4.5/tools/usb/testusb.c +++ /dev/null @@ -1,547 +0,0 @@ -/* $(CROSS_COMPILE)cc -Wall -Wextra -g -lpthread -o testusb testusb.c */ - -/* - * Copyright (c) 2002 by David Brownell - * Copyright (c) 2010 by Samsung Electronics - * 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 - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * This program issues ioctls to perform the tests implemented by the - * kernel driver. It can generate a variety of transfer patterns; you - * should make sure to test both regular streaming and mixes of - * transfer sizes (including short transfers). - * - * For more information on how this can be used and on USB testing - * refer to <URL:http://www.linux-usb.org/usbtest/>. - */ - -#include <stdio.h> -#include <string.h> -#include <ftw.h> -#include <stdlib.h> -#include <pthread.h> -#include <unistd.h> -#include <errno.h> -#include <limits.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include <sys/ioctl.h> -#include <linux/usbdevice_fs.h> - -/*-------------------------------------------------------------------------*/ - -#define TEST_CASES 30 - -// FIXME make these public somewhere; usbdevfs.h? - -struct usbtest_param { - // inputs - unsigned test_num; /* 0..(TEST_CASES-1) */ - unsigned iterations; - unsigned length; - unsigned vary; - unsigned sglen; - - // outputs - struct timeval duration; -}; -#define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param) - -/*-------------------------------------------------------------------------*/ - -/* #include <linux/usb_ch9.h> */ - -#define USB_DT_DEVICE 0x01 -#define USB_DT_INTERFACE 0x04 - -#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ -#define USB_CLASS_VENDOR_SPEC 0xff - - -struct usb_device_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice; - __u8 iManufacturer; - __u8 iProduct; - __u8 iSerialNumber; - __u8 bNumConfigurations; -} __attribute__ ((packed)); - -struct usb_interface_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - __u8 bNumEndpoints; - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - __u8 iInterface; -} __attribute__ ((packed)); - -enum usb_device_speed { - USB_SPEED_UNKNOWN = 0, /* enumerating */ - USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ - USB_SPEED_HIGH /* usb 2.0 */ -}; - -/*-------------------------------------------------------------------------*/ - -static char *speed (enum usb_device_speed s) -{ - switch (s) { - case USB_SPEED_UNKNOWN: return "unknown"; - case USB_SPEED_LOW: return "low"; - case USB_SPEED_FULL: return "full"; - case USB_SPEED_HIGH: return "high"; - default: return "??"; - } -} - -struct testdev { - struct testdev *next; - char *name; - pthread_t thread; - enum usb_device_speed speed; - unsigned ifnum : 8; - unsigned forever : 1; - int test; - - struct usbtest_param param; -}; -static struct testdev *testdevs; - -static int testdev_ffs_ifnum(FILE *fd) -{ - union { - char buf[255]; - struct usb_interface_descriptor intf; - } u; - - for (;;) { - if (fread(u.buf, 1, 1, fd) != 1) - return -1; - if (fread(u.buf + 1, (unsigned char)u.buf[0] - 1, 1, fd) != 1) - return -1; - - if (u.intf.bLength == sizeof u.intf - && u.intf.bDescriptorType == USB_DT_INTERFACE - && u.intf.bNumEndpoints == 2 - && u.intf.bInterfaceClass == USB_CLASS_VENDOR_SPEC - && u.intf.bInterfaceSubClass == 0 - && u.intf.bInterfaceProtocol == 0) - return (unsigned char)u.intf.bInterfaceNumber; - } -} - -static int testdev_ifnum(FILE *fd) -{ - struct usb_device_descriptor dev; - - if (fread(&dev, sizeof dev, 1, fd) != 1) - return -1; - - if (dev.bLength != sizeof dev || dev.bDescriptorType != USB_DT_DEVICE) - return -1; - - /* FX2 with (tweaked) bulksrc firmware */ - if (dev.idVendor == 0x0547 && dev.idProduct == 0x1002) - return 0; - - /*----------------------------------------------------*/ - - /* devices that start up using the EZ-USB default device and - * which we can use after loading simple firmware. hotplug - * can fxload it, and then run this test driver. - * - * we return false positives in two cases: - * - the device has a "real" driver (maybe usb-serial) that - * renumerates. the device should vanish quickly. - * - the device doesn't have the test firmware installed. - */ - - /* generic EZ-USB FX controller */ - if (dev.idVendor == 0x0547 && dev.idProduct == 0x2235) - return 0; - - /* generic EZ-USB FX2 controller */ - if (dev.idVendor == 0x04b4 && dev.idProduct == 0x8613) - return 0; - - /* CY3671 development board with EZ-USB FX */ - if (dev.idVendor == 0x0547 && dev.idProduct == 0x0080) - return 0; - - /* Keyspan 19Qi uses an21xx (original EZ-USB) */ - if (dev.idVendor == 0x06cd && dev.idProduct == 0x010b) - return 0; - - /*----------------------------------------------------*/ - - /* "gadget zero", Linux-USB test software */ - if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a0) - return 0; - - /* user mode subset of that */ - if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a4) - return testdev_ffs_ifnum(fd); - /* return 0; */ - - /* iso version of usermode code */ - if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a3) - return 0; - - /* some GPL'd test firmware uses these IDs */ - - if (dev.idVendor == 0xfff0 && dev.idProduct == 0xfff0) - return 0; - - /*----------------------------------------------------*/ - - /* iBOT2 high speed webcam */ - if (dev.idVendor == 0x0b62 && dev.idProduct == 0x0059) - return 0; - - /*----------------------------------------------------*/ - - /* the FunctionFS gadget can have the source/sink interface - * anywhere. We look for an interface descriptor that match - * what we expect. We ignore configuratiens thou. */ - - if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4ac - && (dev.bDeviceClass == USB_CLASS_PER_INTERFACE - || dev.bDeviceClass == USB_CLASS_VENDOR_SPEC)) - return testdev_ffs_ifnum(fd); - - return -1; -} - -static int find_testdev(const char *name, const struct stat *sb, int flag) -{ - FILE *fd; - int ifnum; - struct testdev *entry; - - (void)sb; /* unused */ - - 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) { - perror(name); - return 0; - } - - ifnum = testdev_ifnum(fd); - fclose(fd); - if (ifnum < 0) - return 0; - - entry = calloc(1, sizeof *entry); - if (!entry) - goto nomem; - - entry->name = strdup(name); - if (!entry->name) { - free(entry); -nomem: - perror("malloc"); - return 0; - } - - entry->ifnum = ifnum; - - /* FIXME ask usbfs what speed; 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); - - entry->next = testdevs; - testdevs = entry; - return 0; -} - -static int -usbdev_ioctl (int fd, int ifno, unsigned request, void *param) -{ - struct usbdevfs_ioctl wrapper; - - wrapper.ifno = ifno; - wrapper.ioctl_code = request; - wrapper.data = param; - - return ioctl (fd, USBDEVFS_IOCTL, &wrapper); -} - -static void *handle_testdev (void *arg) -{ - struct testdev *dev = arg; - int fd, i; - int status; - - if ((fd = open (dev->name, O_RDWR)) < 0) { - perror ("can't open dev file r/w"); - return 0; - } - -restart: - for (i = 0; i < TEST_CASES; i++) { - if (dev->test != -1 && dev->test != i) - continue; - dev->param.test_num = i; - - status = usbdev_ioctl (fd, dev->ifnum, - USBTEST_REQUEST, &dev->param); - if (status < 0 && errno == EOPNOTSUPP) - continue; - - /* FIXME need a "syslog it" option for background testing */ - - /* NOTE: each thread emits complete lines; no fragments! */ - if (status < 0) { - char buf [80]; - int err = errno; - - if (strerror_r (errno, buf, sizeof buf)) { - snprintf (buf, sizeof buf, "error %d", err); - errno = err; - } - printf ("%s test %d --> %d (%s)\n", - dev->name, i, errno, buf); - } else - printf ("%s test %d, %4d.%.06d secs\n", dev->name, i, - (int) dev->param.duration.tv_sec, - (int) dev->param.duration.tv_usec); - - fflush (stdout); - } - if (dev->forever) - goto restart; - - close (fd); - return arg; -} - -static const char *usbfs_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); - - return NULL; -} - -static int parse_num(unsigned *num, const char *str) -{ - unsigned long val; - char *end; - - errno = 0; - val = strtoul(str, &end, 0); - if (errno || *end || val > UINT_MAX) - return -1; - *num = val; - return 0; -} - -int main (int argc, char **argv) -{ - - int c; - struct testdev *entry; - char *device; - const char *usbfs_dir = NULL; - int all = 0, forever = 0, not = 0; - int test = -1 /* all */; - struct usbtest_param param; - - /* pick defaults that works with all speeds, without short packets. - * - * Best per-frame data rates: - * high speed, bulk 512 * 13 * 8 = 53248 - * interrupt 1024 * 3 * 8 = 24576 - * full speed, bulk/intr 64 * 19 = 1216 - * interrupt 64 * 1 = 64 - * low speed, interrupt 8 * 1 = 8 - */ - param.iterations = 1000; - param.length = 512; - param.vary = 512; - param.sglen = 32; - - /* for easy use when hotplugging */ - device = getenv ("DEVICE"); - - while ((c = getopt (argc, argv, "D:aA:c:g:hns: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; - /* FALL THROUGH */ - case 'a': /* use all devices */ - device = NULL; - all = 1; - continue; - case 'c': /* count iterations */ - if (parse_num(¶m.iterations, optarg)) - goto usage; - continue; - case 'g': /* scatter/gather entries */ - if (parse_num(¶m.sglen, optarg)) - goto usage; - continue; - case 'l': /* loop forever */ - forever = 1; - continue; - case 'n': /* no test running! */ - not = 1; - continue; - case 's': /* size of packet */ - if (parse_num(¶m.length, optarg)) - goto usage; - continue; - case 't': /* run just one test */ - test = atoi (optarg); - if (test < 0) - goto usage; - continue; - case 'v': /* vary packet size by ... */ - if (parse_num(¶m.vary, optarg)) - goto usage; - continue; - case '?': - 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]); - 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"); - goto usage; - } - - /* Find usbfs mount point */ - if (!usbfs_dir) { - usbfs_dir = usbfs_dir_find(); - if (!usbfs_dir) { - fputs ("usbfs 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); - return -1; - } - - /* quit, run single test, or create test threads */ - if (!testdevs && !device) { - fputs ("no test devices recognized\n", stderr); - return -1; - } - if (not) - return 0; - if (testdevs && testdevs->next == 0 && !device) - device = testdevs->name; - for (entry = testdevs; entry; entry = entry->next) { - int status; - - entry->param = param; - entry->forever = forever; - entry->test = test; - - if (device) { - if (strcmp (entry->name, device)) - continue; - return handle_testdev (entry) != entry; - } - status = pthread_create (&entry->thread, 0, handle_testdev, entry); - if (status) { - perror ("pthread_create"); - continue; - } - } - if (device) { - struct testdev dev; - - /* kernel can recognize test devices we don't */ - fprintf (stderr, "%s: %s may see only control tests\n", - argv [0], device); - - memset (&dev, 0, sizeof dev); - dev.name = device; - dev.param = param; - dev.forever = forever; - dev.test = test; - return handle_testdev (&dev) != &dev; - } - - /* wait for tests to complete */ - for (entry = testdevs; entry; entry = entry->next) { - void *retval; - - if (pthread_join (entry->thread, &retval)) - perror ("pthread_join"); - /* testing errors discarded! */ - } - - return 0; -} |