puc.c revision 166901
1306196Sjkim/*-
296593Smarkm * Copyright (c) 2006 Marcel Moolenaar
396593Smarkm * All rights reserved.
4142429Snectar *
596593Smarkm * Redistribution and use in source and binary forms, with or without
696593Smarkm * modification, are permitted provided that the following conditions
796593Smarkm * are met:
896593Smarkm *
996593Smarkm * 1. Redistributions of source code must retain the above copyright
1096593Smarkm *    notice, this list of conditions and the following disclaimer.
1196593Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1296593Smarkm *    notice, this list of conditions and the following disclaimer in the
1396593Smarkm *    documentation and/or other materials provided with the distribution.
1496593Smarkm *
1596593Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1696593Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1796593Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1896593Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1996593Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20215698Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21215698Ssimon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22215698Ssimon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23215698Ssimon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24215698Ssimon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2596593Smarkm */
2696593Smarkm
2796593Smarkm#include <sys/cdefs.h>
2896593Smarkm__FBSDID("$FreeBSD: head/sys/dev/puc/puc.c 166901 2007-02-23 12:19:07Z piso $");
2996593Smarkm
3096593Smarkm#include <sys/param.h>
3196593Smarkm#include <sys/systm.h>
3296593Smarkm#include <sys/kernel.h>
3396593Smarkm#include <sys/bus.h>
3496593Smarkm#include <sys/conf.h>
3596593Smarkm#include <sys/malloc.h>
3696593Smarkm#include <sys/mutex.h>
3796593Smarkm
3896593Smarkm#include <machine/bus.h>
3996593Smarkm#include <machine/resource.h>
4096593Smarkm#include <sys/rman.h>
41276864Sjkim
42276864Sjkim#include <dev/pci/pcireg.h>
4396593Smarkm#include <dev/pci/pcivar.h>
4496593Smarkm
45215698Ssimon#include <dev/puc/puc_bus.h>
46215698Ssimon#include <dev/puc/puc_cfg.h>
47215698Ssimon#include <dev/puc/puc_bfe.h>
48215698Ssimon
49142429Snectar#define	PUC_ISRCCNT	5
50215698Ssimon
51142429Snectarstruct puc_port {
52142429Snectar	struct puc_bar	*p_bar;
53276864Sjkim	struct resource *p_rres;
54276864Sjkim	struct resource *p_ires;
55276864Sjkim	device_t	p_dev;
5696593Smarkm	int		p_nr;
57276864Sjkim	int		p_type;
58276864Sjkim	int		p_rclk;
59276864Sjkim
60276864Sjkim	int		p_hasintr:1;
61276864Sjkim
62276864Sjkim	driver_filter_t	*p_ih;
63215698Ssimon	serdev_intr_t	*p_ihsrc[PUC_ISRCCNT];
64276864Sjkim	void		*p_iharg;
65276864Sjkim
66276864Sjkim	int		p_ipend;
67276864Sjkim};
68276864Sjkim
69215698Ssimondevclass_t puc_devclass;
70276864Sjkimconst char puc_driver_name[] = "puc";
7196593Smarkm
7296593SmarkmMALLOC_DEFINE(M_PUC, "PUC", "PUC driver");
7396593Smarkm
7496593Smarkmstruct puc_bar *
7596593Smarkmpuc_get_bar(struct puc_softc *sc, int rid)
7696593Smarkm{
7796593Smarkm	struct puc_bar *bar;
7896593Smarkm	struct rman *rm;
7996593Smarkm	u_long end, start;
8096593Smarkm	int error, i;
8196593Smarkm
8296593Smarkm	/* Find the BAR entry with the given RID. */
8396593Smarkm	i = 0;
8496593Smarkm	while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid)
8596593Smarkm		i++;
8696593Smarkm	if (i < PUC_PCI_BARS)
8796593Smarkm		return (&sc->sc_bar[i]);
8896593Smarkm
8996593Smarkm	/* Not found. If we're looking for an unused entry, return NULL. */
9096593Smarkm	if (rid == -1)
9196593Smarkm		return (NULL);
9296593Smarkm
9396593Smarkm	/* Get an unused entry for us to fill.  */
9496593Smarkm	bar = puc_get_bar(sc, -1);
9596593Smarkm	if (bar == NULL)
9696593Smarkm		return (NULL);
9796593Smarkm	bar->b_rid = rid;
9896593Smarkm	bar->b_type = SYS_RES_IOPORT;
9996593Smarkm	bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
10096593Smarkm	    &bar->b_rid, RF_ACTIVE);
10196593Smarkm	if (bar->b_res == NULL) {
10296593Smarkm		bar->b_rid = rid;
10396593Smarkm		bar->b_type = SYS_RES_MEMORY;
10496593Smarkm		bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
10596593Smarkm		    &bar->b_rid, RF_ACTIVE);
10696593Smarkm		if (bar->b_res == NULL) {
10796593Smarkm			bar->b_rid = -1;
10896593Smarkm			return (NULL);
10996593Smarkm		}
11096593Smarkm	}
11196593Smarkm
11296593Smarkm	/* Update our managed space. */
11396593Smarkm	rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem;
11496593Smarkm	start = rman_get_start(bar->b_res);
11596593Smarkm	end = rman_get_end(bar->b_res);
11696593Smarkm	error = rman_manage_region(rm, start, end);
11796593Smarkm	if (error) {
11896593Smarkm		bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid,
11996593Smarkm		    bar->b_res);
12096593Smarkm		bar->b_res = NULL;
12196593Smarkm		bar->b_rid = -1;
12296593Smarkm		bar = NULL;
12396593Smarkm	}
12496593Smarkm
12596593Smarkm	return (bar);
12696593Smarkm}
12796593Smarkm
12896593Smarkmstatic int
12996593Smarkmpuc_intr(void *arg)
13096593Smarkm{
13196593Smarkm	struct puc_port *port;
13296593Smarkm	struct puc_softc *sc = arg;
133142429Snectar	u_long dev, devs;
13496593Smarkm	int i, idx, ipend, isrc;
135100946Snectar	uint8_t ilr;
136306196Sjkim
137215698Ssimon	devs = sc->sc_serdevs;
138215698Ssimon	if (sc->sc_ilr == PUC_ILR_DIGI) {
139215698Ssimon		idx = 0;
140215698Ssimon		while (devs & (0xfful << idx)) {
14196593Smarkm			ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
142142429Snectar			devs &= ~0ul ^ ((u_long)ilr << idx);
14396593Smarkm			idx += 8;
14496593Smarkm		}
14596593Smarkm	} else if (sc->sc_ilr == PUC_ILR_QUATECH) {
14696593Smarkm		/*
147215698Ssimon		 * Don't trust the value if it's the same as the option
14896593Smarkm		 * register. It may mean that the ILR is not active and
149215698Ssimon		 * we're reading the option register instead. This may
15096593Smarkm		 * lead to false positives on 8-port boards.
15196593Smarkm		 */
15296593Smarkm		ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
15396593Smarkm		if (ilr != (sc->sc_cfg_data & 0xff))
154110010Smarkm			devs &= (u_long)ilr;
155110010Smarkm	}
15696593Smarkm
15796593Smarkm	ipend = 0;
15896593Smarkm	idx = 0, dev = 1UL;
15996593Smarkm	while (devs != 0UL) {
16096593Smarkm		while ((devs & dev) == 0UL)
16196593Smarkm			idx++, dev <<= 1;
16296593Smarkm		devs &= ~dev;
163142429Snectar		port = &sc->sc_port[idx];
16496593Smarkm		port->p_ipend = SERDEV_IPEND(port->p_dev);
16596593Smarkm		ipend |= port->p_ipend;
16696593Smarkm	}
16796593Smarkm
16896593Smarkm	i = 0, isrc = SER_INT_OVERRUN;
169142429Snectar	while (ipend) {
170142429Snectar		while (i < PUC_ISRCCNT && !(ipend & isrc))
171142429Snectar			i++, isrc <<= 1;
17296593Smarkm		KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
17396593Smarkm		ipend &= ~isrc;
17496593Smarkm		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