aio_simple.c 9.5 KB

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