puc.c revision 166901
1147883Sscottl/*-
2147883Sscottl * Copyright (c) 2006 Marcel Moolenaar
3147883Sscottl * All rights reserved.
4147883Sscottl *
5147883Sscottl * Redistribution and use in source and binary forms, with or without
6147883Sscottl * modification, are permitted provided that the following conditions
7147883Sscottl * are met:
8147883Sscottl *
9147883Sscottl * 1. Redistributions of source code must retain the above copyright
10147883Sscottl *    notice, this list of conditions and the following disclaimer.
11147883Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12147883Sscottl *    notice, this list of conditions and the following disclaimer in the
13147883Sscottl *    documentation and/or other materials provided with the distribution.
14147883Sscottl *
15147883Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16147883Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17147883Sscottl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18147883Sscottl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19147883Sscottl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20147883Sscottl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21147883Sscottl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22147883Sscottl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23147883Sscottl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24147883Sscottl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25147883Sscottl */
26147883Sscottl
27156000Smjacob#include <sys/cdefs.h>
28156000Smjacob__FBSDID("$FreeBSD: head/sys/dev/puc/puc.c 166901 2007-02-23 12:19:07Z piso $");
29156000Smjacob
30156000Smjacob#include <sys/param.h>
31156000Smjacob#include <sys/systm.h>
32156000Smjacob#include <sys/kernel.h>
33156000Smjacob#include <sys/bus.h>
34156000Smjacob#include <sys/conf.h>
35156000Smjacob#include <sys/malloc.h>
36156000Smjacob#include <sys/mutex.h>
37156000Smjacob
38156000Smjacob#include <machine/bus.h>
39156000Smjacob#include <machine/resource.h>
40156000Smjacob#include <sys/rman.h>
41156000Smjacob
42156000Smjacob#include <dev/pci/pcireg.h>
43156000Smjacob#include <dev/pci/pcivar.h>
44156000Smjacob
45156000Smjacob#include <dev/puc/puc_bus.h>
46156000Smjacob#include <dev/puc/puc_cfg.h>
47156000Smjacob#include <dev/puc/puc_bfe.h>
48156000Smjacob
49156000Smjacob#define	PUC_ISRCCNT	5
50156000Smjacob
51156000Smjacobstruct puc_port {
52156000Smjacob	struct puc_bar	*p_bar;
53156000Smjacob	struct resource *p_rres;
54156000Smjacob	struct resource *p_ires;
55156000Smjacob	device_t	p_dev;
56156000Smjacob	int		p_nr;
57147883Sscottl	int		p_type;
58156000Smjacob	int		p_rclk;
59156000Smjacob
60159052Smjacob	int		p_hasintr:1;
61159052Smjacob
62159052Smjacob	driver_filter_t	*p_ih;
63147883Sscottl	serdev_intr_t	*p_ihsrc[PUC_ISRCCNT];
64147883Sscottl	void		*p_iharg;
65147883Sscottl
66147883Sscottl	int		p_ipend;
67147883Sscottl};
68147883Sscottl
69147883Sscottldevclass_t puc_devclass;
70147883Sscottlconst char puc_driver_name[] = "puc";
71147883Sscottl
72147883SscottlMALLOC_DEFINE(M_PUC, "PUC", "PUC driver");
73147883Sscottl
74147883Sscottlstruct puc_bar *
75147883Sscottlpuc_get_bar(struct puc_softc *sc, int rid)
76147883Sscottl{
77147883Sscottl	struct puc_bar *bar;
78147883Sscottl	struct rman *rm;
79147883Sscottl	u_long end, start;
80148679Sgibbs	int error, i;
81148679Sgibbs
82148679Sgibbs	/* Find the BAR entry with the given RID. */
83147883Sscottl	i = 0;
84147883Sscottl	while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid)
85147883Sscottl		i++;
86147883Sscottl	if (i < PUC_PCI_BARS)
87147883Sscottl		return (&sc->sc_bar[i]);
88147883Sscottl
89147883Sscottl	/* Not found. If we're looking for an unused entry, return NULL. */
90147883Sscottl	if (rid == -1)
91147883Sscottl		return (NULL);
92147883Sscottl
93147883Sscottl	/* Get an unused entry for us to fill.  */
94147883Sscottl	bar = puc_get_bar(sc, -1);
95147883Sscottl	if (bar == NULL)
96147883Sscottl		return (NULL);
97147883Sscottl	bar->b_rid = rid;
98147883Sscottl	bar->b_type = SYS_RES_IOPORT;
99147883Sscottl	bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
100147883Sscottl	    &bar->b_rid, RF_ACTIVE);
101147883Sscottl	if (bar->b_res == NULL) {
102147883Sscottl		bar->b_rid = rid;
103147883Sscottl		bar->b_type = SYS_RES_MEMORY;
104147883Sscottl		bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
105147883Sscottl		    &bar->b_rid, RF_ACTIVE);
106147883Sscottl		if (bar->b_res == NULL) {
107147883Sscottl			bar->b_rid = -1;
108147883Sscottl			return (NULL);
109147883Sscottl		}
110147883Sscottl	}
111147883Sscottl
112147883Sscottl	/* Update our managed space. */
113147883Sscottl	rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem;
114147883Sscottl	start = rman_get_start(bar->b_res);
115147883Sscottl	end = rman_get_end(bar->b_res);
116147883Sscottl	error = rman_manage_region(rm, start, end);
117147883Sscottl	if (error) {
118147883Sscottl		bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid,
119147883Sscottl		    bar->b_res);
120147883Sscottl		bar->b_res = NULL;
121147883Sscottl		bar->b_rid = -1;
122147883Sscottl		bar = NULL;
123147883Sscottl	}
124147883Sscottl
125147883Sscottl	return (bar);
126147883Sscottl}
127147883Sscottl
128147883Sscottlstatic int
129147883Sscottlpuc_intr(void *arg)
130147883Sscottl{
131147883Sscottl	struct puc_port *port;
132147883Sscottl	struct puc_softc *sc = arg;
133147883Sscottl	u_long dev, devs;
134147883Sscottl	int i, idx, ipend, isrc;
135147883Sscottl	uint8_t ilr;
136147883Sscottl
137147883Sscottl	devs = sc->sc_serdevs;
138147883Sscottl	if (sc->sc_ilr == PUC_ILR_DIGI) {
139147883Sscottl		idx = 0;
140147883Sscottl		while (devs & (0xfful << idx)) {
141147883Sscottl			ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
142147883Sscottl			devs &= ~0ul ^ ((u_long)ilr << idx);
143147883Sscottl			idx += 8;
144147883Sscottl		}
145	} else if (sc->sc_ilr == PUC_ILR_QUATECH) {
146		/*
147		 * Don't trust the value if it's the same as the option
148		 * register. It may mean that the ILR is not active and
149		 * we're reading the option register instead. This may
150		 * lead to false positives on 8-port boards.
151		 */
152		ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
153		if (ilr != (sc->sc_cfg_data & 0xff))
154			devs &= (u_long)ilr;
155	}
156
157	ipend = 0;
158	idx = 0, dev = 1UL;
159	while (devs != 0UL) {
160		while ((devs & dev) == 0UL)
161			idx++, dev <<= 1;
162		devs &= ~dev;
163		port = &sc->sc_port[idx];
164		port->p_ipend = SERDEV_IPEND(port->p_dev);
165		ipend |= port->p_ipend;
166	}
167
168	i = 0, isrc = SER_INT_OVERRUN;
169	while (ipend) {
170		while (i < PUC_ISRCCNT && !(ipend & isrc))
171			i++, isrc <<= 1;
172		KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
173		ipend &= ~isrc;
174		idx = 0, dev = 1UL;
175		devs = sc->sc_serdevs;
176		while (devs != 0UL) {
177			while ((devs & dev) == 0UL)
178				idx++, dev <<= 1;
179			devs &= ~dev;
180			port = &sc->sc_port[idx];
181			if (!(port->p_ipend & isrc))
182				continue;
183			if (port->p_ihsrc[i] != NULL)
184				(*port->p_ihsrc[i])(port->p_iharg);
185		}
186		return (FILTER_HANDLED);
187	}
188	return (FILTER_STRAY);
189}
190
191int
192puc_bfe_attach(device_t dev)
193{
194	char buffer[64];
195	struct puc_bar *bar;
196	struct puc_port *port;
197	struct puc_softc *sc;
198	struct rman *rm;
199	intptr_t res;
200	bus_addr_t ofs, start;
201	bus_size_t size;
202	bus_space_handle_t bsh;
203	bus_space_tag_t bst;
204	int error, idx;
205
206	sc = device_get_softc(dev);
207
208	for (idx = 0; idx < PUC_PCI_BARS; idx++)
209		sc->sc_bar[idx].b_rid = -1;
210
211	do {
212		sc->sc_ioport.rm_type = RMAN_ARRAY;
213		error = rman_init(&sc->sc_ioport);
214		if (!error) {
215			sc->sc_iomem.rm_type = RMAN_ARRAY;
216			error = rman_init(&sc->sc_iomem);
217			if (!error) {
218				sc->sc_irq.rm_type = RMAN_ARRAY;
219				error = rman_init(&sc->sc_irq);
220				if (!error)
221					break;
222				rman_fini(&sc->sc_iomem);
223			}
224			rman_fini(&sc->sc_ioport);
225		}
226		return (error);
227	} while (0);
228
229	snprintf(buffer, sizeof(buffer), "%s I/O port mapping",
230	    device_get_nameunit(dev));
231	sc->sc_ioport.rm_descr = strdup(buffer, M_PUC);
232	snprintf(buffer, sizeof(buffer), "%s I/O memory mapping",
233	    device_get_nameunit(dev));
234	sc->sc_iomem.rm_descr = strdup(buffer, M_PUC);
235	snprintf(buffer, sizeof(buffer), "%s port numbers",
236	    device_get_nameunit(dev));
237	sc->sc_irq.rm_descr = strdup(buffer, M_PUC);
238
239	error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
240	KASSERT(error == 0, ("%s %d", __func__, __LINE__));
241	sc->sc_nports = (int)res;
242	sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port),
243	    M_PUC, M_WAITOK|M_ZERO);
244
245	error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports);
246	if (error)
247		goto fail;
248
249	error = puc_config(sc, PUC_CFG_SETUP, 0, &res);
250	if (error)
251		goto fail;
252
253	for (idx = 0; idx < sc->sc_nports; idx++) {
254		port = &sc->sc_port[idx];
255		port->p_nr = idx + 1;
256		error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res);
257		if (error)
258			goto fail;
259		port->p_type = res;
260		error = puc_config(sc, PUC_CFG_GET_RID, idx, &res);
261		if (error)
262			goto fail;
263		bar = puc_get_bar(sc, res);
264		if (bar == NULL) {
265			error = ENXIO;
266			goto fail;
267		}
268		port->p_bar = bar;
269		start = rman_get_start(bar->b_res);
270		error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res);
271		if (error)
272			goto fail;
273		ofs = res;
274		error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res);
275		if (error)
276			goto fail;
277		size = res;
278		rm = (bar->b_type == SYS_RES_IOPORT)
279		    ? &sc->sc_ioport: &sc->sc_iomem;
280		port->p_rres = rman_reserve_resource(rm, start + ofs,
281		    start + ofs + size - 1, size, 0, NULL);
282		if (port->p_rres != NULL) {
283			bsh = rman_get_bushandle(bar->b_res);
284			bst = rman_get_bustag(bar->b_res);
285			bus_space_subregion(bst, bsh, ofs, size, &bsh);
286			rman_set_bushandle(port->p_rres, bsh);
287			rman_set_bustag(port->p_rres, bst);
288		}
289		port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr,
290		    port->p_nr, 1, 0, NULL);
291		if (port->p_ires == NULL) {
292			error = ENXIO;
293			goto fail;
294		}
295		error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res);
296		if (error)
297			goto fail;
298		port->p_rclk = res;
299
300		port->p_dev = device_add_child(dev, NULL, -1);
301		if (port->p_dev != NULL)
302			device_set_ivars(port->p_dev, (void *)port);
303	}
304
305	error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res);
306	if (error)
307		goto fail;
308	sc->sc_ilr = res;
309	if (bootverbose && sc->sc_ilr != 0)
310		device_printf(dev, "using interrupt latch register\n");
311
312	sc->sc_irid = 0;
313	sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
314	    RF_ACTIVE|RF_SHAREABLE);
315	if (sc->sc_ires != NULL) {
316		error = bus_setup_intr(dev, sc->sc_ires,
317		    INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie);
318		if (error)
319			error = bus_setup_intr(dev, sc->sc_ires,
320			    INTR_TYPE_TTY | INTR_MPSAFE, NULL,
321			    (driver_intr_t *)puc_intr, sc, &sc->sc_icookie);
322		else
323			sc->sc_fastintr = 1;
324
325		if (error) {
326			device_printf(dev, "could not activate interrupt\n");
327			bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
328			    sc->sc_ires);
329			sc->sc_ires = NULL;
330		}
331	}
332	if (sc->sc_ires == NULL) {
333		/* XXX no interrupt resource. Force polled mode. */
334		sc->sc_polled = 1;
335	}
336
337	/* Probe and attach our children. */
338	for (idx = 0; idx < sc->sc_nports; idx++) {
339		port = &sc->sc_port[idx];
340		if (port->p_dev == NULL)
341			continue;
342		error = device_probe_and_attach(port->p_dev);
343		if (error) {
344			device_delete_child(dev, port->p_dev);
345			port->p_dev = NULL;
346		}
347	}
348
349	/*
350	 * If there are no serdev devices, then our interrupt handler
351	 * will do nothing. Tear it down.
352	 */
353	if (sc->sc_serdevs == 0UL)
354		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
355
356	return (0);
357
358fail:
359	for (idx = 0; idx < sc->sc_nports; idx++) {
360		port = &sc->sc_port[idx];
361		if (port->p_dev != NULL)
362			device_delete_child(dev, port->p_dev);
363		if (port->p_rres != NULL)
364			rman_release_resource(port->p_rres);
365		if (port->p_ires != NULL)
366			rman_release_resource(port->p_ires);
367	}
368	for (idx = 0; idx < PUC_PCI_BARS; idx++) {
369		bar = &sc->sc_bar[idx];
370		if (bar->b_res != NULL)
371			bus_release_resource(sc->sc_dev, bar->b_type,
372			    bar->b_rid, bar->b_res);
373	}
374	rman_fini(&sc->sc_irq);
375	free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
376	rman_fini(&sc->sc_iomem);
377	free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
378	rman_fini(&sc->sc_ioport);
379	free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
380	free(sc->sc_port, M_PUC);
381	return (error);
382}
383
384int
385puc_bfe_detach(device_t dev)
386{
387	struct puc_bar *bar;
388	struct puc_port *port;
389	struct puc_softc *sc;
390	int error, idx;
391
392	sc = device_get_softc(dev);
393
394	/* Detach our children. */
395	error = 0;
396	for (idx = 0; idx < sc->sc_nports; idx++) {
397		port = &sc->sc_port[idx];
398		if (port->p_dev == NULL)
399			continue;
400		if (device_detach(port->p_dev) == 0) {
401			device_delete_child(dev, port->p_dev);
402			if (port->p_rres != NULL)
403				rman_release_resource(port->p_rres);
404			if (port->p_ires != NULL)
405				rman_release_resource(port->p_ires);
406		} else
407			error = ENXIO;
408	}
409	if (error)
410		return (error);
411
412	if (sc->sc_serdevs != 0UL)
413		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
414	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
415
416	for (idx = 0; idx < PUC_PCI_BARS; idx++) {
417		bar = &sc->sc_bar[idx];
418		if (bar->b_res != NULL)
419			bus_release_resource(sc->sc_dev, bar->b_type,
420			    bar->b_rid, bar->b_res);
421	}
422
423	rman_fini(&sc->sc_irq);
424	free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
425	rman_fini(&sc->sc_iomem);
426	free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
427	rman_fini(&sc->sc_ioport);
428	free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
429	free(sc->sc_port, M_PUC);
430	return (0);
431}
432
433int
434puc_bfe_probe(device_t dev, const struct puc_cfg *cfg)
435{
436	struct puc_softc *sc;
437	intptr_t res;
438	int error;
439
440	sc = device_get_softc(dev);
441	sc->sc_dev = dev;
442	sc->sc_cfg = cfg;
443
444	/* We don't attach to single-port serial cards. */
445	if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P)
446		return (EDOOFUS);
447	error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
448	if (error)
449		return (error);
450	error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res);
451	if (error)
452		return (error);
453	if (res != 0)
454		device_set_desc(dev, (const char *)res);
455	return (BUS_PROBE_DEFAULT);
456}
457
458struct resource *
459puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
460    u_long start, u_long end, u_long count, u_int flags)
461{
462	struct puc_port *port;
463	struct resource *res;
464	device_t assigned, originator;
465	int error;
466
467	/* Get our immediate child. */
468	originator = child;
469	while (child != NULL && device_get_parent(child) != dev)
470		child = device_get_parent(child);
471	if (child == NULL)
472		return (NULL);
473
474	port = device_get_ivars(child);
475	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
476
477	if (rid == NULL || *rid != 0)
478		return (NULL);
479
480	/* We only support default allocations. */
481	if (start != 0UL || end != ~0UL)
482		return (NULL);
483
484	if (type == port->p_bar->b_type)
485		res = port->p_rres;
486	else if (type == SYS_RES_IRQ)
487		res = port->p_ires;
488	else
489		return (NULL);
490
491	if (res == NULL)
492		return (NULL);
493
494	assigned = rman_get_device(res);
495	if (assigned == NULL)	/* Not allocated */
496		rman_set_device(res, originator);
497	else if (assigned != originator)
498		return (NULL);
499
500	if (flags & RF_ACTIVE) {
501		error = rman_activate_resource(res);
502		if (error) {
503			if (assigned == NULL)
504				rman_set_device(res, NULL);
505			return (NULL);
506		}
507	}
508
509	return (res);
510}
511
512int
513puc_bus_release_resource(device_t dev, device_t child, int type, int rid,
514    struct resource *res)
515{
516	struct puc_port *port;
517	device_t originator;
518
519	/* Get our immediate child. */
520	originator = child;
521	while (child != NULL && device_get_parent(child) != dev)
522		child = device_get_parent(child);
523	if (child == NULL)
524		return (EINVAL);
525
526	port = device_get_ivars(child);
527	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
528
529	if (rid != 0 || res == NULL)
530		return (EINVAL);
531
532	if (type == port->p_bar->b_type) {
533		if (res != port->p_rres)
534			return (EINVAL);
535	} else if (type == SYS_RES_IRQ) {
536		if (res != port->p_ires)
537			return (EINVAL);
538		if (port->p_hasintr)
539			return (EBUSY);
540	} else
541		return (EINVAL);
542
543	if (rman_get_device(res) != originator)
544		return (ENXIO);
545	if (rman_get_flags(res) & RF_ACTIVE)
546		rman_deactivate_resource(res);
547	rman_set_device(res, NULL);
548	return (0);
549}
550
551int
552puc_bus_get_resource(device_t dev, device_t child, int type, int rid,
553    u_long *startp, u_long *countp)
554{
555	struct puc_port *port;
556	struct resource *res;
557	u_long start;
558
559	/* Get our immediate child. */
560	while (child != NULL && device_get_parent(child) != dev)
561		child = device_get_parent(child);
562	if (child == NULL)
563		return (EINVAL);
564
565	port = device_get_ivars(child);
566	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
567
568	if (type == port->p_bar->b_type)
569		res = port->p_rres;
570	else if (type == SYS_RES_IRQ)
571		res = port->p_ires;
572	else
573		return (ENXIO);
574
575	if (rid != 0 || res == NULL)
576		return (ENXIO);
577
578	start = rman_get_start(res);
579	if (startp != NULL)
580		*startp = start;
581	if (countp != NULL)
582		*countp = rman_get_end(res) - start + 1;
583	return (0);
584}
585
586int
587puc_bus_setup_intr(device_t dev, device_t child, struct resource *res,
588    int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
589{
590	struct puc_port *port;
591	struct puc_softc *sc;
592	device_t originator;
593	int i, isrc, serdev;
594
595	sc = device_get_softc(dev);
596
597	/* Get our immediate child. */
598	originator = child;
599	while (child != NULL && device_get_parent(child) != dev)
600		child = device_get_parent(child);
601	if (child == NULL)
602		return (EINVAL);
603
604	port = device_get_ivars(child);
605	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
606
607	if (filt == NULL || cookiep == NULL || res != port->p_ires)
608		return (EINVAL);
609	if (rman_get_device(port->p_ires) != originator)
610		return (ENXIO);
611
612	/*
613	 * Have non-serdev ports handled by the bus implementation. It
614	 * supports multiple handlers for a single interrupt as it is,
615	 * so we wouldn't add value if we did it ourselves.
616	 */
617	serdev = 0;
618	if (port->p_type == PUC_TYPE_SERIAL) {
619		i = 0, isrc = SER_INT_OVERRUN;
620		while (i < PUC_ISRCCNT) {
621			port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc);
622			if (port->p_ihsrc[i] != NULL)
623				serdev = 1;
624			i++, isrc <<= 1;
625		}
626	}
627	if (!serdev)
628		return (BUS_SETUP_INTR(device_get_parent(dev), originator,
629		    sc->sc_ires, flags, filt, ihand, arg, cookiep));
630
631	/* We demand that serdev devices use fast interrupts. */
632	if (filt == NULL)
633		return (ENXIO);
634
635	sc->sc_serdevs |= 1UL << (port->p_nr - 1);
636
637	port->p_hasintr = 1;
638	port->p_ih = filt;
639	port->p_iharg = arg;
640
641	*cookiep = port;
642	return (0);
643}
644
645int
646puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res,
647    void *cookie)
648{
649	struct puc_port *port;
650	struct puc_softc *sc;
651	device_t originator;
652	int i;
653
654	sc = device_get_softc(dev);
655
656	/* Get our immediate child. */
657	originator = child;
658	while (child != NULL && device_get_parent(child) != dev)
659		child = device_get_parent(child);
660	if (child == NULL)
661		return (EINVAL);
662
663	port = device_get_ivars(child);
664	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
665
666	if (res != port->p_ires)
667		return (EINVAL);
668	if (rman_get_device(port->p_ires) != originator)
669		return (ENXIO);
670
671	if (!port->p_hasintr)
672		return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator,
673		    sc->sc_ires, cookie));
674
675	if (cookie != port)
676		return (EINVAL);
677
678	port->p_hasintr = 0;
679	port->p_ih = NULL;
680	port->p_iharg = NULL;
681
682	for (i = 0; i < PUC_ISRCCNT; i++)
683		port->p_ihsrc[i] = NULL;
684
685	return (0);
686}
687
688int
689puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
690{
691	struct puc_port *port;
692
693	/* Get our immediate child. */
694	while (child != NULL && device_get_parent(child) != dev)
695		child = device_get_parent(child);
696	if (child == NULL)
697		return (EINVAL);
698
699	port = device_get_ivars(child);
700	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
701
702	if (result == NULL)
703		return (EINVAL);
704
705	switch(index) {
706	case PUC_IVAR_CLOCK:
707		*result = port->p_rclk;
708		break;
709	case PUC_IVAR_TYPE:
710		*result = port->p_type;
711		break;
712	default:
713		return (ENOENT);
714	}
715	return (0);
716}
717