Commit 5e33f6fd authored by Robert Baldyga's avatar Robert Baldyga Committed by Felipe Balbi

usb: gadget: ffs: add eventfd notification about ffs events

Add eventfd which notifies userspace about ep0 events and AIO completion
events. It simplifies using of FunctionFS with event loop, because now
we need to poll on single file (instead of polling on ep0 and eventfd's
supplied to AIO layer).

FunctionFS eventfd is not triggered if another eventfd is supplied to
AIO layer (in AIO request). It can be useful, for example, when we want
to handle AIO transations for chosen endpoint in separate thread.
Signed-off-by: default avatarRobert Baldyga <r.baldyga@samsung.com>
Acked-by: default avatarMichal Nazarewicz <mina86@mina86.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent acba23fe
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/aio.h> #include <linux/aio.h>
#include <linux/mmu_context.h> #include <linux/mmu_context.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/eventfd.h>
#include "u_fs.h" #include "u_fs.h"
#include "u_f.h" #include "u_f.h"
...@@ -153,6 +154,8 @@ struct ffs_io_data { ...@@ -153,6 +154,8 @@ struct ffs_io_data {
struct usb_ep *ep; struct usb_ep *ep;
struct usb_request *req; struct usb_request *req;
struct ffs_data *ffs;
}; };
struct ffs_desc_helper { struct ffs_desc_helper {
...@@ -674,6 +677,9 @@ static void ffs_user_copy_worker(struct work_struct *work) ...@@ -674,6 +677,9 @@ static void ffs_user_copy_worker(struct work_struct *work)
aio_complete(io_data->kiocb, ret, ret); aio_complete(io_data->kiocb, ret, ret);
if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd)
eventfd_signal(io_data->ffs->ffs_eventfd, 1);
usb_ep_free_request(io_data->ep, io_data->req); usb_ep_free_request(io_data->ep, io_data->req);
io_data->kiocb->private = NULL; io_data->kiocb->private = NULL;
...@@ -827,6 +833,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ...@@ -827,6 +833,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
io_data->buf = data; io_data->buf = data;
io_data->ep = ep->ep; io_data->ep = ep->ep;
io_data->req = req; io_data->req = req;
io_data->ffs = epfile->ffs;
req->context = io_data; req->context = io_data;
req->complete = ffs_epfile_async_io_complete; req->complete = ffs_epfile_async_io_complete;
...@@ -1510,6 +1517,9 @@ static void ffs_data_clear(struct ffs_data *ffs) ...@@ -1510,6 +1517,9 @@ static void ffs_data_clear(struct ffs_data *ffs)
if (ffs->epfiles) if (ffs->epfiles)
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
if (ffs->ffs_eventfd)
eventfd_ctx_put(ffs->ffs_eventfd);
kfree(ffs->raw_descs_data); kfree(ffs->raw_descs_data);
kfree(ffs->raw_strings); kfree(ffs->raw_strings);
kfree(ffs->stringtabs); kfree(ffs->stringtabs);
...@@ -2169,7 +2179,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, ...@@ -2169,7 +2179,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
FUNCTIONFS_HAS_HS_DESC | FUNCTIONFS_HAS_HS_DESC |
FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_SS_DESC |
FUNCTIONFS_HAS_MS_OS_DESC | FUNCTIONFS_HAS_MS_OS_DESC |
FUNCTIONFS_VIRTUAL_ADDR)) { FUNCTIONFS_VIRTUAL_ADDR |
FUNCTIONFS_EVENTFD)) {
ret = -ENOSYS; ret = -ENOSYS;
goto error; goto error;
} }
...@@ -2180,6 +2191,20 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, ...@@ -2180,6 +2191,20 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
goto error; goto error;
} }
if (flags & FUNCTIONFS_EVENTFD) {
if (len < 4)
goto error;
ffs->ffs_eventfd =
eventfd_ctx_fdget((int)get_unaligned_le32(data));
if (IS_ERR(ffs->ffs_eventfd)) {
ret = PTR_ERR(ffs->ffs_eventfd);
ffs->ffs_eventfd = NULL;
goto error;
}
data += 4;
len -= 4;
}
/* Read fs_count, hs_count and ss_count (if present) */ /* Read fs_count, hs_count and ss_count (if present) */
for (i = 0; i < 3; ++i) { for (i = 0; i < 3; ++i) {
if (!(flags & (1 << i))) { if (!(flags & (1 << i))) {
...@@ -2454,6 +2479,8 @@ static void __ffs_event_add(struct ffs_data *ffs, ...@@ -2454,6 +2479,8 @@ static void __ffs_event_add(struct ffs_data *ffs,
pr_vdebug("adding event %d\n", type); pr_vdebug("adding event %d\n", type);
ffs->ev.types[ffs->ev.count++] = type; ffs->ev.types[ffs->ev.count++] = type;
wake_up_locked(&ffs->ev.waitq); wake_up_locked(&ffs->ev.waitq);
if (ffs->ffs_eventfd)
eventfd_signal(ffs->ffs_eventfd, 1);
} }
static void ffs_event_add(struct ffs_data *ffs, static void ffs_event_add(struct ffs_data *ffs,
......
...@@ -272,6 +272,7 @@ struct ffs_data { ...@@ -272,6 +272,7 @@ struct ffs_data {
kgid_t gid; kgid_t gid;
} file_perms; } file_perms;
struct eventfd_ctx *ffs_eventfd;
bool no_disconnect; bool no_disconnect;
struct work_struct reset_work; struct work_struct reset_work;
......
...@@ -20,6 +20,7 @@ enum functionfs_flags { ...@@ -20,6 +20,7 @@ enum functionfs_flags {
FUNCTIONFS_HAS_SS_DESC = 4, FUNCTIONFS_HAS_SS_DESC = 4,
FUNCTIONFS_HAS_MS_OS_DESC = 8, FUNCTIONFS_HAS_MS_OS_DESC = 8,
FUNCTIONFS_VIRTUAL_ADDR = 16, FUNCTIONFS_VIRTUAL_ADDR = 16,
FUNCTIONFS_EVENTFD = 32,
}; };
/* Descriptor of an non-audio endpoint */ /* Descriptor of an non-audio endpoint */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment