1 /* The kernel call implemented in this file:
4 * The parameters for this kernel call are:
5 * m5_s1: IRQ_REQUEST (control operation to perform)
6 * m5_s2: IRQ_VECTOR (irq line that must be controlled)
7 * m5_i1: IRQ_POLICY (irq policy allows reenabling interrupts)
8 * m5_l3: IRQ_HOOK_ID (provides index to be returned on interrupt)
9 * ,, ,, (returns index of irq hook assigned at kernel)
12 #include "kernel/kernel.h"
13 #include "kernel/system.h"
15 #include <minix/endpoint.h>
19 static int generic_handler(irq_hook_t
*hook
);
21 /*===========================================================================*
23 *===========================================================================*/
24 int do_irqctl(struct proc
* caller
, message
* m_ptr
)
26 /* Dismember the request message. */
35 /* Hook identifiers start at 1 and end at NR_IRQ_HOOKS. */
36 irq_hook_id
= (unsigned) m_ptr
->IRQ_HOOK_ID
- 1;
37 irq_vec
= (unsigned) m_ptr
->IRQ_VECTOR
;
39 /* See what is requested and take needed actions. */
40 switch(m_ptr
->IRQ_REQUEST
) {
42 /* Enable or disable IRQs. This is straightforward. */
45 if (irq_hook_id
>= NR_IRQ_HOOKS
|| irq_hook_id
< 0 ||
46 irq_hooks
[irq_hook_id
].proc_nr_e
== NONE
) return(EINVAL
);
47 if (irq_hooks
[irq_hook_id
].proc_nr_e
!= caller
->p_endpoint
) return(EPERM
);
48 if (m_ptr
->IRQ_REQUEST
== IRQ_ENABLE
) {
49 enable_irq(&irq_hooks
[irq_hook_id
]);
52 disable_irq(&irq_hooks
[irq_hook_id
]);
55 /* Control IRQ policies. Set a policy and needed details in the IRQ table.
56 * This policy is used by a generic function to handle hardware interrupts.
60 /* Check if IRQ line is acceptable. */
61 if (irq_vec
< 0 || irq_vec
>= NR_IRQ_VECTORS
) return(EINVAL
);
66 printf("do_irqctl: no priv structure!\n");
69 if (privp
->s_flags
& CHECK_IRQ
)
71 for (i
= 0; i
<privp
->s_nr_irq
; i
++)
73 if (irq_vec
== privp
->s_irq_tab
[i
])
76 if (i
>= privp
->s_nr_irq
)
79 "do_irqctl: IRQ check failed for proc %d, IRQ %d\n",
80 caller
->p_endpoint
, irq_vec
);
85 /* When setting a policy, the caller must provide an identifier that
86 * is returned on the notification message if a interrupt occurs.
88 notify_id
= (unsigned) m_ptr
->IRQ_HOOK_ID
;
89 if (notify_id
> CHAR_BIT
* sizeof(irq_id_t
) - 1) return(EINVAL
);
91 /* Try to find an existing mapping to override. */
93 for (i
=0; !hook_ptr
&& i
<NR_IRQ_HOOKS
; i
++) {
94 if (irq_hooks
[i
].proc_nr_e
== caller
->p_endpoint
95 && irq_hooks
[i
].notify_id
== notify_id
) {
97 hook_ptr
= &irq_hooks
[irq_hook_id
]; /* existing hook */
98 rm_irq_handler(&irq_hooks
[irq_hook_id
]);
102 /* If there is nothing to override, find a free hook for this mapping. */
103 for (i
=0; !hook_ptr
&& i
<NR_IRQ_HOOKS
; i
++) {
104 if (irq_hooks
[i
].proc_nr_e
== NONE
) {
106 hook_ptr
= &irq_hooks
[irq_hook_id
]; /* free hook */
109 if (hook_ptr
== NULL
) return(ENOSPC
);
111 /* Install the handler. */
112 hook_ptr
->proc_nr_e
= caller
->p_endpoint
; /* process to notify */
113 hook_ptr
->notify_id
= notify_id
; /* identifier to pass */
114 hook_ptr
->policy
= m_ptr
->IRQ_POLICY
; /* policy for interrupts */
115 put_irq_handler(hook_ptr
, irq_vec
, generic_handler
);
116 DEBUGBASIC(("IRQ %d handler registered by %s / %d\n",
117 irq_vec
, caller
->p_name
, caller
->p_endpoint
));
119 /* Return index of the IRQ hook in use. */
120 m_ptr
->IRQ_HOOK_ID
= irq_hook_id
+ 1;
124 if (irq_hook_id
< 0 || irq_hook_id
>= NR_IRQ_HOOKS
||
125 irq_hooks
[irq_hook_id
].proc_nr_e
== NONE
) {
127 } else if (caller
->p_endpoint
!= irq_hooks
[irq_hook_id
].proc_nr_e
) {
130 /* Remove the handler and return. */
131 rm_irq_handler(&irq_hooks
[irq_hook_id
]);
132 irq_hooks
[irq_hook_id
].proc_nr_e
= NONE
;
136 r
= EINVAL
; /* invalid IRQ_REQUEST */
141 /*===========================================================================*
143 *===========================================================================*/
144 static int generic_handler(hook
)
147 /* This function handles hardware interrupt in a simple and generic way. All
148 * interrupts are transformed into messages to a driver. The IRQ line will be
149 * reenabled if the policy says so.
153 /* As a side-effect, the interrupt handler gathers random information by
154 * timestamping the interrupt events. This is used for /dev/random.
156 get_randomness(&krandom
, hook
->irq
);
158 /* Check if the handler is still alive.
159 * If it's dead, this should never happen, as processes that die
160 * automatically get their interrupt hooks unhooked.
162 if(!isokendpt(hook
->proc_nr_e
, &proc_nr
))
163 panic("invalid interrupt handler: %d", hook
->proc_nr_e
);
165 /* Add a bit for this interrupt to the process' pending interrupts. When
166 * sending the notification message, this bit map will be magically set
169 priv(proc_addr(proc_nr
))->s_int_pending
|= (1 << hook
->notify_id
);
171 /* Build notification message and return. */
172 mini_notify(proc_addr(HARDWARE
), hook
->proc_nr_e
);
173 return(hook
->policy
& IRQ_REENABLE
);
176 #endif /* USE_IRQCTL */