xref: /freebsd/sys/dev/puc/puc.c (revision 2be1a816)
1 /*-
2  * Copyright (c) 2006 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 
38 #include <machine/bus.h>
39 #include <machine/resource.h>
40 #include <sys/rman.h>
41 
42 #include <dev/pci/pcireg.h>
43 #include <dev/pci/pcivar.h>
44 
45 #include <dev/puc/puc_bus.h>
46 #include <dev/puc/puc_cfg.h>
47 #include <dev/puc/puc_bfe.h>
48 
49 #define	PUC_ISRCCNT	5
50 
51 struct puc_port {
52 	struct puc_bar	*p_bar;
53 	struct resource *p_rres;
54 	struct resource *p_ires;
55 	device_t	p_dev;
56 	int		p_nr;
57 	int		p_type;
58 	int		p_rclk;
59 
60 	int		p_hasintr:1;
61 
62 	serdev_intr_t	*p_ihsrc[PUC_ISRCCNT];
63 	void		*p_iharg;
64 
65 	int		p_ipend;
66 };
67 
68 devclass_t puc_devclass;
69 const char puc_driver_name[] = "puc";
70 
71 MALLOC_DEFINE(M_PUC, "PUC", "PUC driver");
72 
73 struct puc_bar *
74 puc_get_bar(struct puc_softc *sc, int rid)
75 {
76 	struct puc_bar *bar;
77 	struct rman *rm;
78 	u_long end, start;
79 	int error, i;
80 
81 	/* Find the BAR entry with the given RID. */
82 	i = 0;
83 	while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid)
84 		i++;
85 	if (i < PUC_PCI_BARS)
86 		return (&sc->sc_bar[i]);
87 
88 	/* Not found. If we're looking for an unused entry, return NULL. */
89 	if (rid == -1)
90 		return (NULL);
91 
92 	/* Get an unused entry for us to fill.  */
93 	bar = puc_get_bar(sc, -1);
94 	if (bar == NULL)
95 		return (NULL);
96 	bar->b_rid = rid;
97 	bar->b_type = SYS_RES_IOPORT;
98 	bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
99 	    &bar->b_rid, RF_ACTIVE);
100 	if (bar->b_res == NULL) {
101 		bar->b_rid = rid;
102 		bar->b_type = SYS_RES_MEMORY;
103 		bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
104 		    &bar->b_rid, RF_ACTIVE);
105 		if (bar->b_res == NULL) {
106 			bar->b_rid = -1;
107 			return (NULL);
108 		}
109 	}
110 
111 	/* Update our managed space. */
112 	rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem;
113 	start = rman_get_start(bar->b_res);
114 	end = rman_get_end(bar->b_res);
115 	error = rman_manage_region(rm, start, end);
116 	if (error) {
117 		bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid,
118 		    bar->b_res);
119 		bar->b_res = NULL;
120 		bar->b_rid = -1;
121 		bar = NULL;
122 	}
123 
124 	return (bar);
125 }
126 
127 static int
128 puc_intr(void *arg)
129 {
130 	struct puc_port *port;
131 	struct puc_softc *sc = arg;
132 	u_long dev, devs;
133 	int i, idx, ipend, isrc;
134 	uint8_t ilr;
135 
136 	devs = sc->sc_serdevs;
137 	if (sc->sc_ilr == PUC_ILR_DIGI) {
138 		idx = 0;
139 		while (devs & (0xfful << idx)) {
140 			ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
141 			devs &= ~0ul ^ ((u_long)ilr << idx);
142 			idx += 8;
143 		}
144 	} else if (sc->sc_ilr == PUC_ILR_QUATECH) {
145 		/*
146 		 * Don't trust the value if it's the same as the option
147 		 * register. It may mean that the ILR is not active and
148 		 * we're reading the option register instead. This may
149 		 * lead to false positives on 8-port boards.
150 		 */
151 		ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
152 		if (ilr != (sc->sc_cfg_data & 0xff))
153 			devs &= (u_long)ilr;
154 	}
155 
156 	ipend = 0;
157 	idx = 0, dev = 1UL;
158 	while (devs != 0UL) {
159 		while ((devs & dev) == 0UL)
160 			idx++, dev <<= 1;
161 		devs &= ~dev;
162 		port = &sc->sc_port[idx];
163 		port->p_ipend = SERDEV_IPEND(port->p_dev);
164 		ipend |= port->p_ipend;
165 	}
166 
167 	i = 0, isrc = SER_INT_OVERRUN;
168 	while (ipend) {
169 		while (i < PUC_ISRCCNT && !(ipend & isrc))
170 			i++, isrc <<= 1;
171 		KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
172 		ipend &= ~isrc;
173 		idx = 0, dev = 1UL;
174 		devs = sc->sc_serdevs;
175 		while (devs != 0UL) {
176 			while ((devs & dev) == 0UL)
177 				idx++, dev <<= 1;
178 			devs &= ~dev;
179 			port = &sc->sc_port[idx];
180 			if (!(port->p_ipend & isrc))
181 				continue;
182 			if (port->p_ihsrc[i] != NULL)
183 				(*port->p_ihsrc[i])(port->p_iharg);
184 		}
185 		return (FILTER_HANDLED);
186 	}
187 	return (FILTER_STRAY);
188 }
189 
190 int
191 puc_bfe_attach(device_t dev)
192 {
193 	char buffer[64];
194 	struct puc_bar *bar;
195 	struct puc_port *port;
196 	struct puc_softc *sc;
197 	struct rman *rm;
198 	intptr_t res;
199 	bus_addr_t ofs, start;
200 	bus_size_t size;
201 	bus_space_handle_t bsh;
202 	bus_space_tag_t bst;
203 	int error, idx;
204 
205 	sc = device_get_softc(dev);
206 
207 	for (idx = 0; idx < PUC_PCI_BARS; idx++)
208 		sc->sc_bar[idx].b_rid = -1;
209 
210 	do {
211 		sc->sc_ioport.rm_type = RMAN_ARRAY;
212 		error = rman_init(&sc->sc_ioport);
213 		if (!error) {
214 			sc->sc_iomem.rm_type = RMAN_ARRAY;
215 			error = rman_init(&sc->sc_iomem);
216 			if (!error) {
217 				sc->sc_irq.rm_type = RMAN_ARRAY;
218 				error = rman_init(&sc->sc_irq);
219 				if (!error)
220 					break;
221 				rman_fini(&sc->sc_iomem);
222 			}
223 			rman_fini(&sc->sc_ioport);
224 		}
225 		return (error);
226 	} while (0);
227 
228 	snprintf(buffer, sizeof(buffer), "%s I/O port mapping",
229 	    device_get_nameunit(dev));
230 	sc->sc_ioport.rm_descr = strdup(buffer, M_PUC);
231 	snprintf(buffer, sizeof(buffer), "%s I/O memory mapping",
232 	    device_get_nameunit(dev));
233 	sc->sc_iomem.rm_descr = strdup(buffer, M_PUC);
234 	snprintf(buffer, sizeof(buffer), "%s port numbers",
235 	    device_get_nameunit(dev));
236 	sc->sc_irq.rm_descr = strdup(buffer, M_PUC);
237 
238 	error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
239 	KASSERT(error == 0, ("%s %d", __func__, __LINE__));
240 	sc->sc_nports = (int)res;
241 	sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port),
242 	    M_PUC, M_WAITOK|M_ZERO);
243 
244 	error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports);
245 	if (error)
246 		goto fail;
247 
248 	error = puc_config(sc, PUC_CFG_SETUP, 0, &res);
249 	if (error)
250 		goto fail;
251 
252 	for (idx = 0; idx < sc->sc_nports; idx++) {
253 		port = &sc->sc_port[idx];
254 		port->p_nr = idx + 1;
255 		error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res);
256 		if (error)
257 			goto fail;
258 		port->p_type = res;
259 		error = puc_config(sc, PUC_CFG_GET_RID, idx, &res);
260 		if (error)
261 			goto fail;
262 		bar = puc_get_bar(sc, res);
263 		if (bar == NULL) {
264 			error = ENXIO;
265 			goto fail;
266 		}
267 		port->p_bar = bar;
268 		start = rman_get_start(bar->b_res);
269 		error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res);
270 		if (error)
271 			goto fail;
272 		ofs = res;
273 		error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res);
274 		if (error)
275 			goto fail;
276 		size = res;
277 		rm = (bar->b_type == SYS_RES_IOPORT)
278 		    ? &sc->sc_ioport: &sc->sc_iomem;
279 		port->p_rres = rman_reserve_resource(rm, start + ofs,
280 		    start + ofs + size - 1, size, 0, NULL);
281 		if (port->p_rres != NULL) {
282 			bsh = rman_get_bushandle(bar->b_res);
283 			bst = rman_get_bustag(bar->b_res);
284 			bus_space_subregion(bst, bsh, ofs, size, &bsh);
285 			rman_set_bushandle(port->p_rres, bsh);
286 			rman_set_bustag(port->p_rres, bst);
287 		}
288 		port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr,
289 		    port->p_nr, 1, 0, NULL);
290 		if (port->p_ires == NULL) {
291 			error = ENXIO;
292 			goto fail;
293 		}
294 		error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res);
295 		if (error)
296 			goto fail;
297 		port->p_rclk = res;
298 
299 		port->p_dev = device_add_child(dev, NULL, -1);
300 		if (port->p_dev != NULL)
301 			device_set_ivars(port->p_dev, (void *)port);
302 	}
303 
304 	error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res);
305 	if (error)
306 		goto fail;
307 	sc->sc_ilr = res;
308 	if (bootverbose && sc->sc_ilr != 0)
309 		device_printf(dev, "using interrupt latch register\n");
310 
311 	sc->sc_irid = 0;
312 	sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
313 	    RF_ACTIVE|RF_SHAREABLE);
314 	if (sc->sc_ires != NULL) {
315 		error = bus_setup_intr(dev, sc->sc_ires,
316 		    INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie);
317 		if (error)
318 			error = bus_setup_intr(dev, sc->sc_ires,
319 			    INTR_TYPE_TTY | INTR_MPSAFE, NULL,
320 			    (driver_intr_t *)puc_intr, sc, &sc->sc_icookie);
321 		else
322 			sc->sc_fastintr = 1;
323 
324 		if (error) {
325 			device_printf(dev, "could not activate interrupt\n");
326 			bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
327 			    sc->sc_ires);
328 			sc->sc_ires = NULL;
329 		}
330 	}
331 	if (sc->sc_ires == NULL) {
332 		/* XXX no interrupt resource. Force polled mode. */
333 		sc->sc_polled = 1;
334 	}
335 
336 	/* Probe and attach our children. */
337 	for (idx = 0; idx < sc->sc_nports; idx++) {
338 		port = &sc->sc_port[idx];
339 		if (port->p_dev == NULL)
340 			continue;
341 		error = device_probe_and_attach(port->p_dev);
342 		if (error) {
343 			device_delete_child(dev, port->p_dev);
344 			port->p_dev = NULL;
345 		}
346 	}
347 
348 	/*
349 	 * If there are no serdev devices, then our interrupt handler
350 	 * will do nothing. Tear it down.
351 	 */
352 	if (sc->sc_serdevs == 0UL)
353 		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
354 
355 	return (0);
356 
357 fail:
358 	for (idx = 0; idx < sc->sc_nports; idx++) {
359 		port = &sc->sc_port[idx];
360 		if (port->p_dev != NULL)
361 			device_delete_child(dev, port->p_dev);
362 		if (port->p_rres != NULL)
363 			rman_release_resource(port->p_rres);
364 		if (port->p_ires != NULL)
365 			rman_release_resource(port->p_ires);
366 	}
367 	for (idx = 0; idx < PUC_PCI_BARS; idx++) {
368 		bar = &sc->sc_bar[idx];
369 		if (bar->b_res != NULL)
370 			bus_release_resource(sc->sc_dev, bar->b_type,
371 			    bar->b_rid, bar->b_res);
372 	}
373 	rman_fini(&sc->sc_irq);
374 	free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
375 	rman_fini(&sc->sc_iomem);
376 	free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
377 	rman_fini(&sc->sc_ioport);
378 	free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
379 	free(sc->sc_port, M_PUC);
380 	return (error);
381 }
382 
383 int
384 puc_bfe_detach(device_t dev)
385 {
386 	struct puc_bar *bar;
387 	struct puc_port *port;
388 	struct puc_softc *sc;
389 	int error, idx;
390 
391 	sc = device_get_softc(dev);
392 
393 	/* Detach our children. */
394 	error = 0;
395 	for (idx = 0; idx < sc->sc_nports; idx++) {
396 		port = &sc->sc_port[idx];
397 		if (port->p_dev == NULL)
398 			continue;
399 		if (device_detach(port->p_dev) == 0) {
400 			device_delete_child(dev, port->p_dev);
401 			if (port->p_rres != NULL)
402 				rman_release_resource(port->p_rres);
403 			if (port->p_ires != NULL)
404 				rman_release_resource(port->p_ires);
405 		} else
406 			error = ENXIO;
407 	}
408 	if (error)
409 		return (error);
410 
411 	if (sc->sc_serdevs != 0UL)
412 		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
413 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
414 
415 	for (idx = 0; idx < PUC_PCI_BARS; idx++) {
416 		bar = &sc->sc_bar[idx];
417 		if (bar->b_res != NULL)
418 			bus_release_resource(sc->sc_dev, bar->b_type,
419 			    bar->b_rid, bar->b_res);
420 	}
421 
422 	rman_fini(&sc->sc_irq);
423 	free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
424 	rman_fini(&sc->sc_iomem);
425 	free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
426 	rman_fini(&sc->sc_ioport);
427 	free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
428 	free(sc->sc_port, M_PUC);
429 	return (0);
430 }
431 
432 int
433 puc_bfe_probe(device_t dev, const struct puc_cfg *cfg)
434 {
435 	struct puc_softc *sc;
436 	intptr_t res;
437 	int error;
438 
439 	sc = device_get_softc(dev);
440 	sc->sc_dev = dev;
441 	sc->sc_cfg = cfg;
442 
443 	/* We don't attach to single-port serial cards. */
444 	if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P)
445 		return (EDOOFUS);
446 	error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
447 	if (error)
448 		return (error);
449 	error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res);
450 	if (error)
451 		return (error);
452 	if (res != 0)
453 		device_set_desc(dev, (const char *)res);
454 	return (BUS_PROBE_DEFAULT);
455 }
456 
457 struct resource *
458 puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
459     u_long start, u_long end, u_long count, u_int flags)
460 {
461 	struct puc_port *port;
462 	struct resource *res;
463 	device_t assigned, originator;
464 	int error;
465 
466 	/* Get our immediate child. */
467 	originator = child;
468 	while (child != NULL && device_get_parent(child) != dev)
469 		child = device_get_parent(child);
470 	if (child == NULL)
471 		return (NULL);
472 
473 	port = device_get_ivars(child);
474 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
475 
476 	if (rid == NULL || *rid != 0)
477 		return (NULL);
478 
479 	/* We only support default allocations. */
480 	if (start != 0UL || end != ~0UL)
481 		return (NULL);
482 
483 	if (type == port->p_bar->b_type)
484 		res = port->p_rres;
485 	else if (type == SYS_RES_IRQ)
486 		res = port->p_ires;
487 	else
488 		return (NULL);
489 
490 	if (res == NULL)
491 		return (NULL);
492 
493 	assigned = rman_get_device(res);
494 	if (assigned == NULL)	/* Not allocated */
495 		rman_set_device(res, originator);
496 	else if (assigned != originator)
497 		return (NULL);
498 
499 	if (flags & RF_ACTIVE) {
500 		error = rman_activate_resource(res);
501 		if (error) {
502 			if (assigned == NULL)
503 				rman_set_device(res, NULL);
504 			return (NULL);
505 		}
506 	}
507 
508 	return (res);
509 }
510 
511 int
512 puc_bus_release_resource(device_t dev, device_t child, int type, int rid,
513     struct resource *res)
514 {
515 	struct puc_port *port;
516 	device_t originator;
517 
518 	/* Get our immediate child. */
519 	originator = child;
520 	while (child != NULL && device_get_parent(child) != dev)
521 		child = device_get_parent(child);
522 	if (child == NULL)
523 		return (EINVAL);
524 
525 	port = device_get_ivars(child);
526 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
527 
528 	if (rid != 0 || res == NULL)
529 		return (EINVAL);
530 
531 	if (type == port->p_bar->b_type) {
532 		if (res != port->p_rres)
533 			return (EINVAL);
534 	} else if (type == SYS_RES_IRQ) {
535 		if (res != port->p_ires)
536 			return (EINVAL);
537 		if (port->p_hasintr)
538 			return (EBUSY);
539 	} else
540 		return (EINVAL);
541 
542 	if (rman_get_device(res) != originator)
543 		return (ENXIO);
544 	if (rman_get_flags(res) & RF_ACTIVE)
545 		rman_deactivate_resource(res);
546 	rman_set_device(res, NULL);
547 	return (0);
548 }
549 
550 int
551 puc_bus_get_resource(device_t dev, device_t child, int type, int rid,
552     u_long *startp, u_long *countp)
553 {
554 	struct puc_port *port;
555 	struct resource *res;
556 	u_long start;
557 
558 	/* Get our immediate child. */
559 	while (child != NULL && device_get_parent(child) != dev)
560 		child = device_get_parent(child);
561 	if (child == NULL)
562 		return (EINVAL);
563 
564 	port = device_get_ivars(child);
565 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
566 
567 	if (type == port->p_bar->b_type)
568 		res = port->p_rres;
569 	else if (type == SYS_RES_IRQ)
570 		res = port->p_ires;
571 	else
572 		return (ENXIO);
573 
574 	if (rid != 0 || res == NULL)
575 		return (ENXIO);
576 
577 	start = rman_get_start(res);
578 	if (startp != NULL)
579 		*startp = start;
580 	if (countp != NULL)
581 		*countp = rman_get_end(res) - start + 1;
582 	return (0);
583 }
584 
585 int
586 puc_bus_setup_intr(device_t dev, device_t child, struct resource *res,
587     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
588 {
589 	struct puc_port *port;
590 	struct puc_softc *sc;
591 	device_t originator;
592 	int i, isrc, serdev;
593 
594 	sc = device_get_softc(dev);
595 
596 	/* Get our immediate child. */
597 	originator = child;
598 	while (child != NULL && device_get_parent(child) != dev)
599 		child = device_get_parent(child);
600 	if (child == NULL)
601 		return (EINVAL);
602 
603 	port = device_get_ivars(child);
604 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
605 
606 	if (cookiep == NULL || res != port->p_ires)
607 		return (EINVAL);
608 	/* We demand that serdev devices use filter_only interrupts. */
609 	if (ihand != NULL)
610 		return (ENXIO);
611 	if (rman_get_device(port->p_ires) != originator)
612 		return (ENXIO);
613 
614 	/*
615 	 * Have non-serdev ports handled by the bus implementation. It
616 	 * supports multiple handlers for a single interrupt as it is,
617 	 * so we wouldn't add value if we did it ourselves.
618 	 */
619 	serdev = 0;
620 	if (port->p_type == PUC_TYPE_SERIAL) {
621 		i = 0, isrc = SER_INT_OVERRUN;
622 		while (i < PUC_ISRCCNT) {
623 			port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc);
624 			if (port->p_ihsrc[i] != NULL)
625 				serdev = 1;
626 			i++, isrc <<= 1;
627 		}
628 	}
629 	if (!serdev)
630 		return (BUS_SETUP_INTR(device_get_parent(dev), originator,
631 		    sc->sc_ires, flags, filt, ihand, arg, cookiep));
632 
633 	sc->sc_serdevs |= 1UL << (port->p_nr - 1);
634 
635 	port->p_hasintr = 1;
636 	port->p_iharg = arg;
637 
638 	*cookiep = port;
639 	return (0);
640 }
641 
642 int
643 puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res,
644     void *cookie)
645 {
646 	struct puc_port *port;
647 	struct puc_softc *sc;
648 	device_t originator;
649 	int i;
650 
651 	sc = device_get_softc(dev);
652 
653 	/* Get our immediate child. */
654 	originator = child;
655 	while (child != NULL && device_get_parent(child) != dev)
656 		child = device_get_parent(child);
657 	if (child == NULL)
658 		return (EINVAL);
659 
660 	port = device_get_ivars(child);
661 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
662 
663 	if (res != port->p_ires)
664 		return (EINVAL);
665 	if (rman_get_device(port->p_ires) != originator)
666 		return (ENXIO);
667 
668 	if (!port->p_hasintr)
669 		return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator,
670 		    sc->sc_ires, cookie));
671 
672 	if (cookie != port)
673 		return (EINVAL);
674 
675 	port->p_hasintr = 0;
676 	port->p_iharg = NULL;
677 
678 	for (i = 0; i < PUC_ISRCCNT; i++)
679 		port->p_ihsrc[i] = NULL;
680 
681 	return (0);
682 }
683 
684 int
685 puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
686 {
687 	struct puc_port *port;
688 
689 	/* Get our immediate child. */
690 	while (child != NULL && device_get_parent(child) != dev)
691 		child = device_get_parent(child);
692 	if (child == NULL)
693 		return (EINVAL);
694 
695 	port = device_get_ivars(child);
696 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
697 
698 	if (result == NULL)
699 		return (EINVAL);
700 
701 	switch(index) {
702 	case PUC_IVAR_CLOCK:
703 		*result = port->p_rclk;
704 		break;
705 	case PUC_IVAR_TYPE:
706 		*result = port->p_type;
707 		break;
708 	default:
709 		return (ENOENT);
710 	}
711 	return (0);
712 }
713