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 "../system.h"
14 #include <minix/endpoint.h>
18 FORWARD
_PROTOTYPE(int generic_handler
, (irq_hook_t
*hook
));
20 /*===========================================================================*
22 *===========================================================================*/
23 PUBLIC
int do_irqctl(struct proc
* caller
, message
* m_ptr
)
25 /* Dismember the request message. */
34 /* Hook identifiers start at 1 and end at NR_IRQ_HOOKS. */
35 irq_hook_id
= (unsigned) m_ptr
->IRQ_HOOK_ID
- 1;
36 irq_vec
= (unsigned) m_ptr
->IRQ_VECTOR
;
38 /* See what is requested and take needed actions. */
39 switch(m_ptr
->IRQ_REQUEST
) {
41 /* Enable or disable IRQs. This is straightforward. */
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
!= m_ptr
->m_source
) return(EPERM
);
47 if (m_ptr
->IRQ_REQUEST
== IRQ_ENABLE
) {
48 enable_irq(&irq_hooks
[irq_hook_id
]);
51 disable_irq(&irq_hooks
[irq_hook_id
]);
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.
59 /* Check if IRQ line is acceptable. */
60 if (irq_vec
< 0 || irq_vec
>= NR_IRQ_VECTORS
) return(EINVAL
);
65 printf("do_irqctl: no priv structure!\n");
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
])
75 if (i
>= privp
->s_nr_irq
)
78 "do_irqctl: IRQ check failed for proc %d, IRQ %d\n",
79 m_ptr
->m_source
, irq_vec
);
84 /* Find a free IRQ hook for this mapping. */
86 for (irq_hook_id
=0; irq_hook_id
<NR_IRQ_HOOKS
; irq_hook_id
++) {
87 if (irq_hooks
[irq_hook_id
].proc_nr_e
== NONE
) {
88 hook_ptr
= &irq_hooks
[irq_hook_id
]; /* free hook */
92 if (hook_ptr
== NULL
) return(ENOSPC
);
94 /* When setting a policy, the caller must provide an identifier that
95 * is returned on the notification message if a interrupt occurs.
97 notify_id
= (unsigned) m_ptr
->IRQ_HOOK_ID
;
98 if (notify_id
> CHAR_BIT
* sizeof(irq_id_t
) - 1) return(EINVAL
);
100 /* Install the handler. */
101 hook_ptr
->proc_nr_e
= m_ptr
->m_source
; /* process to notify */
102 hook_ptr
->notify_id
= notify_id
; /* identifier to pass */
103 hook_ptr
->policy
= m_ptr
->IRQ_POLICY
; /* policy for interrupts */
104 put_irq_handler(hook_ptr
, irq_vec
, generic_handler
);
106 /* Return index of the IRQ hook in use. */
107 m_ptr
->IRQ_HOOK_ID
= irq_hook_id
+ 1;
111 if (irq_hook_id
< 0 || irq_hook_id
>= NR_IRQ_HOOKS
||
112 irq_hooks
[irq_hook_id
].proc_nr_e
== NONE
) {
114 } else if (m_ptr
->m_source
!= irq_hooks
[irq_hook_id
].proc_nr_e
) {
117 /* Remove the handler and return. */
118 rm_irq_handler(&irq_hooks
[irq_hook_id
]);
119 irq_hooks
[irq_hook_id
].proc_nr_e
= NONE
;
123 r
= EINVAL
; /* invalid IRQ_REQUEST */
128 /*===========================================================================*
130 *===========================================================================*/
131 PRIVATE
int generic_handler(hook
)
134 /* This function handles hardware interrupt in a simple and generic way. All
135 * interrupts are transformed into messages to a driver. The IRQ line will be
136 * reenabled if the policy says so.
140 /* As a side-effect, the interrupt handler gathers random information by
141 * timestamping the interrupt events. This is used for /dev/random.
143 get_randomness(&krandom
, hook
->irq
);
145 /* Check if the handler is still alive.
146 * If it's dead, this should never happen, as processes that die
147 * automatically get their interrupt hooks unhooked.
149 if(!isokendpt(hook
->proc_nr_e
, &proc_nr
))
150 panic("invalid interrupt handler: %d", hook
->proc_nr_e
);
152 /* Add a bit for this interrupt to the process' pending interrupts. When
153 * sending the notification message, this bit map will be magically set
156 priv(proc_addr(proc_nr
))->s_int_pending
|= (1 << hook
->notify_id
);
158 /* Build notification message and return. */
159 mini_notify(proc_addr(HARDWARE
), hook
->proc_nr_e
);
160 return(hook
->policy
& IRQ_REENABLE
);
163 #endif /* USE_IRQCTL */