~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * This is free and unencumbered software released into the public domain.
  3  *
  4  * Anyone is free to copy, modify, publish, use, compile, sell, or
  5  * distribute this software, either in source code form or as a compiled
  6  * binary, for any purpose, commercial or non-commercial, and by any
  7  * means.
  8  *
  9  * In jurisdictions that recognize copyright laws, the author or authors
 10  * of this software dedicate any and all copyright interest in the
 11  * software to the public domain. We make this dedication for the benefit
 12  * of the public at large and to the detriment of our heirs and
 13  * successors. We intend this dedication to be an overt act of
 14  * relinquishment in perpetuity of all present and future rights to this
 15  * software under copyright law.
 16  *
 17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 23  * OTHER DEALINGS IN THE SOFTWARE.
 24  *
 25  * For more information, please refer to <http://unlicense.org/>
 26  */
 27 
 28 #define _BSD_SOURCE /* for endian.h */
 29 
 30 #include <endian.h>
 31 #include <errno.h>
 32 #include <fcntl.h>
 33 #include <stdarg.h>
 34 #include <stdio.h>
 35 #include <stdlib.h>
 36 #include <string.h>
 37 #include <sys/ioctl.h>
 38 #include <sys/stat.h>
 39 #include <sys/types.h>
 40 #include <sys/poll.h>
 41 #include <unistd.h>
 42 #include <stdbool.h>
 43 #include <sys/eventfd.h>
 44 
 45 #include "libaio.h"
 46 #define IOCB_FLAG_RESFD         (1 << 0)
 47 
 48 #include <linux/usb/functionfs.h>
 49 
 50 #define BUF_LEN         8192
 51 #define BUFS_MAX        128
 52 #define AIO_MAX         (BUFS_MAX*2)
 53 
 54 /******************** Descriptors and Strings *******************************/
 55 
 56 static const struct {
 57         struct usb_functionfs_descs_head_v2 header;
 58         __le32 fs_count;
 59         __le32 hs_count;
 60         struct {
 61                 struct usb_interface_descriptor intf;
 62                 struct usb_endpoint_descriptor_no_audio bulk_sink;
 63                 struct usb_endpoint_descriptor_no_audio bulk_source;
 64         } __attribute__ ((__packed__)) fs_descs, hs_descs;
 65 } __attribute__ ((__packed__)) descriptors = {
 66         .header = {
 67                 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
 68                 .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
 69                                      FUNCTIONFS_HAS_HS_DESC),
 70                 .length = htole32(sizeof(descriptors)),
 71         },
 72         .fs_count = htole32(3),
 73         .fs_descs = {
 74                 .intf = {
 75                         .bLength = sizeof(descriptors.fs_descs.intf),
 76                         .bDescriptorType = USB_DT_INTERFACE,
 77                         .bNumEndpoints = 2,
 78                         .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
 79                         .iInterface = 1,
 80                 },
 81                 .bulk_sink = {
 82                         .bLength = sizeof(descriptors.fs_descs.bulk_sink),
 83                         .bDescriptorType = USB_DT_ENDPOINT,
 84                         .bEndpointAddress = 1 | USB_DIR_IN,
 85                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
 86                 },
 87                 .bulk_source = {
 88                         .bLength = sizeof(descriptors.fs_descs.bulk_source),
 89                         .bDescriptorType = USB_DT_ENDPOINT,
 90                         .bEndpointAddress = 2 | USB_DIR_OUT,
 91                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
 92                 },
 93         },
 94         .hs_count = htole32(3),
 95         .hs_descs = {
 96                 .intf = {
 97                         .bLength = sizeof(descriptors.hs_descs.intf),
 98                         .bDescriptorType = USB_DT_INTERFACE,
 99                         .bNumEndpoints = 2,
100                         .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
101                         .iInterface = 1,
102                 },
103                 .bulk_sink = {
104                         .bLength = sizeof(descriptors.hs_descs.bulk_sink),
105                         .bDescriptorType = USB_DT_ENDPOINT,
106                         .bEndpointAddress = 1 | USB_DIR_IN,
107                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
108                         .wMaxPacketSize = htole16(512),
109                 },
110                 .bulk_source = {
111                         .bLength = sizeof(descriptors.hs_descs.bulk_source),
112                         .bDescriptorType = USB_DT_ENDPOINT,
113                         .bEndpointAddress = 2 | USB_DIR_OUT,
114                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
115                         .wMaxPacketSize = htole16(512),
116                 },
117         },
118 };
119 
120 #define STR_INTERFACE "AIO Test"
121 
122 static const struct {
123         struct usb_functionfs_strings_head header;
124         struct {
125                 __le16 code;
126                 const char str1[sizeof(STR_INTERFACE)];
127         } __attribute__ ((__packed__)) lang0;
128 } __attribute__ ((__packed__)) strings = {
129         .header = {
130                 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
131                 .length = htole32(sizeof(strings)),
132                 .str_count = htole32(1),
133                 .lang_count = htole32(1),
134         },
135         .lang0 = {
136                 htole16(0x0409), /* en-us */
137                 STR_INTERFACE,
138         },
139 };
140 
141 /********************** Buffer structure *******************************/
142 
143 struct io_buffer {
144         struct iocb **iocb;
145         unsigned char **buf;
146         unsigned cnt;
147         unsigned len;
148         unsigned requested;
149 };
150 
151 /******************** Endpoints handling *******************************/
152 
153 static void display_event(struct usb_functionfs_event *event)
154 {
155         static const char *const names[] = {
156                 [FUNCTIONFS_BIND] = "BIND",
157                 [FUNCTIONFS_UNBIND] = "UNBIND",
158                 [FUNCTIONFS_ENABLE] = "ENABLE",
159                 [FUNCTIONFS_DISABLE] = "DISABLE",
160                 [FUNCTIONFS_SETUP] = "SETUP",
161                 [FUNCTIONFS_SUSPEND] = "SUSPEND",
162                 [FUNCTIONFS_RESUME] = "RESUME",
163         };
164         switch (event->type) {
165         case FUNCTIONFS_BIND:
166         case FUNCTIONFS_UNBIND:
167         case FUNCTIONFS_ENABLE:
168         case FUNCTIONFS_DISABLE:
169         case FUNCTIONFS_SETUP:
170         case FUNCTIONFS_SUSPEND:
171         case FUNCTIONFS_RESUME:
172                 printf("Event %s\n", names[event->type]);
173         }
174 }
175 
176 static void handle_ep0(int ep0, bool *ready)
177 {
178         int ret;
179         struct usb_functionfs_event event;
180 
181         ret = read(ep0, &event, sizeof(event));
182         if (!ret) {
183                 perror("unable to read event from ep0");
184                 return;
185         }
186         display_event(&event);
187         switch (event.type) {
188         case FUNCTIONFS_SETUP:
189                 if (event.u.setup.bRequestType & USB_DIR_IN)
190                         write(ep0, NULL, 0);
191                 else
192                         read(ep0, NULL, 0);
193                 break;
194 
195         case FUNCTIONFS_ENABLE:
196                 *ready = true;
197                 break;
198 
199         case FUNCTIONFS_DISABLE:
200                 *ready = false;
201                 break;
202 
203         default:
204                 break;
205         }
206 }
207 
208 void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
209 {
210         unsigned i;
211         iobuf->buf = malloc(n*sizeof(*iobuf->buf));
212         iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
213         iobuf->cnt = n;
214         iobuf->len = len;
215         iobuf->requested = 0;
216         for (i = 0; i < n; ++i) {
217                 iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
218                 iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
219         }
220         iobuf->cnt = n;
221 }
222 
223 void delete_bufs(struct io_buffer *iobuf)
224 {
225         unsigned i;
226         for (i = 0; i < iobuf->cnt; ++i) {
227                 free(iobuf->buf[i]);
228                 free(iobuf->iocb[i]);
229         }
230         free(iobuf->buf);
231         free(iobuf->iocb);
232 }
233 
234 int main(int argc, char *argv[])
235 {
236         int ret;
237         unsigned i, j;
238         char *ep_path;
239 
240         int ep0, ep1;
241 
242         io_context_t ctx;
243 
244         int evfd;
245         fd_set rfds;
246 
247         struct io_buffer iobuf[2];
248         int actual = 0;
249         bool ready;
250 
251         if (argc != 2) {
252                 printf("ffs directory not specified!\n");
253                 return 1;
254         }
255 
256         ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
257         if (!ep_path) {
258                 perror("malloc");
259                 return 1;
260         }
261 
262         /* open endpoint files */
263         sprintf(ep_path, "%s/ep0", argv[1]);
264         ep0 = open(ep_path, O_RDWR);
265         if (ep0 < 0) {
266                 perror("unable to open ep0");
267                 return 1;
268         }
269         if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
270                 perror("unable do write descriptors");
271                 return 1;
272         }
273         if (write(ep0, &strings, sizeof(strings)) < 0) {
274                 perror("unable to write strings");
275                 return 1;
276         }
277         sprintf(ep_path, "%s/ep1", argv[1]);
278         ep1 = open(ep_path, O_RDWR);
279         if (ep1 < 0) {
280                 perror("unable to open ep1");
281                 return 1;
282         }
283 
284         free(ep_path);
285 
286         memset(&ctx, 0, sizeof(ctx));
287         /* setup aio context to handle up to AIO_MAX requests */
288         if (io_setup(AIO_MAX, &ctx) < 0) {
289                 perror("unable to setup aio");
290                 return 1;
291         }
292 
293         evfd = eventfd(0, 0);
294         if (evfd < 0) {
295                 perror("unable to open eventfd");
296                 return 1;
297         }
298 
299         for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
300                 init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
301 
302         while (1) {
303                 FD_ZERO(&rfds);
304                 FD_SET(ep0, &rfds);
305                 FD_SET(evfd, &rfds);
306 
307                 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
308                              &rfds, NULL, NULL, NULL);
309                 if (ret < 0) {
310                         if (errno == EINTR)
311                                 continue;
312                         perror("select");
313                         break;
314                 }
315 
316                 if (FD_ISSET(ep0, &rfds))
317                         handle_ep0(ep0, &ready);
318 
319                 /* we are waiting for function ENABLE */
320                 if (!ready)
321                         continue;
322 
323                 /*
324                  * when we're preparing new data to submit,
325                  * second buffer being transmitted
326                  */
327                 for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
328                         if (iobuf[i].requested)
329                                 continue;
330                         /* prepare requests */
331                         for (j = 0; j < iobuf[i].cnt; ++j) {
332                                 io_prep_pwrite(iobuf[i].iocb[j], ep1,
333                                                iobuf[i].buf[j],
334                                                iobuf[i].len, 0);
335                                 /* enable eventfd notification */
336                                 iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
337                                 iobuf[i].iocb[j]->u.c.resfd = evfd;
338                         }
339                         /* submit table of requests */
340                         ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
341                         if (ret >= 0) {
342                                 iobuf[i].requested = ret;
343                                 printf("submit: %d requests buf: %d\n", ret, i);
344                         } else
345                                 perror("unable to submit requests");
346                 }
347 
348                 /* if event is ready to read */
349                 if (!FD_ISSET(evfd, &rfds))
350                         continue;
351 
352                 uint64_t ev_cnt;
353                 ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
354                 if (ret < 0) {
355                         perror("unable to read eventfd");
356                         break;
357                 }
358 
359                 struct io_event e[BUFS_MAX];
360                 /* we read aio events */
361                 ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
362                 if (ret > 0) /* if we got events */
363                         iobuf[actual].requested -= ret;
364 
365                 /* if all req's from iocb completed */
366                 if (!iobuf[actual].requested)
367                         actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
368         }
369 
370         /* free resources */
371 
372         for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
373                 delete_bufs(&iobuf[i]);
374         io_destroy(ctx);
375 
376         close(ep1);
377         close(ep0);
378 
379         return 0;
380 }
381 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php