aio_multibuff.c 7.7 KB

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