diff options
| author | Robert Baldyga <r.baldyga@samsung.com> | 2014-02-11 05:43:03 -0500 |
|---|---|---|
| committer | Felipe Balbi <balbi@ti.com> | 2014-05-14 10:23:24 -0400 |
| commit | b34e08d5c7062c19a3f582d23d5f649c79ff3409 (patch) | |
| tree | 4d7674db849724848d2b4a7731b518dd8c5e4bb6 /tools/usb/ffs-aio-example/simple/device_app | |
| parent | 60b6dbeffb8c253d1f80527b28611e5e236dec51 (diff) | |
tools: usb: aio example applications
This patch adds two example applications showing usage of Asynchronous I/O API
of FunctionFS. First one (aio_simple) is simple example of bidirectional data
transfer. Second one (aio_multibuff) shows multi-buffer data transfer, which
may to be used in high performance applications.
Both examples contains userspace applications for device and for host.
It needs libaio library on the device, and libusb library on host.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'tools/usb/ffs-aio-example/simple/device_app')
| -rw-r--r-- | tools/usb/ffs-aio-example/simple/device_app/aio_simple.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c new file mode 100644 index 000000000000..f558664a3317 --- /dev/null +++ b/tools/usb/ffs-aio-example/simple/device_app/aio_simple.c | |||
| @@ -0,0 +1,335 @@ | |||
| 1 | #define _BSD_SOURCE /* for endian.h */ | ||
| 2 | |||
| 3 | #include <endian.h> | ||
| 4 | #include <errno.h> | ||
| 5 | #include <fcntl.h> | ||
| 6 | #include <stdarg.h> | ||
| 7 | #include <stdio.h> | ||
| 8 | #include <stdlib.h> | ||
| 9 | #include <string.h> | ||
| 10 | #include <sys/ioctl.h> | ||
| 11 | #include <sys/stat.h> | ||
| 12 | #include <sys/types.h> | ||
| 13 | #include <sys/poll.h> | ||
| 14 | #include <unistd.h> | ||
| 15 | #include <stdbool.h> | ||
| 16 | #include <sys/eventfd.h> | ||
| 17 | |||
| 18 | #include "libaio.h" | ||
| 19 | #define IOCB_FLAG_RESFD (1 << 0) | ||
| 20 | |||
| 21 | #include <linux/usb/functionfs.h> | ||
| 22 | |||
| 23 | #define BUF_LEN 8192 | ||
| 24 | |||
| 25 | /******************** Descriptors and Strings *******************************/ | ||
| 26 | |||
| 27 | static const struct { | ||
| 28 | struct usb_functionfs_descs_head header; | ||
| 29 | struct { | ||
| 30 | struct usb_interface_descriptor intf; | ||
| 31 | struct usb_endpoint_descriptor_no_audio bulk_sink; | ||
| 32 | struct usb_endpoint_descriptor_no_audio bulk_source; | ||
| 33 | } __attribute__ ((__packed__)) fs_descs, hs_descs; | ||
| 34 | } __attribute__ ((__packed__)) descriptors = { | ||
| 35 | .header = { | ||
| 36 | .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC), | ||
| 37 | .length = htole32(sizeof(descriptors)), | ||
| 38 | .fs_count = 3, | ||
| 39 | .hs_count = 3, | ||
| 40 | }, | ||
| 41 | .fs_descs = { | ||
| 42 | .intf = { | ||
| 43 | .bLength = sizeof(descriptors.fs_descs.intf), | ||
| 44 | .bDescriptorType = USB_DT_INTERFACE, | ||
| 45 | .bNumEndpoints = 2, | ||
| 46 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | ||
| 47 | .iInterface = 1, | ||
| 48 | }, | ||
| 49 | .bulk_sink = { | ||
| 50 | .bLength = sizeof(descriptors.fs_descs.bulk_sink), | ||
| 51 | .bDescriptorType = USB_DT_ENDPOINT, | ||
| 52 | .bEndpointAddress = 1 | USB_DIR_IN, | ||
| 53 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
| 54 | }, | ||
| 55 | .bulk_source = { | ||
| 56 | .bLength = sizeof(descriptors.fs_descs.bulk_source), | ||
| 57 | .bDescriptorType = USB_DT_ENDPOINT, | ||
| 58 | .bEndpointAddress = 2 | USB_DIR_OUT, | ||
| 59 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
| 60 | }, | ||
| 61 | }, | ||
| 62 | .hs_descs = { | ||
| 63 | .intf = { | ||
| 64 | .bLength = sizeof(descriptors.hs_descs.intf), | ||
| 65 | .bDescriptorType = USB_DT_INTERFACE, | ||
| 66 | .bNumEndpoints = 2, | ||
| 67 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | ||
| 68 | .iInterface = 1, | ||
| 69 | }, | ||
| 70 | .bulk_sink = { | ||
| 71 | .bLength = sizeof(descriptors.hs_descs.bulk_sink), | ||
| 72 | .bDescriptorType = USB_DT_ENDPOINT, | ||
| 73 | .bEndpointAddress = 1 | USB_DIR_IN, | ||
| 74 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
| 75 | }, | ||
| 76 | .bulk_source = { | ||
| 77 | .bLength = sizeof(descriptors.hs_descs.bulk_source), | ||
| 78 | .bDescriptorType = USB_DT_ENDPOINT, | ||
| 79 | .bEndpointAddress = 2 | USB_DIR_OUT, | ||
| 80 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
| 81 | }, | ||
| 82 | }, | ||
| 83 | }; | ||
| 84 | |||
| 85 | #define STR_INTERFACE "AIO Test" | ||
| 86 | |||
| 87 | static const struct { | ||
| 88 | struct usb_functionfs_strings_head header; | ||
| 89 | struct { | ||
| 90 | __le16 code; | ||
| 91 | const char str1[sizeof(STR_INTERFACE)]; | ||
| 92 | } __attribute__ ((__packed__)) lang0; | ||
| 93 | } __attribute__ ((__packed__)) strings = { | ||
| 94 | .header = { | ||
| 95 | .magic = htole32(FUNCTIONFS_STRINGS_MAGIC), | ||
| 96 | .length = htole32(sizeof(strings)), | ||
| 97 | .str_count = htole32(1), | ||
| 98 | .lang_count = htole32(1), | ||
| 99 | }, | ||
| 100 | .lang0 = { | ||
| 101 | htole16(0x0409), /* en-us */ | ||
| 102 | STR_INTERFACE, | ||
| 103 | }, | ||
| 104 | }; | ||
| 105 | |||
| 106 | /******************** Endpoints handling *******************************/ | ||
| 107 | |||
| 108 | static void display_event(struct usb_functionfs_event *event) | ||
| 109 | { | ||
| 110 | static const char *const names[] = { | ||
| 111 | [FUNCTIONFS_BIND] = "BIND", | ||
| 112 | [FUNCTIONFS_UNBIND] = "UNBIND", | ||
| 113 | [FUNCTIONFS_ENABLE] = "ENABLE", | ||
| 114 | [FUNCTIONFS_DISABLE] = "DISABLE", | ||
| 115 | [FUNCTIONFS_SETUP] = "SETUP", | ||
| 116 | [FUNCTIONFS_SUSPEND] = "SUSPEND", | ||
| 117 | [FUNCTIONFS_RESUME] = "RESUME", | ||
| 118 | }; | ||
| 119 | switch (event->type) { | ||
| 120 | case FUNCTIONFS_BIND: | ||
| 121 | case FUNCTIONFS_UNBIND: | ||
| 122 | case FUNCTIONFS_ENABLE: | ||
| 123 | case FUNCTIONFS_DISABLE: | ||
| 124 | case FUNCTIONFS_SETUP: | ||
| 125 | case FUNCTIONFS_SUSPEND: | ||
| 126 | case FUNCTIONFS_RESUME: | ||
| 127 | printf("Event %s\n", names[event->type]); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | static void handle_ep0(int ep0, bool *ready) | ||
| 132 | { | ||
| 133 | struct usb_functionfs_event event; | ||
| 134 | int ret; | ||
| 135 | |||
| 136 | struct pollfd pfds[1]; | ||
| 137 | pfds[0].fd = ep0; | ||
| 138 | pfds[0].events = POLLIN; | ||
| 139 | |||
| 140 | ret = poll(pfds, 1, 0); | ||
| 141 | |||
| 142 | if (ret && (pfds[0].revents & POLLIN)) { | ||
| 143 | ret = read(ep0, &event, sizeof(event)); | ||
| 144 | if (!ret) { | ||
| 145 | perror("unable to read event from ep0"); | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | display_event(&event); | ||
| 149 | switch (event.type) { | ||
| 150 | case FUNCTIONFS_SETUP: | ||
| 151 | if (event.u.setup.bRequestType & USB_DIR_IN) | ||
| 152 | write(ep0, NULL, 0); | ||
| 153 | else | ||
| 154 | read(ep0, NULL, 0); | ||
| 155 | break; | ||
| 156 | |||
| 157 | case FUNCTIONFS_ENABLE: | ||
| 158 | *ready = true; | ||
| 159 | break; | ||
| 160 | |||
| 161 | case FUNCTIONFS_DISABLE: | ||
| 162 | *ready = false; | ||
| 163 | break; | ||
| 164 | |||
| 165 | default: | ||
| 166 | break; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
