root/tools/usb/ffs-aio-example/multibuff/device_app/aio_multibuff.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. display_event
  2. handle_ep0
  3. init_bufs
  4. delete_bufs
  5. main

   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 }

/* [<][>][^][v][top][bottom][index][help] */