xref: /freebsd/sys/kern/kern_intr.c (revision 683523378cabab656bd6c718278953c233e125a1)
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  *
2668352337SDoug Rabson  * $Id: kern_intr.c,v 1.4 1997/06/01 16:05:13 peter Exp $
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>
4068352337SDoug Rabson #include <i386/isa/intr_machdep.h>
4168352337SDoug Rabson #include <sys/interrupt.h>
42425f9fdaSStefan Eßer 
434407ec71SPeter Wemm #include <machine/ipl.h>
44425f9fdaSStefan Eßer 
45425f9fdaSStefan Eßer #include <stddef.h>
46425f9fdaSStefan Eßer 
47425f9fdaSStefan Eßer #include "vector.h"
48425f9fdaSStefan Eßer 
498c046d14SPeter Wemm typedef struct intrec {
508c046d14SPeter Wemm 	intrmask_t	mask;
518c046d14SPeter Wemm 	inthand2_t	*handler;
528c046d14SPeter Wemm 	void		*argument;
538c046d14SPeter Wemm 	struct intrec	*next;
548c046d14SPeter Wemm 	void		*devdata;
558c046d14SPeter Wemm 	int		intr;
568c046d14SPeter Wemm 	intrmask_t	*maskptr;
578c046d14SPeter Wemm 	int		flags;
588c046d14SPeter Wemm #define	INTR_FAST		0x00000001 /* fast interrupt handler */
598c046d14SPeter Wemm #define INTR_EXCL		0x00010000 /* excl. intr, default is shared */
608c046d14SPeter Wemm } intrec;
618c046d14SPeter Wemm 
62425f9fdaSStefan Eßer /*
63425f9fdaSStefan Eßer  * The interrupt multiplexer calls each of the handlers in turn,
64425f9fdaSStefan Eßer  * and applies the associated interrupt mask to "cpl", which is
65425f9fdaSStefan Eßer  * defined as a ".long" in /sys/i386/isa/icu.s
66425f9fdaSStefan Eßer  */
67425f9fdaSStefan Eßer 
684407ec71SPeter Wemm static inline intrmask_t
694407ec71SPeter Wemm splq(intrmask_t mask)
70425f9fdaSStefan Eßer {
714407ec71SPeter Wemm 	intrmask_t tmp = cpl;
72425f9fdaSStefan Eßer 	cpl |= mask;
73425f9fdaSStefan Eßer 	return (tmp);
74425f9fdaSStefan Eßer }
75425f9fdaSStefan Eßer 
76425f9fdaSStefan Eßer static void
77425f9fdaSStefan Eßer intr_mux(void *arg)
78425f9fdaSStefan Eßer {
79425f9fdaSStefan Eßer 	intrec *p = arg;
80425f9fdaSStefan Eßer 
81425f9fdaSStefan Eßer 	while (p != NULL) {
82425f9fdaSStefan Eßer 		int oldspl = splq(p->mask);
83425f9fdaSStefan Eßer 		/* inthand2_t should take (void*) argument */
84425f9fdaSStefan Eßer 		p->handler(p->argument);
85425f9fdaSStefan Eßer 		splx(oldspl);
86425f9fdaSStefan Eßer 		p = p->next;
87425f9fdaSStefan Eßer 	}
88425f9fdaSStefan Eßer }
89425f9fdaSStefan Eßer 
90425f9fdaSStefan Eßer /* XXX better use NHWI from <machine/ipl.h> for array size ??? */
91425f9fdaSStefan Eßer static intrec *intreclist_head[ICU_LEN];
92425f9fdaSStefan Eßer 
93425f9fdaSStefan Eßer static intrec*
94425f9fdaSStefan Eßer find_idesc(unsigned *maskptr, int irq)
95425f9fdaSStefan Eßer {
96425f9fdaSStefan Eßer 	intrec *p = intreclist_head[irq];
97425f9fdaSStefan Eßer 
98425f9fdaSStefan Eßer 	while (p && p->maskptr != maskptr)
99425f9fdaSStefan Eßer 		p = p->next;
100425f9fdaSStefan Eßer 
101425f9fdaSStefan Eßer 	return (p);
102425f9fdaSStefan Eßer }
103425f9fdaSStefan Eßer 
104425f9fdaSStefan Eßer static intrec**
105425f9fdaSStefan Eßer find_pred(intrec *idesc, int irq)
106425f9fdaSStefan Eßer {
107425f9fdaSStefan Eßer 	intrec **pp = &intreclist_head[irq];
108425f9fdaSStefan Eßer 	intrec *p = *pp;
109425f9fdaSStefan Eßer 
110425f9fdaSStefan Eßer 	while (p != idesc) {
111425f9fdaSStefan Eßer 		if (p == NULL)
112425f9fdaSStefan Eßer 			return (NULL);
113425f9fdaSStefan Eßer 		pp = &p->next;
114425f9fdaSStefan Eßer 		p = *pp;
115425f9fdaSStefan Eßer 	}
116425f9fdaSStefan Eßer 	return (pp);
117425f9fdaSStefan Eßer }
118425f9fdaSStefan Eßer 
119425f9fdaSStefan Eßer /*
120425f9fdaSStefan Eßer  * Both the low level handler and the shared interrupt multiplexer
121425f9fdaSStefan Eßer  * block out further interrupts as set in the handlers "mask", while
122425f9fdaSStefan Eßer  * the handler is running. In fact *maskptr should be used for this
123425f9fdaSStefan Eßer  * purpose, but since this requires one more pointer dereference on
124425f9fdaSStefan Eßer  * each interrupt, we rather bother update "mask" whenever *maskptr
125425f9fdaSStefan Eßer  * changes. The function "update_masks" should be called **after**
126425f9fdaSStefan Eßer  * all manipulation of the linked list of interrupt handlers hung
127425f9fdaSStefan Eßer  * off of intrdec_head[irq] is complete, since the chain of handlers
128425f9fdaSStefan Eßer  * will both determine the *maskptr values and the instances of mask
129425f9fdaSStefan Eßer  * that are fixed. This function should be called with the irq for
130425f9fdaSStefan Eßer  * which a new handler has been add blocked, since the masks may not
131425f9fdaSStefan Eßer  * yet know about the use of this irq for a device of a certain class.
132425f9fdaSStefan Eßer  */
133425f9fdaSStefan Eßer 
134425f9fdaSStefan Eßer static void
135425f9fdaSStefan Eßer update_mux_masks(void)
136425f9fdaSStefan Eßer {
137425f9fdaSStefan Eßer 	int irq;
138425f9fdaSStefan Eßer 	for (irq = 0; irq < ICU_LEN; irq++) {
139425f9fdaSStefan Eßer 		intrec *idesc = intreclist_head[irq];
140425f9fdaSStefan Eßer 		while (idesc != NULL) {
141425f9fdaSStefan Eßer 			if (idesc->maskptr != NULL) {
142425f9fdaSStefan Eßer 				/* our copy of *maskptr may be stale, refresh */
143425f9fdaSStefan Eßer 				idesc->mask = *idesc->maskptr;
144425f9fdaSStefan Eßer 			}
145425f9fdaSStefan Eßer 			idesc = idesc->next;
146425f9fdaSStefan Eßer 		}
147425f9fdaSStefan Eßer 	}
148425f9fdaSStefan Eßer }
149425f9fdaSStefan Eßer 
150425f9fdaSStefan Eßer static void
1514407ec71SPeter Wemm update_masks(intrmask_t *maskptr, int irq)
152425f9fdaSStefan Eßer {
1534407ec71SPeter Wemm 	intrmask_t mask = 1 << irq;
154425f9fdaSStefan Eßer 
155425f9fdaSStefan Eßer 	if (maskptr == NULL)
156425f9fdaSStefan Eßer 		return;
157425f9fdaSStefan Eßer 
158425f9fdaSStefan Eßer 	if (find_idesc(maskptr, irq) == NULL) {
159425f9fdaSStefan Eßer 		/* no reference to this maskptr was found in this irq's chain */
160425f9fdaSStefan Eßer 		if ((*maskptr & mask) == 0)
161425f9fdaSStefan Eßer 			return;
162425f9fdaSStefan Eßer 		/* the irq was included in the classes mask, remove it */
163425f9fdaSStefan Eßer 		INTRUNMASK(*maskptr, mask);
164425f9fdaSStefan Eßer 	} else {
165425f9fdaSStefan Eßer 		/* a reference to this maskptr was found in this irq's chain */
166425f9fdaSStefan Eßer 		if ((*maskptr & mask) != 0)
167425f9fdaSStefan Eßer 			return;
168425f9fdaSStefan Eßer 		/* put the irq into the classes mask */
169425f9fdaSStefan Eßer 		INTRMASK(*maskptr, mask);
170425f9fdaSStefan Eßer 	}
171425f9fdaSStefan Eßer 	/* we need to update all values in the intr_mask[irq] array */
172425f9fdaSStefan Eßer 	update_intr_masks();
173425f9fdaSStefan Eßer 	/* update mask in chains of the interrupt multiplex handler as well */
174425f9fdaSStefan Eßer 	update_mux_masks();
175425f9fdaSStefan Eßer }
176425f9fdaSStefan Eßer 
177425f9fdaSStefan Eßer /*
178425f9fdaSStefan Eßer  * Add interrupt handler to linked list hung off of intreclist_head[irq]
179425f9fdaSStefan Eßer  * and install shared interrupt multiplex handler, if necessary
180425f9fdaSStefan Eßer  */
181425f9fdaSStefan Eßer 
182425f9fdaSStefan Eßer static int
183425f9fdaSStefan Eßer add_intrdesc(intrec *idesc)
184425f9fdaSStefan Eßer {
185425f9fdaSStefan Eßer 	int irq = idesc->intr;
186425f9fdaSStefan Eßer 
187425f9fdaSStefan Eßer 	intrec *head = intreclist_head[irq];
188425f9fdaSStefan Eßer 
189425f9fdaSStefan Eßer 	if (head == NULL) {
190425f9fdaSStefan Eßer 		/* first handler for this irq, just install it */
191425f9fdaSStefan Eßer 		if (icu_setup(irq, idesc->handler, idesc->argument,
192425f9fdaSStefan Eßer 			      idesc->maskptr, idesc->flags) != 0)
193425f9fdaSStefan Eßer 			return (-1);
194425f9fdaSStefan Eßer 
195425f9fdaSStefan Eßer 		update_intrname(irq, idesc->devdata);
196425f9fdaSStefan Eßer 		/* keep reference */
197425f9fdaSStefan Eßer 		intreclist_head[irq] = idesc;
198425f9fdaSStefan Eßer 	} else {
199425f9fdaSStefan Eßer 		if ((idesc->flags & INTR_EXCL) != 0
200425f9fdaSStefan Eßer 		    || (head->flags & INTR_EXCL) != 0) {
201425f9fdaSStefan Eßer 			/*
202425f9fdaSStefan Eßer 			 * can't append new handler, if either list head or
203425f9fdaSStefan Eßer 			 * new handler do not allow interrupts to be shared
204425f9fdaSStefan Eßer 			 */
205425f9fdaSStefan Eßer 			printf("\tdevice combination doesn't support shared irq%d\n",
206425f9fdaSStefan Eßer 			       irq);
207425f9fdaSStefan Eßer 			return (-1);
208425f9fdaSStefan Eßer 		}
209425f9fdaSStefan Eßer 		if (head->next == NULL) {
210425f9fdaSStefan Eßer 			/*
211425f9fdaSStefan Eßer 			 * second handler for this irq, replace device driver's
212425f9fdaSStefan Eßer 			 * handler by shared interrupt multiplexer function
213425f9fdaSStefan Eßer 			 */
214425f9fdaSStefan Eßer 			icu_unset(irq, head->handler);
215425f9fdaSStefan Eßer 			if (icu_setup(irq, intr_mux, head, 0, 0) != 0)
216425f9fdaSStefan Eßer 				return (-1);
217425f9fdaSStefan Eßer 			if (bootverbose)
218425f9fdaSStefan Eßer 				printf("\tusing shared irq%d.\n", irq);
219425f9fdaSStefan Eßer 			update_intrname(irq, -1);
220425f9fdaSStefan Eßer 		}
221425f9fdaSStefan Eßer 		/* just append to the end of the chain */
222425f9fdaSStefan Eßer 		while (head->next != NULL)
223425f9fdaSStefan Eßer 			head = head->next;
224425f9fdaSStefan Eßer 		head->next = idesc;
225425f9fdaSStefan Eßer 	}
226425f9fdaSStefan Eßer 	update_masks(idesc->maskptr, irq);
227425f9fdaSStefan Eßer 	return (0);
228425f9fdaSStefan Eßer }
229425f9fdaSStefan Eßer 
230425f9fdaSStefan Eßer /*
231425f9fdaSStefan Eßer  * Add the interrupt handler descriptor data structure created by an
232425f9fdaSStefan Eßer  * earlier call of create_intr() to the linked list for its irq and
233425f9fdaSStefan Eßer  * adjust the interrupt masks if necessary.
234425f9fdaSStefan Eßer  *
235425f9fdaSStefan Eßer  * This function effectively activates the handler.
236425f9fdaSStefan Eßer  */
237425f9fdaSStefan Eßer 
238425f9fdaSStefan Eßer int
239425f9fdaSStefan Eßer intr_connect(intrec *idesc)
240425f9fdaSStefan Eßer {
241425f9fdaSStefan Eßer 	int errcode = -1;
242425f9fdaSStefan Eßer 	int irq;
243425f9fdaSStefan Eßer 
244425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
245425f9fdaSStefan Eßer 	int resflag;
246425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
247425f9fdaSStefan Eßer 
248425f9fdaSStefan Eßer 	if (idesc == NULL)
249425f9fdaSStefan Eßer 		return (-1);
250425f9fdaSStefan Eßer 
251425f9fdaSStefan Eßer 	irq = idesc->intr;
252425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
253425f9fdaSStefan Eßer 	resflag = (idesc->flags & INTR_EXCL) ? RESF_NONE : RESF_SHARED;
254425f9fdaSStefan Eßer 	if (resource_claim(idesc->devdata, REST_INT, resflag, irq, irq) == 0)
255425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
256425f9fdaSStefan Eßer 	{
257425f9fdaSStefan Eßer 		/* block this irq */
2584407ec71SPeter Wemm 		intrmask_t oldspl = splq(1 << irq);
259425f9fdaSStefan Eßer 
260425f9fdaSStefan Eßer 		/* add irq to class selected by maskptr */
261425f9fdaSStefan Eßer 		errcode = add_intrdesc(idesc);
262425f9fdaSStefan Eßer 		splx(oldspl);
263425f9fdaSStefan Eßer 	}
264425f9fdaSStefan Eßer 	if (errcode != 0)
265425f9fdaSStefan Eßer 		printf("\tintr_connect(irq%d) failed, result=%d\n",
266425f9fdaSStefan Eßer 		       irq, errcode);
267425f9fdaSStefan Eßer 
268425f9fdaSStefan Eßer 	return (errcode);
269425f9fdaSStefan Eßer }
270425f9fdaSStefan Eßer 
271425f9fdaSStefan Eßer /*
272425f9fdaSStefan Eßer  * Remove the interrupt handler descriptor data connected created by an
273425f9fdaSStefan Eßer  * earlier call of intr_connect() from the linked list and adjust the
274425f9fdaSStefan Eßer  * interrupt masks if necessary.
275425f9fdaSStefan Eßer  *
276425f9fdaSStefan Eßer  * This function deactivates the handler.
277425f9fdaSStefan Eßer  */
278425f9fdaSStefan Eßer 
279425f9fdaSStefan Eßer int
280425f9fdaSStefan Eßer intr_disconnect(intrec *idesc)
281425f9fdaSStefan Eßer {
282425f9fdaSStefan Eßer 	intrec **hook, *head;
283425f9fdaSStefan Eßer 	int irq;
284425f9fdaSStefan Eßer 	int errcode = 0;
285425f9fdaSStefan Eßer 
286425f9fdaSStefan Eßer 	if (idesc == NULL)
287425f9fdaSStefan Eßer 		return (-1);
288425f9fdaSStefan Eßer 
289425f9fdaSStefan Eßer 	irq = idesc->intr;
290425f9fdaSStefan Eßer 
291425f9fdaSStefan Eßer 	/* find pointer that keeps the reference to this interrupt descriptor */
292425f9fdaSStefan Eßer 	hook = find_pred(idesc, irq);
293425f9fdaSStefan Eßer 	if (hook == NULL)
294425f9fdaSStefan Eßer 		return (-1);
295425f9fdaSStefan Eßer 
296425f9fdaSStefan Eßer 	/* make copy of original list head, the line after may overwrite it */
297425f9fdaSStefan Eßer 	head = intreclist_head[irq];
298425f9fdaSStefan Eßer 
299425f9fdaSStefan Eßer 	/* unlink: make predecessor point to idesc->next instead of to idesc */
300425f9fdaSStefan Eßer 	*hook = idesc->next;
301425f9fdaSStefan Eßer 
302425f9fdaSStefan Eßer 	/* now check whether the element we removed was the list head */
303425f9fdaSStefan Eßer 	if (idesc == head) {
3044407ec71SPeter Wemm 		intrmask_t oldspl = splq(1 << irq);
305425f9fdaSStefan Eßer 
306425f9fdaSStefan Eßer 		/* we want to remove the list head, which was known to intr_mux */
307425f9fdaSStefan Eßer 		icu_unset(irq, intr_mux);
308425f9fdaSStefan Eßer 
309425f9fdaSStefan Eßer 		/* check whether the new list head is the only element on list */
310425f9fdaSStefan Eßer 		head = intreclist_head[irq];
311f9220cdeSStefan Eßer 		if (head != NULL) {
312425f9fdaSStefan Eßer 			if (head->next != NULL) {
313425f9fdaSStefan Eßer 				/* install the multiplex handler with new list head as argument */
314425f9fdaSStefan Eßer 				errcode = icu_setup(irq, intr_mux, head, 0, 0);
315425f9fdaSStefan Eßer 				if (errcode == 0)
316425f9fdaSStefan Eßer 					update_intrname(irq, -1);
317f9220cdeSStefan Eßer 			} else {
318425f9fdaSStefan Eßer 				/* install the one remaining handler for this irq */
319f9220cdeSStefan Eßer 				errcode = icu_setup(irq, head->handler,
320f9220cdeSStefan Eßer 						    head->argument,
321425f9fdaSStefan Eßer 						    head->maskptr, head->flags);
322425f9fdaSStefan Eßer 				if (errcode == 0)
323425f9fdaSStefan Eßer 					update_intrname(irq, head->devdata);
324425f9fdaSStefan Eßer 			}
325f9220cdeSStefan Eßer 		}
326425f9fdaSStefan Eßer 		splx(oldspl);
327425f9fdaSStefan Eßer 	}
328425f9fdaSStefan Eßer 	update_masks(idesc->maskptr, irq);
329425f9fdaSStefan Eßer #ifdef RESOURCE_CHECK
330425f9fdaSStefan Eßer 	resource_free(idesc->devdata);
331425f9fdaSStefan Eßer #endif /* RESOURCE_CHECK */
332425f9fdaSStefan Eßer 	return (0);
333425f9fdaSStefan Eßer }
334425f9fdaSStefan Eßer 
335425f9fdaSStefan Eßer /*
336425f9fdaSStefan Eßer  * Create an interrupt handler descriptor data structure, which later can
337425f9fdaSStefan Eßer  * be activated or deactivated at will by calls of [dis]connect(intrec*).
338425f9fdaSStefan Eßer  *
339425f9fdaSStefan Eßer  * The dev_instance pointer is required for resource management, and will
340425f9fdaSStefan Eßer  * only be passed through to resource_claim().
341425f9fdaSStefan Eßer  *
342425f9fdaSStefan Eßer  * The interrupt handler takes an argument of type (void*), which is not
343425f9fdaSStefan Eßer  * what is currently used for ISA devices. But since the unit number passed
344425f9fdaSStefan Eßer  * to an ISA interrupt handler can be stored in a (void*) variable, this
345425f9fdaSStefan Eßer  * causes no problems. Eventually all the ISA interrupt handlers should be
346425f9fdaSStefan Eßer  * modified to accept the pointer to their private data, too, instead of
347425f9fdaSStefan Eßer  * an integer index.
348425f9fdaSStefan Eßer  *
349425f9fdaSStefan Eßer  * There will be functions that derive a driver and unit name from a
350425f9fdaSStefan Eßer  * dev_instance variable, and those functions will be used to maintain the
351425f9fdaSStefan Eßer  * interrupt counter label array referenced by systat and vmstat to report
352425f9fdaSStefan Eßer  * device interrupt rates (->update_intrlabels).
353425f9fdaSStefan Eßer  */
354425f9fdaSStefan Eßer 
355425f9fdaSStefan Eßer intrec *
356425f9fdaSStefan Eßer intr_create(void *dev_instance, int irq, inthand2_t handler, void *arg,
3574407ec71SPeter Wemm 	     intrmask_t *maskptr, int flags)
358425f9fdaSStefan Eßer {
359425f9fdaSStefan Eßer 	intrec *idesc;
360425f9fdaSStefan Eßer 
361425f9fdaSStefan Eßer 	if (ICU_LEN > 8 * sizeof *maskptr) {
362425f9fdaSStefan Eßer 		printf("create_intr: ICU_LEN of %d too high for %d bit intrmask\n",
363425f9fdaSStefan Eßer 		       ICU_LEN, 8 * sizeof *maskptr);
364425f9fdaSStefan Eßer 		return (NULL);
365425f9fdaSStefan Eßer 	}
366425f9fdaSStefan Eßer 	if ((unsigned)irq >= ICU_LEN) {
367425f9fdaSStefan Eßer 		printf("create_intr: requested irq%d too high, limit is %d\n",
368425f9fdaSStefan Eßer 		       irq, ICU_LEN -1);
369425f9fdaSStefan Eßer 		return (NULL);
370425f9fdaSStefan Eßer 	}
371425f9fdaSStefan Eßer 
372425f9fdaSStefan Eßer 	idesc = malloc(sizeof *idesc, M_DEVBUF, M_WAITOK);
373425f9fdaSStefan Eßer 	if (idesc) {
374425f9fdaSStefan Eßer 		idesc->next     = NULL;
375425f9fdaSStefan Eßer 		bzero(idesc, sizeof *idesc);
376425f9fdaSStefan Eßer 
377425f9fdaSStefan Eßer 		idesc->devdata  = dev_instance;
378425f9fdaSStefan Eßer 		idesc->handler  = handler;
379425f9fdaSStefan Eßer 		idesc->argument = arg;
380425f9fdaSStefan Eßer 		idesc->maskptr  = maskptr;
381425f9fdaSStefan Eßer 		idesc->intr     = irq;
382425f9fdaSStefan Eßer 		idesc->flags    = flags;
383425f9fdaSStefan Eßer 	}
384425f9fdaSStefan Eßer 	return (idesc);
385425f9fdaSStefan Eßer }
386425f9fdaSStefan Eßer 
387425f9fdaSStefan Eßer /*
388425f9fdaSStefan Eßer  * Return the memory held by the interrupt handler descriptor data structure
389425f9fdaSStefan Eßer  * to the system. Make sure, the handler is not actively used anymore, before.
390425f9fdaSStefan Eßer  */
391425f9fdaSStefan Eßer 
392425f9fdaSStefan Eßer int
393425f9fdaSStefan Eßer intr_destroy(intrec *rec)
394425f9fdaSStefan Eßer {
395425f9fdaSStefan Eßer 	if (intr_disconnect(rec) != 0)
396425f9fdaSStefan Eßer 		return (-1);
397425f9fdaSStefan Eßer 	free(rec, M_DEVBUF);
398425f9fdaSStefan Eßer 	return (0);
399425f9fdaSStefan Eßer }
400425f9fdaSStefan Eßer 
401425f9fdaSStefan Eßer /*
402425f9fdaSStefan Eßer  * Emulate the register_intr() call previously defined as low level function.
403425f9fdaSStefan Eßer  * That function (now icu_setup()) may no longer be directly called, since
404425f9fdaSStefan Eßer  * a conflict between an ISA and PCI interrupt might go by unnocticed, else.
405425f9fdaSStefan Eßer  */
406425f9fdaSStefan Eßer 
407425f9fdaSStefan Eßer int
408425f9fdaSStefan Eßer register_intr(int intr, int device_id, u_int flags,
409425f9fdaSStefan Eßer 	      inthand2_t handler, u_int *maskptr, int unit)
410425f9fdaSStefan Eßer {
411425f9fdaSStefan Eßer 	/* XXX modify to include isa_device instead of device_id */
412425f9fdaSStefan Eßer 	intrec *idesc;
413425f9fdaSStefan Eßer 
414425f9fdaSStefan Eßer 	flags |= INTR_EXCL;
415425f9fdaSStefan Eßer 	idesc = intr_create((void *)device_id, intr, handler,
416425f9fdaSStefan Eßer 			    (void*)unit, maskptr, flags);
417425f9fdaSStefan Eßer 	return (intr_connect(idesc));
418425f9fdaSStefan Eßer }
419425f9fdaSStefan Eßer 
420425f9fdaSStefan Eßer /*
421425f9fdaSStefan Eßer  * Emulate the old unregister_intr() low level function.
422425f9fdaSStefan Eßer  * Make sure there is just one interrupt, that it was
423425f9fdaSStefan Eßer  * registered as non-shared, and that the handlers match.
424425f9fdaSStefan Eßer  */
425425f9fdaSStefan Eßer 
426425f9fdaSStefan Eßer int
427425f9fdaSStefan Eßer unregister_intr(int intr, inthand2_t handler)
428425f9fdaSStefan Eßer {
429425f9fdaSStefan Eßer 	intrec *p = intreclist_head[intr];
430425f9fdaSStefan Eßer 
431425f9fdaSStefan Eßer 	if (p != NULL && (p->flags & INTR_EXCL) != 0 && p->handler == handler)
432425f9fdaSStefan Eßer 		return (intr_destroy(p));
433425f9fdaSStefan Eßer 	return (EINVAL);
434425f9fdaSStefan Eßer }
435