xref: /OK3568_Linux_fs/kernel/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 	__le32 ss_count;
61 	__le32 os_count;
62 	struct {
63 		struct usb_interface_descriptor intf;
64 		struct usb_endpoint_descriptor_no_audio bulk_sink;
65 		struct usb_endpoint_descriptor_no_audio bulk_source;
66 	} __attribute__ ((__packed__)) fs_descs, hs_descs;
67 	struct {
68 		struct usb_interface_descriptor intf;
69 		struct usb_endpoint_descriptor_no_audio sink;
70 		struct usb_ss_ep_comp_descriptor sink_comp;
71 		struct usb_endpoint_descriptor_no_audio source;
72 		struct usb_ss_ep_comp_descriptor source_comp;
73 	} __attribute__ ((__packed__)) ss_descs;
74 	struct usb_os_desc_header os_header;
75 	struct usb_ext_compat_desc os_desc;
76 
77 } __attribute__ ((__packed__)) descriptors = {
78 	.header = {
79 		.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
80 		.flags = htole32(FUNCTIONFS_HAS_FS_DESC |
81 				 FUNCTIONFS_HAS_HS_DESC |
82 				 FUNCTIONFS_HAS_SS_DESC |
83 				 FUNCTIONFS_HAS_MS_OS_DESC),
84 		.length = htole32(sizeof(descriptors)),
85 	},
86 	.fs_count = htole32(3),
87 	.fs_descs = {
88 		.intf = {
89 			.bLength = sizeof(descriptors.fs_descs.intf),
90 			.bDescriptorType = USB_DT_INTERFACE,
91 			.bNumEndpoints = 2,
92 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
93 			.iInterface = 1,
94 		},
95 		.bulk_sink = {
96 			.bLength = sizeof(descriptors.fs_descs.bulk_sink),
97 			.bDescriptorType = USB_DT_ENDPOINT,
98 			.bEndpointAddress = 1 | USB_DIR_IN,
99 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
100 		},
101 		.bulk_source = {
102 			.bLength = sizeof(descriptors.fs_descs.bulk_source),
103 			.bDescriptorType = USB_DT_ENDPOINT,
104 			.bEndpointAddress = 2 | USB_DIR_OUT,
105 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
106 		},
107 	},
108 	.hs_count = htole32(3),
109 	.hs_descs = {
110 		.intf = {
111 			.bLength = sizeof(descriptors.hs_descs.intf),
112 			.bDescriptorType = USB_DT_INTERFACE,
113 			.bNumEndpoints = 2,
114 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
115 			.iInterface = 1,
116 		},
117 		.bulk_sink = {
118 			.bLength = sizeof(descriptors.hs_descs.bulk_sink),
119 			.bDescriptorType = USB_DT_ENDPOINT,
120 			.bEndpointAddress = 1 | USB_DIR_IN,
121 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
122 			.wMaxPacketSize = htole16(512),
123 		},
124 		.bulk_source = {
125 			.bLength = sizeof(descriptors.hs_descs.bulk_source),
126 			.bDescriptorType = USB_DT_ENDPOINT,
127 			.bEndpointAddress = 2 | USB_DIR_OUT,
128 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
129 			.wMaxPacketSize = htole16(512),
130 		},
131 	},
132 	.ss_count = htole32(5),
133 	.ss_descs = {
134 		.intf = {
135 			.bLength = sizeof(descriptors.ss_descs.intf),
136 			.bDescriptorType = USB_DT_INTERFACE,
137 			.bInterfaceNumber = 0,
138 			.bNumEndpoints = 2,
139 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
140 			.iInterface = 1,
141 		},
142 		.sink = {
143 			.bLength = sizeof(descriptors.ss_descs.sink),
144 			.bDescriptorType = USB_DT_ENDPOINT,
145 			.bEndpointAddress = 1 | USB_DIR_IN,
146 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
147 			.wMaxPacketSize = htole16(1024),
148 		},
149 		.sink_comp = {
150 			.bLength = sizeof(descriptors.ss_descs.sink_comp),
151 			.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
152 			.bMaxBurst = 4,
153 		},
154 		.source = {
155 			.bLength = sizeof(descriptors.ss_descs.source),
156 			.bDescriptorType = USB_DT_ENDPOINT,
157 			.bEndpointAddress = 2 | USB_DIR_OUT,
158 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
159 			.wMaxPacketSize = htole16(1024),
160 		},
161 		.source_comp = {
162 			.bLength = sizeof(descriptors.ss_descs.source_comp),
163 			.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
164 			.bMaxBurst = 4,
165 		},
166 	},
167 	.os_count = htole32(1),
168 	.os_header = {
169 		.interface = htole32(1),
170 		.dwLength = htole32(sizeof(descriptors.os_header) +
171 			    sizeof(descriptors.os_desc)),
172 		.bcdVersion = htole32(1),
173 		.wIndex = htole32(4),
174 		.bCount = htole32(1),
175 		.Reserved = htole32(0),
176 	},
177 	.os_desc = {
178 		.bFirstInterfaceNumber = 0,
179 		.Reserved1 = htole32(1),
180 		.CompatibleID = {0},
181 		.SubCompatibleID = {0},
182 		.Reserved2 = {0},
183 	},
184 };
185 
186 #define STR_INTERFACE "AIO Test"
187 
188 static const struct {
189 	struct usb_functionfs_strings_head header;
190 	struct {
191 		__le16 code;
192 		const char str1[sizeof(STR_INTERFACE)];
193 	} __attribute__ ((__packed__)) lang0;
194 } __attribute__ ((__packed__)) strings = {
195 	.header = {
196 		.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
197 		.length = htole32(sizeof(strings)),
198 		.str_count = htole32(1),
199 		.lang_count = htole32(1),
200 	},
201 	.lang0 = {
202 		htole16(0x0409), /* en-us */
203 		STR_INTERFACE,
204 	},
205 };
206 
207 /********************** Buffer structure *******************************/
208 
209 struct io_buffer {
210 	struct iocb **iocb;
211 	unsigned char **buf;
212 	unsigned cnt;
213 	unsigned len;
214 	unsigned requested;
215 };
216 
217 /******************** Endpoints handling *******************************/
218 
display_event(struct usb_functionfs_event * event)219 static void display_event(struct usb_functionfs_event *event)
220 {
221 	static const char *const names[] = {
222 		[FUNCTIONFS_BIND] = "BIND",
223 		[FUNCTIONFS_UNBIND] = "UNBIND",
224 		[FUNCTIONFS_ENABLE] = "ENABLE",
225 		[FUNCTIONFS_DISABLE] = "DISABLE",
226 		[FUNCTIONFS_SETUP] = "SETUP",
227 		[FUNCTIONFS_SUSPEND] = "SUSPEND",
228 		[FUNCTIONFS_RESUME] = "RESUME",
229 	};
230 	switch (event->type) {
231 	case FUNCTIONFS_BIND:
232 	case FUNCTIONFS_UNBIND:
233 	case FUNCTIONFS_ENABLE:
234 	case FUNCTIONFS_DISABLE:
235 	case FUNCTIONFS_SETUP:
236 	case FUNCTIONFS_SUSPEND:
237 	case FUNCTIONFS_RESUME:
238 		printf("Event %s\n", names[event->type]);
239 	}
240 }
241 
handle_ep0(int ep0,bool * ready)242 static void handle_ep0(int ep0, bool *ready)
243 {
244 	int ret;
245 	struct usb_functionfs_event event;
246 
247 	ret = read(ep0, &event, sizeof(event));
248 	if (!ret) {
249 		perror("unable to read event from ep0");
250 		return;
251 	}
252 	display_event(&event);
253 	switch (event.type) {
254 	case FUNCTIONFS_SETUP:
255 		if (event.u.setup.bRequestType & USB_DIR_IN)
256 			write(ep0, NULL, 0);
257 		else
258 			read(ep0, NULL, 0);
259 		break;
260 
261 	case FUNCTIONFS_ENABLE:
262 		*ready = true;
263 		break;
264 
265 	case FUNCTIONFS_DISABLE:
266 		*ready = false;
267 		break;
268 
269 	default:
270 		break;
271 	}
272 }
273 
init_bufs(struct io_buffer * iobuf,unsigned n,unsigned len)274 void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
275 {
276 	unsigned i;
277 	iobuf->buf = malloc(n*sizeof(*iobuf->buf));
278 	iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
279 	iobuf->cnt = n;
280 	iobuf->len = len;
281 	iobuf->requested = 0;
282 	for (i = 0; i < n; ++i) {
283 		iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
284 		iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
285 	}
286 	iobuf->cnt = n;
287 }
288 
delete_bufs(struct io_buffer * iobuf)289 void delete_bufs(struct io_buffer *iobuf)
290 {
291 	unsigned i;
292 	for (i = 0; i < iobuf->cnt; ++i) {
293 		free(iobuf->buf[i]);
294 		free(iobuf->iocb[i]);
295 	}
296 	free(iobuf->buf);
297 	free(iobuf->iocb);
298 }
299 
main(int argc,char * argv[])300 int main(int argc, char *argv[])
301 {
302 	int ret;
303 	unsigned i, j;
304 	char *ep_path;
305 
306 	int ep0, ep1;
307 
308 	io_context_t ctx;
309 
310 	int evfd;
311 	fd_set rfds;
312 
313 	struct io_buffer iobuf[2];
314 	int actual = 0;
315 	bool ready;
316 
317 	if (argc != 2) {
318 		printf("ffs directory not specified!\n");
319 		return 1;
320 	}
321 
322 	ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
323 	if (!ep_path) {
324 		perror("malloc");
325 		return 1;
326 	}
327 
328 	/* open endpoint files */
329 	sprintf(ep_path, "%s/ep0", argv[1]);
330 	ep0 = open(ep_path, O_RDWR);
331 	if (ep0 < 0) {
332 		perror("unable to open ep0");
333 		return 1;
334 	}
335 	if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
336 		perror("unable do write descriptors");
337 		return 1;
338 	}
339 	if (write(ep0, &strings, sizeof(strings)) < 0) {
340 		perror("unable to write strings");
341 		return 1;
342 	}
343 	sprintf(ep_path, "%s/ep1", argv[1]);
344 	ep1 = open(ep_path, O_RDWR);
345 	if (ep1 < 0) {
346 		perror("unable to open ep1");
347 		return 1;
348 	}
349 
350 	free(ep_path);
351 
352 	memset(&ctx, 0, sizeof(ctx));
353 	/* setup aio context to handle up to AIO_MAX requests */
354 	if (io_setup(AIO_MAX, &ctx) < 0) {
355 		perror("unable to setup aio");
356 		return 1;
357 	}
358 
359 	evfd = eventfd(0, 0);
360 	if (evfd < 0) {
361 		perror("unable to open eventfd");
362 		return 1;
363 	}
364 
365 	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
366 		init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
367 
368 	while (1) {
369 		FD_ZERO(&rfds);
370 		FD_SET(ep0, &rfds);
371 		FD_SET(evfd, &rfds);
372 
373 		ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
374 			     &rfds, NULL, NULL, NULL);
375 		if (ret < 0) {
376 			if (errno == EINTR)
377 				continue;
378 			perror("select");
379 			break;
380 		}
381 
382 		if (FD_ISSET(ep0, &rfds))
383 			handle_ep0(ep0, &ready);
384 
385 		/* we are waiting for function ENABLE */
386 		if (!ready)
387 			continue;
388 
389 		/*
390 		 * when we're preparing new data to submit,
391 		 * second buffer being transmitted
392 		 */
393 		for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
394 			if (iobuf[i].requested)
395 				continue;
396 			/* prepare requests */
397 			for (j = 0; j < iobuf[i].cnt; ++j) {
398 				io_prep_pwrite(iobuf[i].iocb[j], ep1,
399 					       iobuf[i].buf[j],
400 					       iobuf[i].len, 0);
401 				/* enable eventfd notification */
402 				iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
403 				iobuf[i].iocb[j]->u.c.resfd = evfd;
404 			}
405 			/* submit table of requests */
406 			ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
407 			if (ret >= 0) {
408 				iobuf[i].requested = ret;
409 				printf("submit: %d requests buf: %d\n", ret, i);
410 			} else
411 				perror("unable to submit requests");
412 		}
413 
414 		/* if event is ready to read */
415 		if (!FD_ISSET(evfd, &rfds))
416 			continue;
417 
418 		uint64_t ev_cnt;
419 		ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
420 		if (ret < 0) {
421 			perror("unable to read eventfd");
422 			break;
423 		}
424 
425 		struct io_event e[BUFS_MAX];
426 		/* we read aio events */
427 		ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
428 		if (ret > 0) /* if we got events */
429 			iobuf[actual].requested -= ret;
430 
431 		/* if all req's from iocb completed */
432 		if (!iobuf[actual].requested)
433 			actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
434 	}
435 
436 	/* free resources */
437 
438 	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
439 		delete_bufs(&iobuf[i]);
440 	io_destroy(ctx);
441 
442 	close(ep1);
443 	close(ep0);
444 
445 	return 0;
446 }
447