[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/os/linux/linux-3.4.x/tools/usb/Makefile b/ap/os/linux/linux-3.4.x/tools/usb/Makefile
new file mode 100644
index 0000000..396d6c4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/tools/usb/Makefile
@@ -0,0 +1,13 @@
+# 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/ap/os/linux/linux-3.4.x/tools/usb/ffs-test.c b/ap/os/linux/linux-3.4.x/tools/usb/ffs-test.c
new file mode 100644
index 0000000..b3dbf8e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/tools/usb/ffs-test.c
@@ -0,0 +1,527 @@
+/*
+ * 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 = cpu_to_le32(3),
+		.hs_count = cpu_to_le32(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/ap/os/linux/linux-3.4.x/tools/usb/hcd-tests.sh b/ap/os/linux/linux-3.4.x/tools/usb/hcd-tests.sh
new file mode 100644
index 0000000..b30b3dc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/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/ap/os/linux/linux-3.4.x/tools/usb/testusb.c b/ap/os/linux/linux-3.4.x/tools/usb/testusb.c
new file mode 100644
index 0000000..6e0f567
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/tools/usb/testusb.c
@@ -0,0 +1,547 @@
+/* $(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(&param.iterations, optarg))
+			goto usage;
+		continue;
+	case 'g':	/* scatter/gather entries */
+		if (parse_num(&param.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(&param.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(&param.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;
+}