Module: xenomai-3 Branch: next Commit: 778b648d4b8b5845c52397bab02a1eba55c143bc URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=778b648d4b8b5845c52397bab02a1eba55c143bc
Author: Philippe Gerum <r...@xenomai.org> Date: Fri Apr 24 10:39:32 2015 +0200 drivers/udd: add sync mode to IRQ enable/disable requests --- include/cobalt/kernel/rtdm/udd.h | 24 +++++++++++++++-- include/rtdm/uapi/udd.h | 14 +++++----- kernel/drivers/udd/udd.c | 55 +++++++++++++++++++++++++++----------- 3 files changed, 70 insertions(+), 23 deletions(-) diff --git a/include/cobalt/kernel/rtdm/udd.h b/include/cobalt/kernel/rtdm/udd.h index 028e602..67ca6ed 100644 --- a/include/cobalt/kernel/rtdm/udd.h +++ b/include/cobalt/kernel/rtdm/udd.h @@ -211,16 +211,30 @@ struct udd_device { /** * Ancillary open() handler, optional. See * rtdm_open_handler(). + * + * @note This handler is called from secondary mode + * only. */ int (*open)(struct rtdm_fd *fd, int oflags); /** * Ancillary close() handler, optional. See * rtdm_close_handler(). + * + * @note This handler is called from secondary mode + * only. */ void (*close)(struct rtdm_fd *fd); /** * Ancillary ioctl() handler, optional. See * rtdm_ioctl_handler(). + * + * If this routine returns -ENOSYS, the default action + * implemented by the UDD core for the corresponding + * request will be applied, as if no ioctl handler had + * been defined. + * + * @note This handler is called from primary mode + * only. */ int (*ioctl)(struct rtdm_fd *fd, unsigned int request, void *arg); @@ -234,6 +248,9 @@ struct udd_device { * If this handler is NULL, the UDD core establishes * the mapping automatically, depending on the memory * type defined for the region. + * + * @note This handler is called from secondary mode + * only. */ int (*mmap)(struct rtdm_fd *fd, struct vm_area_struct *vma); @@ -261,6 +278,9 @@ struct udd_device { * Once the ->interrupt() handler has returned, the * UDD core notifies user-space Cobalt threads waiting * for IRQ events (if any). + * + * @note This handler is called from primary mode + * only. */ int (*interrupt)(struct udd_device *udd); } ops; @@ -304,9 +324,9 @@ struct udd_device *udd_get_device(struct rtdm_fd *fd); void udd_notify_event(struct udd_device *udd); -void udd_post_irq_enable(int irq); +void udd_post_irq_enable(int irq, rtdm_event_t *done); -void udd_post_irq_disable(int irq); +void udd_post_irq_disable(int irq, rtdm_event_t *done); /** @} */ diff --git a/include/rtdm/uapi/udd.h b/include/rtdm/uapi/udd.h index 210f0ce..5ac9b92 100644 --- a/include/rtdm/uapi/udd.h +++ b/include/rtdm/uapi/udd.h @@ -64,15 +64,17 @@ struct udd_signotify { */ /** - * Enable the interrupt line. The UDD-class mini-driver in kernel - * space should act upon this request appropriately when received via - * its ->ioctl() handler. + * Enable the interrupt line. The UDD-class mini-driver should handle + * this request when received through its ->ioctl() handler if + * provided. Otherwise, the UDD core enables the interrupt line in the + * interrupt controller. */ #define UDD_RTIOC_IRQEN _IO(RTDM_CLASS_UDD, 0) /** - * Disable the interrupt line. The UDD-class mini-driver in kernel - * should act upon this request appropriately when received via its - * ->ioctl() handler. + * Disable the interrupt line. The UDD-class mini-driver should handle + * this request when received through its ->ioctl() handler if + * provided. Otherwise, the UDD core disables the interrupt line in + * the interrupt controller. */ #define UDD_RTIOC_IRQDIS _IO(RTDM_CLASS_UDD, 1) /** diff --git a/kernel/drivers/udd/udd.c b/kernel/drivers/udd/udd.c index edac81a..aaae6f7 100644 --- a/kernel/drivers/udd/udd.c +++ b/kernel/drivers/udd/udd.c @@ -63,7 +63,8 @@ static int udd_ioctl_rt(struct rtdm_fd *fd, struct udd_signotify signfy; struct udd_reserved *ur; struct udd_device *udd; - int ret = 0; + rtdm_event_t done; + int ret; udd = container_of(rtdm_fd_device(fd), struct udd_device, __reserved.device); if (udd->ops.ioctl) { @@ -91,15 +92,20 @@ static int udd_ioctl_rt(struct rtdm_fd *fd, } break; case UDD_RTIOC_IRQEN: - if (udd->irq == UDD_IRQ_NONE) - return -EIO; - udd_post_irq_enable(udd->irq); - break; case UDD_RTIOC_IRQDIS: if (udd->irq == UDD_IRQ_NONE) return -EIO; - udd_post_irq_disable(udd->irq); + rtdm_event_init(&done, 0); + if (request == UDD_RTIOC_IRQEN) + udd_post_irq_enable(udd->irq, &done); + else + udd_post_irq_disable(udd->irq, &done); + ret = rtdm_event_wait(&done); + if (ret != -EIDRM) + rtdm_event_destroy(&done); break; + default: + ret = -EINVAL; } return ret; @@ -513,6 +519,7 @@ struct irqswitch_work { struct ipipe_work_header work; /* Must be first. */ int irq; int enabled; + rtdm_event_t *done; }; static void lostage_irqswitch_line(struct ipipe_work_header *work) @@ -528,9 +535,12 @@ static void lostage_irqswitch_line(struct ipipe_work_header *work) ipipe_enable_irq(rq->irq); else ipipe_disable_irq(rq->irq); + + if (rq->done) + rtdm_event_signal(rq->done); } -static void switch_irq_line(int irq, int enable) +static void switch_irq_line(int irq, int enable, rtdm_event_t *done) { struct irqswitch_work switchwork = { .work = { @@ -539,6 +549,7 @@ static void switch_irq_line(int irq, int enable) }, .irq = irq, .enabled = enable, + .done = done, }; /* @@ -556,19 +567,26 @@ static void switch_irq_line(int irq, int enable) * This service issues a request to the regular kernel for enabling * the IRQ line mentioned. If the caller runs in primary mode, the * request is scheduled but deferred until the current CPU leaves the - * real-time domain. Otherwise, the request is immediately handled. + * real-time domain (see note). Otherwise, the request is immediately + * handled. * * @param irq IRQ line to enable. * + * @param done Optional event to signal upon completion. If non-NULL, + * @a done will be posted by a call to rtdm_event_signal() after the + * interrupt line is enabled. + * * @coretags{unrestricted} * * @note The deferral is required as some interrupt management code * involved in enabling interrupt lines may not be safely executed - * from primary mode. + * from primary mode. By passing a valid @a done object address, the + * caller can wait for the request to complete, by sleeping on + * rtdm_event_wait(). */ -void udd_post_irq_enable(int irq) +void udd_post_irq_enable(int irq, rtdm_event_t *done) { - switch_irq_line(irq, 1); + switch_irq_line(irq, 1, done); } EXPORT_SYMBOL_GPL(udd_post_irq_enable); @@ -578,19 +596,26 @@ EXPORT_SYMBOL_GPL(udd_post_irq_enable); * This service issues a request to the regular kernel for disabling * the IRQ line mentioned. If the caller runs in primary mode, the * request is scheduled but deferred until the current CPU leaves the - * real-time domain. Otherwise, the request is immediately handled. + * real-time domain (see note). Otherwise, the request is immediately + * handled. * * @param irq IRQ line to disable. * + * @param done Optional event to signal upon completion. If non-NULL, + * @a done will be posted by a call to rtdm_event_signal() after the + * interrupt line is disabled. + * * @coretags{unrestricted} * * @note The deferral is required as some interrupt management code * involved in disabling interrupt lines may not be safely executed - * from primary mode. + * from primary mode. By passing a valid @a done object address, the + * caller can wait for the request to complete, by sleeping on + * rtdm_event_wait(). */ -void udd_post_irq_disable(int irq) +void udd_post_irq_disable(int irq, rtdm_event_t *done) { - switch_irq_line(irq, 0); + switch_irq_line(irq, 0, done); } EXPORT_SYMBOL_GPL(udd_post_irq_disable); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git