?? psc.c
字號:
/* * (C) Finite State Machine Labs Inc. 2000 business@fsmlabs.com * * Released under the terms of GPL 2. * Open RTLinux makes use of a patented process described in * US Patent 5,995,745. Use of this process is governed * by the Open RTLinux Patent License which can be obtained from * www.fsmlabs.com/PATENT or by sending email to * licensequestions@fsmlabs.com */#include <linux/module.h>#include <linux/proc_fs.h>#include <linux/irq.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/signal.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/mmu_context.h>#include <rtl_debug.h>#include <rtl_core.h>#include <rtlinux_signal.h>#include <psc.h>#include <rtl_sync.h>#include <rtl_time.h>#include <rtl_sched.h>#include <rtl_fifo.h>#include <arch/rtl_switch.h>/* posix/signal.h defines these. It's an ugly hack and this * is a ugly workaround. -- Cort */#undef sa_sigaction#undef sa_handler#undef sigactionMODULE_AUTHOR("FSMLabs <support@fsmlabs.com>");MODULE_DESCRIPTION("RTLinux user-level real-time Module");MODULE_LICENSE("GPL v2");#define PSC_DEVNAME "RTLinux user-level IRQ handler"extern long sys_call_table[256];unsigned long sys_ni_syscall;unsigned long __NR_rtf_destroy = 0;unsigned long __NR_rtf_create = 0;struct proc_dir_entry *proc_rtlinux, *proc_sigaction, *proc_sigprocmask, *proc_gethrtime, *proc_rtf_put, *proc_rtf_get, *proc_rtf_create, *proc_rtf_destroy;struct irq_thread { struct rtlinux_sigaction action; pid_t pid; pthread_t ptid;} irq_threads[NR_IRQS];struct timer_thread { struct rtlinux_sigaction action; pid_t pid; pthread_t ptid; struct timer_thread *next; int pending;} *timer_threads;/* support function for checking signal masks. -Nathan */int rtlinux_sigismember(const rtlinux_sigset_t * set, int sig){ int offset; unsigned long int value; if (set == NULL) return (-1); if (sig > RTLINUX_SIGMAX) { errno = EINVAL; return (-1); } offset = (int) ((sig / (sizeof(unsigned long int) * 8))); value = 1 << (sig % (sizeof(unsigned long int) * 8)); if (((unsigned long int) (set->__val[offset] & value)) > 0) return (1); return (0);}int rtlinux_sigemptyset(rtlinux_sigset_t * set){ if (set == NULL) return (-1); memset(set, 0x00, sizeof(rtlinux_sigset_t)); return (0);}static void insert_timer_thread(struct timer_thread *thread){ unsigned long flags; rtl_hard_savef_and_cli(flags); rtlinux_sigemptyset(&(thread->action.sa_mask)); thread->pending = 0; thread->next = timer_threads; timer_threads = thread; rtl_hard_restore_flags(flags);}static struct timer_thread *remove_timer_thread(struct timer_thread *tt){ unsigned long flags; struct timer_thread *ret = NULL, *die = NULL; rtl_hard_savef_and_cli(flags); if ((tt = timer_threads)) { timer_threads = timer_threads->next; goto out; } for (ret = timer_threads; ret->next && (ret->next != tt); ret = ret->next) /* nothing */ ; die = ret->next; if (ret->next) ret->next = ret->next->next; kfree(die); out: rtl_hard_restore_flags(flags); return ret;}static struct timer_thread *find_timer_thread(pid_t pid, int signal){ unsigned long flags; struct timer_thread *ret; rtl_hard_savef_and_cli(flags); for (ret = timer_threads; ret && ((ret->pid != pid) || (ret->action.sa_signal != signal)); ret = ret->next) /* nothing */ ; rtl_hard_restore_flags(flags); return ret;}static int call_handler(struct rtlinux_sigaction *act, pid_t pid){ rtl_irqstate_t flags;#ifdef RTL_PSC_NEW rtl_mmu_state_t mmu_state;#else struct task_struct *linux_current = get_linux_current();#endif struct task_struct *tsk; int ret = 0; /* make sure the task that wants this interrupt is still running */ if (!(tsk = find_task_by_pid(pid))) { /* TODO is this really safe? */ /* make sure the handler is disabled */ act->sa_flags |= RTLINUX_SA_ONESHOT; rtl_printf("task %d is gone!\n", pid); ret = -1; goto out; } if (!tsk->mm) { /* make sure the handler is disabled */ act->sa_flags |= RTLINUX_SA_ONESHOT; rtl_printf("task has no ->mm, not calling\n"); ret = -1; goto out; }#ifndef RTL_PSC_NEW if (!linux_current->active_mm) { act->sa_flags |= RTLINUX_SA_ONESHOT; rtl_printf("current has no ->mm, not calling\n"); ret = -1; goto out; }#endif rtl_no_interrupts(flags); rtl_make_psc_active();#ifdef RTL_PSC_NEW rtl_mmu_save(&mmu_state); rtl_mmu_switch_to(tsk); act->sa_handler(act->sa_signal); rtl_mmu_restore(&mmu_state);#else switch_mm(linux_current->active_mm, tsk->mm, tsk, rtl_getcpuid()); act->sa_handler(act->sa_signal); switch_mm(tsk->mm, linux_current->active_mm, tsk, rtl_getcpuid());#endif rtl_make_psc_inactive(); rtl_restore_interrupts(flags); out: return ret;}static void *psc_irq_thread(void *t){ ulong flags; struct irq_thread *my_irq_thread = (struct irq_thread *) t; rtl_stop_interrupts(); while (1) { pthread_suspend_np(pthread_self()); /* if the handler call fails or we don't want to reset the * handler remove it */ if (call_handler (&my_irq_thread->action, my_irq_thread->pid) || (my_irq_thread-> action.sa_flags & RTLINUX_SA_ONESHOT)) { /* we are synchronizing with RTL, so hard cli */ rtl_hard_savef_and_cli(flags); rtl_free_global_irq(my_irq_thread-> action.sa_signal); my_irq_thread->pid = 0; rtl_hard_restore_flags(flags); } rtl_global_pend_irq(my_irq_thread->action.sa_signal); rtl_hard_enable_irq(my_irq_thread->action.sa_signal); }}static void *timer_handler(void *t){ struct timer_thread *ptr = (struct timer_thread *) t; struct sched_param p; p.sched_priority = 1; pthread_setschedparam(pthread_self(), SCHED_FIFO, &p); if (pthread_make_periodic_np(pthread_self(), gethrtime() + ptr->action.sa_period, ptr->action.sa_period)) rtl_printf("Error from pthread_make_periodic_np()\n"); while (1) { pthread_wait_np(); /* if the handler call fails or we don't want to reset the handler * remove it */ if (ptr->pending == 0) { if (call_handler(&ptr->action, ptr->pid) || (ptr->action.sa_flags & RTLINUX_SA_ONESHOT)) { remove_timer_thread(ptr); pthread_exit(NULL); } } else ptr->pending++; } return NULL;}static unsigned int psc_irq_handler(unsigned int irq, struct pt_regs *regs){ /* just wake the stinking IRQ thread up and let it handle it -Nathan */ pthread_wakeup_np(irq_threads[irq].ptid); return 0;}static int sigaction_write(struct file *file, const char *buffer, unsigned long count, void *data){ struct rtlinux_sigaction action; ulong flags; struct timer_thread *tt = NULL; if (count != sizeof(action)) return -EINVAL; /* make sure the buffer we were passed is good, then copy it */ if (copy_from_user ((void *) &action, (void *) buffer, sizeof(action))) return -EFAULT; rtlinux_sigemptyset(&(action.sa_mask)); /* if the signal is < SIGTIMER0 it's an IRQ request */ if (action.sa_signal < RTLINUX_SIGTIMER0) { /* a request to free the irq */ if ((action.sa_handler == RTLINUX_SIG_DFL) || (action.sa_handler == RTLINUX_SIG_IGN)) { pthread_kill(irq_threads[action.sa_signal].ptid, RTL_SIGNAL_CANCEL); if (rtl_free_global_irq(action.sa_signal)) return -EALREADY; else return count; } /* we are synchronizing with RTL, so hard cli */ rtl_hard_savef_and_cli(flags); /* grab the interrupt */ if (rtl_request_global_irq (action.sa_signal, psc_irq_handler)) { rtl_hard_restore_flags(flags); return -EBUSY; } /* hmm, somehow we need to threadify IRQs so they have state * so they can be switched and stuff. hmmm . . . -Nathan */ /* we now own the real-time irq, assign the code */ irq_threads[action.sa_signal].pid = current->pid; irq_threads[action.sa_signal].action = action; pthread_create(&irq_threads[action.sa_signal].ptid, NULL, psc_irq_thread, (void *) &irq_threads[action.sa_signal]);#ifdef CONFIG_RTL_FP_SUPPORT
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -