usb: gadget: ffs: add eventfd notification about ffs events
authorRobert Baldyga <r.baldyga@samsung.com>
Fri, 23 Jan 2015 12:41:01 +0000 (13:41 +0100)
committerFelipe Balbi <balbi@ti.com>
Tue, 27 Jan 2015 15:34:59 +0000 (09:34 -0600)
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: Robert Baldyga <r.baldyga@samsung.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/u_fs.h
include/uapi/linux/usb/functionfs.h

index 14e44d7083a14a45fc284c7e562413e038748b55..af98b096af2fde060aea8978005e8ea620762566 100644 (file)
@@ -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,
index 284a1f00a980583adf4d2ee93428c14cd9b3c7c4..60139854e0b1b320d66f15b5b1f0d954e72e634d 100644 (file)
@@ -272,6 +272,7 @@ struct ffs_data {
                kgid_t                          gid;
        }                               file_perms;
 
+       struct eventfd_ctx *ffs_eventfd;
        bool no_disconnect;
        struct work_struct reset_work;
 
index 295ba299e7bdb6b57f59b2f642fe43cae348e86a..108dd799701449f8e7693f30596b3c3ab9dd030c 100644 (file)
@@ -20,6 +20,7 @@ enum functionfs_flags {
        FUNCTIONFS_HAS_SS_DESC = 4,
        FUNCTIONFS_HAS_MS_OS_DESC = 8,
        FUNCTIONFS_VIRTUAL_ADDR = 16,
+       FUNCTIONFS_EVENTFD = 32,
 };
 
 /* Descriptor of an non-audio endpoint */