xref: /freebsd/sys/kern/kern_intr.c (revision 425f9fda525adeeb51a81f5e6f5291ac5d3ea2f0)
1425f9fdaSStefan Eßer /*
2425f9fdaSStefan Eßer  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3425f9fdaSStefan Eßer  * All rights reserved.
4425f9fdaSStefan Eßer  *
5425f9fdaSStefan Eßer  * Redistribution and use in source and binary forms, with or without
6425f9fdaSStefan Eßer  * modification, are permitted provided that the following conditions
7425f9fdaSStefan Eßer  * are met:
8425f9fdaSStefan Eßer  * 1. Redistributions of source code must retain the above copyright
9425f9fdaSStefan Eßer  *    notice unmodified, this list of conditions, and the following
10425f9fdaSStefan Eßer  *    disclaimer.
11425f9fdaSStefan Eßer  * 2. Redistributions in binary form must reproduce the above copyright
12425f9fdaSStefan Eßer  *    notice, this list of conditions and the following disclaimer in the
13425f9fdaSStefan Eßer  *    documentation and/or other materials provided with the distribution.
14425f9fdaSStefan Eßer  *
15425f9fdaSStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16425f9fdaSStefan Eßer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17425f9fdaSStefan Eßer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18425f9fdaSStefan Eßer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19425f9fdaSStefan Eßer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20425f9fdaSStefan Eßer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21425f9fdaSStefan Eßer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22425f9fdaSStefan Eßer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23425f9fdaSStefan Eßer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24425f9fdaSStefan Eßer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25425f9fdaSStefan Eßer  *
26425f9fdaSStefan Eßer  * $Id$
27425f9fdaSStefan Eßer  *
28425f9fdaSStefan Eßer  */
29425f9fdaSStefan Eßer 
30425f9fdaSStefan Eßer #include <sys/types.h>
31425f9fdaSStefan Eßer #include <sys/malloc.h>
32425f9fdaSStefan Eßer #include <sys/time.h>
33425f9fdaSStefan Eßer #include <sys/systm.h>
34425f9fdaSStefan Eßer #include <sys/errno.h>
35425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
36425f9fdaSStefan Eßer #include <sys/drvresource.h>
37425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
38425f9fdaSStefan Eßer 
39425f9fdaSStefan Eßer #include <i386/isa/icu.h>
40425f9fdaSStefan Eßer #include <i386/isa/isa_device.h>
41425f9fdaSStefan Eßer #include <sys/interrupt.h> /* XXX needs inthand2_t from isa_device.h */
42425f9fdaSStefan Eßer 
43425f9fdaSStefan Eßer #include <machine/spl.h>
44425f9fdaSStefan Eßer 
45425f9fdaSStefan Eßer #include <stddef.h>
46425f9fdaSStefan Eßer 
47425f9fdaSStefan Eßer #include "vector.h"
48425f9fdaSStefan Eßer 
49425f9fdaSStefan Eßer /*
50425f9fdaSStefan Eßer  * The interrupt multiplexer calls each of the handlers in turn,
51425f9fdaSStefan Eßer  * and applies the associated interrupt mask to "cpl", which is
52425f9fdaSStefan Eßer  * defined as a ".long" in /sys/i386/isa/icu.s
53425f9fdaSStefan Eßer  */
54425f9fdaSStefan Eßer 
55425f9fdaSStefan Eßer static inline intrmask
56425f9fdaSStefan Eßer splq(intrmask mask)
57425f9fdaSStefan Eßer {
58425f9fdaSStefan Eßer 	intrmask tmp = cpl;
59425f9fdaSStefan Eßer 	cpl |= mask;
60425f9fdaSStefan Eßer 	return (tmp);
61425f9fdaSStefan Eßer }
62425f9fdaSStefan Eßer 
63425f9fdaSStefan Eßer static void
64425f9fdaSStefan Eßer intr_mux(void *arg)
65425f9fdaSStefan Eßer {
66425f9fdaSStefan Eßer 	intrec *p = arg;
67425f9fdaSStefan Eßer 
68425f9fdaSStefan Eßer 	while (p != NULL) {
69425f9fdaSStefan Eßer 		int oldspl = splq(p->mask);
70425f9fdaSStefan Eßer 		/* inthand2_t should take (void*) argument */
71425f9fdaSStefan Eßer 		p->handler(p->argument);
72425f9fdaSStefan Eßer 		splx(oldspl);
73425f9fdaSStefan Eßer 		p = p->next;
74425f9fdaSStefan Eßer 	}
75425f9fdaSStefan Eßer }
76425f9fdaSStefan Eßer 
77425f9fdaSStefan Eßer /* XXX better use NHWI from <machine/ipl.h> for array size ??? */
78425f9fdaSStefan Eßer static intrec *intreclist_head[ICU_LEN];
79425f9fdaSStefan Eßer 
80425f9fdaSStefan Eßer static intrec*
81425f9fdaSStefan Eßer find_idesc(unsigned *maskptr, int irq)
82425f9fdaSStefan Eßer {
83425f9fdaSStefan Eßer 	intrec *p = intreclist_head[irq];
84425f9fdaSStefan Eßer 
85425f9fdaSStefan Eßer 	while (p && p->maskptr != maskptr)
86425f9fdaSStefan Eßer 		p = p->next;
87425f9fdaSStefan Eßer 
88425f9fdaSStefan Eßer 	return (p);
89425f9fdaSStefan Eßer }
90425f9fdaSStefan Eßer 
91425f9fdaSStefan Eßer static intrec**
92425f9fdaSStefan Eßer find_pred(intrec *idesc, int irq)
93425f9fdaSStefan Eßer {
94425f9fdaSStefan Eßer 	intrec **pp = &intreclist_head[irq];
95425f9fdaSStefan Eßer 	intrec *p = *pp;
96425f9fdaSStefan Eßer 
97425f9fdaSStefan Eßer 	while (p != idesc) {
98425f9fdaSStefan Eßer 		if (p == NULL)
99425f9fdaSStefan Eßer 			return (NULL);
100425f9fdaSStefan Eßer 		pp = &p->next;
101425f9fdaSStefan Eßer 		p = *pp;
102425f9fdaSStefan Eßer 	}
103425f9fdaSStefan Eßer 	return (pp);
104425f9fdaSStefan Eßer }
105425f9fdaSStefan Eßer 
106425f9fdaSStefan Eßer /*
107425f9fdaSStefan Eßer  * Both the low level handler and the shared interrupt multiplexer
108425f9fdaSStefan Eßer  * block out further interrupts as set in the handlers "mask", while
109425f9fdaSStefan Eßer  * the handler is running. In fact *maskptr should be used for this
110425f9fdaSStefan Eßer  * purpose, but since this requires one more pointer dereference on
111425f9fdaSStefan Eßer  * each interrupt, we rather bother update "mask" whenever *maskptr
112425f9fdaSStefan Eßer  * changes. The function "update_masks" should be called **after**
113425f9fdaSStefan Eßer  * all manipulation of the linked list of interrupt handlers hung
114425f9fdaSStefan Eßer  * off of intrdec_head[irq] is complete, since the chain of handlers
115425f9fdaSStefan Eßer  * will both determine the *maskptr values and the instances of mask
116425f9fdaSStefan Eßer  * that are fixed. This function should be called with the irq for
117425f9fdaSStefan Eßer  * which a new handler has been add blocked, since the masks may not
118425f9fdaSStefan Eßer  * yet know about the use of this irq for a device of a certain class.
119425f9fdaSStefan Eßer  */
120425f9fdaSStefan Eßer 
121425f9fdaSStefan Eßer static void
122425f9fdaSStefan Eßer update_mux_masks(void)
123425f9fdaSStefan Eßer {
124425f9fdaSStefan Eßer 	int irq;
125425f9fdaSStefan Eßer 	for (irq = 0; irq < ICU_LEN; irq++) {
126425f9fdaSStefan Eßer 		intrec *idesc = intreclist_head[irq];
127425f9fdaSStefan Eßer 		while (idesc != NULL) {
128425f9fdaSStefan Eßer 			if (idesc->maskptr != NULL) {
129425f9fdaSStefan Eßer 				/* our copy of *maskptr may be stale, refresh */
130425f9fdaSStefan Eßer 				idesc->mask = *idesc->maskptr;
131425f9fdaSStefan Eßer 			}
132425f9fdaSStefan Eßer 			idesc = idesc->next;
133425f9fdaSStefan Eßer 		}
134425f9fdaSStefan Eßer 	}
135425f9fdaSStefan Eßer }
136425f9fdaSStefan Eßer 
137425f9fdaSStefan Eßer static void
138425f9fdaSStefan Eßer update_masks(intrmask *maskptr, int irq)
139425f9fdaSStefan Eßer {
140425f9fdaSStefan Eßer 	intrmask mask = 1 << irq;
141425f9fdaSStefan Eßer 
142425f9fdaSStefan Eßer 	if (maskptr == NULL)
143425f9fdaSStefan Eßer 		return;
144425f9fdaSStefan Eßer 
145425f9fdaSStefan Eßer 	if (find_idesc(maskptr, irq) == NULL) {
146425f9fdaSStefan Eßer 		/* no reference to this maskptr was found in this irq's chain */
147425f9fdaSStefan Eßer 		if ((*maskptr & mask) == 0)
148425f9fdaSStefan Eßer 			return;
149425f9fdaSStefan Eßer 		/* the irq was included in the classes mask, remove it */
150425f9fdaSStefan Eßer 		INTRUNMASK(*maskptr, mask);
151425f9fdaSStefan Eßer 	} else {
152425f9fdaSStefan Eßer 		/* a reference to this maskptr was found in this irq's chain */
153425f9fdaSStefan Eßer 		if ((*maskptr & mask) != 0)
154425f9fdaSStefan Eßer 			return;
155425f9fdaSStefan Eßer 		/* put the irq into the classes mask */
156425f9fdaSStefan Eßer 		INTRMASK(*maskptr, mask);
157425f9fdaSStefan Eßer 	}
158425f9fdaSStefan Eßer 	/* we need to update all values in the intr_mask[irq] array */
159425f9fdaSStefan Eßer 	update_intr_masks();
160425f9fdaSStefan Eßer 	/* update mask in chains of the interrupt multiplex handler as well */
161425f9fdaSStefan Eßer 	update_mux_masks();
162425f9fdaSStefan Eßer }
163425f9fdaSStefan Eßer 
164425f9fdaSStefan Eßer /*
165425f9fdaSStefan Eßer  * Add interrupt handler to linked list hung off of intreclist_head[irq]
166425f9fdaSStefan Eßer  * and install shared interrupt multiplex handler, if necessary
167425f9fdaSStefan Eßer  */
168425f9fdaSStefan Eßer 
169425f9fdaSStefan Eßer static int
170425f9fdaSStefan Eßer add_intrdesc(intrec *idesc)
171425f9fdaSStefan Eßer {
172425f9fdaSStefan Eßer 	int irq = idesc->intr;
173425f9fdaSStefan Eßer 
174425f9fdaSStefan Eßer 	intrec *head = intreclist_head[irq];
175425f9fdaSStefan Eßer 
176425f9fdaSStefan Eßer 	if (head == NULL) {
177425f9fdaSStefan Eßer 		/* first handler for this irq, just install it */
178425f9fdaSStefan Eßer 		if (icu_setup(irq, idesc->handler, idesc->argument,
179425f9fdaSStefan Eßer 			      idesc->maskptr, idesc->flags) != 0)
180425f9fdaSStefan Eßer 			return (-1);
181425f9fdaSStefan Eßer 
182425f9fdaSStefan Eßer 		update_intrname(irq, idesc->devdata);
183425f9fdaSStefan Eßer 		/* keep reference */
184425f9fdaSStefan Eßer 		intreclist_head[irq] = idesc;
185425f9fdaSStefan Eßer 	} else {
186425f9fdaSStefan Eßer 		if ((idesc->flags & INTR_EXCL) != 0
187425f9fdaSStefan Eßer 		    || (head->flags & INTR_EXCL) != 0) {
188425f9fdaSStefan Eßer 			/*
189425f9fdaSStefan Eßer 			 * can't append new handler, if either list head or
190425f9fdaSStefan Eßer 			 * new handler do not allow interrupts to be shared
191425f9fdaSStefan Eßer 			 */
192425f9fdaSStefan Eßer 			printf("\tdevice combination doesn't support shared irq%d\n",
193425f9fdaSStefan Eßer 			       irq);
194425f9fdaSStefan Eßer 			return (-1);
195425f9fdaSStefan Eßer 		}
196425f9fdaSStefan Eßer 		if (head->next == NULL) {
197425f9fdaSStefan Eßer 			/*
198425f9fdaSStefan Eßer 			 * second handler for this irq, replace device driver's
199425f9fdaSStefan Eßer 			 * handler by shared interrupt multiplexer function
200425f9fdaSStefan Eßer 			 */
201425f9fdaSStefan Eßer 			icu_unset(irq, head->handler);
202425f9fdaSStefan Eßer 			if (icu_setup(irq, intr_mux, head, 0, 0) != 0)
203425f9fdaSStefan Eßer 				return (-1);
204425f9fdaSStefan Eßer 			if (bootverbose)
205425f9fdaSStefan Eßer 				printf("\tusing shared irq%d.\n", irq);
206425f9fdaSStefan Eßer 			update_intrname(irq, -1);
207425f9fdaSStefan Eßer 		}
208425f9fdaSStefan Eßer 		/* just append to the end of the chain */
209425f9fdaSStefan Eßer 		while (head->next != NULL)
210425f9fdaSStefan Eßer 			head = head->next;
211425f9fdaSStefan Eßer 		head->next = idesc;
212425f9fdaSStefan Eßer 	}
213425f9fdaSStefan Eßer 	update_masks(idesc->maskptr, irq);
214425f9fdaSStefan Eßer 	return (0);
215425f9fdaSStefan Eßer }
216425f9fdaSStefan Eßer 
217425f9fdaSStefan Eßer /*
218425f9fdaSStefan Eßer  * Add the interrupt handler descriptor data structure created by an
219425f9fdaSStefan Eßer  * earlier call of create_intr() to the linked list for its irq and
220425f9fdaSStefan Eßer  * adjust the interrupt masks if necessary.
221425f9fdaSStefan Eßer  *
222425f9fdaSStefan Eßer  * This function effectively activates the handler.
223425f9fdaSStefan Eßer  */
224425f9fdaSStefan Eßer 
225425f9fdaSStefan Eßer int
226425f9fdaSStefan Eßer intr_connect(intrec *idesc)
227425f9fdaSStefan Eßer {
228425f9fdaSStefan Eßer 	int errcode = -1;
229425f9fdaSStefan Eßer 	int irq;
230425f9fdaSStefan Eßer 
231425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
232425f9fdaSStefan Eßer 	int resflag;
233425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
234425f9fdaSStefan Eßer 
235425f9fdaSStefan Eßer 	if (idesc == NULL)
236425f9fdaSStefan Eßer 		return (-1);
237425f9fdaSStefan Eßer 
238425f9fdaSStefan Eßer 	irq = idesc->intr;
239425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
240425f9fdaSStefan Eßer 	resflag = (idesc->flags & INTR_EXCL) ? RESF_NONE : RESF_SHARED;
241425f9fdaSStefan Eßer 	if (resource_claim(idesc->devdata, REST_INT, resflag, irq, irq) == 0)
242425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
243425f9fdaSStefan Eßer 	{
244425f9fdaSStefan Eßer 		/* block this irq */
245425f9fdaSStefan Eßer 		intrmask oldspl = splq(1 << irq);
246425f9fdaSStefan Eßer 
247425f9fdaSStefan Eßer 		/* add irq to class selected by maskptr */
248425f9fdaSStefan Eßer 		errcode = add_intrdesc(idesc);
249425f9fdaSStefan Eßer 		splx(oldspl);
250425f9fdaSStefan Eßer 	}
251425f9fdaSStefan Eßer 	if (errcode != 0)
252425f9fdaSStefan Eßer 		printf("\tintr_connect(irq%d) failed, result=%d\n",
253425f9fdaSStefan Eßer 		       irq, errcode);
254425f9fdaSStefan Eßer 
255425f9fdaSStefan Eßer 	return (errcode);
256425f9fdaSStefan Eßer }
257425f9fdaSStefan Eßer 
258425f9fdaSStefan Eßer /*
259425f9fdaSStefan Eßer  * Remove the interrupt handler descriptor data connected created by an
260425f9fdaSStefan Eßer  * earlier call of intr_connect() from the linked list and adjust the
261425f9fdaSStefan Eßer  * interrupt masks if necessary.
262425f9fdaSStefan Eßer  *
263425f9fdaSStefan Eßer  * This function deactivates the handler.
264425f9fdaSStefan Eßer  */
265425f9fdaSStefan Eßer 
266425f9fdaSStefan Eßer int
267425f9fdaSStefan Eßer intr_disconnect(intrec *idesc)
268425f9fdaSStefan Eßer {
269425f9fdaSStefan Eßer 	intrec **hook, *head;
270425f9fdaSStefan Eßer 	int irq;
271425f9fdaSStefan Eßer 	int errcode = 0;
272425f9fdaSStefan Eßer 
273425f9fdaSStefan Eßer 	if (idesc == NULL)
274425f9fdaSStefan Eßer 		return (-1);
275425f9fdaSStefan Eßer 
276425f9fdaSStefan Eßer 	irq = idesc->intr;
277425f9fdaSStefan Eßer 
278425f9fdaSStefan Eßer 	/* find pointer that keeps the reference to this interrupt descriptor */
279425f9fdaSStefan Eßer 	hook = find_pred(idesc, irq);
280425f9fdaSStefan Eßer 	if (hook == NULL)
281425f9fdaSStefan Eßer 		return (-1);
282425f9fdaSStefan Eßer 
283425f9fdaSStefan Eßer 	/* make copy of original list head, the line after may overwrite it */
284425f9fdaSStefan Eßer 	head = intreclist_head[irq];
285425f9fdaSStefan Eßer 
286425f9fdaSStefan Eßer 	/* unlink: make predecessor point to idesc->next instead of to idesc */
287425f9fdaSStefan Eßer 	*hook = idesc->next;
288425f9fdaSStefan Eßer 
289425f9fdaSStefan Eßer 	/* now check whether the element we removed was the list head */
290425f9fdaSStefan Eßer 	if (idesc == head) {
291425f9fdaSStefan Eßer 		intrmask oldspl = splq(1 << irq);
292425f9fdaSStefan Eßer 
293425f9fdaSStefan Eßer 		/* we want to remove the list head, which was known to intr_mux */
294425f9fdaSStefan Eßer 		icu_unset(irq, intr_mux);
295425f9fdaSStefan Eßer 
296425f9fdaSStefan Eßer 		/* check whether the new list head is the only element on list */
297425f9fdaSStefan Eßer 		head = intreclist_head[irq];
298425f9fdaSStefan Eßer 		if (head->next != NULL) {
299425f9fdaSStefan Eßer 			/* install the multiplex handler with new list head as argument */
300425f9fdaSStefan Eßer 			errcode = icu_setup(irq, intr_mux, head, 0, 0);
301425f9fdaSStefan Eßer 			if (errcode == 0)
302425f9fdaSStefan Eßer 				update_intrname(irq, -1);
303425f9fdaSStefan Eßer 		} else if (head != NULL) {
304425f9fdaSStefan Eßer 			/* install the one remaining handler for this irq */
305425f9fdaSStefan Eßer 			errcode = icu_setup(irq, head->handler, head->argument,
306425f9fdaSStefan Eßer 					    head->maskptr, head->flags);
307425f9fdaSStefan Eßer 			if (errcode == 0)
308425f9fdaSStefan Eßer 				update_intrname(irq, head->devdata);
309425f9fdaSStefan Eßer 		}
310425f9fdaSStefan Eßer 		splx(oldspl);
311425f9fdaSStefan Eßer 	}
312425f9fdaSStefan Eßer 	update_masks(idesc->maskptr, irq);
313425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
314425f9fdaSStefan Eßer 	resource_free(idesc->devdata);
315425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
316425f9fdaSStefan Eßer 	return (0);
317425f9fdaSStefan Eßer }
318425f9fdaSStefan Eßer 
319425f9fdaSStefan Eßer /*
320425f9fdaSStefan Eßer  * Create an interrupt handler descriptor data structure, which later can
321425f9fdaSStefan Eßer  * be activated or deactivated at will by calls of [dis]connect(intrec*).
322425f9fdaSStefan Eßer  *
323425f9fdaSStefan Eßer  * The dev_instance pointer is required for resource management, and will
324425f9fdaSStefan Eßer  * only be passed through to resource_claim().
325425f9fdaSStefan Eßer  *
326425f9fdaSStefan Eßer  * The interrupt handler takes an argument of type (void*), which is not
327425f9fdaSStefan Eßer  * what is currently used for ISA devices. But since the unit number passed
328425f9fdaSStefan Eßer  * to an ISA interrupt handler can be stored in a (void*) variable, this
329425f9fdaSStefan Eßer  * causes no problems. Eventually all the ISA interrupt handlers should be
330425f9fdaSStefan Eßer  * modified to accept the pointer to their private data, too, instead of
331425f9fdaSStefan Eßer  * an integer index.
332425f9fdaSStefan Eßer  *
333425f9fdaSStefan Eßer  * There will be functions that derive a driver and unit name from a
334425f9fdaSStefan Eßer  * dev_instance variable, and those functions will be used to maintain the
335425f9fdaSStefan Eßer  * interrupt counter label array referenced by systat and vmstat to report
336425f9fdaSStefan Eßer  * device interrupt rates (->update_intrlabels).
337425f9fdaSStefan Eßer  */
338425f9fdaSStefan Eßer 
339425f9fdaSStefan Eßer intrec *
340425f9fdaSStefan Eßer intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg,
341425f9fdaSStefan Eßer 	     intrmask *maskptr, int flags)
342425f9fdaSStefan Eßer {
343425f9fdaSStefan Eßer 	intrec *idesc;
344425f9fdaSStefan Eßer 
345425f9fdaSStefan Eßer 	if (ICU_LEN > 8 * sizeof *maskptr) {
346425f9fdaSStefan Eßer 		printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
347425f9fdaSStefan Eßer 		       ICU_LEN, 8 * sizeof *maskptr);
348425f9fdaSStefan Eßer 		return (NULL);
349425f9fdaSStefan Eßer 	}
350425f9fdaSStefan Eßer 	if ((unsigned)irq >= ICU_LEN) {
351425f9fdaSStefan Eßer 		printf("create_intr: requested irq%d too high, limit is %d\n",
352425f9fdaSStefan Eßer 		       irq, ICU_LEN -1);
353425f9fdaSStefan Eßer 		return (NULL);
354425f9fdaSStefan Eßer 	}
355425f9fdaSStefan Eßer 
356425f9fdaSStefan Eßer 	idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
357425f9fdaSStefan Eßer 	if (idesc) {
358425f9fdaSStefan Eßer 		idesc->next     = NULL;
359425f9fdaSStefan Eßer 		bzero(idesc, sizeof *idesc);
360425f9fdaSStefan Eßer 
361425f9fdaSStefan Eßer 		idesc->devdata  = dev_instance;
362425f9fdaSStefan Eßer 		idesc->handler  = handler;
363425f9fdaSStefan Eßer 		idesc->argument = arg;
364425f9fdaSStefan Eßer 		idesc->maskptr  = maskptr;
365425f9fdaSStefan Eßer 		idesc->intr     = irq;
366425f9fdaSStefan Eßer 		idesc->flags    = flags;
367425f9fdaSStefan Eßer 	}
368425f9fdaSStefan Eßer 	return (idesc);
369425f9fdaSStefan Eßer }
370425f9fdaSStefan Eßer 
371425f9fdaSStefan Eßer /*
372425f9fdaSStefan Eßer  * Return the memory held by the interrupt handler descriptor data structure
373425f9fdaSStefan Eßer  * to the system. Make sure, the handler is not actively used anymore, before.
374425f9fdaSStefan Eßer  */
375425f9fdaSStefan Eßer 
376425f9fdaSStefan Eßer int
377425f9fdaSStefan Eßer intr_destroy(intrec *rec)
378425f9fdaSStefan Eßer {
379425f9fdaSStefan Eßer 	if (intr_disconnect(rec) != 0)
380425f9fdaSStefan Eßer 		return (-1);
381425f9fdaSStefan Eßer 	free(rec, M_DEVBUF);
382425f9fdaSStefan Eßer 	return (0);
383425f9fdaSStefan Eßer }
384425f9fdaSStefan Eßer 
385425f9fdaSStefan Eßer /*
386425f9fdaSStefan Eßer  * Emulate the register_intr() call previously defined as low level function.
387425f9fdaSStefan Eßer  * That function (now icu_setup()) may no longer be directly called, since
388425f9fdaSStefan Eßer  * a conflict between an ISA and PCI interrupt might go by unnocticed, else.
389425f9fdaSStefan Eßer  */
390425f9fdaSStefan Eßer 
391425f9fdaSStefan Eßer int
392425f9fdaSStefan Eßer register_intr(int intr, int device_id, u_int flags,
393425f9fdaSStefan Eßer 	      inthand2_t handler, u_int *maskptr, int unit)
394425f9fdaSStefan Eßer {
395425f9fdaSStefan Eßer 	/* XXX modify to include isa_device instead of device_id */
396425f9fdaSStefan Eßer 	intrec *idesc;
397425f9fdaSStefan Eßer 
398425f9fdaSStefan Eßer 	flags |= INTR_EXCL;
399425f9fdaSStefan Eßer 	idesc = intr_create((void *)device_id, intr, handler,
400425f9fdaSStefan Eßer 			    (void*)unit, maskptr, flags);
401425f9fdaSStefan Eßer 	return (intr_connect(idesc));
402425f9fdaSStefan Eßer }
403425f9fdaSStefan Eßer 
404425f9fdaSStefan Eßer /*
405425f9fdaSStefan Eßer  * Emulate the old unregister_intr() low level function.
406425f9fdaSStefan Eßer  * Make sure there is just one interrupt, that it was
407425f9fdaSStefan Eßer  * registered as non-shared, and that the handlers match.
408425f9fdaSStefan Eßer  */
409425f9fdaSStefan Eßer 
410425f9fdaSStefan Eßer int
411425f9fdaSStefan Eßer unregister_intr(int intr, inthand2_t handler)
412425f9fdaSStefan Eßer {
413425f9fdaSStefan Eßer 	intrec *p = intreclist_head[intr];
414425f9fdaSStefan Eßer 
415425f9fdaSStefan Eßer 	if (p != NULL && (p->flags & INTR_EXCL) != 0 && p->handler == handler)
416425f9fdaSStefan Eßer 		return (intr_destroy(p));
417425f9fdaSStefan Eßer 	return (EINVAL);
418425f9fdaSStefan Eßer }
419