xref: /openbmc/linux/tools/usb/ffs-test.c (revision 4800cd83)
1 /*
2  * ffs-test.c.c -- user mode filesystem api for usb composite function
3  *
4  * Copyright (C) 2010 Samsung Electronics
5  *                    Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 /* $(CROSS_COMPILE)cc -Wall -Wextra -g -o ffs-test ffs-test.c -lpthread */
23 
24 
25 #define _BSD_SOURCE /* for endian.h */
26 
27 #include <endian.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <pthread.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/ioctl.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 
40 #include <linux/usb/functionfs.h>
41 
42 
43 /******************** Little Endian Handling ********************************/
44 
45 #define cpu_to_le16(x)  htole16(x)
46 #define cpu_to_le32(x)  htole32(x)
47 #define le32_to_cpu(x)  le32toh(x)
48 #define le16_to_cpu(x)  le16toh(x)
49 
50 static inline __u16 get_unaligned_le16(const void *_ptr)
51 {
52 	const __u8 *ptr = _ptr;
53 	return ptr[0] | (ptr[1] << 8);
54 }
55 
56 static inline __u32 get_unaligned_le32(const void *_ptr)
57 {
58 	const __u8 *ptr = _ptr;
59 	return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
60 }
61 
62 static inline void put_unaligned_le16(__u16 val, void *_ptr)
63 {
64 	__u8 *ptr = _ptr;
65 	*ptr++ = val;
66 	*ptr++ = val >> 8;
67 }
68 
69 static inline void put_unaligned_le32(__u32 val, void *_ptr)
70 {
71 	__u8 *ptr = _ptr;
72 	*ptr++ = val;
73 	*ptr++ = val >>  8;
74 	*ptr++ = val >> 16;
75 	*ptr++ = val >> 24;
76 }
77 
78 
79 /******************** Messages and Errors ***********************************/
80 
81 static const char argv0[] = "ffs-test";
82 
83 static unsigned verbosity = 7;
84 
85 static void _msg(unsigned level, const char *fmt, ...)
86 {
87 	if (level < 2)
88 		level = 2;
89 	else if (level > 7)
90 		level = 7;
91 
92 	if (level <= verbosity) {
93 		static const char levels[8][6] = {
94 			[2] = "crit:",
95 			[3] = "err: ",
96 			[4] = "warn:",
97 			[5] = "note:",
98 			[6] = "info:",
99 			[7] = "dbg: "
100 		};
101 
102 		int _errno = errno;
103 		va_list ap;
104 
105 		fprintf(stderr, "%s: %s ", argv0, levels[level]);
106 		va_start(ap, fmt);
107 		vfprintf(stderr, fmt, ap);
108 		va_end(ap);
109 
110 		if (fmt[strlen(fmt) - 1] != '\n') {
111 			char buffer[128];
112 			strerror_r(_errno, buffer, sizeof buffer);
113 			fprintf(stderr, ": (-%d) %s\n", _errno, buffer);
114 		}
115 
116 		fflush(stderr);
117 	}
118 }
119 
120 #define die(...)  (_msg(2, __VA_ARGS__), exit(1))
121 #define err(...)   _msg(3, __VA_ARGS__)
122 #define warn(...)  _msg(4, __VA_ARGS__)
123 #define note(...)  _msg(5, __VA_ARGS__)
124 #define info(...)  _msg(6, __VA_ARGS__)
125 #define debug(...) _msg(7, __VA_ARGS__)
126 
127 #define die_on(cond, ...) do { \
128 	if (cond) \
129 		die(__VA_ARGS__); \
130 	} while (0)
131 
132 
133 /******************** Descriptors and Strings *******************************/
134 
135 static const struct {
136 	struct usb_functionfs_descs_head header;
137 	struct {
138 		struct usb_interface_descriptor intf;
139 		struct usb_endpoint_descriptor_no_audio sink;
140 		struct usb_endpoint_descriptor_no_audio source;
141 	} __attribute__((packed)) fs_descs, hs_descs;
142 } __attribute__((packed)) descriptors = {
143 	.header = {
144 		.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
145 		.length = cpu_to_le32(sizeof descriptors),
146 		.fs_count = 3,
147 		.hs_count = 3,
148 	},
149 	.fs_descs = {
150 		.intf = {
151 			.bLength = sizeof descriptors.fs_descs.intf,
152 			.bDescriptorType = USB_DT_INTERFACE,
153 			.bNumEndpoints = 2,
154 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
155 			.iInterface = 1,
156 		},
157 		.sink = {
158 			.bLength = sizeof descriptors.fs_descs.sink,
159 			.bDescriptorType = USB_DT_ENDPOINT,
160 			.bEndpointAddress = 1 | USB_DIR_IN,
161 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
162 			/* .wMaxPacketSize = autoconfiguration (kernel) */
163 		},
164 		.source = {
165 			.bLength = sizeof descriptors.fs_descs.source,
166 			.bDescriptorType = USB_DT_ENDPOINT,
167 			.bEndpointAddress = 2 | USB_DIR_OUT,
168 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
169 			/* .wMaxPacketSize = autoconfiguration (kernel) */
170 		},
171 	},
172 	.hs_descs = {
173 		.intf = {
174 			.bLength = sizeof descriptors.fs_descs.intf,
175 			.bDescriptorType = USB_DT_INTERFACE,
176 			.bNumEndpoints = 2,
177 			.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
178 			.iInterface = 1,
179 		},
180 		.sink = {
181 			.bLength = sizeof descriptors.hs_descs.sink,
182 			.bDescriptorType = USB_DT_ENDPOINT,
183 			.bEndpointAddress = 1 | USB_DIR_IN,
184 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
185 			.wMaxPacketSize = cpu_to_le16(512),
186 		},
187 		.source = {
188 			.bLength = sizeof descriptors.hs_descs.source,
189 			.bDescriptorType = USB_DT_ENDPOINT,
190 			.bEndpointAddress = 2 | USB_DIR_OUT,
191 			.bmAttributes = USB_ENDPOINT_XFER_BULK,
192 			.wMaxPacketSize = cpu_to_le16(512),
193 			.bInterval = 1, /* NAK every 1 uframe */
194 		},
195 	},
196 };
197 
198 
199 #define STR_INTERFACE_ "Source/Sink"
200 
201 static const struct {
202 	struct usb_functionfs_strings_head header;
203 	struct {
204 		__le16 code;
205 		const char str1[sizeof STR_INTERFACE_];
206 	} __attribute__((packed)) lang0;
207 } __attribute__((packed)) strings = {
208 	.header = {
209 		.magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
210 		.length = cpu_to_le32(sizeof strings),
211 		.str_count = cpu_to_le32(1),
212 		.lang_count = cpu_to_le32(1),
213 	},
214 	.lang0 = {
215 		cpu_to_le16(0x0409), /* en-us */
216 		STR_INTERFACE_,
217 	},
218 };
219 
220 #define STR_INTERFACE strings.lang0.str1
221 
222 
223 /******************** Files and Threads Handling ****************************/
224 
225 struct thread;
226 
227 static ssize_t read_wrap(struct thread *t, void *buf, size_t nbytes);
228 static ssize_t write_wrap(struct thread *t, const void *buf, size_t nbytes);
229 static ssize_t ep0_consume(struct thread *t, const void *buf, size_t nbytes);
230 static ssize_t fill_in_buf(struct thread *t, void *buf, size_t nbytes);
231 static ssize_t empty_out_buf(struct thread *t, const void *buf, size_t nbytes);
232 
233 
234 static struct thread {
235 	const char *const filename;
236 	size_t buf_size;
237 
238 	ssize_t (*in)(struct thread *, void *, size_t);
239 	const char *const in_name;
240 
241 	ssize_t (*out)(struct thread *, const void *, size_t);
242 	const char *const out_name;
243 
244 	int fd;
245 	pthread_t id;
246 	void *buf;
247 	ssize_t status;
248 } threads[] = {
249 	{
250 		"ep0", 4 * sizeof(struct usb_functionfs_event),
251 		read_wrap, NULL,
252 		ep0_consume, "<consume>",
253 		0, 0, NULL, 0
254 	},
255 	{
256 		"ep1", 8 * 1024,
257 		fill_in_buf, "<in>",
258 		write_wrap, NULL,
259 		0, 0, NULL, 0
260 	},
261 	{
262 		"ep2", 8 * 1024,
263 		read_wrap, NULL,
264 		empty_out_buf, "<out>",
265 		0, 0, NULL, 0
266 	},
267 };
268 
269 
270 static void init_thread(struct thread *t)
271 {
272 	t->buf = malloc(t->buf_size);
273 	die_on(!t->buf, "malloc");
274 
275 	t->fd = open(t->filename, O_RDWR);
276 	die_on(t->fd < 0, "%s", t->filename);
277 }
278 
279 static void cleanup_thread(void *arg)
280 {
281 	struct thread *t = arg;
282 	int ret, fd;
283 
284 	fd = t->fd;
285 	if (t->fd < 0)
286 		return;
287 	t->fd = -1;
288 
289 	/* test the FIFO ioctls (non-ep0 code paths) */
290 	if (t != threads) {
291 		ret = ioctl(fd, FUNCTIONFS_FIFO_STATUS);
292 		if (ret < 0) {
293 			/* ENODEV reported after disconnect */
294 			if (errno != ENODEV)
295 				err("%s: get fifo status", t->filename);
296 		} else if (ret) {
297 			warn("%s: unclaimed = %d\n", t->filename, ret);
298 			if (ioctl(fd, FUNCTIONFS_FIFO_FLUSH) < 0)
299 				err("%s: fifo flush", t->filename);
300 		}
301 	}
302 
303 	if (close(fd) < 0)
304 		err("%s: close", t->filename);
305 
306 	free(t->buf);
307 	t->buf = NULL;
308 }
309 
310 static void *start_thread_helper(void *arg)
311 {
312 	const char *name, *op, *in_name, *out_name;
313 	struct thread *t = arg;
314 	ssize_t ret;
315 
316 	info("%s: starts\n", t->filename);
317 	in_name = t->in_name ? t->in_name : t->filename;
318 	out_name = t->out_name ? t->out_name : t->filename;
319 
320 	pthread_cleanup_push(cleanup_thread, arg);
321 
322 	for (;;) {
323 		pthread_testcancel();
324 
325 		ret = t->in(t, t->buf, t->buf_size);
326 		if (ret > 0) {
327 			ret = t->out(t, t->buf, t->buf_size);
328 			name = out_name;
329 			op = "write";
330 		} else {
331 			name = in_name;
332 			op = "read";
333 		}
334 
335 		if (ret > 0) {
336 			/* nop */
337 		} else if (!ret) {
338 			debug("%s: %s: EOF", name, op);
339 			break;
340 		} else if (errno == EINTR || errno == EAGAIN) {
341 			debug("%s: %s", name, op);
342 		} else {
343 			warn("%s: %s", name, op);
344 			break;
345 		}
346 	}
347 
348 	pthread_cleanup_pop(1);
349 
350 	t->status = ret;
351 	info("%s: ends\n", t->filename);
352 	return NULL;
353 }
354 
355 static void start_thread(struct thread *t)
356 {
357 	debug("%s: starting\n", t->filename);
358 
359 	die_on(pthread_create(&t->id, NULL, start_thread_helper, t) < 0,
360 	       "pthread_create(%s)", t->filename);
361 }
362 
363 static void join_thread(struct thread *t)
364 {
365 	int ret = pthread_join(t->id, NULL);
366 
367 	if (ret < 0)
368 		err("%s: joining thread", t->filename);
369 	else
370 		debug("%s: joined\n", t->filename);
371 }
372 
373 
374 static ssize_t read_wrap(struct thread *t, void *buf, size_t nbytes)
375 {
376 	return read(t->fd, buf, nbytes);
377 }
378 
379 static ssize_t write_wrap(struct thread *t, const void *buf, size_t nbytes)
380 {
381 	return write(t->fd, buf, nbytes);
382 }
383 
384 
385 /******************** Empty/Fill buffer routines ****************************/
386 
387 /* 0 -- stream of zeros, 1 -- i % 63, 2 -- pipe */
388 enum pattern { PAT_ZERO, PAT_SEQ, PAT_PIPE };
389 static enum pattern pattern;
390 
391 static ssize_t
392 fill_in_buf(struct thread *ignore, void *buf, size_t nbytes)
393 {
394 	size_t i;
395 	__u8 *p;
396 
397 	(void)ignore;
398 
399 	switch (pattern) {
400 	case PAT_ZERO:
401 		memset(buf, 0, nbytes);
402 		break;
403 
404 	case PAT_SEQ:
405 		for (p = buf, i = 0; i < nbytes; ++i, ++p)
406 			*p = i % 63;
407 		break;
408 
409 	case PAT_PIPE:
410 		return fread(buf, 1, nbytes, stdin);
411 	}
412 
413 	return nbytes;
414 }
415 
416 static ssize_t
417 empty_out_buf(struct thread *ignore, const void *buf, size_t nbytes)
418 {
419 	const __u8 *p;
420 	__u8 expected;
421 	ssize_t ret;
422 	size_t len;
423 
424 	(void)ignore;
425 
426 	switch (pattern) {
427 	case PAT_ZERO:
428 		expected = 0;
429 		for (p = buf, len = 0; len < nbytes; ++p, ++len)
430 			if (*p)
431 				goto invalid;
432 		break;
433 
434 	case PAT_SEQ:
435 		for (p = buf, len = 0; len < nbytes; ++p, ++len)
436 			if (*p != len % 63) {
437 				expected = len % 63;
438 				goto invalid;
439 			}
440 		break;
441 
442 	case PAT_PIPE:
443 		ret = fwrite(buf, nbytes, 1, stdout);
444 		if (ret > 0)
445 			fflush(stdout);
446 		break;
447 
448 invalid:
449 		err("bad OUT byte %zd, expected %02x got %02x\n",
450 		    len, expected, *p);
451 		for (p = buf, len = 0; len < nbytes; ++p, ++len) {
452 			if (0 == (len % 32))
453 				fprintf(stderr, "%4d:", len);
454 			fprintf(stderr, " %02x", *p);
455 			if (31 == (len % 32))
456 				fprintf(stderr, "\n");
457 		}
458 		fflush(stderr);
459 		errno = EILSEQ;
460 		return -1;
461 	}
462 
463 	return len;
464 }
465 
466 
467 /******************** Endpoints routines ************************************/
468 
469 static void handle_setup(const struct usb_ctrlrequest *setup)
470 {
471 	printf("bRequestType = %d\n", setup->bRequestType);
472 	printf("bRequest     = %d\n", setup->bRequest);
473 	printf("wValue       = %d\n", le16_to_cpu(setup->wValue));
474 	printf("wIndex       = %d\n", le16_to_cpu(setup->wIndex));
475 	printf("wLength      = %d\n", le16_to_cpu(setup->wLength));
476 }
477 
478 static ssize_t
479 ep0_consume(struct thread *ignore, const void *buf, size_t nbytes)
480 {
481 	static const char *const names[] = {
482 		[FUNCTIONFS_BIND] = "BIND",
483 		[FUNCTIONFS_UNBIND] = "UNBIND",
484 		[FUNCTIONFS_ENABLE] = "ENABLE",
485 		[FUNCTIONFS_DISABLE] = "DISABLE",
486 		[FUNCTIONFS_SETUP] = "SETUP",
487 		[FUNCTIONFS_SUSPEND] = "SUSPEND",
488 		[FUNCTIONFS_RESUME] = "RESUME",
489 	};
490 
491 	const struct usb_functionfs_event *event = buf;
492 	size_t n;
493 
494 	(void)ignore;
495 
496 	for (n = nbytes / sizeof *event; n; --n, ++event)
497 		switch (event->type) {
498 		case FUNCTIONFS_BIND:
499 		case FUNCTIONFS_UNBIND:
500 		case FUNCTIONFS_ENABLE:
501 		case FUNCTIONFS_DISABLE:
502 		case FUNCTIONFS_SETUP:
503 		case FUNCTIONFS_SUSPEND:
504 		case FUNCTIONFS_RESUME:
505 			printf("Event %s\n", names[event->type]);
506 			if (event->type == FUNCTIONFS_SETUP)
507 				handle_setup(&event->u.setup);
508 			break;
509 
510 		default:
511 			printf("Event %03u (unknown)\n", event->type);
512 		}
513 
514 	return nbytes;
515 }
516 
517 static void ep0_init(struct thread *t)
518 {
519 	ssize_t ret;
520 
521 	info("%s: writing descriptors\n", t->filename);
522 	ret = write(t->fd, &descriptors, sizeof descriptors);
523 	die_on(ret < 0, "%s: write: descriptors", t->filename);
524 
525 	info("%s: writing strings\n", t->filename);
526 	ret = write(t->fd, &strings, sizeof strings);
527 	die_on(ret < 0, "%s: write: strings", t->filename);
528 }
529 
530 
531 /******************** Main **************************************************/
532 
533 int main(void)
534 {
535 	unsigned i;
536 
537 	/* XXX TODO: Argument parsing missing */
538 
539 	init_thread(threads);
540 	ep0_init(threads);
541 
542 	for (i = 1; i < sizeof threads / sizeof *threads; ++i)
543 		init_thread(threads + i);
544 
545 	for (i = 1; i < sizeof threads / sizeof *threads; ++i)
546 		start_thread(threads + i);
547 
548 	start_thread_helper(threads);
549 
550 	for (i = 1; i < sizeof threads / sizeof *threads; ++i)
551 		join_thread(threads + i);
552 
553 	return 0;
554 }
555