Remove building with NOCRYPTO option
[minix.git] / minix / kernel / system / do_irqctl.c
blobc56bee41321846b6f297b13eed0d47e3e8093525
1 /* The kernel call implemented in this file:
2 * m_type: SYS_IRQCTL
4 * The parameters for this kernel call are:
5 * m_lsys_krn_sys_irqctl.request (control operation to perform)
6 * m_lsys_krn_sys_irqctl.vector (irq line that must be controlled)
7 * m_lsys_krn_sys_irqctl.policy (irq policy allows reenabling interrupts)
8 * m_lsys_krn_sys_irqctl.hook_id (provides index to be returned on interrupt)
9 * m_krn_lsys_sys_irqctl.hook_id (returns index of irq hook assigned at kernel)
12 #include "kernel/system.h"
14 #include <minix/endpoint.h>
16 #if USE_IRQCTL
18 static int generic_handler(irq_hook_t *hook);
20 /*===========================================================================*
21 * do_irqctl *
22 *===========================================================================*/
23 int do_irqctl(struct proc * caller, message * m_ptr)
25 /* Dismember the request message. */
26 int irq_vec;
27 int irq_hook_id;
28 int notify_id;
29 int r = OK;
30 int i;
31 irq_hook_t *hook_ptr;
32 struct priv *privp;
34 /* Hook identifiers start at 1 and end at NR_IRQ_HOOKS. */
35 irq_hook_id = m_ptr->m_lsys_krn_sys_irqctl.hook_id - 1;
36 irq_vec = m_ptr->m_lsys_krn_sys_irqctl.vector;
38 /* See what is requested and take needed actions. */
39 switch(m_ptr->m_lsys_krn_sys_irqctl.request) {
41 /* Enable or disable IRQs. This is straightforward. */
42 case IRQ_ENABLE:
43 case IRQ_DISABLE:
44 if (irq_hook_id >= NR_IRQ_HOOKS || irq_hook_id < 0 ||
45 irq_hooks[irq_hook_id].proc_nr_e == NONE) return(EINVAL);
46 if (irq_hooks[irq_hook_id].proc_nr_e != caller->p_endpoint) return(EPERM);
47 if (m_ptr->m_lsys_krn_sys_irqctl.request == IRQ_ENABLE) {
48 enable_irq(&irq_hooks[irq_hook_id]);
50 else
51 disable_irq(&irq_hooks[irq_hook_id]);
52 break;
54 /* Control IRQ policies. Set a policy and needed details in the IRQ table.
55 * This policy is used by a generic function to handle hardware interrupts.
57 case IRQ_SETPOLICY:
59 /* Check if IRQ line is acceptable. */
60 if (irq_vec < 0 || irq_vec >= NR_IRQ_VECTORS) return(EINVAL);
62 privp= priv(caller);
63 if (!privp)
65 printf("do_irqctl: no priv structure!\n");
66 return EPERM;
68 if (privp->s_flags & CHECK_IRQ)
70 for (i= 0; i<privp->s_nr_irq; i++)
72 if (irq_vec == privp->s_irq_tab[i])
73 break;
75 if (i >= privp->s_nr_irq)
77 printf(
78 "do_irqctl: IRQ check failed for proc %d, IRQ %d\n",
79 caller->p_endpoint, irq_vec);
80 return EPERM;
84 /* When setting a policy, the caller must provide an identifier that
85 * is returned on the notification message if a interrupt occurs.
87 notify_id = m_ptr->m_lsys_krn_sys_irqctl.hook_id;
88 if (notify_id > CHAR_BIT * sizeof(irq_id_t) - 1) return(EINVAL);
90 /* Try to find an existing mapping to override. */
91 hook_ptr = NULL;
92 for (i=0; !hook_ptr && i<NR_IRQ_HOOKS; i++) {
93 if (irq_hooks[i].proc_nr_e == caller->p_endpoint
94 && irq_hooks[i].notify_id == notify_id) {
95 irq_hook_id = i;
96 hook_ptr = &irq_hooks[irq_hook_id]; /* existing hook */
97 rm_irq_handler(&irq_hooks[irq_hook_id]);
101 /* If there is nothing to override, find a free hook for this mapping. */
102 for (i=0; !hook_ptr && i<NR_IRQ_HOOKS; i++) {
103 if (irq_hooks[i].proc_nr_e == NONE) {
104 irq_hook_id = i;
105 hook_ptr = &irq_hooks[irq_hook_id]; /* free hook */
108 if (hook_ptr == NULL) return(ENOSPC);
110 /* Install the handler. */
111 hook_ptr->proc_nr_e = caller->p_endpoint; /* process to notify */
112 hook_ptr->notify_id = notify_id; /* identifier to pass */
113 hook_ptr->policy = m_ptr->m_lsys_krn_sys_irqctl.policy; /* policy for interrupts */
114 put_irq_handler(hook_ptr, irq_vec, generic_handler);
115 DEBUGBASIC(("IRQ %d handler registered by %s / %d\n",
116 irq_vec, caller->p_name, caller->p_endpoint));
118 /* Return index of the IRQ hook in use. */
119 m_ptr->m_krn_lsys_sys_irqctl.hook_id = irq_hook_id + 1;
120 break;
122 case IRQ_RMPOLICY:
123 if (irq_hook_id < 0 || irq_hook_id >= NR_IRQ_HOOKS ||
124 irq_hooks[irq_hook_id].proc_nr_e == NONE) {
125 return(EINVAL);
126 } else if (caller->p_endpoint != irq_hooks[irq_hook_id].proc_nr_e) {
127 return(EPERM);
129 /* Remove the handler and return. */
130 rm_irq_handler(&irq_hooks[irq_hook_id]);
131 irq_hooks[irq_hook_id].proc_nr_e = NONE;
132 break;
134 default:
135 r = EINVAL; /* invalid IRQ REQUEST */
137 return(r);
140 /*===========================================================================*
141 * generic_handler *
142 *===========================================================================*/
143 static int generic_handler(irq_hook_t * hook)
145 /* This function handles hardware interrupt in a simple and generic way. All
146 * interrupts are transformed into messages to a driver. The IRQ line will be
147 * reenabled if the policy says so.
149 int proc_nr;
151 /* As a side-effect, the interrupt handler gathers random information by
152 * timestamping the interrupt events. This is used for /dev/random.
154 get_randomness(&krandom, hook->irq);
156 /* Check if the handler is still alive.
157 * If it's dead, this should never happen, as processes that die
158 * automatically get their interrupt hooks unhooked.
160 if(!isokendpt(hook->proc_nr_e, &proc_nr))
161 panic("invalid interrupt handler: %d", hook->proc_nr_e);
163 /* Add a bit for this interrupt to the process' pending interrupts. When
164 * sending the notification message, this bit map will be magically set
165 * as an argument.
167 priv(proc_addr(proc_nr))->s_int_pending |= (1 << hook->notify_id);
169 /* Build notification message and return. */
170 mini_notify(proc_addr(HARDWARE), hook->proc_nr_e);
171 return(hook->policy & IRQ_REENABLE);
174 #endif /* USE_IRQCTL */