* [PATCHv4 0/8] The FunctionFS composite function @ 2010-05-05 10:53 Michal Nazarewicz 2010-05-05 10:53 ` [PATCHv4 1/8] wait_event_interruptible_locked() interface Michal Nazarewicz 2010-05-06 8:44 ` [PATCHv4 0/8] The FunctionFS composite function Michał Nazarewicz 0 siblings, 2 replies; 4+ messages in thread From: Michal Nazarewicz @ 2010-05-05 10:53 UTC (permalink / raw) To: linux-usb-u79uwXL29TY76Z2rM5mHXA Cc: Michal Nazarewicz, Greg KH, Kyungmin Park, Marek Szyprowski, Davide Libenzi, Thomas Gleixner, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: TEXT/PLAIN; charset=EUC-KR, Size: 9075 bytes --] From: Michal Nazarewicz <mina86-deATy8a+UHjQT0dZR+AlfA@public.gmane.org> Hello everyone, Yet another version of the FunctionFS patchset. The code has been tested with a user-space MTP driver and there was no problems including with setup requests. As such, it is believed that the data transfers are reliable. *Changes from Previous Version* 1. Minor bug fixes and clean-ups. 2. More verbose error messages when user space driver provides invalid descriptors. This makes it easier to find what FunctionFS things is wrong with descriptors when wirte() returns EINVAL. 3. g_ffs now has total of three possible configurations and all may be included in the driver -- this is configured via Kconfig -- rather then a single configuration which may or may not have ECM depending on Kconfig. 4. __cold removed as per Greg's comment. Previously I replaced __init and __exit with __cold but Greg didn't seem impressed. ;) *Request for Comments and Future Work* Regarding presented version there are following aspects I'd like to discuss. 1. First of all, the current code uses similar approach GadgetFS used -- there is a single file ("ep0" in case of FunctionFS and named after the controller in case of GadgetFS) that is used to receive events from kernel and handle ep0 communication. I think it is not the best approach as it'd be simpler and cleaner if there were two files: one for receiving events and another for handling ep0 communication. What do you think? Should I keep the current version or change to code to use two files? 2. Descriptors and strings are transferred using two writes. I'm wondering, whether it was better to use a single write to transfer all the data. This should simplify driver's logic a bit and I believe also user-space driver but maybe there are some cases, where it is better to have to writes? 3. What still needs to be implemented is a mechanism allowing double buffering (and in effect transmission without pauses) and maybe single-thread user-space driver implementation. I'd like to ask what would be the best way to achieve this. GadgetFS implements asynchronous I/O -- is it still the best option? There was some work by Felipe Balbi which parts of may be ported and used with FunctionFS but it cannot be used as the only mechanism as it introduces buffering and thus interferes with control of flow of packets and requests. *The Patches* The first patch creates a new wait_event_interruptible_locked() interface for waiting on events. While holding the wait queue's lock. Refer to the commit message for usage. The second patch makes use of the new interface in fs/timerfd.c file replacing some 20 lines by a single macro call. Next three patches implement the FunctionFS and a composite gadget that uses FunctionFS and Ethernet function (with the later function optionally disabled via Kconfig). The last three patches provide a testing code for the FunctionFS. My original intend was to provide those just for anyone who'd like to test the code and not to include them in the Linux source tree but if that seems appropriate then why not? *How FunctionFS works* (Copied from third patch commit message.) From kernel point of view it is just a composite function with some unique behaviour. It may be added to an USB configuration only after the user space driver has registered by writing descriptors and strings (the user space program has to provide the same information that kernel level composite functions provide when they are added to the configuration). This in particular means that the composite initialisation functions may not be in init section (ie. may not use the __init tag) hence the first and fourth patch in the series. From user space point of view it is a file system which when mounted provide an "ep0" file. User space driver need to write descriptors and strings to that file. It does not need to worry about endpoints, interfaces or strings numbers but simply provide descriptors such as if the function was the only one (endpoints and strings numbers starting from one and interface numbers starting from core). The FunctionFS changes numbers of those as needed also handling situation when numbers differ in different configurations. When descriptors and strings are written "ep#" files appear (one for each declared endpoint) which handle communication on a single endpoint. Again, FunctionFS takes care of the real numbers and changing of the configuration (which means that "ep1" file may be really mapped to (say) endpoint 3 (and when configuration changes to (say) endpoint 2)). "ep0" is used for receiving events and handling setup requests. When all files are closed the function disables itself. What I also want to mention is that the FunctionFS is designed in such a way that with a little work it will be able to mount it several times so in the end a gadget could use several FunctionFS functions. The idea is that each FunctionFS instance is identified by the device name used when mounting. One can imagine a gadget that has an Ethernet, MTP and HID interfaces where the last two are implemented via FunctionFS. On user space level it would look like this: $ modprobe g_foo $ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp $ ( cd /dev/ffs-mtp && mtp-daemon ) & $ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid $ ( cd /dev/ffs-hid && hid-daemon ) & On kernel level the gadget would check ffs_data->dev_name to identify whether it's FunctionFS designed for MTP ("mtp") or HID ("hid"). *Testing* The fifth patch implement a simple source/sink FunctionFS driver based on similar driver for GadgetFS by David Brownell (<http://www.linux-usb.org/gadget/usb.c>). It registers a dual-speed function with a single IN and single OUT endpoints. The sixth and seventh patch provide a host-side testing code. This is what David Brownell has created a while back (<http://www.linux-usb.org/usbtest/testusb.c>) with a simple fix to make the tool detect the number of our source/sink interface. Still, you will need to configure the gadget to report idProduct == 0xa4a4 (an "echo 0xa4a4 >/sys/module/g_ffs/parameters/usb_product" should suffice) or configure host to handle 0x0525:0xa4ac devices using the usbtest driver. Hence, the simplest way to run the test is to do the following: * On target (machine that runs has the gadget) as root: $ echo 0xa4a4 >/sys/module/g_ffs/parameters/usb_product && $ mkdir /dev/ffs && $ mount -t functionfs ffs /dev/ffs && $ cd /dev/ffs && $ /path/to/ffs-test * On host (as root): $ testusb -a At this point I have to admit that communication on EP0 has not yet been tested, so beware of bugs there. David Brownell (1): USB: testusb: an USB testing application Michal Nazarewicz (7): wait_event_interruptible_locked() interface fs/timerfd.c: make use of wait_event_interruptible_locked_irq() USB: gadget: __init and __exit tags removed USB: f_fs: the FunctionFS driver USB: g_ffs: the FunctionFS gadget driver USB: ffs-test: FunctionFS testing program USB: testusb: testusb compatibility with FunctionFS gadget drivers/usb/gadget/Kconfig | 37 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/composite.c | 21 +- drivers/usb/gadget/config.c | 4 +- drivers/usb/gadget/epautoconf.c | 12 +- drivers/usb/gadget/f_acm.c | 32 +- drivers/usb/gadget/f_ecm.c | 33 +- drivers/usb/gadget/f_fs.c | 2441 +++++++++++++++++++++++++++++++++++ drivers/usb/gadget/f_mass_storage.c | 2 +- drivers/usb/gadget/f_rndis.c | 33 +- drivers/usb/gadget/g_ffs.c | 427 ++++++ drivers/usb/gadget/u_ether.c | 4 +- fs/timerfd.c | 25 +- include/linux/usb/functionfs.h | 199 +++ include/linux/wait.h | 149 +++ kernel/sched.c | 1 + tools/usb/ffs-test.c | 554 ++++++++ tools/usb/testusb.c | 547 ++++++++ 18 files changed, 4432 insertions(+), 91 deletions(-) create mode 100644 drivers/usb/gadget/f_fs.c create mode 100644 drivers/usb/gadget/g_ffs.c create mode 100644 include/linux/usb/functionfs.h create mode 100644 tools/usb/ffs-test.c create mode 100644 tools/usb/testusb.c -- Best regards, _ _ | Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o | Computer Science, Michał "mina86" Nazarewicz (o o) +----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo-- -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCHv4 1/8] wait_event_interruptible_locked() interface 2010-05-05 10:53 [PATCHv4 0/8] The FunctionFS composite function Michal Nazarewicz @ 2010-05-05 10:53 ` Michal Nazarewicz 2010-05-05 10:53 ` [PATCHv4 2/8] fs/timerfd.c: make use of wait_event_interruptible_locked_irq() Michal Nazarewicz 2010-05-06 8:44 ` [PATCHv4 0/8] The FunctionFS composite function Michał Nazarewicz 1 sibling, 1 reply; 4+ messages in thread From: Michal Nazarewicz @ 2010-05-05 10:53 UTC (permalink / raw) To: linux-usb Cc: Michal Nazarewicz, Greg KH, Kyungmin Park, Marek Szyprowski, Davide Libenzi, Thomas Gleixner, linux-fsdevel, linux-kernel New wait_event_interruptible{,_exclusive}_locked{,_irq} macros added. They work just like versions without _locked* suffix but require the wait queue's lock to be held. Also __wake_up_locked() is now exported as to pair it with the above macros. The use case of this new facility is when one uses wait queue's lock to protect a data structure. This may be advantageous if the structure needs to be protected by a spinlock anyway. In particular, with additional spinlock the following code has to be used to wait for a condition: spin_lock(&data.lock); ... for (ret = 0; !ret && !(condition); ) { spin_unlock(&data.lock); ret = wait_event_interruptible(data.wqh, (condition)); spin_lock(&data.lock); } ... spin_unlock(&data.lock); This looks bizarre plus wait_event_interruptible() locks the wait queue's lock anyway so there is a unlock+lock sequence where it could be avoided. To avoid those problems and benefit from wait queue's lock, a code similar to the following should be used: /* Waiting */ spin_lock(&data.wqh.lock); ... ret = wait_event_interruptible_locked(data.wqh, (condition)); ... spin_unlock(&data.wqh.lock); /* Waiting exclusively */ spin_lock(&data.whq.lock); ... ret = wait_event_interruptible_exclusive_locked(data.whq, (condition)); ... spin_unlock(&data.whq.lock); /* Waking up */ spin_lock(&data.wqh.lock); ... wake_up_locked(&data.wqh); ... spin_unlock(&data.wqh.lock); When spin_lock_irq() is used matching versions of macros need to be used (*_locked_irq()). Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> --- include/linux/wait.h | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/sched.c | 1 + 2 files changed, 150 insertions(+), 0 deletions(-) diff --git a/include/linux/wait.h b/include/linux/wait.h index a48e16b..fc3c040 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -362,6 +362,155 @@ do { \ __ret; \ }) + +#define __wait_event_interruptible_locked(wq, condition, exclusive, irq) \ +({ \ + int __ret = 0; \ + DEFINE_WAIT(__wait); \ + if (exclusive) \ + __wait.flags |= WQ_FLAG_EXCLUSIVE; \ + do { \ + if (likely(list_empty(&__wait.task_list))) \ + __add_wait_queue_tail(&(wq), &__wait); \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (signal_pending(current)) { \ + __ret = -ERESTARTSYS; \ + break; \ + } \ + if (irq) \ + spin_unlock_irq(&(wq).lock); \ + else \ + spin_unlock(&(wq).lock); \ + schedule(); \ + if (irq) \ + spin_lock_irq(&(wq).lock); \ + else \ + spin_lock(&(wq).lock); \ + } while (!(condition)); \ + __remove_wait_queue(&(wq), &__wait); \ + __set_current_state(TASK_RUNNING); \ + __ret; \ +}) + + +/** + * wait_event_interruptible_locked - sleep until a condition gets true + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_INTERRUPTIBLE) until the + * @condition evaluates to true or a signal is received. + * The @condition is checked each time the waitqueue @wq is woken up. + * + * It must be called with wq.lock being held. This spinlock is + * unlocked while sleeping but @condition testing is done while lock + * is held and when this macro exits the lock is held. + * + * The lock is locked/unlocked using spin_lock()/spin_unlock() + * functions which must match the way they are locked/unlocked outside + * of this macro. + * + * wake_up_locked() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function will return -ERESTARTSYS if it was interrupted by a + * signal and 0 if @condition evaluated to true. + */ +#define wait_event_interruptible_locked(wq, condition) \ + ((condition) \ + ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 0)) + +/** + * wait_event_interruptible_locked_irq - sleep until a condition gets true + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_INTERRUPTIBLE) until the + * @condition evaluates to true or a signal is received. + * The @condition is checked each time the waitqueue @wq is woken up. + * + * It must be called with wq.lock being held. This spinlock is + * unlocked while sleeping but @condition testing is done while lock + * is held and when this macro exits the lock is held. + * + * The lock is locked/unlocked using spin_lock_irq()/spin_unlock_irq() + * functions which must match the way they are locked/unlocked outside + * of this macro. + * + * wake_up_locked() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function will return -ERESTARTSYS if it was interrupted by a + * signal and 0 if @condition evaluated to true. + */ +#define wait_event_interruptible_locked_irq(wq, condition) \ + ((condition) \ + ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 1)) + +/** + * wait_event_interruptible_exclusive_locked - sleep exclusively until a condition gets true + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_INTERRUPTIBLE) until the + * @condition evaluates to true or a signal is received. + * The @condition is checked each time the waitqueue @wq is woken up. + * + * It must be called with wq.lock being held. This spinlock is + * unlocked while sleeping but @condition testing is done while lock + * is held and when this macro exits the lock is held. + * + * The lock is locked/unlocked using spin_lock()/spin_unlock() + * functions which must match the way they are locked/unlocked outside + * of this macro. + * + * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag + * set thus when other process waits process on the list if this + * process is awaken further processes are not considered. + * + * wake_up_locked() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function will return -ERESTARTSYS if it was interrupted by a + * signal and 0 if @condition evaluated to true. + */ +#define wait_event_interruptible_exclusive_locked(wq, condition) \ + ((condition) \ + ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 0)) + +/** + * wait_event_interruptible_exclusive_locked_irq - sleep until a condition gets true + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_INTERRUPTIBLE) until the + * @condition evaluates to true or a signal is received. + * The @condition is checked each time the waitqueue @wq is woken up. + * + * It must be called with wq.lock being held. This spinlock is + * unlocked while sleeping but @condition testing is done while lock + * is held and when this macro exits the lock is held. + * + * The lock is locked/unlocked using spin_lock_irq()/spin_unlock_irq() + * functions which must match the way they are locked/unlocked outside + * of this macro. + * + * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag + * set thus when other process waits process on the list if this + * process is awaken further processes are not considered. + * + * wake_up_locked() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function will return -ERESTARTSYS if it was interrupted by a + * signal and 0 if @condition evaluated to true. + */ +#define wait_event_interruptible_exclusive_locked_irq(wq, condition) \ + ((condition) \ + ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 1)) + + + #define __wait_event_killable(wq, condition, ret) \ do { \ DEFINE_WAIT(__wait); \ diff --git a/kernel/sched.c b/kernel/sched.c index c76ba43..20afbe6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3861,6 +3861,7 @@ void __wake_up_locked(wait_queue_head_t *q, unsigned int mode) { __wake_up_common(q, mode, 1, 0, NULL); } +EXPORT_SYMBOL_GPL(__wake_up_locked); void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key) { -- 1.7.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCHv4 2/8] fs/timerfd.c: make use of wait_event_interruptible_locked_irq() 2010-05-05 10:53 ` [PATCHv4 1/8] wait_event_interruptible_locked() interface Michal Nazarewicz @ 2010-05-05 10:53 ` Michal Nazarewicz 0 siblings, 0 replies; 4+ messages in thread From: Michal Nazarewicz @ 2010-05-05 10:53 UTC (permalink / raw) To: linux-usb Cc: Michal Nazarewicz, Greg KH, Kyungmin Park, Marek Szyprowski, Davide Libenzi, Thomas Gleixner, linux-fsdevel, linux-kernel This patch modifies the fs/timerfd.c to use the newly created wait_event_interruptible_locked_irq() macro. This replaces an open code implementation with a single macro call. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> --- fs/timerfd.c | 25 ++++--------------------- 1 files changed, 4 insertions(+), 21 deletions(-) diff --git a/fs/timerfd.c b/fs/timerfd.c index 98158de..b86ab8e 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -110,31 +110,14 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, struct timerfd_ctx *ctx = file->private_data; ssize_t res; u64 ticks = 0; - DECLARE_WAITQUEUE(wait, current); if (count < sizeof(ticks)) return -EINVAL; spin_lock_irq(&ctx->wqh.lock); - res = -EAGAIN; - if (!ctx->ticks && !(file->f_flags & O_NONBLOCK)) { - __add_wait_queue(&ctx->wqh, &wait); - for (res = 0;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (ctx->ticks) { - res = 0; - break; - } - if (signal_pending(current)) { - res = -ERESTARTSYS; - break; - } - spin_unlock_irq(&ctx->wqh.lock); - schedule(); - spin_lock_irq(&ctx->wqh.lock); - } - __remove_wait_queue(&ctx->wqh, &wait); - __set_current_state(TASK_RUNNING); - } + if (file->f_flags & O_NONBLOCK) + res = -EAGAIN; + else + res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks); if (ctx->ticks) { ticks = ctx->ticks; if (ctx->expired && ctx->tintv.tv64) { -- 1.7.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCHv4 0/8] The FunctionFS composite function 2010-05-05 10:53 [PATCHv4 0/8] The FunctionFS composite function Michal Nazarewicz 2010-05-05 10:53 ` [PATCHv4 1/8] wait_event_interruptible_locked() interface Michal Nazarewicz @ 2010-05-06 8:44 ` Michał Nazarewicz 1 sibling, 0 replies; 4+ messages in thread From: Michał Nazarewicz @ 2010-05-06 8:44 UTC (permalink / raw) To: Michal Nazarewicz, linux-usb Cc: Michal Nazarewicz, Greg KH, Kyungmin Park, Marek Szyprowski, Davide Libenzi, Thomas Gleixner, linux-fsdevel, linux-kernel On Wed, 05 May 2010 12:53:10 +0200, Michal Nazarewicz <m.nazarewicz@samsung.com> wrote: > The code has been tested with a user-space MTP driver and there was no > problems including with setup requests. As such, it is believed that > the data transfers are reliable. > At this point I have to admit that communication on EP0 has not yet > been tested, so beware of bugs there. This last sentence is of course incorrect. EP0 has been tested as well as the first sentence implies. Again forgot to edit the whole cover letter. Sorry about the confusion. -- Best regards, _ _ | Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o | Computer Science, Michał "mina86" Nazarewicz (o o) +----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo-- ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2010-05-06 8:44 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-05-05 10:53 [PATCHv4 0/8] The FunctionFS composite function Michal Nazarewicz 2010-05-05 10:53 ` [PATCHv4 1/8] wait_event_interruptible_locked() interface Michal Nazarewicz 2010-05-05 10:53 ` [PATCHv4 2/8] fs/timerfd.c: make use of wait_event_interruptible_locked_irq() Michal Nazarewicz 2010-05-06 8:44 ` [PATCHv4 0/8] The FunctionFS composite function Michał Nazarewicz
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).