xref: /linux/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c (revision 5e2aa2ed08e2e280121dc7cf5609c87d464f12ef)
1 #define _BSD_SOURCE /* for endian.h */
2 
3 #include <endian.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/ioctl.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <sys/poll.h>
14 #include <unistd.h>
15 #include <stdbool.h>
16 #include <sys/eventfd.h>
17 
18 #include "libaio.h"
19 #define IOCB_FLAG_RESFD         (1 << 0)
20 
21 #include <linux/usb/functionfs.h>
22 
23 #define BUF_LEN		8192
24 #define BUFS_MAX	128
25 #define AIO_MAX		(BUFS_MAX*2)
26 
27 /******************** Descriptors and Strings *******************************/
28 
29 static const struct {
30 	struct usb_functionfs_descs_head header;
31 	struct {
32 		struct usb_interface_descriptor intf;
33 		struct usb_endpoint_descriptor_no_audio bulk_sink;
34 		struct usb_endpoint_descriptor_no_audio bulk_source;
35 	} __attribute__ ((__packed__)) fs_descs, hs_descs;
36 } __attribute__ ((__packed__)) descriptors = {
37 	.header = {
38 		.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
39 		.length = htole32(sizeof(descriptors)),
40 		.fs_count = 3,
41 		.hs_count = 3,
42 	},
43 	.fs_descs = {
44 		.intf = {
45 			.bLength = sizeof(descriptors.fs_descs.intf),
46 			.bDescriptorType = USB_DT_INTERFACE,
47 			.bNumEndpoints = 2,
48 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
49 			.iInterface = 1,
50 		},
51 		.bulk_sink = {
52 			.bLength = sizeof(descriptors.fs_descs.bulk_sink),
53 			.bDescriptorType = USB_DT_ENDPOINT,
54 			.bEndpointAddress = 1 | USB_DIR_IN,
55 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
56 		},
57 		.bulk_source = {
58 			.bLength = sizeof(descriptors.fs_descs.bulk_source),
59 			.bDescriptorType = USB_DT_ENDPOINT,
60 			.bEndpointAddress = 2 | USB_DIR_OUT,
61 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
62 		},
63 	},
64 	.hs_descs = {
65 		.intf = {
66 			.bLength = sizeof(descriptors.hs_descs.intf),
67 			.bDescriptorType = USB_DT_INTERFACE,
68 			.bNumEndpoints = 2,
69 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
70 			.iInterface = 1,
71 		},
72 		.bulk_sink = {
73 			.bLength = sizeof(descriptors.hs_descs.bulk_sink),
74 			.bDescriptorType = USB_DT_ENDPOINT,
75 			.bEndpointAddress = 1 | USB_DIR_IN,
76 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
77 			.wMaxPacketSize = htole16(512),
78 		},
79 		.bulk_source = {
80 			.bLength = sizeof(descriptors.hs_descs.bulk_source),
81 			.bDescriptorType = USB_DT_ENDPOINT,
82 			.bEndpointAddress = 2 | USB_DIR_OUT,
83 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
84 			.wMaxPacketSize = htole16(512),
85 		},
86 	},
87 };
88 
89 #define STR_INTERFACE "AIO Test"
90 
91 static const struct {
92 	struct usb_functionfs_strings_head header;
93 	struct {
94 		__le16 code;
95 		const char str1[sizeof(STR_INTERFACE)];
96 	} __attribute__ ((__packed__)) lang0;
97 } __attribute__ ((__packed__)) strings = {
98 	.header = {
99 		.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
100 		.length = htole32(sizeof(strings)),
101 		.str_count = htole32(1),
102 		.lang_count = htole32(1),
103 	},
104 	.lang0 = {
105 		htole16(0x0409), /* en-us */
106 		STR_INTERFACE,
107 	},
108 };
109 
110 /********************** Buffer structure *******************************/
111 
112 struct io_buffer {
113 	struct iocb **iocb;
114 	unsigned char **buf;
115 	unsigned cnt;
116 	unsigned len;
117 	unsigned requested;
118 };
119 
120 /******************** Endpoints handling *******************************/
121 
122 static void display_event(struct usb_functionfs_event *event)
123 {
124 	static const char *const names[] = {
125 		[FUNCTIONFS_BIND] = "BIND",
126 		[FUNCTIONFS_UNBIND] = "UNBIND",
127 		[FUNCTIONFS_ENABLE] = "ENABLE",
128 		[FUNCTIONFS_DISABLE] = "DISABLE",
129 		[FUNCTIONFS_SETUP] = "SETUP",
130 		[FUNCTIONFS_SUSPEND] = "SUSPEND",
131 		[FUNCTIONFS_RESUME] = "RESUME",
132 	};
133 	switch (event->type) {
134 	case FUNCTIONFS_BIND:
135 	case FUNCTIONFS_UNBIND:
136 	case FUNCTIONFS_ENABLE:
137 	case FUNCTIONFS_DISABLE:
138 	case FUNCTIONFS_SETUP:
139 	case FUNCTIONFS_SUSPEND:
140 	case FUNCTIONFS_RESUME:
141 		printf("Event %s\n", names[event->type]);
142 	}
143 }
144 
145 static void handle_ep0(int ep0, bool *ready)
146 {
147 	int ret;
148 	struct usb_functionfs_event event;
149 
150 	ret = read(ep0, &event, sizeof(event));
151 	if (!ret) {
152 		perror("unable to read event from ep0");
153 		return;
154 	}
155 	display_event(&event);
156 	switch (event.type) {
157 	case FUNCTIONFS_SETUP:
158 		if (event.u.setup.bRequestType & USB_DIR_IN)
159 			write(ep0, NULL, 0);
160 		else
161 			read(ep0, NULL, 0);
162 		break;
163 
164 	case FUNCTIONFS_ENABLE:
165 		*ready = true;
166 		break;
167 
168 	case FUNCTIONFS_DISABLE:
169 		*ready = false;
170 		break;
171 
172 	default:
173 		break;
174 	}
175 }
176 
177 void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
178 {
179 	unsigned i;
180 	iobuf->buf = malloc(n*sizeof(*iobuf->buf));
181 	iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
182 	iobuf->cnt = n;
183 	iobuf->len = len;
184 	iobuf->requested = 0;
185 	for (i = 0; i < n; ++i) {
186 		iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
187 		iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
188 	}
189 	iobuf->cnt = n;
190 }
191 
192 void delete_bufs(struct io_buffer *iobuf)
193 {
194 	unsigned i;
195 	for (i = 0; i < iobuf->cnt; ++i) {
196 		free(iobuf->buf[i]);
197 		free(iobuf->iocb[i]);
198 	}
199 	free(iobuf->buf);
200 	free(iobuf->iocb);
201 }
202 
203 int main(int argc, char *argv[])
204 {
205 	int ret;
206 	unsigned i, j;
207 	char *ep_path;
208 
209 	int ep0, ep1;
210 
211 	io_context_t ctx;
212 
213 	int evfd;
214 	fd_set rfds;
215 
216 	struct io_buffer iobuf[2];
217 	int actual = 0;
218 	bool ready;
219 
220 	if (argc != 2) {
221 		printf("ffs directory not specified!\n");
222 		return 1;
223 	}
224 
225 	ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
226 	if (!ep_path) {
227 		perror("malloc");
228 		return 1;
229 	}
230 
231 	/* open endpoint files */
232 	sprintf(ep_path, "%s/ep0", argv[1]);
233 	ep0 = open(ep_path, O_RDWR);
234 	if (ep0 < 0) {
235 		perror("unable to open ep0");
236 		return 1;
237 	}
238 	if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
239 		perror("unable do write descriptors");
240 		return 1;
241 	}
242 	if (write(ep0, &strings, sizeof(strings)) < 0) {
243 		perror("unable to write strings");
244 		return 1;
245 	}
246 	sprintf(ep_path, "%s/ep1", argv[1]);
247 	ep1 = open(ep_path, O_RDWR);
248 	if (ep1 < 0) {
249 		perror("unable to open ep1");
250 		return 1;
251 	}
252 
253 	free(ep_path);
254 
255 	memset(&ctx, 0, sizeof(ctx));
256 	/* setup aio context to handle up to AIO_MAX requests */
257 	if (io_setup(AIO_MAX, &ctx) < 0) {
258 		perror("unable to setup aio");
259 		return 1;
260 	}
261 
262 	evfd = eventfd(0, 0);
263 	if (evfd < 0) {
264 		perror("unable to open eventfd");
265 		return 1;
266 	}
267 
268 	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
269 		init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
270 
271 	while (1) {
272 		FD_ZERO(&rfds);
273 		FD_SET(ep0, &rfds);
274 		FD_SET(evfd, &rfds);
275 
276 		ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
277 			     &rfds, NULL, NULL, NULL);
278 		if (ret < 0) {
279 			if (errno == EINTR)
280 				continue;
281 			perror("select");
282 			break;
283 		}
284 
285 		if (FD_ISSET(ep0, &rfds))
286 			handle_ep0(ep0, &ready);
287 
288 		/* we are waiting for function ENABLE */
289 		if (!ready)
290 			continue;
291 
292 		/*
293 		 * when we're preparing new data to submit,
294 		 * second buffer being transmitted
295 		 */
296 		for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
297 			if (iobuf[i].requested)
298 				continue;
299 			/* prepare requests */
300 			for (j = 0; j < iobuf[i].cnt; ++j) {
301 				io_prep_pwrite(iobuf[i].iocb[j], ep1,
302 					       iobuf[i].buf[j],
303 					       iobuf[i].len, 0);
304 				/* enable eventfd notification */
305 				iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
306 				iobuf[i].iocb[j]->u.c.resfd = evfd;
307 			}
308 			/* submit table of requests */
309 			ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
310 			if (ret >= 0) {
311 				iobuf[i].requested = ret;
312 				printf("submit: %d requests buf: %d\n", ret, i);
313 			} else
314 				perror("unable to submit reqests");
315 		}
316 
317 		/* if event is ready to read */
318 		if (!FD_ISSET(evfd, &rfds))
319 			continue;
320 
321 		uint64_t ev_cnt;
322 		ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
323 		if (ret < 0) {
324 			perror("unable to read eventfd");
325 			break;
326 		}
327 
328 		struct io_event e[BUFS_MAX];
329 		/* we read aio events */
330 		ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
331 		if (ret > 0) /* if we got events */
332 			iobuf[actual].requested -= ret;
333 
334 		/* if all req's from iocb completed */
335 		if (!iobuf[actual].requested)
336 			actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
337 	}
338 
339 	/* free resources */
340 
341 	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
342 		delete_bufs(&iobuf[i]);
343 	io_destroy(ctx);
344 
345 	close(ep1);
346 	close(ep0);
347 
348 	return 0;
349 }
350