aio_multibuff.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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. #define _BSD_SOURCE /* for endian.h */
  28. #include <endian.h>
  29. #include <errno.h>
  30. #include <fcntl.h>
  31. #include <stdarg.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sys/ioctl.h>
  36. #include <sys/stat.h>
  37. #include <sys/types.h>
  38. #include <sys/poll.h>
  39. #include <unistd.h>
  40. #include <stdbool.h>
  41. #include <sys/eventfd.h>
  42. #include "libaio.h"
  43. #define IOCB_FLAG_RESFD (1 << 0)
  44. #include <linux/usb/functionfs.h>
  45. #define BUF_LEN 8192
  46. #define BUFS_MAX 128
  47. #define AIO_MAX (BUFS_MAX*2)
  48. /******************** Descriptors and Strings *******************************/
  49. static const struct {
  50. struct usb_functionfs_descs_head_v2 header;
  51. __le32 fs_count;
  52. __le32 hs_count;
  53. struct {
  54. struct usb_interface_descriptor intf;
  55. struct usb_endpoint_descriptor_no_audio bulk_sink;
  56. struct usb_endpoint_descriptor_no_audio bulk_source;
  57. } __attribute__ ((__packed__)) fs_descs, hs_descs;
  58. } __attribute__ ((__packed__)) descriptors = {
  59. .header = {
  60. .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
  61. .flags = htole32(FUNCTIONFS_HAS_FS_DESC |
  62. FUNCTIONFS_HAS_HS_DESC),
  63. .length = htole32(sizeof(descriptors)),
  64. },
  65. .fs_count = htole32(3),
  66. .fs_descs = {
  67. .intf = {
  68. .bLength = sizeof(descriptors.fs_descs.intf),
  69. .bDescriptorType = USB_DT_INTERFACE,
  70. .bNumEndpoints = 2,
  71. .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
  72. .iInterface = 1,
  73. },
  74. .bulk_sink = {
  75. .bLength = sizeof(descriptors.fs_descs.bulk_sink),
  76. .bDescriptorType = USB_DT_ENDPOINT,
  77. .bEndpointAddress = 1 | USB_DIR_IN,
  78. .bmAttributes = USB_ENDPOINT_XFER_BULK,
  79. },
  80. .bulk_source = {
  81. .bLength = sizeof(descriptors.fs_descs.bulk_source),
  82. .bDescriptorType = USB_DT_ENDPOINT,
  83. .bEndpointAddress = 2 | USB_DIR_OUT,
  84. .bmAttributes = USB_ENDPOINT_XFER_BULK,
  85. },
  86. },
  87. .hs_count = htole32(3),
  88. .hs_descs = {
  89. .intf = {
  90. .bLength = sizeof(descriptors.hs_descs.intf),
  91. .bDescriptorType = USB_DT_INTERFACE,
  92. .bNumEndpoints = 2,
  93. .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
  94. .iInterface = 1,
  95. },
  96. .bulk_sink = {
  97. .bLength = sizeof(descriptors.hs_descs.bulk_sink),
  98. .bDescriptorType = USB_DT_ENDPOINT,
  99. .bEndpointAddress = 1 | USB_DIR_IN,
  100. .bmAttributes = USB_ENDPOINT_XFER_BULK,
  101. .wMaxPacketSize = htole16(512),
  102. },
  103. .bulk_source = {
  104. .bLength = sizeof(descriptors.hs_descs.bulk_source),
  105. .bDescriptorType = USB_DT_ENDPOINT,
  106. .bEndpointAddress = 2 | USB_DIR_OUT,
  107. .bmAttributes = USB_ENDPOINT_XFER_BULK,
  108. .wMaxPacketSize = htole16(512),
  109. },
  110. },
  111. };
  112. #define STR_INTERFACE "AIO Test"
  113. static const struct {
  114. struct usb_functionfs_strings_head header;
  115. struct {
  116. __le16 code;
  117. const char str1[sizeof(STR_INTERFACE)];
  118. } __attribute__ ((__packed__)) lang0;
  119. } __attribute__ ((__packed__)) strings = {
  120. .header = {
  121. .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
  122. .length = htole32(sizeof(strings)),
  123. .str_count = htole32(1),
  124. .lang_count = htole32(1),
  125. },
  126. .lang0 = {
  127. htole16(0x0409), /* en-us */
  128. STR_INTERFACE,
  129. },
  130. };
  131. /********************** Buffer structure *******************************/
  132. struct io_buffer {
  133. struct iocb **iocb;
  134. unsigned char **buf;
  135. unsigned cnt;
  136. unsigned len;
  137. unsigned requested;
  138. };
  139. /******************** Endpoints handling *******************************/
  140. static void display_event(struct usb_functionfs_event *event)
  141. {
  142. static const char *const names[] = {
  143. [FUNCTIONFS_BIND] = "BIND",
  144. [FUNCTIONFS_UNBIND] = "UNBIND",
  145. [FUNCTIONFS_ENABLE] = "ENABLE",
  146. [FUNCTIONFS_DISABLE] = "DISABLE",
  147. [FUNCTIONFS_SETUP] = "SETUP",
  148. [FUNCTIONFS_SUSPEND] = "SUSPEND",
  149. [FUNCTIONFS_RESUME] = "RESUME",
  150. };
  151. switch (event->type) {
  152. case FUNCTIONFS_BIND:
  153. case FUNCTIONFS_UNBIND:
  154. case FUNCTIONFS_ENABLE:
  155. case FUNCTIONFS_DISABLE:
  156. case FUNCTIONFS_SETUP:
  157. case FUNCTIONFS_SUSPEND:
  158. case FUNCTIONFS_RESUME:
  159. printf("Event %s\n", names[event->type]);
  160. }
  161. }
  162. static void handle_ep0(int ep0, bool *ready)
  163. {
  164. int ret;
  165. struct usb_functionfs_event event;
  166. ret = read(ep0, &event, sizeof(event));
  167. if (!ret) {
  168. perror("unable to read event from ep0");
  169. return;
  170. }
  171. display_event(&event);
  172. switch (event.type) {
  173. case FUNCTIONFS_SETUP:
  174. if (event.u.setup.bRequestType & USB_DIR_IN)
  175. write(ep0, NULL, 0);
  176. else
  177. read(ep0, NULL, 0);
  178. break;
  179. case FUNCTIONFS_ENABLE:
  180. *ready = true;
  181. break;
  182. case FUNCTIONFS_DISABLE:
  183. *ready = false;
  184. break;
  185. default:
  186. break;
  187. }
  188. }
  189. void init_bufs(struct io_buffer *iobuf, unsigned n, unsigned len)
  190. {
  191. unsigned i;
  192. iobuf->buf = malloc(n*sizeof(*iobuf->buf));
  193. iobuf->iocb = malloc(n*sizeof(*iobuf->iocb));
  194. iobuf->cnt = n;
  195. iobuf->len = len;
  196. iobuf->requested = 0;
  197. for (i = 0; i < n; ++i) {
  198. iobuf->buf[i] = malloc(len*sizeof(**iobuf->buf));
  199. iobuf->iocb[i] = malloc(sizeof(**iobuf->iocb));
  200. }
  201. iobuf->cnt = n;
  202. }
  203. void delete_bufs(struct io_buffer *iobuf)
  204. {
  205. unsigned i;
  206. for (i = 0; i < iobuf->cnt; ++i) {
  207. free(iobuf->buf[i]);
  208. free(iobuf->iocb[i]);
  209. }
  210. free(iobuf->buf);
  211. free(iobuf->iocb);
  212. }
  213. int main(int argc, char *argv[])
  214. {
  215. int ret;
  216. unsigned i, j;
  217. char *ep_path;
  218. int ep0, ep1;
  219. io_context_t ctx;
  220. int evfd;
  221. fd_set rfds;
  222. struct io_buffer iobuf[2];
  223. int actual = 0;
  224. bool ready;
  225. if (argc != 2) {
  226. printf("ffs directory not specified!\n");
  227. return 1;
  228. }
  229. ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
  230. if (!ep_path) {
  231. perror("malloc");
  232. return 1;
  233. }
  234. /* open endpoint files */
  235. sprintf(ep_path, "%s/ep0", argv[1]);
  236. ep0 = open(ep_path, O_RDWR);
  237. if (ep0 < 0) {
  238. perror("unable to open ep0");
  239. return 1;
  240. }
  241. if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
  242. perror("unable do write descriptors");
  243. return 1;
  244. }
  245. if (write(ep0, &strings, sizeof(strings)) < 0) {
  246. perror("unable to write strings");
  247. return 1;
  248. }
  249. sprintf(ep_path, "%s/ep1", argv[1]);
  250. ep1 = open(ep_path, O_RDWR);
  251. if (ep1 < 0) {
  252. perror("unable to open ep1");
  253. return 1;
  254. }
  255. free(ep_path);
  256. memset(&ctx, 0, sizeof(ctx));
  257. /* setup aio context to handle up to AIO_MAX requests */
  258. if (io_setup(AIO_MAX, &ctx) < 0) {
  259. perror("unable to setup aio");
  260. return 1;
  261. }
  262. evfd = eventfd(0, 0);
  263. if (evfd < 0) {
  264. perror("unable to open eventfd");
  265. return 1;
  266. }
  267. for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
  268. init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
  269. while (1) {
  270. FD_ZERO(&rfds);
  271. FD_SET(ep0, &rfds);
  272. FD_SET(evfd, &rfds);
  273. ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
  274. &rfds, NULL, NULL, NULL);
  275. if (ret < 0) {
  276. if (errno == EINTR)
  277. continue;
  278. perror("select");
  279. break;
  280. }
  281. if (FD_ISSET(ep0, &rfds))
  282. handle_ep0(ep0, &ready);
  283. /* we are waiting for function ENABLE */
  284. if (!ready)
  285. continue;
  286. /*
  287. * when we're preparing new data to submit,
  288. * second buffer being transmitted
  289. */
  290. for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
  291. if (iobuf[i].requested)
  292. continue;
  293. /* prepare requests */
  294. for (j = 0; j < iobuf[i].cnt; ++j) {
  295. io_prep_pwrite(iobuf[i].iocb[j], ep1,
  296. iobuf[i].buf[j],
  297. iobuf[i].len, 0);
  298. /* enable eventfd notification */
  299. iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
  300. iobuf[i].iocb[j]->u.c.resfd = evfd;
  301. }
  302. /* submit table of requests */
  303. ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
  304. if (ret >= 0) {
  305. iobuf[i].requested = ret;
  306. printf("submit: %d requests buf: %d\n", ret, i);
  307. } else
  308. perror("unable to submit requests");
  309. }
  310. /* if event is ready to read */
  311. if (!FD_ISSET(evfd, &rfds))
  312. continue;
  313. uint64_t ev_cnt;
  314. ret = read(evfd, &ev_cnt, sizeof(ev_cnt));
  315. if (ret < 0) {
  316. perror("unable to read eventfd");
  317. break;
  318. }
  319. struct io_event e[BUFS_MAX];
  320. /* we read aio events */
  321. ret = io_getevents(ctx, 1, BUFS_MAX, e, NULL);
  322. if (ret > 0) /* if we got events */
  323. iobuf[actual].requested -= ret;
  324. /* if all req's from iocb completed */
  325. if (!iobuf[actual].requested)
  326. actual = (actual + 1)%(sizeof(iobuf)/sizeof(*iobuf));
  327. }
  328. /* free resources */
  329. for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
  330. delete_bufs(&iobuf[i]);
  331. io_destroy(ctx);
  332. close(ep1);
  333. close(ep0);
  334. return 0;
  335. }