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