xref: /openbmc/linux/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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 
28*c5edb757SBhupesh Sharma /* $(CROSS_COMPILE)cc -g -o aio_simple aio_simple.c -laio */
29*c5edb757SBhupesh Sharma 
30*c5edb757SBhupesh Sharma #define _DEFAULT_SOURCE /* for endian.h */
31b34e08d5SRobert Baldyga 
32b34e08d5SRobert Baldyga #include <endian.h>
33b34e08d5SRobert Baldyga #include <errno.h>
34b34e08d5SRobert Baldyga #include <fcntl.h>
35b34e08d5SRobert Baldyga #include <stdarg.h>
36b34e08d5SRobert Baldyga #include <stdio.h>
37b34e08d5SRobert Baldyga #include <stdlib.h>
38b34e08d5SRobert Baldyga #include <string.h>
39b34e08d5SRobert Baldyga #include <sys/ioctl.h>
40b34e08d5SRobert Baldyga #include <sys/stat.h>
41b34e08d5SRobert Baldyga #include <sys/types.h>
42b34e08d5SRobert Baldyga #include <sys/poll.h>
43b34e08d5SRobert Baldyga #include <unistd.h>
44b34e08d5SRobert Baldyga #include <stdbool.h>
45b34e08d5SRobert Baldyga #include <sys/eventfd.h>
46b34e08d5SRobert Baldyga 
47b34e08d5SRobert Baldyga #include "libaio.h"
48b34e08d5SRobert Baldyga #define IOCB_FLAG_RESFD         (1 << 0)
49b34e08d5SRobert Baldyga 
50b34e08d5SRobert Baldyga #include <linux/usb/functionfs.h>
51b34e08d5SRobert Baldyga 
52b34e08d5SRobert Baldyga #define BUF_LEN		8192
53b34e08d5SRobert Baldyga 
54*c5edb757SBhupesh Sharma /*
55*c5edb757SBhupesh Sharma  * cpu_to_le16/32 are used when initializing structures, a context where a
56*c5edb757SBhupesh Sharma  * function call is not allowed. To solve this, we code cpu_to_le16/32 in a way
57*c5edb757SBhupesh Sharma  * that allows them to be used when initializing structures.
58*c5edb757SBhupesh Sharma  */
59*c5edb757SBhupesh Sharma 
60*c5edb757SBhupesh Sharma #if BYTE_ORDER == __LITTLE_ENDIAN
61*c5edb757SBhupesh Sharma #define cpu_to_le16(x)  (x)
62*c5edb757SBhupesh Sharma #define cpu_to_le32(x)  (x)
63*c5edb757SBhupesh Sharma #else
64*c5edb757SBhupesh Sharma #define cpu_to_le16(x)  ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
65*c5edb757SBhupesh Sharma #define cpu_to_le32(x)  \
66*c5edb757SBhupesh Sharma 	((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >>  8) | \
67*c5edb757SBhupesh Sharma 	(((x) & 0x0000ff00u) <<  8) | (((x) & 0x000000ffu) << 24))
68*c5edb757SBhupesh Sharma #endif
69*c5edb757SBhupesh Sharma 
70b34e08d5SRobert Baldyga /******************** Descriptors and Strings *******************************/
71b34e08d5SRobert Baldyga 
72b34e08d5SRobert Baldyga static const struct {
730ebe9910SRobert Baldyga 	struct usb_functionfs_descs_head_v2 header;
740ebe9910SRobert Baldyga 	__le32 fs_count;
750ebe9910SRobert Baldyga 	__le32 hs_count;
76b34e08d5SRobert Baldyga 	struct {
77b34e08d5SRobert Baldyga 		struct usb_interface_descriptor intf;
78b34e08d5SRobert Baldyga 		struct usb_endpoint_descriptor_no_audio bulk_sink;
79b34e08d5SRobert Baldyga 		struct usb_endpoint_descriptor_no_audio bulk_source;
80b34e08d5SRobert Baldyga 	} __attribute__ ((__packed__)) fs_descs, hs_descs;
81b34e08d5SRobert Baldyga } __attribute__ ((__packed__)) descriptors = {
82b34e08d5SRobert Baldyga 	.header = {
83*c5edb757SBhupesh Sharma 		.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
84*c5edb757SBhupesh Sharma 		.flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC |
850ebe9910SRobert Baldyga 				     FUNCTIONFS_HAS_HS_DESC),
86*c5edb757SBhupesh Sharma 		.length = cpu_to_le32(sizeof(descriptors)),
87b34e08d5SRobert Baldyga 	},
88*c5edb757SBhupesh Sharma 	.fs_count = cpu_to_le32(3),
89b34e08d5SRobert Baldyga 	.fs_descs = {
90b34e08d5SRobert Baldyga 		.intf = {
91b34e08d5SRobert Baldyga 			.bLength = sizeof(descriptors.fs_descs.intf),
92b34e08d5SRobert Baldyga 			.bDescriptorType = USB_DT_INTERFACE,
93b34e08d5SRobert Baldyga 			.bNumEndpoints = 2,
94b34e08d5SRobert Baldyga 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
95b34e08d5SRobert Baldyga 			.iInterface = 1,
96b34e08d5SRobert Baldyga 		},
97b34e08d5SRobert Baldyga 		.bulk_sink = {
98b34e08d5SRobert Baldyga 			.bLength = sizeof(descriptors.fs_descs.bulk_sink),
99b34e08d5SRobert Baldyga 			.bDescriptorType = USB_DT_ENDPOINT,
100b34e08d5SRobert Baldyga 			.bEndpointAddress = 1 | USB_DIR_IN,
101b34e08d5SRobert Baldyga 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
102b34e08d5SRobert Baldyga 		},
103b34e08d5SRobert Baldyga 		.bulk_source = {
104b34e08d5SRobert Baldyga 			.bLength = sizeof(descriptors.fs_descs.bulk_source),
105b34e08d5SRobert Baldyga 			.bDescriptorType = USB_DT_ENDPOINT,
106b34e08d5SRobert Baldyga 			.bEndpointAddress = 2 | USB_DIR_OUT,
107b34e08d5SRobert Baldyga 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
108b34e08d5SRobert Baldyga 		},
109b34e08d5SRobert Baldyga 	},
110*c5edb757SBhupesh Sharma 	.hs_count = cpu_to_le32(3),
111b34e08d5SRobert Baldyga 	.hs_descs = {
112b34e08d5SRobert Baldyga 		.intf = {
113b34e08d5SRobert Baldyga 			.bLength = sizeof(descriptors.hs_descs.intf),
114b34e08d5SRobert Baldyga 			.bDescriptorType = USB_DT_INTERFACE,
115b34e08d5SRobert Baldyga 			.bNumEndpoints = 2,
116b34e08d5SRobert Baldyga 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
117b34e08d5SRobert Baldyga 			.iInterface = 1,
118b34e08d5SRobert Baldyga 		},
119b34e08d5SRobert Baldyga 		.bulk_sink = {
120b34e08d5SRobert Baldyga 			.bLength = sizeof(descriptors.hs_descs.bulk_sink),
121b34e08d5SRobert Baldyga 			.bDescriptorType = USB_DT_ENDPOINT,
122b34e08d5SRobert Baldyga 			.bEndpointAddress = 1 | USB_DIR_IN,
123b34e08d5SRobert Baldyga 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
124*c5edb757SBhupesh Sharma 			.wMaxPacketSize = cpu_to_le16(512),
125b34e08d5SRobert Baldyga 		},
126b34e08d5SRobert Baldyga 		.bulk_source = {
127b34e08d5SRobert Baldyga 			.bLength = sizeof(descriptors.hs_descs.bulk_source),
128b34e08d5SRobert Baldyga 			.bDescriptorType = USB_DT_ENDPOINT,
129b34e08d5SRobert Baldyga 			.bEndpointAddress = 2 | USB_DIR_OUT,
130b34e08d5SRobert Baldyga 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
131*c5edb757SBhupesh Sharma 			.wMaxPacketSize = cpu_to_le16(512),
132b34e08d5SRobert Baldyga 		},
133b34e08d5SRobert Baldyga 	},
134b34e08d5SRobert Baldyga };
135b34e08d5SRobert Baldyga 
136b34e08d5SRobert Baldyga #define STR_INTERFACE "AIO Test"
137b34e08d5SRobert Baldyga 
138b34e08d5SRobert Baldyga static const struct {
139b34e08d5SRobert Baldyga 	struct usb_functionfs_strings_head header;
140b34e08d5SRobert Baldyga 	struct {
141b34e08d5SRobert Baldyga 		__le16 code;
142b34e08d5SRobert Baldyga 		const char str1[sizeof(STR_INTERFACE)];
143b34e08d5SRobert Baldyga 	} __attribute__ ((__packed__)) lang0;
144b34e08d5SRobert Baldyga } __attribute__ ((__packed__)) strings = {
145b34e08d5SRobert Baldyga 	.header = {
146*c5edb757SBhupesh Sharma 		.magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
147*c5edb757SBhupesh Sharma 		.length = cpu_to_le32(sizeof(strings)),
148*c5edb757SBhupesh Sharma 		.str_count = cpu_to_le32(1),
149*c5edb757SBhupesh Sharma 		.lang_count = cpu_to_le32(1),
150b34e08d5SRobert Baldyga 	},
151b34e08d5SRobert Baldyga 	.lang0 = {
152*c5edb757SBhupesh Sharma 		cpu_to_le16(0x0409), /* en-us */
153b34e08d5SRobert Baldyga 		STR_INTERFACE,
154b34e08d5SRobert Baldyga 	},
155b34e08d5SRobert Baldyga };
156b34e08d5SRobert Baldyga 
157b34e08d5SRobert Baldyga /******************** Endpoints handling *******************************/
158b34e08d5SRobert Baldyga 
display_event(struct usb_functionfs_event * event)159b34e08d5SRobert Baldyga static void display_event(struct usb_functionfs_event *event)
160b34e08d5SRobert Baldyga {
161b34e08d5SRobert Baldyga 	static const char *const names[] = {
162b34e08d5SRobert Baldyga 		[FUNCTIONFS_BIND] = "BIND",
163b34e08d5SRobert Baldyga 		[FUNCTIONFS_UNBIND] = "UNBIND",
164b34e08d5SRobert Baldyga 		[FUNCTIONFS_ENABLE] = "ENABLE",
165b34e08d5SRobert Baldyga 		[FUNCTIONFS_DISABLE] = "DISABLE",
166b34e08d5SRobert Baldyga 		[FUNCTIONFS_SETUP] = "SETUP",
167b34e08d5SRobert Baldyga 		[FUNCTIONFS_SUSPEND] = "SUSPEND",
168b34e08d5SRobert Baldyga 		[FUNCTIONFS_RESUME] = "RESUME",
169b34e08d5SRobert Baldyga 	};
170b34e08d5SRobert Baldyga 	switch (event->type) {
171b34e08d5SRobert Baldyga 	case FUNCTIONFS_BIND:
172b34e08d5SRobert Baldyga 	case FUNCTIONFS_UNBIND:
173b34e08d5SRobert Baldyga 	case FUNCTIONFS_ENABLE:
174b34e08d5SRobert Baldyga 	case FUNCTIONFS_DISABLE:
175b34e08d5SRobert Baldyga 	case FUNCTIONFS_SETUP:
176b34e08d5SRobert Baldyga 	case FUNCTIONFS_SUSPEND:
177b34e08d5SRobert Baldyga 	case FUNCTIONFS_RESUME:
178b34e08d5SRobert Baldyga 		printf("Event %s\n", names[event->type]);
179b34e08d5SRobert Baldyga 	}
180b34e08d5SRobert Baldyga }
181b34e08d5SRobert Baldyga 
handle_ep0(int ep0,bool * ready)182b34e08d5SRobert Baldyga static void handle_ep0(int ep0, bool *ready)
183b34e08d5SRobert Baldyga {
184b34e08d5SRobert Baldyga 	struct usb_functionfs_event event;
185b34e08d5SRobert Baldyga 	int ret;
186b34e08d5SRobert Baldyga 
187b34e08d5SRobert Baldyga 	struct pollfd pfds[1];
188b34e08d5SRobert Baldyga 	pfds[0].fd = ep0;
189b34e08d5SRobert Baldyga 	pfds[0].events = POLLIN;
190b34e08d5SRobert Baldyga 
191b34e08d5SRobert Baldyga 	ret = poll(pfds, 1, 0);
192b34e08d5SRobert Baldyga 
193b34e08d5SRobert Baldyga 	if (ret && (pfds[0].revents & POLLIN)) {
194b34e08d5SRobert Baldyga 		ret = read(ep0, &event, sizeof(event));
195b34e08d5SRobert Baldyga 		if (!ret) {
196b34e08d5SRobert Baldyga 			perror("unable to read event from ep0");
197b34e08d5SRobert Baldyga 			return;
198b34e08d5SRobert Baldyga 		}
199b34e08d5SRobert Baldyga 		display_event(&event);
200b34e08d5SRobert Baldyga 		switch (event.type) {
201b34e08d5SRobert Baldyga 		case FUNCTIONFS_SETUP:
202b34e08d5SRobert Baldyga 			if (event.u.setup.bRequestType & USB_DIR_IN)
203b34e08d5SRobert Baldyga 				write(ep0, NULL, 0);
204b34e08d5SRobert Baldyga 			else
205b34e08d5SRobert Baldyga 				read(ep0, NULL, 0);
206b34e08d5SRobert Baldyga 			break;
207b34e08d5SRobert Baldyga 
208b34e08d5SRobert Baldyga 		case FUNCTIONFS_ENABLE:
209b34e08d5SRobert Baldyga 			*ready = true;
210b34e08d5SRobert Baldyga 			break;
211b34e08d5SRobert Baldyga 
212b34e08d5SRobert Baldyga 		case FUNCTIONFS_DISABLE:
213b34e08d5SRobert Baldyga 			*ready = false;
214b34e08d5SRobert Baldyga 			break;
215b34e08d5SRobert Baldyga 
216b34e08d5SRobert Baldyga 		default:
217b34e08d5SRobert Baldyga 			break;
218b34e08d5SRobert Baldyga 		}
219b34e08d5SRobert Baldyga 	}
220b34e08d5SRobert Baldyga }
221b34e08d5SRobert Baldyga 
main(int argc,char * argv[])222b34e08d5SRobert Baldyga int main(int argc, char *argv[])
223b34e08d5SRobert Baldyga {
224b34e08d5SRobert Baldyga 	int i, ret;
225b34e08d5SRobert Baldyga 	char *ep_path;
226b34e08d5SRobert Baldyga 
227b34e08d5SRobert Baldyga 	int ep0;
228b34e08d5SRobert Baldyga 	int ep[2];
229b34e08d5SRobert Baldyga 
230b34e08d5SRobert Baldyga 	io_context_t ctx;
231b34e08d5SRobert Baldyga 
232b34e08d5SRobert Baldyga 	int evfd;
233b34e08d5SRobert Baldyga 	fd_set rfds;
234b34e08d5SRobert Baldyga 
235b34e08d5SRobert Baldyga 	char *buf_in, *buf_out;
236b34e08d5SRobert Baldyga 	struct iocb *iocb_in, *iocb_out;
237b34e08d5SRobert Baldyga 	int req_in = 0, req_out = 0;
238b34e08d5SRobert Baldyga 	bool ready;
239b34e08d5SRobert Baldyga 
240b34e08d5SRobert Baldyga 	if (argc != 2) {
241b34e08d5SRobert Baldyga 		printf("ffs directory not specified!\n");
242b34e08d5SRobert Baldyga 		return 1;
243b34e08d5SRobert Baldyga 	}
244b34e08d5SRobert Baldyga 
245b34e08d5SRobert Baldyga 	ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
246b34e08d5SRobert Baldyga 	if (!ep_path) {
247b34e08d5SRobert Baldyga 		perror("malloc");
248b34e08d5SRobert Baldyga 		return 1;
249b34e08d5SRobert Baldyga 	}
250b34e08d5SRobert Baldyga 
251b34e08d5SRobert Baldyga 	/* open endpoint files */
252b34e08d5SRobert Baldyga 	sprintf(ep_path, "%s/ep0", argv[1]);
253b34e08d5SRobert Baldyga 	ep0 = open(ep_path, O_RDWR);
254b34e08d5SRobert Baldyga 	if (ep0 < 0) {
255b34e08d5SRobert Baldyga 		perror("unable to open ep0");
256b34e08d5SRobert Baldyga 		return 1;
257b34e08d5SRobert Baldyga 	}
258b34e08d5SRobert Baldyga 	if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
259b34e08d5SRobert Baldyga 		perror("unable do write descriptors");
260b34e08d5SRobert Baldyga 		return 1;
261b34e08d5SRobert Baldyga 	}
262b34e08d5SRobert Baldyga 	if (write(ep0, &strings, sizeof(strings)) < 0) {
263b34e08d5SRobert Baldyga 		perror("unable to write strings");
264b34e08d5SRobert Baldyga 		return 1;
265b34e08d5SRobert Baldyga 	}
266b34e08d5SRobert Baldyga 	for (i = 0; i < 2; ++i) {
267b34e08d5SRobert Baldyga 		sprintf(ep_path, "%s/ep%d", argv[1], i+1);
268b34e08d5SRobert Baldyga 		ep[i] = open(ep_path, O_RDWR);
269b34e08d5SRobert Baldyga 		if (ep[i] < 0) {
270b34e08d5SRobert Baldyga 			printf("unable to open ep%d: %s\n", i+1,
271b34e08d5SRobert Baldyga 			       strerror(errno));
272b34e08d5SRobert Baldyga 			return 1;
273b34e08d5SRobert Baldyga 		}
274b34e08d5SRobert Baldyga 	}
275b34e08d5SRobert Baldyga 
276b34e08d5SRobert Baldyga 	free(ep_path);
277b34e08d5SRobert Baldyga 
278b34e08d5SRobert Baldyga 	memset(&ctx, 0, sizeof(ctx));
279b34e08d5SRobert Baldyga 	/* setup aio context to handle up to 2 requests */
280b34e08d5SRobert Baldyga 	if (io_setup(2, &ctx) < 0) {
281b34e08d5SRobert Baldyga 		perror("unable to setup aio");
282b34e08d5SRobert Baldyga 		return 1;
283b34e08d5SRobert Baldyga 	}
284b34e08d5SRobert Baldyga 
285b34e08d5SRobert Baldyga 	evfd = eventfd(0, 0);
286b34e08d5SRobert Baldyga 	if (evfd < 0) {
287b34e08d5SRobert Baldyga 		perror("unable to open eventfd");
288b34e08d5SRobert Baldyga 		return 1;
289b34e08d5SRobert Baldyga 	}
290b34e08d5SRobert Baldyga 
291b34e08d5SRobert Baldyga 	/* alloc buffers and requests */
292b34e08d5SRobert Baldyga 	buf_in = malloc(BUF_LEN);
293b34e08d5SRobert Baldyga 	buf_out = malloc(BUF_LEN);
294b34e08d5SRobert Baldyga 	iocb_in = malloc(sizeof(*iocb_in));
295b34e08d5SRobert Baldyga 	iocb_out = malloc(sizeof(*iocb_out));
296b34e08d5SRobert Baldyga 
297b34e08d5SRobert Baldyga 	while (1) {
298b34e08d5SRobert Baldyga 		FD_ZERO(&rfds);
299b34e08d5SRobert Baldyga 		FD_SET(ep0, &rfds);
300b34e08d5SRobert Baldyga 		FD_SET(evfd, &rfds);
301b34e08d5SRobert Baldyga 
302b34e08d5SRobert Baldyga 		ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
303b34e08d5SRobert Baldyga 			     &rfds, NULL, NULL, NULL);
304b34e08d5SRobert Baldyga 		if (ret < 0) {
305b34e08d5SRobert Baldyga 			if (errno == EINTR)
306b34e08d5SRobert Baldyga 				continue;
307b34e08d5SRobert Baldyga 			perror("select");
308b34e08d5SRobert Baldyga 			break;
309b34e08d5SRobert Baldyga 		}
310b34e08d5SRobert Baldyga 
311b34e08d5SRobert Baldyga 		if (FD_ISSET(ep0, &rfds))
312b34e08d5SRobert Baldyga 			handle_ep0(ep0, &ready);
313b34e08d5SRobert Baldyga 
314b34e08d5SRobert Baldyga 		/* we are waiting for function ENABLE */
315b34e08d5SRobert Baldyga 		if (!ready)
316b34e08d5SRobert Baldyga 			continue;
317b34e08d5SRobert Baldyga 
318b34e08d5SRobert Baldyga 		/* if something was submitted we wait for event */
319b34e08d5SRobert Baldyga 		if (FD_ISSET(evfd, &rfds)) {
320b34e08d5SRobert Baldyga 			uint64_t ev_cnt;
321b34e08d5SRobert Baldyga 			ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
322b34e08d5SRobert Baldyga 			if (ret < 0) {
323b34e08d5SRobert Baldyga 				perror("unable to read eventfd");
324b34e08d5SRobert Baldyga 				break;
325b34e08d5SRobert Baldyga 			}
326b34e08d5SRobert Baldyga 
327b34e08d5SRobert Baldyga 			struct io_event e[2];
328b34e08d5SRobert Baldyga 			/* we wait for one event */
329b34e08d5SRobert Baldyga 			ret = io_getevents(ctx, 1, 2, e, NULL);
330b34e08d5SRobert Baldyga 			/* if we got event */
331b34e08d5SRobert Baldyga 			for (i = 0; i < ret; ++i) {
332b34e08d5SRobert Baldyga 				if (e[i].obj->aio_fildes == ep[0]) {
333b34e08d5SRobert Baldyga 					printf("ev=in; ret=%lu\n", e[i].res);
334b34e08d5SRobert Baldyga 					req_in = 0;
335b34e08d5SRobert Baldyga 				} else if (e[i].obj->aio_fildes == ep[1]) {
336b34e08d5SRobert Baldyga 					printf("ev=out; ret=%lu\n", e[i].res);
337b34e08d5SRobert Baldyga 					req_out = 0;
338b34e08d5SRobert Baldyga 				}
339b34e08d5SRobert Baldyga 			}
340b34e08d5SRobert Baldyga 		}
341b34e08d5SRobert Baldyga 
342b34e08d5SRobert Baldyga 		if (!req_in) { /* if IN transfer not requested*/
343b34e08d5SRobert Baldyga 			/* prepare write request */
344b34e08d5SRobert Baldyga 			io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0);
345b34e08d5SRobert Baldyga 			/* enable eventfd notification */
346b34e08d5SRobert Baldyga 			iocb_in->u.c.flags |= IOCB_FLAG_RESFD;
347b34e08d5SRobert Baldyga 			iocb_in->u.c.resfd = evfd;
348b34e08d5SRobert Baldyga 			/* submit table of requests */
349b34e08d5SRobert Baldyga 			ret = io_submit(ctx, 1, &iocb_in);
350b34e08d5SRobert Baldyga 			if (ret >= 0) { /* if ret > 0 request is queued */
351b34e08d5SRobert Baldyga 				req_in = 1;
352b34e08d5SRobert Baldyga 				printf("submit: in\n");
353b34e08d5SRobert Baldyga 			} else
354b34e08d5SRobert Baldyga 				perror("unable to submit request");
355b34e08d5SRobert Baldyga 		}
356b34e08d5SRobert Baldyga 		if (!req_out) { /* if OUT transfer not requested */
357b34e08d5SRobert Baldyga 			/* prepare read request */
358b34e08d5SRobert Baldyga 			io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0);
359b34e08d5SRobert Baldyga 			/* enable eventfs notification */
360b34e08d5SRobert Baldyga 			iocb_out->u.c.flags |= IOCB_FLAG_RESFD;
361b34e08d5SRobert Baldyga 			iocb_out->u.c.resfd = evfd;
362b34e08d5SRobert Baldyga 			/* submit table of requests */
363b34e08d5SRobert Baldyga 			ret = io_submit(ctx, 1, &iocb_out);
364b34e08d5SRobert Baldyga 			if (ret >= 0) { /* if ret > 0 request is queued */
365b34e08d5SRobert Baldyga 				req_out = 1;
366b34e08d5SRobert Baldyga 				printf("submit: out\n");
367b34e08d5SRobert Baldyga 			} else
368b34e08d5SRobert Baldyga 				perror("unable to submit request");
369b34e08d5SRobert Baldyga 		}
370b34e08d5SRobert Baldyga 	}
371b34e08d5SRobert Baldyga 
372b34e08d5SRobert Baldyga 	/* free resources */
373b34e08d5SRobert Baldyga 
374b34e08d5SRobert Baldyga 	io_destroy(ctx);
375b34e08d5SRobert Baldyga 
376b34e08d5SRobert Baldyga 	free(buf_in);
377b34e08d5SRobert Baldyga 	free(buf_out);
378b34e08d5SRobert Baldyga 	free(iocb_in);
379b34e08d5SRobert Baldyga 	free(iocb_out);
380b34e08d5SRobert Baldyga 
381b34e08d5SRobert Baldyga 	for (i = 0; i < 2; ++i)
382b34e08d5SRobert Baldyga 		close(ep[i]);
383b34e08d5SRobert Baldyga 	close(ep0);
384b34e08d5SRobert Baldyga 
385b34e08d5SRobert Baldyga 	return 0;
386b34e08d5SRobert Baldyga }
387