xref: /freebsd/sys/dev/puc/puc.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
19c564b6cSJohn Hay /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
464220a7eSMarcel Moolenaar  * Copyright (c) 2006 Marcel Moolenaar
564220a7eSMarcel Moolenaar  * All rights reserved.
69c564b6cSJohn Hay  *
79c564b6cSJohn Hay  * Redistribution and use in source and binary forms, with or without
89c564b6cSJohn Hay  * modification, are permitted provided that the following conditions
99c564b6cSJohn Hay  * are met:
1064220a7eSMarcel Moolenaar  *
119c564b6cSJohn Hay  * 1. Redistributions of source code must retain the above copyright
12ac673f9aSWarner Losh  *    notice, this list of conditions and the following disclaimer.
139c564b6cSJohn Hay  * 2. Redistributions in binary form must reproduce the above copyright
149c564b6cSJohn Hay  *    notice, this list of conditions and the following disclaimer in the
159c564b6cSJohn Hay  *    documentation and/or other materials provided with the distribution.
169c564b6cSJohn Hay  *
179c564b6cSJohn Hay  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189c564b6cSJohn Hay  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199c564b6cSJohn Hay  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209c564b6cSJohn Hay  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219c564b6cSJohn Hay  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229c564b6cSJohn Hay  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239c564b6cSJohn Hay  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249c564b6cSJohn Hay  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259c564b6cSJohn Hay  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269c564b6cSJohn Hay  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279c564b6cSJohn Hay  */
289c564b6cSJohn Hay 
299c564b6cSJohn Hay #include <sys/cdefs.h>
309c564b6cSJohn Hay __FBSDID("$FreeBSD$");
319c564b6cSJohn Hay 
329c564b6cSJohn Hay #include <sys/param.h>
339c564b6cSJohn Hay #include <sys/systm.h>
349c564b6cSJohn Hay #include <sys/kernel.h>
359c564b6cSJohn Hay #include <sys/bus.h>
369c564b6cSJohn Hay #include <sys/conf.h>
379c564b6cSJohn Hay #include <sys/malloc.h>
3864220a7eSMarcel Moolenaar #include <sys/mutex.h>
39ddfc9c4cSWarner Losh #include <sys/sbuf.h>
409725900bSRyan Stone #include <sys/sysctl.h>
419c564b6cSJohn Hay 
429c564b6cSJohn Hay #include <machine/bus.h>
439c564b6cSJohn Hay #include <machine/resource.h>
449c564b6cSJohn Hay #include <sys/rman.h>
459c564b6cSJohn Hay 
469c564b6cSJohn Hay #include <dev/pci/pcireg.h>
479c564b6cSJohn Hay #include <dev/pci/pcivar.h>
4832f606d1SPoul-Henning Kamp 
4964220a7eSMarcel Moolenaar #include <dev/puc/puc_bus.h>
5064220a7eSMarcel Moolenaar #include <dev/puc/puc_cfg.h>
51482aa6a3SDavid E. O'Brien #include <dev/puc/puc_bfe.h>
529c564b6cSJohn Hay 
5364220a7eSMarcel Moolenaar #define	PUC_ISRCCNT	5
5464220a7eSMarcel Moolenaar 
5564220a7eSMarcel Moolenaar struct puc_port {
5664220a7eSMarcel Moolenaar 	struct puc_bar	*p_bar;
5764220a7eSMarcel Moolenaar 	struct resource *p_rres;
5864220a7eSMarcel Moolenaar 	struct resource *p_ires;
5964220a7eSMarcel Moolenaar 	device_t	p_dev;
6064220a7eSMarcel Moolenaar 	int		p_nr;
6164220a7eSMarcel Moolenaar 	int		p_type;
6264220a7eSMarcel Moolenaar 	int		p_rclk;
6364220a7eSMarcel Moolenaar 
64bab8274cSDimitry Andric 	bool		p_hasintr:1;
6564220a7eSMarcel Moolenaar 
6664220a7eSMarcel Moolenaar 	serdev_intr_t	*p_ihsrc[PUC_ISRCCNT];
6764220a7eSMarcel Moolenaar 	void		*p_iharg;
6864220a7eSMarcel Moolenaar 
6964220a7eSMarcel Moolenaar 	int		p_ipend;
709c564b6cSJohn Hay };
719c564b6cSJohn Hay 
7264220a7eSMarcel Moolenaar const char puc_driver_name[] = "puc";
73c9168019SPoul-Henning Kamp 
74d745c852SEd Schouten static MALLOC_DEFINE(M_PUC, "PUC", "PUC driver");
7564220a7eSMarcel Moolenaar 
767029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, puc, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
777029da5cSPawel Biernacki     "puc(9) driver configuration");
789725900bSRyan Stone 
7964220a7eSMarcel Moolenaar struct puc_bar *
8064220a7eSMarcel Moolenaar puc_get_bar(struct puc_softc *sc, int rid)
811e89655aSPoul-Henning Kamp {
8264220a7eSMarcel Moolenaar 	struct puc_bar *bar;
8364220a7eSMarcel Moolenaar 	struct rman *rm;
842dd1bdf1SJustin Hibbits 	rman_res_t end, start;
8564220a7eSMarcel Moolenaar 	int error, i;
861e89655aSPoul-Henning Kamp 
8764220a7eSMarcel Moolenaar 	/* Find the BAR entry with the given RID. */
8864220a7eSMarcel Moolenaar 	i = 0;
8964220a7eSMarcel Moolenaar 	while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid)
9064220a7eSMarcel Moolenaar 		i++;
9164220a7eSMarcel Moolenaar 	if (i < PUC_PCI_BARS)
9264220a7eSMarcel Moolenaar 		return (&sc->sc_bar[i]);
931e89655aSPoul-Henning Kamp 
9464220a7eSMarcel Moolenaar 	/* Not found. If we're looking for an unused entry, return NULL. */
9564220a7eSMarcel Moolenaar 	if (rid == -1)
9664220a7eSMarcel Moolenaar 		return (NULL);
97084254f8SMaxim Sobolev 
9864220a7eSMarcel Moolenaar 	/* Get an unused entry for us to fill.  */
9964220a7eSMarcel Moolenaar 	bar = puc_get_bar(sc, -1);
10064220a7eSMarcel Moolenaar 	if (bar == NULL)
10164220a7eSMarcel Moolenaar 		return (NULL);
10264220a7eSMarcel Moolenaar 	bar->b_rid = rid;
10364220a7eSMarcel Moolenaar 	bar->b_type = SYS_RES_IOPORT;
10464220a7eSMarcel Moolenaar 	bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
10564220a7eSMarcel Moolenaar 	    &bar->b_rid, RF_ACTIVE);
10664220a7eSMarcel Moolenaar 	if (bar->b_res == NULL) {
10764220a7eSMarcel Moolenaar 		bar->b_rid = rid;
10864220a7eSMarcel Moolenaar 		bar->b_type = SYS_RES_MEMORY;
10964220a7eSMarcel Moolenaar 		bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
11064220a7eSMarcel Moolenaar 		    &bar->b_rid, RF_ACTIVE);
11164220a7eSMarcel Moolenaar 		if (bar->b_res == NULL) {
11264220a7eSMarcel Moolenaar 			bar->b_rid = -1;
11364220a7eSMarcel Moolenaar 			return (NULL);
1145aa967d9SYoshihiro Takahashi 		}
1155aa967d9SYoshihiro Takahashi 	}
11664220a7eSMarcel Moolenaar 
11764220a7eSMarcel Moolenaar 	/* Update our managed space. */
11864220a7eSMarcel Moolenaar 	rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem;
11964220a7eSMarcel Moolenaar 	start = rman_get_start(bar->b_res);
12064220a7eSMarcel Moolenaar 	end = rman_get_end(bar->b_res);
12164220a7eSMarcel Moolenaar 	error = rman_manage_region(rm, start, end);
12264220a7eSMarcel Moolenaar 	if (error) {
12364220a7eSMarcel Moolenaar 		bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid,
12464220a7eSMarcel Moolenaar 		    bar->b_res);
12564220a7eSMarcel Moolenaar 		bar->b_res = NULL;
12664220a7eSMarcel Moolenaar 		bar->b_rid = -1;
12764220a7eSMarcel Moolenaar 		bar = NULL;
1289c564b6cSJohn Hay 	}
1299c564b6cSJohn Hay 
13064220a7eSMarcel Moolenaar 	return (bar);
1319c564b6cSJohn Hay }
1329c564b6cSJohn Hay 
133ef544f63SPaolo Pisati static int
1349c564b6cSJohn Hay puc_intr(void *arg)
1359c564b6cSJohn Hay {
13664220a7eSMarcel Moolenaar 	struct puc_port *port;
13764220a7eSMarcel Moolenaar 	struct puc_softc *sc = arg;
13857467e59SMarcel Moolenaar 	u_long ds, dev, devs;
13957467e59SMarcel Moolenaar 	int i, idx, ipend, isrc, nints;
14064220a7eSMarcel Moolenaar 	uint8_t ilr;
14164220a7eSMarcel Moolenaar 
14257467e59SMarcel Moolenaar 	nints = 0;
14357467e59SMarcel Moolenaar 	while (1) {
14457467e59SMarcel Moolenaar 		/*
14557467e59SMarcel Moolenaar 		 * Obtain the set of devices with pending interrupts.
14657467e59SMarcel Moolenaar 		 */
14764220a7eSMarcel Moolenaar 		devs = sc->sc_serdevs;
14864220a7eSMarcel Moolenaar 		if (sc->sc_ilr == PUC_ILR_DIGI) {
14964220a7eSMarcel Moolenaar 			idx = 0;
15064220a7eSMarcel Moolenaar 			while (devs & (0xfful << idx)) {
15164220a7eSMarcel Moolenaar 				ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
15264220a7eSMarcel Moolenaar 				devs &= ~0ul ^ ((u_long)ilr << idx);
15364220a7eSMarcel Moolenaar 				idx += 8;
15464220a7eSMarcel Moolenaar 			}
15564220a7eSMarcel Moolenaar 		} else if (sc->sc_ilr == PUC_ILR_QUATECH) {
15664220a7eSMarcel Moolenaar 			/*
15764220a7eSMarcel Moolenaar 			 * Don't trust the value if it's the same as the option
15864220a7eSMarcel Moolenaar 			 * register. It may mean that the ILR is not active and
15964220a7eSMarcel Moolenaar 			 * we're reading the option register instead. This may
16064220a7eSMarcel Moolenaar 			 * lead to false positives on 8-port boards.
16164220a7eSMarcel Moolenaar 			 */
16264220a7eSMarcel Moolenaar 			ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
16364220a7eSMarcel Moolenaar 			if (ilr != (sc->sc_cfg_data & 0xff))
16464220a7eSMarcel Moolenaar 				devs &= (u_long)ilr;
16564220a7eSMarcel Moolenaar 		}
16657467e59SMarcel Moolenaar 		if (devs == 0UL)
16757467e59SMarcel Moolenaar 			break;
16864220a7eSMarcel Moolenaar 
16957467e59SMarcel Moolenaar 		/*
17057467e59SMarcel Moolenaar 		 * Obtain the set of interrupt sources from those devices
17157467e59SMarcel Moolenaar 		 * that have pending interrupts.
17257467e59SMarcel Moolenaar 		 */
17364220a7eSMarcel Moolenaar 		ipend = 0;
17464220a7eSMarcel Moolenaar 		idx = 0, dev = 1UL;
17557467e59SMarcel Moolenaar 		ds = devs;
17657467e59SMarcel Moolenaar 		while (ds != 0UL) {
17757467e59SMarcel Moolenaar 			while ((ds & dev) == 0UL)
17864220a7eSMarcel Moolenaar 				idx++, dev <<= 1;
17957467e59SMarcel Moolenaar 			ds &= ~dev;
18064220a7eSMarcel Moolenaar 			port = &sc->sc_port[idx];
18164220a7eSMarcel Moolenaar 			port->p_ipend = SERDEV_IPEND(port->p_dev);
18264220a7eSMarcel Moolenaar 			ipend |= port->p_ipend;
18364220a7eSMarcel Moolenaar 		}
18457467e59SMarcel Moolenaar 		if (ipend == 0)
18557467e59SMarcel Moolenaar 			break;
18664220a7eSMarcel Moolenaar 
18764220a7eSMarcel Moolenaar 		i = 0, isrc = SER_INT_OVERRUN;
18864220a7eSMarcel Moolenaar 		while (ipend) {
18964220a7eSMarcel Moolenaar 			while (i < PUC_ISRCCNT && !(ipend & isrc))
19064220a7eSMarcel Moolenaar 				i++, isrc <<= 1;
19164220a7eSMarcel Moolenaar 			KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
19264220a7eSMarcel Moolenaar 			ipend &= ~isrc;
19364220a7eSMarcel Moolenaar 			idx = 0, dev = 1UL;
19457467e59SMarcel Moolenaar 			ds = devs;
19557467e59SMarcel Moolenaar 			while (ds != 0UL) {
19657467e59SMarcel Moolenaar 				while ((ds & dev) == 0UL)
19764220a7eSMarcel Moolenaar 					idx++, dev <<= 1;
19857467e59SMarcel Moolenaar 				ds &= ~dev;
19964220a7eSMarcel Moolenaar 				port = &sc->sc_port[idx];
20064220a7eSMarcel Moolenaar 				if (!(port->p_ipend & isrc))
20164220a7eSMarcel Moolenaar 					continue;
20264220a7eSMarcel Moolenaar 				if (port->p_ihsrc[i] != NULL)
20364220a7eSMarcel Moolenaar 					(*port->p_ihsrc[i])(port->p_iharg);
20457467e59SMarcel Moolenaar 				nints++;
20564220a7eSMarcel Moolenaar 			}
20664220a7eSMarcel Moolenaar 		}
20757467e59SMarcel Moolenaar 	}
20857467e59SMarcel Moolenaar 
20957467e59SMarcel Moolenaar 	return ((nints > 0) ? FILTER_HANDLED : FILTER_STRAY);
21064220a7eSMarcel Moolenaar }
21164220a7eSMarcel Moolenaar 
21264220a7eSMarcel Moolenaar int
21364220a7eSMarcel Moolenaar puc_bfe_attach(device_t dev)
21464220a7eSMarcel Moolenaar {
21564220a7eSMarcel Moolenaar 	char buffer[64];
21664220a7eSMarcel Moolenaar 	struct puc_bar *bar;
21764220a7eSMarcel Moolenaar 	struct puc_port *port;
2189c564b6cSJohn Hay 	struct puc_softc *sc;
21964220a7eSMarcel Moolenaar 	struct rman *rm;
22064220a7eSMarcel Moolenaar 	intptr_t res;
22164220a7eSMarcel Moolenaar 	bus_addr_t ofs, start;
22264220a7eSMarcel Moolenaar 	bus_size_t size;
22364220a7eSMarcel Moolenaar 	bus_space_handle_t bsh;
22464220a7eSMarcel Moolenaar 	bus_space_tag_t bst;
22564220a7eSMarcel Moolenaar 	int error, idx;
2269c564b6cSJohn Hay 
22764220a7eSMarcel Moolenaar 	sc = device_get_softc(dev);
22864220a7eSMarcel Moolenaar 
22964220a7eSMarcel Moolenaar 	for (idx = 0; idx < PUC_PCI_BARS; idx++)
23064220a7eSMarcel Moolenaar 		sc->sc_bar[idx].b_rid = -1;
23164220a7eSMarcel Moolenaar 
23264220a7eSMarcel Moolenaar 	do {
23364220a7eSMarcel Moolenaar 		sc->sc_ioport.rm_type = RMAN_ARRAY;
23464220a7eSMarcel Moolenaar 		error = rman_init(&sc->sc_ioport);
23564220a7eSMarcel Moolenaar 		if (!error) {
23664220a7eSMarcel Moolenaar 			sc->sc_iomem.rm_type = RMAN_ARRAY;
23764220a7eSMarcel Moolenaar 			error = rman_init(&sc->sc_iomem);
23864220a7eSMarcel Moolenaar 			if (!error) {
23964220a7eSMarcel Moolenaar 				sc->sc_irq.rm_type = RMAN_ARRAY;
24064220a7eSMarcel Moolenaar 				error = rman_init(&sc->sc_irq);
24164220a7eSMarcel Moolenaar 				if (!error)
24264220a7eSMarcel Moolenaar 					break;
24364220a7eSMarcel Moolenaar 				rman_fini(&sc->sc_iomem);
24464220a7eSMarcel Moolenaar 			}
24564220a7eSMarcel Moolenaar 			rman_fini(&sc->sc_ioport);
24664220a7eSMarcel Moolenaar 		}
24764220a7eSMarcel Moolenaar 		return (error);
24864220a7eSMarcel Moolenaar 	} while (0);
24964220a7eSMarcel Moolenaar 
25064220a7eSMarcel Moolenaar 	snprintf(buffer, sizeof(buffer), "%s I/O port mapping",
25164220a7eSMarcel Moolenaar 	    device_get_nameunit(dev));
25264220a7eSMarcel Moolenaar 	sc->sc_ioport.rm_descr = strdup(buffer, M_PUC);
25364220a7eSMarcel Moolenaar 	snprintf(buffer, sizeof(buffer), "%s I/O memory mapping",
25464220a7eSMarcel Moolenaar 	    device_get_nameunit(dev));
25564220a7eSMarcel Moolenaar 	sc->sc_iomem.rm_descr = strdup(buffer, M_PUC);
25664220a7eSMarcel Moolenaar 	snprintf(buffer, sizeof(buffer), "%s port numbers",
25764220a7eSMarcel Moolenaar 	    device_get_nameunit(dev));
25864220a7eSMarcel Moolenaar 	sc->sc_irq.rm_descr = strdup(buffer, M_PUC);
25964220a7eSMarcel Moolenaar 
26064220a7eSMarcel Moolenaar 	error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
26164220a7eSMarcel Moolenaar 	KASSERT(error == 0, ("%s %d", __func__, __LINE__));
26264220a7eSMarcel Moolenaar 	sc->sc_nports = (int)res;
26364220a7eSMarcel Moolenaar 	sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port),
26464220a7eSMarcel Moolenaar 	    M_PUC, M_WAITOK|M_ZERO);
26564220a7eSMarcel Moolenaar 
26664220a7eSMarcel Moolenaar 	error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports);
26764220a7eSMarcel Moolenaar 	if (error)
26864220a7eSMarcel Moolenaar 		goto fail;
26964220a7eSMarcel Moolenaar 
27064220a7eSMarcel Moolenaar 	error = puc_config(sc, PUC_CFG_SETUP, 0, &res);
27164220a7eSMarcel Moolenaar 	if (error)
27264220a7eSMarcel Moolenaar 		goto fail;
27364220a7eSMarcel Moolenaar 
27464220a7eSMarcel Moolenaar 	for (idx = 0; idx < sc->sc_nports; idx++) {
27564220a7eSMarcel Moolenaar 		port = &sc->sc_port[idx];
27664220a7eSMarcel Moolenaar 		port->p_nr = idx + 1;
27764220a7eSMarcel Moolenaar 		error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res);
27864220a7eSMarcel Moolenaar 		if (error)
27964220a7eSMarcel Moolenaar 			goto fail;
28064220a7eSMarcel Moolenaar 		port->p_type = res;
28164220a7eSMarcel Moolenaar 		error = puc_config(sc, PUC_CFG_GET_RID, idx, &res);
28264220a7eSMarcel Moolenaar 		if (error)
28364220a7eSMarcel Moolenaar 			goto fail;
28464220a7eSMarcel Moolenaar 		bar = puc_get_bar(sc, res);
28564220a7eSMarcel Moolenaar 		if (bar == NULL) {
28664220a7eSMarcel Moolenaar 			error = ENXIO;
28764220a7eSMarcel Moolenaar 			goto fail;
28864220a7eSMarcel Moolenaar 		}
28964220a7eSMarcel Moolenaar 		port->p_bar = bar;
29064220a7eSMarcel Moolenaar 		start = rman_get_start(bar->b_res);
29164220a7eSMarcel Moolenaar 		error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res);
29264220a7eSMarcel Moolenaar 		if (error)
29364220a7eSMarcel Moolenaar 			goto fail;
29464220a7eSMarcel Moolenaar 		ofs = res;
29564220a7eSMarcel Moolenaar 		error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res);
29664220a7eSMarcel Moolenaar 		if (error)
29764220a7eSMarcel Moolenaar 			goto fail;
29864220a7eSMarcel Moolenaar 		size = res;
29964220a7eSMarcel Moolenaar 		rm = (bar->b_type == SYS_RES_IOPORT)
30064220a7eSMarcel Moolenaar 		    ? &sc->sc_ioport: &sc->sc_iomem;
30164220a7eSMarcel Moolenaar 		port->p_rres = rman_reserve_resource(rm, start + ofs,
30264220a7eSMarcel Moolenaar 		    start + ofs + size - 1, size, 0, NULL);
30364220a7eSMarcel Moolenaar 		if (port->p_rres != NULL) {
30464220a7eSMarcel Moolenaar 			bsh = rman_get_bushandle(bar->b_res);
30564220a7eSMarcel Moolenaar 			bst = rman_get_bustag(bar->b_res);
30664220a7eSMarcel Moolenaar 			bus_space_subregion(bst, bsh, ofs, size, &bsh);
30764220a7eSMarcel Moolenaar 			rman_set_bushandle(port->p_rres, bsh);
30864220a7eSMarcel Moolenaar 			rman_set_bustag(port->p_rres, bst);
30964220a7eSMarcel Moolenaar 		}
31064220a7eSMarcel Moolenaar 		port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr,
31164220a7eSMarcel Moolenaar 		    port->p_nr, 1, 0, NULL);
31264220a7eSMarcel Moolenaar 		if (port->p_ires == NULL) {
31364220a7eSMarcel Moolenaar 			error = ENXIO;
31464220a7eSMarcel Moolenaar 			goto fail;
31564220a7eSMarcel Moolenaar 		}
31664220a7eSMarcel Moolenaar 		error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res);
31764220a7eSMarcel Moolenaar 		if (error)
31864220a7eSMarcel Moolenaar 			goto fail;
31964220a7eSMarcel Moolenaar 		port->p_rclk = res;
32064220a7eSMarcel Moolenaar 
32164220a7eSMarcel Moolenaar 		port->p_dev = device_add_child(dev, NULL, -1);
32264220a7eSMarcel Moolenaar 		if (port->p_dev != NULL)
32364220a7eSMarcel Moolenaar 			device_set_ivars(port->p_dev, (void *)port);
3249c564b6cSJohn Hay 	}
3259c564b6cSJohn Hay 
32664220a7eSMarcel Moolenaar 	error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res);
32764220a7eSMarcel Moolenaar 	if (error)
32864220a7eSMarcel Moolenaar 		goto fail;
32964220a7eSMarcel Moolenaar 	sc->sc_ilr = res;
33064220a7eSMarcel Moolenaar 	if (bootverbose && sc->sc_ilr != 0)
33164220a7eSMarcel Moolenaar 		device_printf(dev, "using interrupt latch register\n");
3329c564b6cSJohn Hay 
33364220a7eSMarcel Moolenaar 	sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
33464220a7eSMarcel Moolenaar 	    RF_ACTIVE|RF_SHAREABLE);
33564220a7eSMarcel Moolenaar 	if (sc->sc_ires != NULL) {
33664220a7eSMarcel Moolenaar 		error = bus_setup_intr(dev, sc->sc_ires,
337ef544f63SPaolo Pisati 		    INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie);
33864220a7eSMarcel Moolenaar 		if (error)
33964220a7eSMarcel Moolenaar 			error = bus_setup_intr(dev, sc->sc_ires,
340ef544f63SPaolo Pisati 			    INTR_TYPE_TTY | INTR_MPSAFE, NULL,
341ef544f63SPaolo Pisati 			    (driver_intr_t *)puc_intr, sc, &sc->sc_icookie);
34264220a7eSMarcel Moolenaar 		else
34364220a7eSMarcel Moolenaar 			sc->sc_fastintr = 1;
34464220a7eSMarcel Moolenaar 
34564220a7eSMarcel Moolenaar 		if (error) {
34664220a7eSMarcel Moolenaar 			device_printf(dev, "could not activate interrupt\n");
34764220a7eSMarcel Moolenaar 			bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
34864220a7eSMarcel Moolenaar 			    sc->sc_ires);
34964220a7eSMarcel Moolenaar 			sc->sc_ires = NULL;
35064220a7eSMarcel Moolenaar 		}
35164220a7eSMarcel Moolenaar 	}
35264220a7eSMarcel Moolenaar 	if (sc->sc_ires == NULL) {
35364220a7eSMarcel Moolenaar 		/* XXX no interrupt resource. Force polled mode. */
35464220a7eSMarcel Moolenaar 		sc->sc_polled = 1;
3559c564b6cSJohn Hay 	}
3569c564b6cSJohn Hay 
35764220a7eSMarcel Moolenaar 	/* Probe and attach our children. */
35864220a7eSMarcel Moolenaar 	for (idx = 0; idx < sc->sc_nports; idx++) {
35964220a7eSMarcel Moolenaar 		port = &sc->sc_port[idx];
36064220a7eSMarcel Moolenaar 		if (port->p_dev == NULL)
36164220a7eSMarcel Moolenaar 			continue;
36264220a7eSMarcel Moolenaar 		error = device_probe_and_attach(port->p_dev);
36364220a7eSMarcel Moolenaar 		if (error) {
36464220a7eSMarcel Moolenaar 			device_delete_child(dev, port->p_dev);
36564220a7eSMarcel Moolenaar 			port->p_dev = NULL;
3669c564b6cSJohn Hay 		}
36764220a7eSMarcel Moolenaar 	}
3689c564b6cSJohn Hay 
369a3732274SDoug Ambrisko 	/*
37064220a7eSMarcel Moolenaar 	 * If there are no serdev devices, then our interrupt handler
37164220a7eSMarcel Moolenaar 	 * will do nothing. Tear it down.
372a3732274SDoug Ambrisko 	 */
37364220a7eSMarcel Moolenaar 	if (sc->sc_serdevs == 0UL)
37464220a7eSMarcel Moolenaar 		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
375a3732274SDoug Ambrisko 
37664220a7eSMarcel Moolenaar 	return (0);
3779c564b6cSJohn Hay 
37864220a7eSMarcel Moolenaar fail:
37964220a7eSMarcel Moolenaar 	for (idx = 0; idx < sc->sc_nports; idx++) {
38064220a7eSMarcel Moolenaar 		port = &sc->sc_port[idx];
38164220a7eSMarcel Moolenaar 		if (port->p_dev != NULL)
38264220a7eSMarcel Moolenaar 			device_delete_child(dev, port->p_dev);
38364220a7eSMarcel Moolenaar 		if (port->p_rres != NULL)
38464220a7eSMarcel Moolenaar 			rman_release_resource(port->p_rres);
38564220a7eSMarcel Moolenaar 		if (port->p_ires != NULL)
38664220a7eSMarcel Moolenaar 			rman_release_resource(port->p_ires);
387a3732274SDoug Ambrisko 	}
38864220a7eSMarcel Moolenaar 	for (idx = 0; idx < PUC_PCI_BARS; idx++) {
38964220a7eSMarcel Moolenaar 		bar = &sc->sc_bar[idx];
39064220a7eSMarcel Moolenaar 		if (bar->b_res != NULL)
39164220a7eSMarcel Moolenaar 			bus_release_resource(sc->sc_dev, bar->b_type,
39264220a7eSMarcel Moolenaar 			    bar->b_rid, bar->b_res);
39364220a7eSMarcel Moolenaar 	}
39464220a7eSMarcel Moolenaar 	rman_fini(&sc->sc_irq);
39564220a7eSMarcel Moolenaar 	free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
39664220a7eSMarcel Moolenaar 	rman_fini(&sc->sc_iomem);
39764220a7eSMarcel Moolenaar 	free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
39864220a7eSMarcel Moolenaar 	rman_fini(&sc->sc_ioport);
39964220a7eSMarcel Moolenaar 	free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
40064220a7eSMarcel Moolenaar 	free(sc->sc_port, M_PUC);
40164220a7eSMarcel Moolenaar 	return (error);
4029c564b6cSJohn Hay }
4039c564b6cSJohn Hay 
40432f606d1SPoul-Henning Kamp int
40564220a7eSMarcel Moolenaar puc_bfe_detach(device_t dev)
40664220a7eSMarcel Moolenaar {
40764220a7eSMarcel Moolenaar 	struct puc_bar *bar;
40864220a7eSMarcel Moolenaar 	struct puc_port *port;
40964220a7eSMarcel Moolenaar 	struct puc_softc *sc;
41064220a7eSMarcel Moolenaar 	int error, idx;
41164220a7eSMarcel Moolenaar 
41264220a7eSMarcel Moolenaar 	sc = device_get_softc(dev);
41364220a7eSMarcel Moolenaar 
41464220a7eSMarcel Moolenaar 	/* Detach our children. */
41564220a7eSMarcel Moolenaar 	error = 0;
41664220a7eSMarcel Moolenaar 	for (idx = 0; idx < sc->sc_nports; idx++) {
41764220a7eSMarcel Moolenaar 		port = &sc->sc_port[idx];
41864220a7eSMarcel Moolenaar 		if (port->p_dev == NULL)
41964220a7eSMarcel Moolenaar 			continue;
420d3bf5efcSHans Petter Selasky 		if (device_delete_child(dev, port->p_dev) == 0) {
42164220a7eSMarcel Moolenaar 			if (port->p_rres != NULL)
42264220a7eSMarcel Moolenaar 				rman_release_resource(port->p_rres);
42364220a7eSMarcel Moolenaar 			if (port->p_ires != NULL)
42464220a7eSMarcel Moolenaar 				rman_release_resource(port->p_ires);
42564220a7eSMarcel Moolenaar 		} else
42664220a7eSMarcel Moolenaar 			error = ENXIO;
42764220a7eSMarcel Moolenaar 	}
42864220a7eSMarcel Moolenaar 	if (error)
42964220a7eSMarcel Moolenaar 		return (error);
43064220a7eSMarcel Moolenaar 
43164220a7eSMarcel Moolenaar 	if (sc->sc_serdevs != 0UL)
43264220a7eSMarcel Moolenaar 		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
43364220a7eSMarcel Moolenaar 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
43464220a7eSMarcel Moolenaar 
43564220a7eSMarcel Moolenaar 	for (idx = 0; idx < PUC_PCI_BARS; idx++) {
43664220a7eSMarcel Moolenaar 		bar = &sc->sc_bar[idx];
43764220a7eSMarcel Moolenaar 		if (bar->b_res != NULL)
43864220a7eSMarcel Moolenaar 			bus_release_resource(sc->sc_dev, bar->b_type,
43964220a7eSMarcel Moolenaar 			    bar->b_rid, bar->b_res);
44064220a7eSMarcel Moolenaar 	}
44164220a7eSMarcel Moolenaar 
44264220a7eSMarcel Moolenaar 	rman_fini(&sc->sc_irq);
44364220a7eSMarcel Moolenaar 	free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
44464220a7eSMarcel Moolenaar 	rman_fini(&sc->sc_iomem);
44564220a7eSMarcel Moolenaar 	free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
44664220a7eSMarcel Moolenaar 	rman_fini(&sc->sc_ioport);
44764220a7eSMarcel Moolenaar 	free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
44864220a7eSMarcel Moolenaar 	free(sc->sc_port, M_PUC);
44964220a7eSMarcel Moolenaar 	return (0);
45064220a7eSMarcel Moolenaar }
45164220a7eSMarcel Moolenaar 
45264220a7eSMarcel Moolenaar int
45364220a7eSMarcel Moolenaar puc_bfe_probe(device_t dev, const struct puc_cfg *cfg)
45464220a7eSMarcel Moolenaar {
45564220a7eSMarcel Moolenaar 	struct puc_softc *sc;
45664220a7eSMarcel Moolenaar 	intptr_t res;
45764220a7eSMarcel Moolenaar 	int error;
45864220a7eSMarcel Moolenaar 
45964220a7eSMarcel Moolenaar 	sc = device_get_softc(dev);
46064220a7eSMarcel Moolenaar 	sc->sc_dev = dev;
46164220a7eSMarcel Moolenaar 	sc->sc_cfg = cfg;
46264220a7eSMarcel Moolenaar 
46364220a7eSMarcel Moolenaar 	/* We don't attach to single-port serial cards. */
46464220a7eSMarcel Moolenaar 	if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P)
46564220a7eSMarcel Moolenaar 		return (EDOOFUS);
46664220a7eSMarcel Moolenaar 	error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
46764220a7eSMarcel Moolenaar 	if (error)
46864220a7eSMarcel Moolenaar 		return (error);
46964220a7eSMarcel Moolenaar 	error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res);
47064220a7eSMarcel Moolenaar 	if (error)
47164220a7eSMarcel Moolenaar 		return (error);
47264220a7eSMarcel Moolenaar 	if (res != 0)
47364220a7eSMarcel Moolenaar 		device_set_desc(dev, (const char *)res);
47464220a7eSMarcel Moolenaar 	return (BUS_PROBE_DEFAULT);
47564220a7eSMarcel Moolenaar }
47664220a7eSMarcel Moolenaar 
47764220a7eSMarcel Moolenaar struct resource *
47864220a7eSMarcel Moolenaar puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
4792dd1bdf1SJustin Hibbits     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
48064220a7eSMarcel Moolenaar {
48164220a7eSMarcel Moolenaar 	struct puc_port *port;
48264220a7eSMarcel Moolenaar 	struct resource *res;
48364220a7eSMarcel Moolenaar 	device_t assigned, originator;
48464220a7eSMarcel Moolenaar 	int error;
48564220a7eSMarcel Moolenaar 
48664220a7eSMarcel Moolenaar 	/* Get our immediate child. */
48764220a7eSMarcel Moolenaar 	originator = child;
48864220a7eSMarcel Moolenaar 	while (child != NULL && device_get_parent(child) != dev)
48964220a7eSMarcel Moolenaar 		child = device_get_parent(child);
49064220a7eSMarcel Moolenaar 	if (child == NULL)
49164220a7eSMarcel Moolenaar 		return (NULL);
49264220a7eSMarcel Moolenaar 
49364220a7eSMarcel Moolenaar 	port = device_get_ivars(child);
49464220a7eSMarcel Moolenaar 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
49564220a7eSMarcel Moolenaar 
49664220a7eSMarcel Moolenaar 	if (rid == NULL || *rid != 0)
49764220a7eSMarcel Moolenaar 		return (NULL);
49864220a7eSMarcel Moolenaar 
49964220a7eSMarcel Moolenaar 	/* We only support default allocations. */
50082ed3cb0SJustin Hibbits 	if (!RMAN_IS_DEFAULT_RANGE(start, end))
50164220a7eSMarcel Moolenaar 		return (NULL);
50264220a7eSMarcel Moolenaar 
50364220a7eSMarcel Moolenaar 	if (type == port->p_bar->b_type)
50464220a7eSMarcel Moolenaar 		res = port->p_rres;
50564220a7eSMarcel Moolenaar 	else if (type == SYS_RES_IRQ)
50664220a7eSMarcel Moolenaar 		res = port->p_ires;
50764220a7eSMarcel Moolenaar 	else
50864220a7eSMarcel Moolenaar 		return (NULL);
50964220a7eSMarcel Moolenaar 
51064220a7eSMarcel Moolenaar 	if (res == NULL)
51164220a7eSMarcel Moolenaar 		return (NULL);
51264220a7eSMarcel Moolenaar 
51364220a7eSMarcel Moolenaar 	assigned = rman_get_device(res);
51464220a7eSMarcel Moolenaar 	if (assigned == NULL)	/* Not allocated */
51564220a7eSMarcel Moolenaar 		rman_set_device(res, originator);
51664220a7eSMarcel Moolenaar 	else if (assigned != originator)
51764220a7eSMarcel Moolenaar 		return (NULL);
51864220a7eSMarcel Moolenaar 
51964220a7eSMarcel Moolenaar 	if (flags & RF_ACTIVE) {
52064220a7eSMarcel Moolenaar 		error = rman_activate_resource(res);
52164220a7eSMarcel Moolenaar 		if (error) {
52264220a7eSMarcel Moolenaar 			if (assigned == NULL)
52364220a7eSMarcel Moolenaar 				rman_set_device(res, NULL);
52464220a7eSMarcel Moolenaar 			return (NULL);
52564220a7eSMarcel Moolenaar 		}
52664220a7eSMarcel Moolenaar 	}
52764220a7eSMarcel Moolenaar 
52864220a7eSMarcel Moolenaar 	return (res);
52964220a7eSMarcel Moolenaar }
53064220a7eSMarcel Moolenaar 
53164220a7eSMarcel Moolenaar int
53264220a7eSMarcel Moolenaar puc_bus_release_resource(device_t dev, device_t child, int type, int rid,
5339c564b6cSJohn Hay     struct resource *res)
5349c564b6cSJohn Hay {
53564220a7eSMarcel Moolenaar 	struct puc_port *port;
53664220a7eSMarcel Moolenaar 	device_t originator;
53764220a7eSMarcel Moolenaar 
53864220a7eSMarcel Moolenaar 	/* Get our immediate child. */
53964220a7eSMarcel Moolenaar 	originator = child;
54064220a7eSMarcel Moolenaar 	while (child != NULL && device_get_parent(child) != dev)
54164220a7eSMarcel Moolenaar 		child = device_get_parent(child);
54264220a7eSMarcel Moolenaar 	if (child == NULL)
54364220a7eSMarcel Moolenaar 		return (EINVAL);
54464220a7eSMarcel Moolenaar 
54564220a7eSMarcel Moolenaar 	port = device_get_ivars(child);
54664220a7eSMarcel Moolenaar 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
54764220a7eSMarcel Moolenaar 
54864220a7eSMarcel Moolenaar 	if (rid != 0 || res == NULL)
54964220a7eSMarcel Moolenaar 		return (EINVAL);
55064220a7eSMarcel Moolenaar 
55164220a7eSMarcel Moolenaar 	if (type == port->p_bar->b_type) {
55264220a7eSMarcel Moolenaar 		if (res != port->p_rres)
55364220a7eSMarcel Moolenaar 			return (EINVAL);
55464220a7eSMarcel Moolenaar 	} else if (type == SYS_RES_IRQ) {
55564220a7eSMarcel Moolenaar 		if (res != port->p_ires)
55664220a7eSMarcel Moolenaar 			return (EINVAL);
55764220a7eSMarcel Moolenaar 		if (port->p_hasintr)
55864220a7eSMarcel Moolenaar 			return (EBUSY);
55964220a7eSMarcel Moolenaar 	} else
56064220a7eSMarcel Moolenaar 		return (EINVAL);
56164220a7eSMarcel Moolenaar 
56264220a7eSMarcel Moolenaar 	if (rman_get_device(res) != originator)
56364220a7eSMarcel Moolenaar 		return (ENXIO);
56464220a7eSMarcel Moolenaar 	if (rman_get_flags(res) & RF_ACTIVE)
56564220a7eSMarcel Moolenaar 		rman_deactivate_resource(res);
56664220a7eSMarcel Moolenaar 	rman_set_device(res, NULL);
5679c564b6cSJohn Hay 	return (0);
5689c564b6cSJohn Hay }
5699c564b6cSJohn Hay 
57032f606d1SPoul-Henning Kamp int
57164220a7eSMarcel Moolenaar puc_bus_get_resource(device_t dev, device_t child, int type, int rid,
5722dd1bdf1SJustin Hibbits     rman_res_t *startp, rman_res_t *countp)
5739c564b6cSJohn Hay {
57464220a7eSMarcel Moolenaar 	struct puc_port *port;
57564220a7eSMarcel Moolenaar 	struct resource *res;
5762dd1bdf1SJustin Hibbits 	rman_res_t start;
5779c564b6cSJohn Hay 
57864220a7eSMarcel Moolenaar 	/* Get our immediate child. */
57964220a7eSMarcel Moolenaar 	while (child != NULL && device_get_parent(child) != dev)
58064220a7eSMarcel Moolenaar 		child = device_get_parent(child);
58164220a7eSMarcel Moolenaar 	if (child == NULL)
58264220a7eSMarcel Moolenaar 		return (EINVAL);
5839c564b6cSJohn Hay 
58464220a7eSMarcel Moolenaar 	port = device_get_ivars(child);
58564220a7eSMarcel Moolenaar 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
58664220a7eSMarcel Moolenaar 
58764220a7eSMarcel Moolenaar 	if (type == port->p_bar->b_type)
58864220a7eSMarcel Moolenaar 		res = port->p_rres;
58964220a7eSMarcel Moolenaar 	else if (type == SYS_RES_IRQ)
59064220a7eSMarcel Moolenaar 		res = port->p_ires;
59164220a7eSMarcel Moolenaar 	else
59264220a7eSMarcel Moolenaar 		return (ENXIO);
59364220a7eSMarcel Moolenaar 
59464220a7eSMarcel Moolenaar 	if (rid != 0 || res == NULL)
59564220a7eSMarcel Moolenaar 		return (ENXIO);
59664220a7eSMarcel Moolenaar 
59764220a7eSMarcel Moolenaar 	start = rman_get_start(res);
5989c564b6cSJohn Hay 	if (startp != NULL)
59964220a7eSMarcel Moolenaar 		*startp = start;
6009c564b6cSJohn Hay 	if (countp != NULL)
60164220a7eSMarcel Moolenaar 		*countp = rman_get_end(res) - start + 1;
6029c564b6cSJohn Hay 	return (0);
6039c564b6cSJohn Hay }
6049c564b6cSJohn Hay 
60532f606d1SPoul-Henning Kamp int
60664220a7eSMarcel Moolenaar puc_bus_setup_intr(device_t dev, device_t child, struct resource *res,
607ef544f63SPaolo Pisati     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
6089c564b6cSJohn Hay {
60964220a7eSMarcel Moolenaar 	struct puc_port *port;
6109c564b6cSJohn Hay 	struct puc_softc *sc;
61164220a7eSMarcel Moolenaar 	device_t originator;
61264220a7eSMarcel Moolenaar 	int i, isrc, serdev;
6139c564b6cSJohn Hay 
61464220a7eSMarcel Moolenaar 	sc = device_get_softc(dev);
61564220a7eSMarcel Moolenaar 
61664220a7eSMarcel Moolenaar 	/* Get our immediate child. */
61764220a7eSMarcel Moolenaar 	originator = child;
61864220a7eSMarcel Moolenaar 	while (child != NULL && device_get_parent(child) != dev)
61964220a7eSMarcel Moolenaar 		child = device_get_parent(child);
62064220a7eSMarcel Moolenaar 	if (child == NULL)
62164220a7eSMarcel Moolenaar 		return (EINVAL);
62264220a7eSMarcel Moolenaar 
62364220a7eSMarcel Moolenaar 	port = device_get_ivars(child);
62464220a7eSMarcel Moolenaar 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
62564220a7eSMarcel Moolenaar 
6268d715a35SPaolo Pisati 	if (cookiep == NULL || res != port->p_ires)
62764220a7eSMarcel Moolenaar 		return (EINVAL);
6288d715a35SPaolo Pisati 	/* We demand that serdev devices use filter_only interrupts. */
629323e149aSJohn Baldwin 	if (port->p_type == PUC_TYPE_SERIAL && ihand != NULL)
6308d715a35SPaolo Pisati 		return (ENXIO);
63164220a7eSMarcel Moolenaar 	if (rman_get_device(port->p_ires) != originator)
632d3c10e33SPoul-Henning Kamp 		return (ENXIO);
63364220a7eSMarcel Moolenaar 
63464220a7eSMarcel Moolenaar 	/*
63564220a7eSMarcel Moolenaar 	 * Have non-serdev ports handled by the bus implementation. It
63664220a7eSMarcel Moolenaar 	 * supports multiple handlers for a single interrupt as it is,
63764220a7eSMarcel Moolenaar 	 * so we wouldn't add value if we did it ourselves.
63864220a7eSMarcel Moolenaar 	 */
63964220a7eSMarcel Moolenaar 	serdev = 0;
64064220a7eSMarcel Moolenaar 	if (port->p_type == PUC_TYPE_SERIAL) {
64164220a7eSMarcel Moolenaar 		i = 0, isrc = SER_INT_OVERRUN;
64264220a7eSMarcel Moolenaar 		while (i < PUC_ISRCCNT) {
64364220a7eSMarcel Moolenaar 			port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc);
64464220a7eSMarcel Moolenaar 			if (port->p_ihsrc[i] != NULL)
64564220a7eSMarcel Moolenaar 				serdev = 1;
64664220a7eSMarcel Moolenaar 			i++, isrc <<= 1;
64764220a7eSMarcel Moolenaar 		}
64864220a7eSMarcel Moolenaar 	}
64964220a7eSMarcel Moolenaar 	if (!serdev)
65064220a7eSMarcel Moolenaar 		return (BUS_SETUP_INTR(device_get_parent(dev), originator,
651ef544f63SPaolo Pisati 		    sc->sc_ires, flags, filt, ihand, arg, cookiep));
65264220a7eSMarcel Moolenaar 
65364220a7eSMarcel Moolenaar 	sc->sc_serdevs |= 1UL << (port->p_nr - 1);
65464220a7eSMarcel Moolenaar 
65564220a7eSMarcel Moolenaar 	port->p_hasintr = 1;
65664220a7eSMarcel Moolenaar 	port->p_iharg = arg;
65764220a7eSMarcel Moolenaar 
65864220a7eSMarcel Moolenaar 	*cookiep = port;
6599c564b6cSJohn Hay 	return (0);
6609c564b6cSJohn Hay }
6619c564b6cSJohn Hay 
66232f606d1SPoul-Henning Kamp int
66364220a7eSMarcel Moolenaar puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res,
6649c564b6cSJohn Hay     void *cookie)
6659c564b6cSJohn Hay {
66664220a7eSMarcel Moolenaar 	struct puc_port *port;
6679c564b6cSJohn Hay 	struct puc_softc *sc;
66864220a7eSMarcel Moolenaar 	device_t originator;
66964220a7eSMarcel Moolenaar 	int i;
6709c564b6cSJohn Hay 
67164220a7eSMarcel Moolenaar 	sc = device_get_softc(dev);
67264220a7eSMarcel Moolenaar 
67364220a7eSMarcel Moolenaar 	/* Get our immediate child. */
67464220a7eSMarcel Moolenaar 	originator = child;
67564220a7eSMarcel Moolenaar 	while (child != NULL && device_get_parent(child) != dev)
67664220a7eSMarcel Moolenaar 		child = device_get_parent(child);
67764220a7eSMarcel Moolenaar 	if (child == NULL)
67864220a7eSMarcel Moolenaar 		return (EINVAL);
67964220a7eSMarcel Moolenaar 
68064220a7eSMarcel Moolenaar 	port = device_get_ivars(child);
68164220a7eSMarcel Moolenaar 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
68264220a7eSMarcel Moolenaar 
68364220a7eSMarcel Moolenaar 	if (res != port->p_ires)
68464220a7eSMarcel Moolenaar 		return (EINVAL);
68564220a7eSMarcel Moolenaar 	if (rman_get_device(port->p_ires) != originator)
6869c564b6cSJohn Hay 		return (ENXIO);
68764220a7eSMarcel Moolenaar 
68864220a7eSMarcel Moolenaar 	if (!port->p_hasintr)
68964220a7eSMarcel Moolenaar 		return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator,
69064220a7eSMarcel Moolenaar 		    sc->sc_ires, cookie));
69164220a7eSMarcel Moolenaar 
69264220a7eSMarcel Moolenaar 	if (cookie != port)
69364220a7eSMarcel Moolenaar 		return (EINVAL);
69464220a7eSMarcel Moolenaar 
69564220a7eSMarcel Moolenaar 	port->p_hasintr = 0;
69664220a7eSMarcel Moolenaar 	port->p_iharg = NULL;
69764220a7eSMarcel Moolenaar 
69864220a7eSMarcel Moolenaar 	for (i = 0; i < PUC_ISRCCNT; i++)
69964220a7eSMarcel Moolenaar 		port->p_ihsrc[i] = NULL;
70064220a7eSMarcel Moolenaar 
70164220a7eSMarcel Moolenaar 	return (0);
7029c564b6cSJohn Hay }
7039c564b6cSJohn Hay 
70432f606d1SPoul-Henning Kamp int
70564220a7eSMarcel Moolenaar puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
7069c564b6cSJohn Hay {
70764220a7eSMarcel Moolenaar 	struct puc_port *port;
7089c564b6cSJohn Hay 
70964220a7eSMarcel Moolenaar 	/* Get our immediate child. */
71064220a7eSMarcel Moolenaar 	while (child != NULL && device_get_parent(child) != dev)
71164220a7eSMarcel Moolenaar 		child = device_get_parent(child);
71264220a7eSMarcel Moolenaar 	if (child == NULL)
71364220a7eSMarcel Moolenaar 		return (EINVAL);
71464220a7eSMarcel Moolenaar 
71564220a7eSMarcel Moolenaar 	port = device_get_ivars(child);
71664220a7eSMarcel Moolenaar 	KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
71764220a7eSMarcel Moolenaar 
71864220a7eSMarcel Moolenaar 	if (result == NULL)
71964220a7eSMarcel Moolenaar 		return (EINVAL);
7209c564b6cSJohn Hay 
7219c564b6cSJohn Hay 	switch(index) {
72264220a7eSMarcel Moolenaar 	case PUC_IVAR_CLOCK:
72364220a7eSMarcel Moolenaar 		*result = port->p_rclk;
7249c564b6cSJohn Hay 		break;
72564220a7eSMarcel Moolenaar 	case PUC_IVAR_TYPE:
72664220a7eSMarcel Moolenaar 		*result = port->p_type;
727153bbe3eSMarcel Moolenaar 		break;
7289c564b6cSJohn Hay 	default:
7299c564b6cSJohn Hay 		return (ENOENT);
7309c564b6cSJohn Hay 	}
7319c564b6cSJohn Hay 	return (0);
7329c564b6cSJohn Hay }
733573e64d4SJohn Baldwin 
734573e64d4SJohn Baldwin int
735573e64d4SJohn Baldwin puc_bus_print_child(device_t dev, device_t child)
736573e64d4SJohn Baldwin {
737573e64d4SJohn Baldwin 	struct puc_port *port;
738573e64d4SJohn Baldwin 	int retval;
739573e64d4SJohn Baldwin 
740573e64d4SJohn Baldwin 	port = device_get_ivars(child);
741573e64d4SJohn Baldwin 	retval = 0;
742573e64d4SJohn Baldwin 
743573e64d4SJohn Baldwin 	retval += bus_print_child_header(dev, child);
744573e64d4SJohn Baldwin 	retval += printf(" at port %d", port->p_nr);
745573e64d4SJohn Baldwin 	retval += bus_print_child_footer(dev, child);
746573e64d4SJohn Baldwin 
747573e64d4SJohn Baldwin 	return (retval);
748573e64d4SJohn Baldwin }
749573e64d4SJohn Baldwin 
750573e64d4SJohn Baldwin int
751ddfc9c4cSWarner Losh puc_bus_child_location(device_t dev, device_t child, struct sbuf *sb)
752573e64d4SJohn Baldwin {
753573e64d4SJohn Baldwin 	struct puc_port *port;
754573e64d4SJohn Baldwin 
755573e64d4SJohn Baldwin 	port = device_get_ivars(child);
756ddfc9c4cSWarner Losh 	sbuf_printf(sb, "port=%d", port->p_nr);
757573e64d4SJohn Baldwin 	return (0);
758573e64d4SJohn Baldwin }
759573e64d4SJohn Baldwin 
760573e64d4SJohn Baldwin int
761ddfc9c4cSWarner Losh puc_bus_child_pnpinfo(device_t dev, device_t child, struct sbuf *sb)
762573e64d4SJohn Baldwin {
763573e64d4SJohn Baldwin 	struct puc_port *port;
764573e64d4SJohn Baldwin 
765573e64d4SJohn Baldwin 	port = device_get_ivars(child);
766ddfc9c4cSWarner Losh 	sbuf_printf(sb, "type=%d", port->p_type);
767573e64d4SJohn Baldwin 	return (0);
768573e64d4SJohn Baldwin }
769