diff options
Diffstat (limited to 'tools/usb')
| -rw-r--r-- | tools/usb/Makefile | 5 | ||||
| -rw-r--r-- | tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c | 349 | ||||
| -rw-r--r-- | tools/usb/ffs-aio-example/multibuff/host_app/Makefile | 13 | ||||
| -rw-r--r-- | tools/usb/ffs-aio-example/multibuff/host_app/test.c | 146 | ||||
| -rw-r--r-- | tools/usb/ffs-aio-example/simple/device_app/aio_simple.c | 335 | ||||
| -rw-r--r-- | tools/usb/ffs-aio-example/simple/host_app/Makefile | 13 | ||||
| -rw-r--r-- | tools/usb/ffs-aio-example/simple/host_app/test.c | 148 | ||||
| -rw-r--r-- | tools/usb/ffs-test.c | 4 | 
8 files changed, 1009 insertions, 4 deletions
diff --git a/tools/usb/Makefile b/tools/usb/Makefile index 396d6c44e9d..acf2165c04e 100644 --- a/tools/usb/Makefile +++ b/tools/usb/Makefile @@ -3,11 +3,12 @@  CC = $(CROSS_COMPILE)gcc  PTHREAD_LIBS = -lpthread  WARNINGS = -Wall -Wextra -CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) -I../include +CFLAGS = $(WARNINGS) -g -I../include +LDFLAGS = $(PTHREAD_LIBS)  all: testusb ffs-test  %: %.c -	$(CC) $(CFLAGS) -o $@ $^ +	$(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 fe1e66b6ef4..a87e99f37c5 100644 --- a/tools/usb/ffs-test.c +++ b/tools/usb/ffs-test.c @@ -116,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 = {  | 
