1/*
2 * This is free and unencumbered software released into the public domain.
3 *
4 * Anyone is free to copy, modify, publish, use, compile, sell, or
5 * distribute this software, either in source code form or as a compiled
6 * binary, for any purpose, commercial or non-commercial, and by any
7 * means.
8 *
9 * In jurisdictions that recognize copyright laws, the author or authors
10 * of this software dedicate any and all copyright interest in the
11 * software to the public domain. We make this dedication for the benefit
12 * of the public at large and to the detriment of our heirs and
13 * successors. We intend this dedication to be an overt act of
14 * relinquishment in perpetuity of all present and future rights to this
15 * software under copyright law.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * For more information, please refer to <http://unlicense.org/>
26 */
27
28#define _BSD_SOURCE /* for endian.h */
29
30#include <endian.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <stdarg.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/ioctl.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <sys/poll.h>
41#include <unistd.h>
42#include <stdbool.h>
43#include <sys/eventfd.h>
44
45#include "libaio.h"
46#define IOCB_FLAG_RESFD         (1 << 0)
47
48#include <linux/usb/functionfs.h>
49
50#define BUF_LEN		8192
51#define BUFS_MAX	128
52#define AIO_MAX		(BUFS_MAX*2)
53
54/******************** Descriptors and Strings *******************************/
55
56static const struct {
57	struct usb_functionfs_descs_head_v2 header;
58	__le32 fs_count;
59	__le32 hs_count;
60	struct {
61		struct usb_interface_descriptor intf;
62		struct usb_endpoint_descriptor_no_audio bulk_sink;
63		struct usb_endpoint_descriptor_no_audio bulk_source;
64	} __attribute__ ((__packed__)) fs_descs, hs_descs;
65} __attribute__ ((__packed__)) descriptors = {
66	.header = {
67		.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
68		.flags = htole32(FUNCTIONFS_HAS_FS_DESC |
69				     FUNCTIONFS_HAS_HS_DESC),
70		.length = htole32(sizeof(descriptors)),
71	},
72	.fs_count = htole32(3),
73	.fs_descs = {
74		.intf = {
75			.bLength = sizeof(descriptors.fs_descs.intf),
76			.bDescriptorType = USB_DT_INTERFACE,
77			.bNumEndpoints = 2,
78			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
79			.iInterface = 1,
80		},
81		.bulk_sink = {
82			.bLength = sizeof(descriptors.fs_descs.bulk_sink),
83			.bDescriptorType = USB_DT_ENDPOINT,
84			.bEndpointAddress = 1 | USB_DIR_IN,
85			.bmAttributes = USB_ENDPOINT_XFER_BULK,
86		},
87		.bulk_source = {
88			.bLength = sizeof(descriptors.fs_descs.bulk_source),
89			.bDescriptorType = USB_DT_ENDPOINT,
90			.bEndpointAddress = 2 | USB_DIR_OUT,
91			.bmAttributes = USB_ENDPOINT_XFER_BULK,
92		},
93	},
94	.hs_count = htole32(3),
95	.hs_descs = {
96		.intf = {
97			.bLength = sizeof(descriptors.hs_descs.intf),
98			.bDescriptorType = USB_DT_INTERFACE,
99			.bNumEndpoints = 2,
100			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
101			.iInterface = 1,
102		},
103		.bulk_sink = {
104			.bLength = sizeof(descriptors.hs_descs.bulk_sink),
105			.bDescriptorType = USB_DT_ENDPOINT,
106			.bEndpointAddress = 1 | USB_DIR_IN,
107			.bmAttributes = USB_ENDPOINT_XFER_BULK,
108			.wMaxPacketSize = htole16(512),
109		},
110		.bulk_source = {
111			.bLength = sizeof(descriptors.hs_descs.bulk_source),
112			.bDescriptorType = USB_DT_ENDPOINT,
113			.bEndpointAddress = 2 | USB_DIR_OUT,
114			.bmAttributes = USB_ENDPOINT_XFER_BULK,
115			.wMaxPacketSize = htole16(512),
116		},
117	},
118};
119
120#define STR_INTERFACE "AIO Test"
121
122static const struct {
123	struct usb_functionfs_strings_head header;
124	struct {
125		__le16 code;
126		const char str1[sizeof(STR_INTERFACE)];
127	} __attribute__ ((__packed__)) lang0;
128} __attribute__ ((__packed__)) strings = {
129	.header = {
130		.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
131		.length = htole32(sizeof(strings)),
132		.str_count = htole32(1),
133		.lang_count = htole32(1),
134	},
135	.lang0 = {
136		htole16(0x0409), /* en-us */
137		STR_INTERFACE,
138	},
139};
140
141/********************** Buffer structure *******************************/
142
143struct io_buffer {
144	struct iocb **iocb;
145	unsigned char **buf;
146	unsigned cnt;
147	unsigned len;
148	unsigned requested;
149};
150
151/******************** Endpoints handling *******************************/
152
153static void display_event(struct usb_functionfs_event *event)
154{
155	static const char *const names[] = {
156		[FUNCTIONFS_BIND] = "BIND",
157		[FUNCTIONFS_UNBIND] = "UNBIND",
158		[FUNCTIONFS_ENABLE] = "ENABLE",
159		[FUNCTIONFS_DISABLE] = "DISABLE",
160		[FUNCTIONFS_SETUP] = "SETUP",
161		[FUNCTIONFS_SUSPEND] = "SUSPEND",
162		[FUNCTIONFS_RESUME] = "RESUME",
163	};
164	switch (event->type) {
165	case FUNCTIONFS_BIND:
166	case FUNCTIONFS_UNBIND:
167	case FUNCTIONFS_ENABLE:
168	case FUNCTIONFS_DISABLE:
169	case FUNCTIONFS_SETUP:
170	case FUNCTIONFS_SUSPEND:
171	case FUNCTIONFS_RESUME:
172		printf("Event %s\n", names[event->type]);
173	}
174}
175
176static void handle_ep0(int ep0, bool *ready)
177{
178	int ret;
179	struct usb_functionfs_event event;
180
181	ret = read(ep0, &event, sizeof(event));
182	if (!ret) {
183		perror("unable to read event from ep0");
184		return;
185	}
186	display_event(&event);
187	switch (event.type) {
188	case FUNCTIONFS_SETUP:
189		if (event.u.setup.bRequestType & USB_DIR_IN)
190			write(ep0, NULL, 0);
191		else
192			read(ep0, NULL, 0);
193		break;
194
195	case FUNCTIONFS_ENABLE:
196		*ready = true;
197		break;
198
199	case FUNCTIONFS_DISABLE:
200		*ready = false;
201		break;
202
203	default:
204		break;
205	}
206}
207
208void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
209{
210	unsigned i;
211	iobuf->buf = malloc(n*sizeof(*iobuf->buf));
212	iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
213	iobuf->cnt = n;
214	iobuf->len = len;
215	iobuf->requested = 0;
216	for (i = 0; i < n; ++i) {
217		iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
218		iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
219	}
220	iobuf->cnt = n;
221}
222
223void delete_bufs(struct io_buffer *iobuf)
224{
225	unsigned i;
226	for (i = 0; i < iobuf->cnt; ++i) {
227		free(iobuf->buf[i]);
228		free(iobuf->iocb[i]);
229	}
230	free(iobuf->buf);
231	free(iobuf->iocb);
232}
233
234int main(int argc, char *argv[])
235{
236	int ret;
237	unsigned i, j;
238	char *ep_path;
239
240	int ep0, ep1;
241
242	io_context_t ctx;
243
244	int evfd;
245	fd_set rfds;
246
247	struct io_buffer iobuf[2];
248	int actual = 0;
249	bool ready;
250
251	if (argc != 2) {
252		printf("ffs directory not specified!\n");
253		return 1;
254	}
255
256	ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
257	if (!ep_path) {
258		perror("malloc");
259		return 1;
260	}
261
262	/* open endpoint files */
263	sprintf(ep_path, "%s/ep0", argv[1]);
264	ep0 = open(ep_path, O_RDWR);
265	if (ep0 < 0) {
266		perror("unable to open ep0");
267		return 1;
268	}
269	if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
270		perror("unable do write descriptors");
271		return 1;
272	}
273	if (write(ep0, &strings, sizeof(strings)) < 0) {
274		perror("unable to write strings");
275		return 1;
276	}
277	sprintf(ep_path, "%s/ep1", argv[1]);
278	ep1 = open(ep_path, O_RDWR);
279	if (ep1 < 0) {
280		perror("unable to open ep1");
281		return 1;
282	}
283
284	free(ep_path);
285
286	memset(&ctx, 0, sizeof(ctx));
287	/* setup aio context to handle up to AIO_MAX requests */
288	if (io_setup(AIO_MAX, &ctx) < 0) {
289		perror("unable to setup aio");
290		return 1;
291	}
292
293	evfd = eventfd(0, 0);
294	if (evfd < 0) {
295		perror("unable to open eventfd");
296		return 1;
297	}
298
299	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
300		init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
301
302	while (1) {
303		FD_ZERO(&rfds);
304		FD_SET(ep0, &rfds);
305		FD_SET(evfd, &rfds);
306
307		ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
308			     &rfds, NULL, NULL, NULL);
309		if (ret < 0) {
310			if (errno == EINTR)
311				continue;
312			perror("select");
313			break;
314		}
315
316		if (FD_ISSET(ep0, &rfds))
317			handle_ep0(ep0, &ready);
318
319		/* we are waiting for function ENABLE */
320		if (!ready)
321			continue;
322
323		/*
324		 * when we're preparing new data to submit,
325		 * second buffer being transmitted
326		 */
327		for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
328			if (iobuf[i].requested)
329				continue;
330			/* prepare requests */
331			for (j = 0; j < iobuf[i].cnt; ++j) {
332				io_prep_pwrite(iobuf[i].iocb[j], ep1,
333					       iobuf[i].buf[j],
334					       iobuf[i].len, 0);
335				/* enable eventfd notification */
336				iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
337				iobuf[i].iocb[j]->u.c.resfd = evfd;
338			}
339			/* submit table of requests */
340			ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
341			if (ret >= 0) {
342				iobuf[i].requested = ret;
343				printf("submit: %d requests buf: %d\n", ret, i);
344			} else
345				perror("unable to submit requests");
346		}
347
348		/* if event is ready to read */
349		if (!FD_ISSET(evfd, &rfds))
350			continue;
351
352		uint64_t ev_cnt;
353		ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
354		if (ret < 0) {
355			perror("unable to read eventfd");
356			break;
357		}
358
359		struct io_event e[BUFS_MAX];
360		/* we read aio events */
361		ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
362		if (ret > 0) /* if we got events */
363			iobuf[actual].requested -= ret;
364
365		/* if all req's from iocb completed */
366		if (!iobuf[actual].requested)
367			actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
368	}
369
370	/* free resources */
371
372	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
373		delete_bufs(&iobuf[i]);
374	io_destroy(ctx);
375
376	close(ep1);
377	close(ep0);
378
379	return 0;
380}
381