root/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c

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

DEFINITIONS

This source file includes following definitions.
  1. display_event
  2. handle_ep0
  3. 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 
  52 /******************** Descriptors and Strings *******************************/
  53 
  54 static const struct {
  55         struct usb_functionfs_descs_head_v2 header;
  56         __le32 fs_count;
  57         __le32 hs_count;
  58         struct {
  59                 struct usb_interface_descriptor intf;
  60                 struct usb_endpoint_descriptor_no_audio bulk_sink;
  61                 struct usb_endpoint_descriptor_no_audio bulk_source;
  62         } __attribute__ ((__packed__)) fs_descs, hs_descs;
  63 } __attribute__ ((__packed__)) descriptors = {
  64         .header = {
  65                 .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
  66                 .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
  67                                      FUNCTIONFS_HAS_HS_DESC),
  68                 .length = htole32(sizeof(descriptors)),
  69         },
  70         .fs_count = htole32(3),
  71         .fs_descs = {
  72                 .intf = {
  73                         .bLength = sizeof(descriptors.fs_descs.intf),
  74                         .bDescriptorType = USB_DT_INTERFACE,
  75                         .bNumEndpoints = 2,
  76                         .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
  77                         .iInterface = 1,
  78                 },
  79                 .bulk_sink = {
  80                         .bLength = sizeof(descriptors.fs_descs.bulk_sink),
  81                         .bDescriptorType = USB_DT_ENDPOINT,
  82                         .bEndpointAddress = 1 | USB_DIR_IN,
  83                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
  84                 },
  85                 .bulk_source = {
  86                         .bLength = sizeof(descriptors.fs_descs.bulk_source),
  87                         .bDescriptorType = USB_DT_ENDPOINT,
  88                         .bEndpointAddress = 2 | USB_DIR_OUT,
  89                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
  90                 },
  91         },
  92         .hs_count = htole32(3),
  93         .hs_descs = {
  94                 .intf = {
  95                         .bLength = sizeof(descriptors.hs_descs.intf),
  96                         .bDescriptorType = USB_DT_INTERFACE,
  97                         .bNumEndpoints = 2,
  98                         .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
  99                         .iInterface = 1,
 100                 },
 101                 .bulk_sink = {
 102                         .bLength = sizeof(descriptors.hs_descs.bulk_sink),
 103                         .bDescriptorType = USB_DT_ENDPOINT,
 104                         .bEndpointAddress = 1 | USB_DIR_IN,
 105                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
 106                         .wMaxPacketSize = htole16(512),
 107                 },
 108                 .bulk_source = {
 109                         .bLength = sizeof(descriptors.hs_descs.bulk_source),
 110                         .bDescriptorType = USB_DT_ENDPOINT,
 111                         .bEndpointAddress = 2 | USB_DIR_OUT,
 112                         .bmAttributes = USB_ENDPOINT_XFER_BULK,
 113                         .wMaxPacketSize = htole16(512),
 114                 },
 115         },
 116 };
 117 
 118 #define STR_INTERFACE "AIO Test"
 119 
 120 static const struct {
 121         struct usb_functionfs_strings_head header;
 122         struct {
 123                 __le16 code;
 124                 const char str1[sizeof(STR_INTERFACE)];
 125         } __attribute__ ((__packed__)) lang0;
 126 } __attribute__ ((__packed__)) strings = {
 127         .header = {
 128                 .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
 129                 .length = htole32(sizeof(strings)),
 130                 .str_count = htole32(1),
 131                 .lang_count = htole32(1),
 132         },
 133         .lang0 = {
 134                 htole16(0x0409), /* en-us */
 135                 STR_INTERFACE,
 136         },
 137 };
 138 
 139 /******************** Endpoints handling *******************************/
 140 
 141 static void display_event(struct usb_functionfs_event *event)
 142 {
 143         static const char *const names[] = {
 144                 [FUNCTIONFS_BIND] = "BIND",
 145                 [FUNCTIONFS_UNBIND] = "UNBIND",
 146                 [FUNCTIONFS_ENABLE] = "ENABLE",
 147                 [FUNCTIONFS_DISABLE] = "DISABLE",
 148                 [FUNCTIONFS_SETUP] = "SETUP",
 149                 [FUNCTIONFS_SUSPEND] = "SUSPEND",
 150                 [FUNCTIONFS_RESUME] = "RESUME",
 151         };
 152         switch (event->type) {
 153         case FUNCTIONFS_BIND:
 154         case FUNCTIONFS_UNBIND:
 155         case FUNCTIONFS_ENABLE:
 156         case FUNCTIONFS_DISABLE:
 157         case FUNCTIONFS_SETUP:
 158         case FUNCTIONFS_SUSPEND:
 159         case FUNCTIONFS_RESUME:
 160                 printf("Event %s\n", names[event->type]);
 161         }
 162 }
 163 
 164 static void handle_ep0(int ep0, bool *ready)
 165 {
 166         struct usb_functionfs_event event;
 167         int ret;
 168 
 169         struct pollfd pfds[1];
 170         pfds[0].fd = ep0;
 171         pfds[0].events = POLLIN;
 172 
 173         ret = poll(pfds, 1, 0);
 174 
 175         if (ret && (pfds[0].revents & POLLIN)) {
 176                 ret = read(ep0, &event, sizeof(event));
 177                 if (!ret) {
 178                         perror("unable to read event from ep0");
 179                         return;
 180                 }
 181                 display_event(&event);
 182                 switch (event.type) {
 183                 case FUNCTIONFS_SETUP:
 184                         if (event.u.setup.bRequestType & USB_DIR_IN)
 185                                 write(ep0, NULL, 0);
 186                         else
 187                                 read(ep0, NULL, 0);
 188                         break;
 189 
 190                 case FUNCTIONFS_ENABLE:
 191                         *ready = true;
 192                         break;
 193 
 194                 case FUNCTIONFS_DISABLE:
 195                         *ready = false;
 196                         break;
 197 
 198                 default:
 199                         break;
 200                 }
 201         }
 202 }
 203 
 204 int main(int argc, char *argv[])
 205 {
 206         int i, ret;
 207         char *ep_path;
 208 
 209         int ep0;
 210         int ep[2];
 211 
 212         io_context_t ctx;
 213 
 214         int evfd;
 215         fd_set rfds;
 216 
 217         char *buf_in, *buf_out;
 218         struct iocb *iocb_in, *iocb_out;
 219         int req_in = 0, req_out = 0;
 220         bool ready;
 221 
 222         if (argc != 2) {
 223                 printf("ffs directory not specified!\n");
 224                 return 1;
 225         }
 226 
 227         ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
 228         if (!ep_path) {
 229                 perror("malloc");
 230                 return 1;
 231         }
 232 
 233         /* open endpoint files */
 234         sprintf(ep_path, "%s/ep0", argv[1]);
 235         ep0 = open(ep_path, O_RDWR);
 236         if (ep0 < 0) {
 237                 perror("unable to open ep0");
 238                 return 1;
 239         }
 240         if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
 241                 perror("unable do write descriptors");
 242                 return 1;
 243         }
 244         if (write(ep0, &strings, sizeof(strings)) < 0) {
 245                 perror("unable to write strings");
 246                 return 1;
 247         }
 248         for (i = 0; i < 2; ++i) {
 249                 sprintf(ep_path, "%s/ep%d", argv[1], i+1);
 250                 ep[i] = open(ep_path, O_RDWR);
 251                 if (ep[i] < 0) {
 252                         printf("unable to open ep%d: %s\n", i+1,
 253                                strerror(errno));
 254                         return 1;
 255                 }
 256         }
 257 
 258         free(ep_path);
 259 
 260         memset(&ctx, 0, sizeof(ctx));
 261         /* setup aio context to handle up to 2 requests */
 262         if (io_setup(2, &ctx) < 0) {
 263                 perror("unable to setup aio");
 264                 return 1;
 265         }
 266 
 267         evfd = eventfd(0, 0);
 268         if (evfd < 0) {
 269                 perror("unable to open eventfd");
 270                 return 1;
 271         }
 272 
 273         /* alloc buffers and requests */
 274         buf_in = malloc(BUF_LEN);
 275         buf_out = malloc(BUF_LEN);
 276         iocb_in = malloc(sizeof(*iocb_in));
 277         iocb_out = malloc(sizeof(*iocb_out));
 278 
 279         while (1) {
 280                 FD_ZERO(&rfds);
 281                 FD_SET(ep0, &rfds);
 282                 FD_SET(evfd, &rfds);
 283 
 284                 ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
 285                              &rfds, NULL, NULL, NULL);
 286                 if (ret < 0) {
 287                         if (errno == EINTR)
 288                                 continue;
 289                         perror("select");
 290                         break;
 291                 }
 292 
 293                 if (FD_ISSET(ep0, &rfds))
 294                         handle_ep0(ep0, &ready);
 295 
 296                 /* we are waiting for function ENABLE */
 297                 if (!ready)
 298                         continue;
 299 
 300                 /* if something was submitted we wait for event */
 301                 if (FD_ISSET(evfd, &rfds)) {
 302                         uint64_t ev_cnt;
 303                         ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
 304                         if (ret < 0) {
 305                                 perror("unable to read eventfd");
 306                                 break;
 307                         }
 308 
 309                         struct io_event e[2];
 310                         /* we wait for one event */
 311                         ret = io_getevents(ctx, 1, 2, e, NULL);
 312                         /* if we got event */
 313                         for (i = 0; i < ret; ++i) {
 314                                 if (e[i].obj->aio_fildes == ep[0]) {
 315                                         printf("ev=in; ret=%lu\n", e[i].res);
 316                                         req_in = 0;
 317                                 } else if (e[i].obj->aio_fildes == ep[1]) {
 318                                         printf("ev=out; ret=%lu\n", e[i].res);
 319                                         req_out = 0;
 320                                 }
 321                         }
 322                 }
 323 
 324                 if (!req_in) { /* if IN transfer not requested*/
 325                         /* prepare write request */
 326                         io_prep_pwrite(iocb_in, ep[0], buf_in, BUF_LEN, 0);
 327                         /* enable eventfd notification */
 328                         iocb_in->u.c.flags |= IOCB_FLAG_RESFD;
 329                         iocb_in->u.c.resfd = evfd;
 330                         /* submit table of requests */
 331                         ret = io_submit(ctx, 1, &iocb_in);
 332                         if (ret >= 0) { /* if ret > 0 request is queued */
 333                                 req_in = 1;
 334                                 printf("submit: in\n");
 335                         } else
 336                                 perror("unable to submit request");
 337                 }
 338                 if (!req_out) { /* if OUT transfer not requested */
 339                         /* prepare read request */
 340                         io_prep_pread(iocb_out, ep[1], buf_out, BUF_LEN, 0);
 341                         /* enable eventfs notification */
 342                         iocb_out->u.c.flags |= IOCB_FLAG_RESFD;
 343                         iocb_out->u.c.resfd = evfd;
 344                         /* submit table of requests */
 345                         ret = io_submit(ctx, 1, &iocb_out);
 346                         if (ret >= 0) { /* if ret > 0 request is queued */
 347                                 req_out = 1;
 348                                 printf("submit: out\n");
 349                         } else
 350                                 perror("unable to submit request");
 351                 }
 352         }
 353 
 354         /* free resources */
 355 
 356         io_destroy(ctx);
 357 
 358         free(buf_in);
 359         free(buf_out);
 360         free(iocb_in);
 361         free(iocb_out);
 362 
 363         for (i = 0; i < 2; ++i)
 364                 close(ep[i]);
 365         close(ep0);
 366 
 367         return 0;
 368 }

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