xref: /linux/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
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 
56 static 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 
122 static 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 
143 struct 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 
153 static 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 
176 static 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 
208 void 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 
223 void 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 
234 int 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