/**************************************************************************** * sched/irq/irq_attach_thread.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include "irq/irq.h" #include "sched/sched.h" /**************************************************************************** * Privte Types ****************************************************************************/ /* This is the type of the list of interrupt handlers, one for each IRQ. * This type provided all of the information necessary to irq_dispatch to * transfer control to interrupt handlers after the occurrence of an * interrupt. */ struct irq_thread_info_s { xcpt_t handler; /* Address of the interrupt handler */ FAR void *arg; /* The argument provided to the interrupt handler. */ FAR sem_t *sem; /* irq sem used to notify irq thread */ }; /**************************************************************************** * Private Data ****************************************************************************/ static pid_t g_irq_thread_pid[NR_IRQS]; /**************************************************************************** * Private Functions ****************************************************************************/ /* Default interrupt handler for threaded interrupts. * Useful for oneshot interrupts. */ static int irq_default_handler(int irq, FAR void *regs, FAR void *arg) { FAR struct irq_thread_info_s *info = arg; int ret = IRQ_WAKE_THREAD; DEBUGASSERT(info->handler != NULL); ret = info->handler(irq, regs, info->arg); if (ret == IRQ_WAKE_THREAD) { nxsem_post(info->sem); ret = OK; } return ret; } static int isr_thread_main(int argc, FAR char *argv[]) { int irq = atoi(argv[1]); xcpt_t isr = (xcpt_t)((uintptr_t)strtoul(argv[2], NULL, 16)); xcpt_t isrthread = (xcpt_t)((uintptr_t)strtoul(argv[3], NULL, 16)); FAR void *arg = (FAR void *)((uintptr_t)strtoul(argv[4], NULL, 16)); struct irq_thread_info_s info; sem_t sem; info.sem = &sem; info.arg = arg; info.handler = isr; nxsem_init(&sem, 0, 0); irq_attach(irq, irq_default_handler, &info); #if !defined(CONFIG_ARCH_NOINTC) up_enable_irq(irq); #endif for (; ; ) { if (nxsem_wait_uninterruptible(&sem) < 0) { continue; } isrthread(irq, NULL, arg); } return OK; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: irq_attach_thread * * Description: * Configure the IRQ subsystem so that IRQ number 'irq' is dispatched to * 'isrthread' and up_enable_irq will be invoked after isrthread started. * * Input Parameters: * irq - Irq num * isr - Function to be called when the IRQ occurs, called in interrupt * context. * If isr is NULL the default handler is installed(irq_default_handler). * isrthread - called in thread context, If the isrthread is NULL, * then the ISR is being detached. * arg - privdate data * priority - Priority of the new task * stack_size - size (in bytes) of the stack needed * * Returned Value: * Zero on success; a negated errno value on failure. * ****************************************************************************/ int irq_attach_thread(int irq, xcpt_t isr, xcpt_t isrthread, FAR void *arg, int priority, int stack_size) { #if NR_IRQS > 0 FAR char *argv[5]; char arg1[32]; /* irq */ char arg2[32]; /* isr */ char arg3[32]; /* isrthread */ char arg4[32]; /* arg */ pid_t pid; int ndx; if ((unsigned)irq >= NR_IRQS) { return -EINVAL; } ndx = IRQ_TO_NDX(irq); if (ndx < 0) { return ndx; } /* If the isrthread is NULL, then the ISR is being detached. */ if (isrthread == NULL) { irq_detach(irq); DEBUGASSERT(g_irq_thread_pid[ndx] != 0); kthread_delete(g_irq_thread_pid[ndx]); g_irq_thread_pid[ndx] = 0; return OK; } if (g_irq_thread_pid[ndx] != 0) { return -EINVAL; } snprintf(arg1, sizeof(arg1), "%d", irq); snprintf(arg2, sizeof(arg2), "%p", isr); snprintf(arg3, sizeof(arg3), "%p", isrthread); snprintf(arg4, sizeof(arg4), "%p", arg); argv[0] = arg1; argv[1] = arg2; argv[2] = arg3; argv[3] = arg4; argv[4] = NULL; pid = kthread_create("isr_thread", priority, stack_size, isr_thread_main, argv); if (pid < 0) { return pid; } g_irq_thread_pid[ndx] = pid; #endif /* NR_IRQS */ return OK; }