Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Robert Baldyga <r.baldyga@samsung.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>

authored by

Robert Baldyga and committed by
Felipe Balbi
5e33f6fd acba23fe

+30 -1
+28 -1
drivers/usb/gadget/function/f_fs.c
··· 31 31 #include <linux/aio.h> 32 32 #include <linux/mmu_context.h> 33 33 #include <linux/poll.h> 34 + #include <linux/eventfd.h> 34 35 35 36 #include "u_fs.h" 36 37 #include "u_f.h" ··· 154 153 155 154 struct usb_ep *ep; 156 155 struct usb_request *req; 156 + 157 + struct ffs_data *ffs; 157 158 }; 158 159 159 160 struct ffs_desc_helper { ··· 677 674 678 675 aio_complete(io_data->kiocb, ret, ret); 679 676 677 + if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd) 678 + eventfd_signal(io_data->ffs->ffs_eventfd, 1); 679 + 680 680 usb_ep_free_request(io_data->ep, io_data->req); 681 681 682 682 io_data->kiocb->private = NULL; ··· 833 827 io_data->buf = data; 834 828 io_data->ep = ep->ep; 835 829 io_data->req = req; 830 + io_data->ffs = epfile->ffs; 836 831 837 832 req->context = io_data; 838 833 req->complete = ffs_epfile_async_io_complete; ··· 1517 1510 if (ffs->epfiles) 1518 1511 ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); 1519 1512 1513 + if (ffs->ffs_eventfd) 1514 + eventfd_ctx_put(ffs->ffs_eventfd); 1515 + 1520 1516 kfree(ffs->raw_descs_data); 1521 1517 kfree(ffs->raw_strings); 1522 1518 kfree(ffs->stringtabs); ··· 2179 2169 FUNCTIONFS_HAS_HS_DESC | 2180 2170 FUNCTIONFS_HAS_SS_DESC | 2181 2171 FUNCTIONFS_HAS_MS_OS_DESC | 2182 - FUNCTIONFS_VIRTUAL_ADDR)) { 2172 + FUNCTIONFS_VIRTUAL_ADDR | 2173 + FUNCTIONFS_EVENTFD)) { 2183 2174 ret = -ENOSYS; 2184 2175 goto error; 2185 2176 } ··· 2189 2178 break; 2190 2179 default: 2191 2180 goto error; 2181 + } 2182 + 2183 + if (flags & FUNCTIONFS_EVENTFD) { 2184 + if (len < 4) 2185 + goto error; 2186 + ffs->ffs_eventfd = 2187 + eventfd_ctx_fdget((int)get_unaligned_le32(data)); 2188 + if (IS_ERR(ffs->ffs_eventfd)) { 2189 + ret = PTR_ERR(ffs->ffs_eventfd); 2190 + ffs->ffs_eventfd = NULL; 2191 + goto error; 2192 + } 2193 + data += 4; 2194 + len -= 4; 2192 2195 } 2193 2196 2194 2197 /* Read fs_count, hs_count and ss_count (if present) */ ··· 2479 2454 pr_vdebug("adding event %d\n", type); 2480 2455 ffs->ev.types[ffs->ev.count++] = type; 2481 2456 wake_up_locked(&ffs->ev.waitq); 2457 + if (ffs->ffs_eventfd) 2458 + eventfd_signal(ffs->ffs_eventfd, 1); 2482 2459 } 2483 2460 2484 2461 static void ffs_event_add(struct ffs_data *ffs,
+1
drivers/usb/gadget/function/u_fs.h
··· 272 272 kgid_t gid; 273 273 } file_perms; 274 274 275 + struct eventfd_ctx *ffs_eventfd; 275 276 bool no_disconnect; 276 277 struct work_struct reset_work; 277 278
+1
include/uapi/linux/usb/functionfs.h
··· 20 20 FUNCTIONFS_HAS_SS_DESC = 4, 21 21 FUNCTIONFS_HAS_MS_OS_DESC = 8, 22 22 FUNCTIONFS_VIRTUAL_ADDR = 16, 23 + FUNCTIONFS_EVENTFD = 32, 23 24 }; 24 25 25 26 /* Descriptor of an non-audio endpoint */