aboutsummaryrefslogtreecommitdiffstats
path: root/tools/usb
diff options
context:
space:
mode:
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}