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