1 /* The kernel call implemented in this file:
4 * The parameters for this kernel call are:
5 * m5_c1: IRQ_REQUEST (control operation to perform)
6 * m5_c2: 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(m_ptr
)
24 register message
*m_ptr
; /* pointer to request message */
26 /* Dismember the request message. */
36 /* Hook identifiers start at 1 and end at NR_IRQ_HOOKS. */
37 irq_hook_id
= (unsigned) m_ptr
->IRQ_HOOK_ID
- 1;
38 irq_vec
= (unsigned) m_ptr
->IRQ_VECTOR
;
40 /* See what is requested and take needed actions. */
41 switch(m_ptr
->IRQ_REQUEST
) {
43 /* Enable or disable IRQs. This is straightforward. */
46 if (irq_hook_id
>= NR_IRQ_HOOKS
|| irq_hook_id
< 0 ||
47 irq_hooks
[irq_hook_id
].proc_nr_e
== NONE
) return(EINVAL
);
48 if (irq_hooks
[irq_hook_id
].proc_nr_e
!= m_ptr
->m_source
) return(EPERM
);
49 if (m_ptr
->IRQ_REQUEST
== IRQ_ENABLE
)
50 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
);
67 kprintf("no priv structure!\n");
70 if (privp
->s_flags
& CHECK_IRQ
)
72 for (i
= 0; i
<privp
->s_nr_irq
; i
++)
74 if (irq_vec
== privp
->s_irq_tab
[i
])
77 if (i
>= privp
->s_nr_irq
)
80 "do_irqctl: IRQ check failed for proc %d, IRQ %d\n",
81 m_ptr
->m_source
, irq_vec
);
86 /* Find a free IRQ hook for this mapping. */
88 for (irq_hook_id
=0; irq_hook_id
<NR_IRQ_HOOKS
; irq_hook_id
++) {
89 if (irq_hooks
[irq_hook_id
].proc_nr_e
== NONE
) {
90 hook_ptr
= &irq_hooks
[irq_hook_id
]; /* free hook */
94 if (hook_ptr
== NULL
) return(ENOSPC
);
96 /* When setting a policy, the caller must provide an identifier that
97 * is returned on the notification message if a interrupt occurs.
99 notify_id
= (unsigned) m_ptr
->IRQ_HOOK_ID
;
100 if (notify_id
> CHAR_BIT
* sizeof(irq_id_t
) - 1) return(EINVAL
);
102 /* Install the handler. */
103 hook_ptr
->proc_nr_e
= m_ptr
->m_source
; /* process to notify */
104 hook_ptr
->notify_id
= notify_id
; /* identifier to pass */
105 hook_ptr
->policy
= m_ptr
->IRQ_POLICY
; /* policy for interrupts */
106 put_irq_handler(hook_ptr
, irq_vec
, generic_handler
);
108 /* Return index of the IRQ hook in use. */
109 m_ptr
->IRQ_HOOK_ID
= irq_hook_id
+ 1;
113 if (irq_hook_id
< 0 || irq_hook_id
>= NR_IRQ_HOOKS
||
114 irq_hooks
[irq_hook_id
].proc_nr_e
== NONE
) {
116 } else if (m_ptr
->m_source
!= irq_hooks
[irq_hook_id
].proc_nr_e
) {
119 /* Remove the handler and return. */
120 rm_irq_handler(&irq_hooks
[irq_hook_id
]);
124 r
= EINVAL
; /* invalid IRQ_REQUEST */
129 /*===========================================================================*
131 *===========================================================================*/
132 PRIVATE
int generic_handler(hook
)
135 /* This function handles hardware interrupt in a simple and generic way. All
136 * interrupts are transformed into messages to a driver. The IRQ line will be
137 * reenabled if the policy says so.
141 /* As a side-effect, the interrupt handler gathers random information by
142 * timestamping the interrupt events. This is used for /dev/random.
144 get_randomness(hook
->irq
);
146 /* Check if the handler is still alive. If not, forget about the
147 * interrupt. This should never happen, as processes that die
148 * automatically get their interrupt hooks unhooked.
150 if(!isokendpt(hook
->proc_nr_e
, &proc
)) {
151 hook
->proc_nr_e
= NONE
;
155 /* Add a bit for this interrupt to the process' pending interrupts. When
156 * sending the notification message, this bit map will be magically set
159 priv(proc_addr(proc
))->s_int_pending
|= (1 << hook
->notify_id
);
161 /* Build notification message and return. */
162 lock_notify(HARDWARE
, hook
->proc_nr_e
);
163 return(hook
->policy
& IRQ_REENABLE
);
166 #endif /* USE_IRQCTL */