aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/comedi/rt_pend_tq.c
diff options
context:
space:
mode:
authormerge <null@invalid>2009-01-22 13:55:32 +0000
committerAndy Green <agreen@octopus.localdomain>2009-01-22 13:55:32 +0000
commitaa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 (patch)
treefbb786d0ac6f8a774fd834e9ce951197e60fbffa /drivers/staging/comedi/rt_pend_tq.c
parentf2d78193eae5dccd3d588d2c8ea0866efc368332 (diff)
MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141
pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage: From: merge <null@invalid> MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage: From: merge <null@invalid> MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage: From: Andy Green <andy@openmoko.com> fix-stray-endmenu.patch Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/staging/comedi/rt_pend_tq.c')
-rw-r--r--drivers/staging/comedi/rt_pend_tq.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/drivers/staging/comedi/rt_pend_tq.c b/drivers/staging/comedi/rt_pend_tq.c
new file mode 100644
index 00000000000..995f076e0af
--- /dev/null
+++ b/drivers/staging/comedi/rt_pend_tq.c
@@ -0,0 +1,113 @@
+#define __NO_VERSION__
+/* rt_pend_tq.c */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include "comedidev.h" // for rt spinlocks
+#include "rt_pend_tq.h"
+#ifdef CONFIG_COMEDI_RTAI
+#include <rtai.h>
+#endif
+#ifdef CONFIG_COMEDI_FUSION
+#include <nucleus/asm/hal.h>
+#endif
+#ifdef CONFIG_COMEDI_RTL
+#include <rtl_core.h>
+#endif
+
+#ifdef standalone
+#include <linux/module.h>
+#define rt_pend_tq_init init_module
+#define rt_pend_tq_cleanup cleanup_module
+#endif
+
+volatile static struct rt_pend_tq rt_pend_tq[RT_PEND_TQ_SIZE];
+volatile static struct rt_pend_tq *volatile rt_pend_head = rt_pend_tq,
+ *volatile rt_pend_tail = rt_pend_tq;
+int rt_pend_tq_irq = 0;
+spinlock_t rt_pend_tq_lock = SPIN_LOCK_UNLOCKED;
+
+// WARNING: following code not checked against race conditions yet.
+#define INC_CIRCULAR_PTR(ptr,begin,size) do {if(++(ptr)>=(begin)+(size)) (ptr)=(begin); } while(0)
+#define DEC_CIRCULAR_PTR(ptr,begin,size) do {if(--(ptr)<(begin)) (ptr)=(begin)+(size)-1; } while(0)
+
+int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1, void *arg2)
+{
+ unsigned long flags;
+
+ if (func == NULL)
+ return -EINVAL;
+ if (rt_pend_tq_irq <= 0)
+ return -ENODEV;
+ comedi_spin_lock_irqsave(&rt_pend_tq_lock, flags);
+ INC_CIRCULAR_PTR(rt_pend_head, rt_pend_tq, RT_PEND_TQ_SIZE);
+ if (rt_pend_head == rt_pend_tail) {
+ // overflow, we just refuse to take this request
+ DEC_CIRCULAR_PTR(rt_pend_head, rt_pend_tq, RT_PEND_TQ_SIZE);
+ comedi_spin_unlock_irqrestore(&rt_pend_tq_lock, flags);
+ return -EAGAIN;
+ }
+ rt_pend_head->func = func;
+ rt_pend_head->arg1 = arg1;
+ rt_pend_head->arg2 = arg2;
+ comedi_spin_unlock_irqrestore(&rt_pend_tq_lock, flags);
+#ifdef CONFIG_COMEDI_RTAI
+ rt_pend_linux_srq(rt_pend_tq_irq);
+#endif
+#ifdef CONFIG_COMEDI_FUSION
+ rthal_apc_schedule(rt_pend_tq_irq);
+#endif
+#ifdef CONFIG_COMEDI_RTL
+ rtl_global_pend_irq(rt_pend_tq_irq);
+
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_COMEDI_RTAI
+void rt_pend_irq_handler(void)
+#elif defined(CONFIG_COMEDI_FUSION)
+void rt_pend_irq_handler(void *cookie)
+#elif defined(CONFIG_COMEDI_RTL)
+void rt_pend_irq_handler(int irq, void *dev PT_REGS_ARG)
+#endif
+{
+ while (rt_pend_head != rt_pend_tail) {
+ INC_CIRCULAR_PTR(rt_pend_tail, rt_pend_tq, RT_PEND_TQ_SIZE);
+ rt_pend_tail->func(rt_pend_tail->arg1, rt_pend_tail->arg2);
+ }
+}
+
+int rt_pend_tq_init(void)
+{
+ rt_pend_head = rt_pend_tail = rt_pend_tq;
+#ifdef CONFIG_COMEDI_RTAI
+ rt_pend_tq_irq = rt_request_srq(0, rt_pend_irq_handler, NULL);
+#endif
+#ifdef CONFIG_COMEDI_FUSION
+ rt_pend_tq_irq =
+ rthal_apc_alloc("comedi APC", rt_pend_irq_handler, NULL);
+#endif
+#ifdef CONFIG_COMEDI_RTL
+ rt_pend_tq_irq = rtl_get_soft_irq(rt_pend_irq_handler, "rt_pend_irq");
+#endif
+ if (rt_pend_tq_irq > 0)
+ printk("rt_pend_tq: RT bottom half scheduler initialized OK\n");
+ else
+ printk("rt_pend_tq: rtl_get_soft_irq failed\n");
+ return 0;
+}
+
+void rt_pend_tq_cleanup(void)
+{
+ printk("rt_pend_tq: unloading\n");
+#ifdef CONFIG_COMEDI_RTAI
+ rt_free_srq(rt_pend_tq_irq);
+#endif
+#ifdef CONFIG_COMEDI_FUSION
+ rthal_apc_free(rt_pend_tq_irq);
+#endif
+#ifdef CONFIG_COMEDI_RTL
+ free_irq(rt_pend_tq_irq, NULL);
+#endif
+}