diff options
Diffstat (limited to 'drivers/usb/gadget/function/f_fs.c')
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 14e44d7083a1..af98b096af2f 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -31,6 +31,7 @@ #include <linux/aio.h> #include <linux/mmu_context.h> #include <linux/poll.h> +#include <linux/eventfd.h> #include "u_fs.h" #include "u_f.h" @@ -153,6 +154,8 @@ struct ffs_io_data { struct usb_ep *ep; struct usb_request *req; + + struct ffs_data *ffs; }; struct ffs_desc_helper { @@ -674,6 +677,9 @@ static void ffs_user_copy_worker(struct work_struct *work) 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); io_data->kiocb->private = NULL; @@ -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->ep = ep->ep; io_data->req = req; + io_data->ffs = epfile->ffs; req->context = io_data; req->complete = ffs_epfile_async_io_complete; @@ -1510,6 +1517,9 @@ static void ffs_data_clear(struct ffs_data *ffs) if (ffs->epfiles) 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_strings); kfree(ffs->stringtabs); @@ -2169,7 +2179,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, FUNCTIONFS_HAS_HS_DESC | FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC | - FUNCTIONFS_VIRTUAL_ADDR)) { + FUNCTIONFS_VIRTUAL_ADDR | + FUNCTIONFS_EVENTFD)) { ret = -ENOSYS; goto error; } @@ -2180,6 +2191,20 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, 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) */ for (i = 0; i < 3; ++i) { if (!(flags & (1 << i))) { @@ -2454,6 +2479,8 @@ static void __ffs_event_add(struct ffs_data *ffs, pr_vdebug("adding event %d\n", type); ffs->ev.types[ffs->ev.count++] = type; 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, |