summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2021-03-30 13:58:29 +1100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2021-03-31 00:28:28 +0200
commit1c02564abe7cea7d2fc6df82aeecce5bb6b0d93a (patch)
treebda6b0363cb012c53f4eea2c049296e665d2022d
parent66b55623f3072ec000b01577b93a94cf387c16c8 (diff)
intr: Add user interrupt handling code for non-Linux case
* device/intr.c: Include <kern/assert.h> (struct intr_list): New structure. (user_intr_handlers): New array. (user_irq_handler): New function. (install_user_intr_handler): New function. Message-Id: <20210330025830.63528-2-damien@zamaudio.com>
-rw-r--r--device/intr.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/device/intr.c b/device/intr.c
index fbb9f495..ac213ecf 100644
--- a/device/intr.c
+++ b/device/intr.c
@@ -12,6 +12,7 @@
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*/
+#include <kern/assert.h>
#include <device/intr.h>
#include <device/device_types.h>
#include <device/device_port.h>
@@ -26,6 +27,17 @@
queue_head_t main_intr_queue;
static boolean_t deliver_intr (int id, ipc_port_t dst_port);
+#ifndef LINUX_DEV
+#define SA_SHIRQ 0x04000000
+
+struct intr_list {
+ user_intr_t *user_intr;
+ unsigned long flags;
+ struct intr_list *next;
+};
+static struct intr_list *user_intr_handlers[NINTR];
+#endif
+
static user_intr_t *
search_intr (struct irqdev *dev, ipc_port_t dst_port)
{
@@ -147,6 +159,74 @@ out:
return ret;
}
+#ifndef LINUX_DEV
+
+static void
+user_irq_handler (int id)
+{
+ struct intr_list *handler;
+ struct intr_list **prev = &user_intr_handlers[id];
+ user_intr_t *e;
+ spl_t s;
+
+ s = splhigh();
+
+ for (handler = *prev; handler; handler = handler->next)
+ {
+ e = handler->user_intr;
+ if (!deliver_user_intr(&irqtab, id, e))
+ {
+ /* We failed to deliver this interrupt, remove handler from list */
+ *prev = handler->next;
+ }
+ prev = &handler->next;
+ }
+ splx(s);
+}
+
+int
+install_user_intr_handler (struct irqdev *dev, int id, unsigned long flags,
+ user_intr_t *user_intr)
+{
+ unsigned int irq = dev->irq[id];
+ struct intr_list **head = &user_intr_handlers[id];
+ struct intr_list *new, *old = *head;
+ spl_t s;
+
+ assert (irq < NINTR);
+
+ /* Don't allow overriding hardclock/kdintr etc */
+ if ((ivect[irq] != user_irq_handler) && (ivect[irq] != intnull))
+ {
+ mach_print("You can't have this interrupt\n");
+ return D_ALREADY_OPEN;
+ }
+
+ if (old)
+ {
+ if (!(old->flags & flags & SA_SHIRQ))
+ {
+ mach_print ("Cannot share irq\n");
+ return D_ALREADY_OPEN;
+ }
+ }
+
+ new = (struct intr_list *)kalloc (sizeof (struct intr_list));
+ new->user_intr = user_intr;
+ new->flags = flags;
+
+ s = splhigh();
+ new->next = *head;
+ *head = new;
+ ivect[irq] = user_irq_handler;
+ iunit[irq] = (int)irq;
+ unmask_irq (irq);
+ splx(s);
+
+ return D_SUCCESS;
+}
+#endif
+
void
intr_thread (void)
{