aboutsummaryrefslogtreecommitdiffstats
path: root/tools/usb
diff options
context:
space:
mode:
authorRobert Baldyga <r.baldyga@samsung.com>2014-02-11 05:43:03 -0500
committerFelipe Balbi <balbi@ti.com>2014-05-14 10:23:24 -0400
commitb34e08d5c7062c19a3f582d23d5f649c79ff3409 (patch)
tree4d7674db849724848d2b4a7731b518dd8c5e4bb6 /tools/usb
parent60b6dbeffb8c253d1f80527b28611e5e236dec51 (diff)
tools: usb: aio example applications
This patch adds two example applications showing usage of Asynchronous I/O API of FunctionFS. First one (aio_simple) is simple example of bidirectional data transfer. Second one (aio_multibuff) shows multi-buffer data transfer, which may to be used in high performance applications. Both examples contains userspace applications for device and for host. It needs libaio library on the device, and libusb library on host. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'tools/usb')
-rw-r--r--tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c349
-rw-r--r--tools/usb/ffs-aio-example/multibuff/host_app/Makefile13
-rw-r--r--tools/usb/ffs-aio-example/multibuff/host_app/test.c146
-rw-r--r--tools/usb/ffs-aio-example/simple/device_app/aio_simple.c335
-rw-r--r--tools/usb/ffs-aio-example/simple/host_app/Makefile13
-rw-r--r--tools/usb/ffs-aio-example/simple/host_app/test.c148
6 files changed, 1004 insertions, 0 deletions
diff --git a/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
new file mode 100644
index 000000000000..87216a0c4a8b
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c
@@ -0,0 +1,349 @@
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
29static 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
91static 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
112struct 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
122static 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
145static 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
177void 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
192void 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
203int 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}
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/Makefile b/tools/usb/ffs-aio-example/multibuff/host_app/Makefile
new file mode 100644
index 000000000000..8c4a6f0aa82d
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/Makefile
@@ -0,0 +1,13 @@
1CC = gcc
2LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0)
3LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0)
4WARNINGS = -Wall -Wextra
5CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS)
6LDFLAGS = $(LIBUSB_LIBS)
7
8all: test
9%: %.c
10 $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
11
12clean:
13 $(RM) test
diff --git a/tools/usb/ffs-aio-example/multibuff/host_app/test.c b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
new file mode 100644
index 000000000000..b0ad8747d03f
--- /dev/null
+++ b/tools/usb/ffs-aio-example/multibuff/host_app/test.c
@@ -0,0 +1,146 @@
1#include <libusb.h>
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5
6#define VENDOR 0x1d6b
7#define PRODUCT 0x0105
8
9/* endpoints indexes */
10
11#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN)
12#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT)
13
14#define BUF_LEN 8192
15
16/*
17 * struct test_state - describes test program state
18 * @list: list of devices returned by libusb_get_device_list function
19 * @found: pointer to struct describing tested device
20 * @ctx: context, set to NULL
21 * @handle: handle of tested device
22 * @attached: indicates that device was attached to kernel, and has to be
23 * reattached at the end of test program
24 */
25
26struct test_state {
27 libusb_device *found;
28 libusb_context *ctx;
29 libusb_device_handle *handle;
30 int attached;
31};
32
33/*
34 * test_init - initialize test program
35 */
36
37int test_init(struct test_state *state)
38{
39 int i, ret;
40 ssize_t cnt;
41 libusb_device **list;
42
43 state->found = NULL;
44 state->ctx = NULL;
45 state->handle = NULL;
46 state->attached = 0;
47
48 ret = libusb_init(&state->ctx);
49 if (ret) {
50 printf("cannot init libusb: %s\n", libusb_error_name(ret));
51 return 1;
52 }
53
54 cnt = libusb_get_device_list(state->ctx, &list);
55 if (cnt <= 0) {
56 printf("no devices found\n");
57 goto error1;
58 }
59
60 for (i = 0; i < cnt; ++i) {
61 libusb_device *dev = list[i];
62 struct libusb_device_descriptor desc;
63 ret = libusb_get_device_descriptor(dev, &desc);
64 if (ret) {
65 printf("unable to get device descriptor: %s\n",
66 libusb_error_name(ret));
67 goto error2;
68 }
69 if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
70 state->found = dev;
71 break;
72 }
73 }
74
75 if (!state->found) {
76 printf("no devices found\n");
77 goto error2;
78 }
79
80 ret = libusb_open(state->found, &state->handle);
81 if (ret) {
82 printf("cannot open device: %s\n", libusb_error_name(ret));
83 goto error2;
84 }
85
86 if (libusb_claim_interface(state->handle, 0)) {
87 ret = libusb_detach_kernel_driver(state->handle, 0);
88 if (ret) {
89 printf("unable to detach kernel driver: %s\n",
90 libusb_error_name(ret));
91 goto error3;
92 }
93 state->attached = 1;
94 ret = libusb_claim_interface(state->handle, 0);
95 if (ret) {
96 printf("cannot claim interface: %s\n",
97 libusb_error_name(ret));
98 goto error4;
99 }
100 }
101
102 return 0;
103
104error4:
105 if (state->attached == 1)
106 libusb_attach_kernel_driver(state->handle, 0);
107
108error3:
109 libusb_close(state->handle);
110
111error2:
112 libusb_free_device_list(list, 1);
113
114error1:
115 libusb_exit(state->ctx);
116 return 1;
117}
118
119/*
120 * test_exit - cleanup test program
121 */
122
123void test_exit(struct test_state *state)
124{
125 libusb_release_interface(state->handle, 0);
126 if (state->attached == 1)
127 libusb_attach_kernel_driver(state->handle, 0);
128 libusb_close(state->handle);
129 libusb_exit(state->ctx);
130}
131
132int main(void)
133{
134 struct test_state state;
135
136 if (test_init(&state))
137 return 1;
138
139 while (1) {
140 static unsigned char buffer[BUF_LEN];
141 int bytes;
142 libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
143 &bytes, 500);
144 }
145 test_exit(&state);
146}
diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
new file mode 100644
index 000000000000..f558664a3317
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c
@@ -0,0 +1,335 @@
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
25/******************** Descriptors and Strings *******************************/
26
27static const struct {
28 struct usb_functionfs_descs_head header;
29 struct {
30 struct usb_interface_descriptor intf;
31 struct usb_endpoint_descriptor_no_audio bulk_sink;
32 struct usb_endpoint_descriptor_no_audio bulk_source;
33 } __attribute__ ((__packed__)) fs_descs, hs_descs;
34} __attribute__ ((__packed__)) descriptors = {
35 .header = {
36 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
37 .length = htole32(sizeof(descriptors)),
38 .fs_count = 3,
39 .hs_count = 3,
40 },
41 .fs_descs = {
42 .intf = {
43 .bLength = sizeof(descriptors.fs_descs.intf),
44 .bDescriptorType = USB_DT_INTERFACE,
45 .bNumEndpoints = 2,
46 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
47 .iInterface = 1,
48 },
49 .bulk_sink = {
50 .bLength = sizeof(descriptors.fs_descs.bulk_sink),
51 .bDescriptorType = USB_DT_ENDPOINT,
52 .bEndpointAddress = 1 | USB_DIR_IN,
53 .bmAttributes = USB_ENDPOINT_XFER_BULK,
54 },
55 .bulk_source = {
56 .bLength = sizeof(descriptors.fs_descs.bulk_source),
57 .bDescriptorType = USB_DT_ENDPOINT,
58 .bEndpointAddress = 2 | USB_DIR_OUT,
59 .bmAttributes = USB_ENDPOINT_XFER_BULK,
60 },
61 },
62 .hs_descs = {
63 .intf = {
64 .bLength = sizeof(descriptors.hs_descs.intf),
65 .bDescriptorType = USB_DT_INTERFACE,
66 .bNumEndpoints = 2,
67 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
68 .iInterface = 1,
69 },
70 .bulk_sink = {
71 .bLength = sizeof(descriptors.hs_descs.bulk_sink),
72 .bDescriptorType = USB_DT_ENDPOINT,
73 .bEndpointAddress = 1 | USB_DIR_IN,
74 .bmAttributes = USB_ENDPOINT_XFER_BULK,
75 },
76 .bulk_source = {
77 .bLength = sizeof(descriptors.hs_descs.bulk_source),
78 .bDescriptorType = USB_DT_ENDPOINT,
79 .bEndpointAddress = 2 | USB_DIR_OUT,
80 .bmAttributes = USB_ENDPOINT_XFER_BULK,
81 },
82 },
83};
84
85#define STR_INTERFACE "AIO Test"
86
87static const struct {
88 struct usb_functionfs_strings_head header;
89 struct {
90 __le16 code;
91 const char str1[sizeof(STR_INTERFACE)];
92 } __attribute__ ((__packed__)) lang0;
93} __attribute__ ((__packed__)) strings = {
94 .header = {
95 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
96 .length = htole32(sizeof(strings)),
97 .str_count = htole32(1),
98 .lang_count = htole32(1),
99 },
100 .lang0 = {
101 htole16(0x0409), /* en-us */
102 STR_INTERFACE,
103 },
104};
105
106/******************** Endpoints handling *******************************/
107
108static void display_event(struct usb_functionfs_event *event)
109{
110 static const char *const names[] = {
111 [FUNCTIONFS_BIND] = "BIND",
112 [FUNCTIONFS_UNBIND] = "UNBIND",
113 [FUNCTIONFS_ENABLE] = "ENABLE",
114 [FUNCTIONFS_DISABLE] = "DISABLE",
115 [FUNCTIONFS_SETUP] = "SETUP",
116 [FUNCTIONFS_SUSPEND] = "SUSPEND",
117 [FUNCTIONFS_RESUME] = "RESUME",
118 };
119 switch (event->type) {
120 case FUNCTIONFS_BIND:
121 case FUNCTIONFS_UNBIND:
122 case FUNCTIONFS_ENABLE:
123 case FUNCTIONFS_DISABLE:
124 case FUNCTIONFS_SETUP:
125 case FUNCTIONFS_SUSPEND:
126 case FUNCTIONFS_RESUME:
127 printf("Event %s\n", names[event->type]);
128 }
129}
130
131static void handle_ep0(int ep0, bool *ready)
132{
133 struct usb_functionfs_event event;
134 int ret;
135
136 struct pollfd pfds[1];
137 pfds[0].fd = ep0;
138 pfds[0].events = POLLIN;
139
140 ret = poll(pfds, 1, 0);
141
142 if (ret && (pfds[0].revents & POLLIN)) {
143 ret = read(ep0, &event, sizeof(event));
144 if (!ret) {
145 perror("unable to read event from ep0");
146 return;
147 }
148 display_event(&event);
149 switch (event.type) {
150 case FUNCTIONFS_SETUP:
151 if (event.u.setup.bRequestType & USB_DIR_IN)
152 write(ep0, NULL, 0);
153 else
154 read(ep0, NULL, 0);
155 break;
156
157 case FUNCTIONFS_ENABLE:
158 *ready = true;
159 break;
160
161 case FUNCTIONFS_DISABLE:
162 *ready = false;
163 break;
164
165 default:
166 break;
167 }
168 }
169}
170
171int main(int argc, char *argv[])
172{
173 int i, ret;
174 char *ep_path;
175
176 int ep0;
177 int ep[2];
178
179 io_context_t ctx;
180
181 int evfd;
182 fd_set rfds;
183
184 char *buf_in, *buf_out;
185 struct iocb *iocb_in, *iocb_out;
186 int req_in = 0, req_out = 0;
187 bool ready;
188
189 if (argc != 2) {
190 printf("ffs directory not specified!\n");
191 return 1;
192 }
193
194 ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
195 if (!ep_path) {
196 perror("malloc");
197 return 1;
198 }
199
200 /* open endpoint files */
201 sprintf(ep_path, "%s/ep0", argv[1]);
202 ep0 = open(ep_path, O_RDWR);
203 if (ep0 < 0) {
204 perror("unable to open ep0");
205 return 1;
206 }
207 if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
208 perror("unable do write descriptors");
209 return 1;
210 }
211 if (write(ep0, &strings, sizeof(strings)) < 0) {
212 perror("unable to write strings");
213 return 1;
214 }
215 for (i = 0; i < 2; ++i) {
216 sprintf(ep_path, "%s/ep%d", argv[1], i+1);
217 ep[i] = open(ep_path, O_RDWR);
218 if (ep[i] < 0) {
219 printf("unable to open ep%d: %s\n", i+1,
220 strerror(errno));
221 return 1;
222 }
223 }
224
225 free(ep_path);
226
227 memset(&ctx, 0, sizeof(ctx));
228 /* setup aio context to handle up to 2 requests */
229 if (io_setup(2, &ctx) < 0) {
230 perror("unable to setup aio");
231 return 1;
232 }
233
234 evfd = eventfd(0, 0);
235 if (evfd < 0) {
236 perror("unable to open eventfd");
237 return 1;
238 }
239
240 /* alloc buffers and requests */
241 buf_in = malloc(BUF_LEN);
242 buf_out = malloc(BUF_LEN);
243 iocb_in = malloc(sizeof(*iocb_in));
244 iocb_out = malloc(sizeof(*iocb_out));
245
246 while (1) {
247 FD_ZERO(&rfds);
248 FD_SET(ep0, &rfds);
249 FD_SET(evfd, &rfds);
250
251 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
252 &rfds, NULL, NULL, NULL);
253 if (ret < 0) {
254 if (errno == EINTR)
255 continue;
256 perror("select");
257 break;
258 }
259
260 if (FD_ISSET(ep0, &rfds))
261 handle_ep0(ep0, &ready);
262
263 /* we are waiting for function ENABLE */
264 if (!ready)
265 continue;
266
267 /* if something was submitted we wait for event */
268 if (FD_ISSET(evfd, &rfds)) {
269 uint64_t ev_cnt;
270 ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
271 if (ret < 0) {
272 perror("unable to read eventfd");
273 break;
274 }
275
276 struct io_event e[2];
277 /* we wait for one event */
278 ret = io_getevents(ctx, 1, 2, e, NULL);
279 /* if we got event */
280 for (i = 0; i < ret; ++i) {
281 if (e[i].obj->aio_fildes == ep[0]) {
282 printf("ev=in; ret=%lu\n", e[i].res);
283 req_in = 0;
284 } else if (e[i].obj->aio_fildes == ep[1]) {
285 printf("ev=out; ret=%lu\n", e[i].res);
286 req_out = 0;
287 }
288 }
289 }
290
291 if (!req_in) { /* if IN transfer not requested*/
292 /* prepare write request */
293 io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0);
294 /* enable eventfd notification */
295 iocb_in->u.c.flags |= IOCB_FLAG_RESFD;
296 iocb_in->u.c.resfd = evfd;
297 /* submit table of requests */
298 ret = io_submit(ctx, 1, &iocb_in);
299 if (ret >= 0) { /* if ret > 0 request is queued */
300 req_in = 1;
301 printf("submit: in\n");
302 } else
303 perror("unable to submit request");
304 }
305 if (!req_out) { /* if OUT transfer not requested */
306 /* prepare read request */
307 io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0);
308 /* enable eventfs notification */
309 iocb_out->u.c.flags |= IOCB_FLAG_RESFD;
310 iocb_out->u.c.resfd = evfd;
311 /* submit table of requests */
312 ret = io_submit(ctx, 1, &iocb_out);
313 if (ret >= 0) { /* if ret > 0 request is queued */
314 req_out = 1;
315 printf("submit: out\n");
316 } else
317 perror("unable to submit request");
318 }
319 }
320
321 /* free resources */
322
323 io_destroy(ctx);
324
325 free(buf_in);
326 free(buf_out);
327 free(iocb_in);
328 free(iocb_out);
329
330 for (i = 0; i < 2; ++i)
331 close(ep[i]);
332 close(ep0);
333
334 return 0;
335}
diff --git a/tools/usb/ffs-aio-example/simple/host_app/Makefile b/tools/usb/ffs-aio-example/simple/host_app/Makefile
new file mode 100644
index 000000000000..8c4a6f0aa82d
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/host_app/Makefile
@@ -0,0 +1,13 @@
1CC = gcc
2LIBUSB_CFLAGS = $(shell pkg-config --cflags libusb-1.0)
3LIBUSB_LIBS = $(shell pkg-config --libs libusb-1.0)
4WARNINGS = -Wall -Wextra
5CFLAGS = $(LIBUSB_CFLAGS) $(WARNINGS)
6LDFLAGS = $(LIBUSB_LIBS)
7
8all: test
9%: %.c
10 $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
11
12clean:
13 $(RM) test
diff --git a/tools/usb/ffs-aio-example/simple/host_app/test.c b/tools/usb/ffs-aio-example/simple/host_app/test.c
new file mode 100644
index 000000000000..64b6a57d8ca3
--- /dev/null
+++ b/tools/usb/ffs-aio-example/simple/host_app/test.c
@@ -0,0 +1,148 @@
1#include <libusb.h>
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5
6#define VENDOR 0x1d6b
7#define PRODUCT 0x0105
8
9/* endpoints indexes */
10
11#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN)
12#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT)
13
14#define BUF_LEN 8192
15
16/*
17 * struct test_state - describes test program state
18 * @list: list of devices returned by libusb_get_device_list function
19 * @found: pointer to struct describing tested device
20 * @ctx: context, set to NULL
21 * @handle: handle of tested device
22 * @attached: indicates that device was attached to kernel, and has to be
23 * reattached at the end of test program
24 */
25
26struct test_state {
27 libusb_device *found;
28 libusb_context *ctx;
29 libusb_device_handle *handle;
30 int attached;
31};
32
33/*
34 * test_init - initialize test program
35 */
36
37int test_init(struct test_state *state)
38{
39 int i, ret;
40 ssize_t cnt;
41 libusb_device **list;
42
43 state->found = NULL;
44 state->ctx = NULL;
45 state->handle = NULL;
46 state->attached = 0;
47
48 ret = libusb_init(&state->ctx);
49 if (ret) {
50 printf("cannot init libusb: %s\n", libusb_error_name(ret));
51 return 1;
52 }
53
54 cnt = libusb_get_device_list(state->ctx, &list);
55 if (cnt <= 0) {
56 printf("no devices found\n");
57 goto error1;
58 }
59
60 for (i = 0; i < cnt; ++i) {
61 libusb_device *dev = list[i];
62 struct libusb_device_descriptor desc;
63 ret = libusb_get_device_descriptor(dev, &desc);
64 if (ret) {
65 printf("unable to get device descriptor: %s\n",
66 libusb_error_name(ret));
67 goto error2;
68 }
69 if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT) {
70 state->found = dev;
71 break;
72 }
73 }
74
75 if (!state->found) {
76 printf("no devices found\n");
77 goto error2;
78 }
79
80 ret = libusb_open(state->found, &state->handle);
81 if (ret) {
82 printf("cannot open device: %s\n", libusb_error_name(ret));
83 goto error2;
84 }
85
86 if (libusb_claim_interface(state->handle, 0)) {
87 ret = libusb_detach_kernel_driver(state->handle, 0);
88 if (ret) {
89 printf("unable to detach kernel driver: %s\n",
90 libusb_error_name(ret));
91 goto error3;
92 }
93 state->attached = 1;
94 ret = libusb_claim_interface(state->handle, 0);
95 if (ret) {
96 printf("cannot claim interface: %s\n",
97 libusb_error_name(ret));
98 goto error4;
99 }
100 }
101
102 return 0;
103
104error4:
105 if (state->attached == 1)
106 libusb_attach_kernel_driver(state->handle, 0);
107
108error3:
109 libusb_close(state->handle);
110
111error2:
112 libusb_free_device_list(list, 1);
113
114error1:
115 libusb_exit(state->ctx);
116 return 1;
117}
118
119/*
120 * test_exit - cleanup test program
121 */
122
123void test_exit(struct test_state *state)
124{
125 libusb_release_interface(state->handle, 0);
126 if (state->attached == 1)
127 libusb_attach_kernel_driver(state->handle, 0);
128 libusb_close(state->handle);
129 libusb_exit(state->ctx);
130}
131
132int main(void)
133{
134 struct test_state state;
135
136 if (test_init(&state))
137 return 1;
138
139 while (1) {
140 static unsigned char buffer[BUF_LEN];
141 int bytes;
142 libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
143 &bytes, 500);
144 libusb_bulk_transfer(state.handle, EP_BULK_OUT, buffer, BUF_LEN,
145 &bytes, 500);
146 }
147 test_exit(&state);
148}