xref: /freebsd/sys/dev/puc/puc.c (revision 1e89655a31bab0c99f0223662795db6059d88fad)
19c564b6cSJohn Hay /*	$NetBSD: puc.c,v 1.7 2000/07/29 17:43:38 jlam Exp $	*/
29c564b6cSJohn Hay 
39c564b6cSJohn Hay /*-
49c564b6cSJohn Hay  * Copyright (c) 2002 JF Hay.  All rights reserved.
59c564b6cSJohn Hay  * Copyright (c) 2000 M. Warner Losh.  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:
109c564b6cSJohn Hay  * 1. Redistributions of source code must retain the above copyright
119c564b6cSJohn Hay  *    notice unmodified, this list of conditions, and the following
129c564b6cSJohn Hay  *    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 /*
309c564b6cSJohn Hay  * Copyright (c) 1996, 1998, 1999
319c564b6cSJohn Hay  *	Christopher G. Demetriou.  All rights reserved.
329c564b6cSJohn Hay  *
339c564b6cSJohn Hay  * Redistribution and use in source and binary forms, with or without
349c564b6cSJohn Hay  * modification, are permitted provided that the following conditions
359c564b6cSJohn Hay  * are met:
369c564b6cSJohn Hay  * 1. Redistributions of source code must retain the above copyright
379c564b6cSJohn Hay  *    notice, this list of conditions and the following disclaimer.
389c564b6cSJohn Hay  * 2. Redistributions in binary form must reproduce the above copyright
399c564b6cSJohn Hay  *    notice, this list of conditions and the following disclaimer in the
409c564b6cSJohn Hay  *    documentation and/or other materials provided with the distribution.
419c564b6cSJohn Hay  * 3. All advertising materials mentioning features or use of this software
429c564b6cSJohn Hay  *    must display the following acknowledgement:
439c564b6cSJohn Hay  *      This product includes software developed by Christopher G. Demetriou
449c564b6cSJohn Hay  *	for the NetBSD Project.
459c564b6cSJohn Hay  * 4. The name of the author may not be used to endorse or promote products
469c564b6cSJohn Hay  *    derived from this software without specific prior written permission
479c564b6cSJohn Hay  *
489c564b6cSJohn Hay  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
499c564b6cSJohn Hay  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
509c564b6cSJohn Hay  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
519c564b6cSJohn Hay  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
529c564b6cSJohn Hay  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
539c564b6cSJohn Hay  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
549c564b6cSJohn Hay  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
559c564b6cSJohn Hay  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
569c564b6cSJohn Hay  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
579c564b6cSJohn Hay  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
589c564b6cSJohn Hay  */
599c564b6cSJohn Hay 
609c564b6cSJohn Hay #include <sys/cdefs.h>
619c564b6cSJohn Hay __FBSDID("$FreeBSD$");
629c564b6cSJohn Hay 
639c564b6cSJohn Hay /*
649c564b6cSJohn Hay  * PCI "universal" communication card device driver, glues com, lpt,
659c564b6cSJohn Hay  * and similar ports to PCI via bridge chip often much larger than
669c564b6cSJohn Hay  * the devices being glued.
679c564b6cSJohn Hay  *
689c564b6cSJohn Hay  * Author: Christopher G. Demetriou, May 14, 1998 (derived from NetBSD
699c564b6cSJohn Hay  * sys/dev/pci/pciide.c, revision 1.6).
709c564b6cSJohn Hay  *
719c564b6cSJohn Hay  * These devices could be (and some times are) described as
729c564b6cSJohn Hay  * communications/{serial,parallel}, etc. devices with known
739c564b6cSJohn Hay  * programming interfaces, but those programming interfaces (in
749c564b6cSJohn Hay  * particular the BAR assignments for devices, etc.) in fact are not
759c564b6cSJohn Hay  * particularly well defined.
769c564b6cSJohn Hay  *
779c564b6cSJohn Hay  * After I/we have seen more of these devices, it may be possible
789c564b6cSJohn Hay  * to generalize some of these bits.  In particular, devices which
799c564b6cSJohn Hay  * describe themselves as communications/serial/16[45]50, and
809c564b6cSJohn Hay  * communications/parallel/??? might be attached via direct
819c564b6cSJohn Hay  * 'com' and 'lpt' attachments to pci.
829c564b6cSJohn Hay  */
839c564b6cSJohn Hay 
849c564b6cSJohn Hay #include <sys/param.h>
859c564b6cSJohn Hay #include <sys/systm.h>
869c564b6cSJohn Hay #include <sys/kernel.h>
879c564b6cSJohn Hay #include <sys/bus.h>
889c564b6cSJohn Hay #include <sys/conf.h>
899c564b6cSJohn Hay #include <sys/malloc.h>
909c564b6cSJohn Hay 
919c564b6cSJohn Hay #include <machine/bus.h>
929c564b6cSJohn Hay #include <machine/resource.h>
939c564b6cSJohn Hay #include <sys/rman.h>
949c564b6cSJohn Hay 
959c564b6cSJohn Hay #include <dev/pci/pcireg.h>
969c564b6cSJohn Hay #include <dev/pci/pcivar.h>
9732f606d1SPoul-Henning Kamp 
9832f606d1SPoul-Henning Kamp #define PUC_ENTRAILS	1
999c564b6cSJohn Hay #include <dev/puc/pucvar.h>
1009c564b6cSJohn Hay 
1019c564b6cSJohn Hay #include <opt_puc.h>
1029c564b6cSJohn Hay 
1039c564b6cSJohn Hay 
1049c564b6cSJohn Hay struct puc_device {
1059c564b6cSJohn Hay 	struct resource_list resources;
1069c564b6cSJohn Hay 	u_int serialfreq;
1079c564b6cSJohn Hay };
1089c564b6cSJohn Hay 
1099c564b6cSJohn Hay static void puc_intr(void *arg);
1109c564b6cSJohn Hay 
1119c564b6cSJohn Hay static int puc_find_free_unit(char *);
1129c564b6cSJohn Hay #ifdef PUC_DEBUG
1139c564b6cSJohn Hay static void puc_print_resource_list(struct resource_list *);
1149c564b6cSJohn Hay #endif
1159c564b6cSJohn Hay 
1161e89655aSPoul-Henning Kamp static int
1171e89655aSPoul-Henning Kamp puc_port_bar_index(struct puc_softc *sc, int bar)
1181e89655aSPoul-Henning Kamp {
1191e89655aSPoul-Henning Kamp 	int i;
1201e89655aSPoul-Henning Kamp 
1211e89655aSPoul-Henning Kamp 	for (i = 0; i < PUC_MAX_BAR; i += 1) {
1221e89655aSPoul-Henning Kamp 		if (!sc->sc_bar_mappings[i].used)
1231e89655aSPoul-Henning Kamp 			break;
1241e89655aSPoul-Henning Kamp 		if (sc->sc_bar_mappings[i].bar == bar)
1251e89655aSPoul-Henning Kamp 			return (i);
1261e89655aSPoul-Henning Kamp 	}
1271e89655aSPoul-Henning Kamp 	sc->sc_bar_mappings[i].bar = bar;
1281e89655aSPoul-Henning Kamp 	sc->sc_bar_mappings[i].used = 1;
1291e89655aSPoul-Henning Kamp 	return (i);
1301e89655aSPoul-Henning Kamp }
1311e89655aSPoul-Henning Kamp 
13232f606d1SPoul-Henning Kamp int
13332f606d1SPoul-Henning Kamp puc_attach(device_t dev, const struct puc_device_description *desc)
1349c564b6cSJohn Hay {
1359c564b6cSJohn Hay 	char *typestr;
1369c564b6cSJohn Hay 	int bidx, childunit, i, irq_setup, rid;
1379c564b6cSJohn Hay 	struct puc_softc *sc;
1389c564b6cSJohn Hay 	struct puc_device *pdev;
1399c564b6cSJohn Hay 	struct resource *res;
1409c564b6cSJohn Hay 	struct resource_list_entry *rle;
1419c564b6cSJohn Hay 
1429c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
1439c564b6cSJohn Hay 	bzero(sc, sizeof(*sc));
14432f606d1SPoul-Henning Kamp 	sc->sc_desc = desc;
1459c564b6cSJohn Hay 	if (sc->sc_desc == NULL)
1469c564b6cSJohn Hay 		return (ENXIO);
1479c564b6cSJohn Hay 
1489c564b6cSJohn Hay #ifdef PUC_DEBUG
1499c564b6cSJohn Hay 	bootverbose = 1;
1509c564b6cSJohn Hay 
1519c564b6cSJohn Hay 	printf("puc: name: %s\n", sc->sc_desc->name);
1529c564b6cSJohn Hay #endif
1539c564b6cSJohn Hay 	rid = 0;
1549c564b6cSJohn Hay 	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
1559c564b6cSJohn Hay 	    RF_ACTIVE | RF_SHAREABLE);
1569c564b6cSJohn Hay 	if (!res)
1579c564b6cSJohn Hay 		return (ENXIO);
1589c564b6cSJohn Hay 
1599c564b6cSJohn Hay 	sc->irqres = res;
1609c564b6cSJohn Hay 	sc->irqrid = rid;
1619c564b6cSJohn Hay #ifdef PUC_FASTINTR
1629c564b6cSJohn Hay 	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
1639c564b6cSJohn Hay 	    INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie);
1649c564b6cSJohn Hay #else
1659c564b6cSJohn Hay 	irq_setup = ENXIO;
1669c564b6cSJohn Hay #endif
1679c564b6cSJohn Hay 	if (irq_setup != 0)
1689c564b6cSJohn Hay 		irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
1699c564b6cSJohn Hay 		    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
1709c564b6cSJohn Hay 	if (irq_setup != 0)
1719c564b6cSJohn Hay 		return (ENXIO);
1729c564b6cSJohn Hay 
1739c564b6cSJohn Hay 	rid = 0;
1749c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
1751e89655aSPoul-Henning Kamp 		if (i > 0 && rid == sc->sc_desc->ports[i].bar)
1769c564b6cSJohn Hay 			sc->barmuxed = 1;
1779c564b6cSJohn Hay 		rid = sc->sc_desc->ports[i].bar;
1781e89655aSPoul-Henning Kamp 		bidx = puc_port_bar_index(sc, rid);
1799c564b6cSJohn Hay 
1809c564b6cSJohn Hay 		if (sc->sc_bar_mappings[bidx].res != NULL)
1819c564b6cSJohn Hay 			continue;
1829c564b6cSJohn Hay 		res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
1839c564b6cSJohn Hay 		    0ul, ~0ul, 1, RF_ACTIVE);
1849c564b6cSJohn Hay 		if (res == NULL) {
1859c564b6cSJohn Hay 			printf("could not get resource\n");
1869c564b6cSJohn Hay 			continue;
1879c564b6cSJohn Hay 		}
1889c564b6cSJohn Hay 		sc->sc_bar_mappings[bidx].res = res;
1899c564b6cSJohn Hay #ifdef PUC_DEBUG
1901e89655aSPoul-Henning Kamp 		printf("port rid %d bst %x, start %x, end %x\n", rid,
1919c564b6cSJohn Hay 		    (u_int)rman_get_bustag(res), (u_int)rman_get_start(res),
1929c564b6cSJohn Hay 		    (u_int)rman_get_end(res));
1939c564b6cSJohn Hay #endif
1949c564b6cSJohn Hay 	}
1959c564b6cSJohn Hay 
1961e89655aSPoul-Henning Kamp 	if (desc->init != NULL) {
1971e89655aSPoul-Henning Kamp 		i = desc->init(sc);
1981e89655aSPoul-Henning Kamp 		if (i != 0)
1991e89655aSPoul-Henning Kamp 			return (i);
2001e89655aSPoul-Henning Kamp 	}
2019c564b6cSJohn Hay 
2029c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
2039c564b6cSJohn Hay 		rid = sc->sc_desc->ports[i].bar;
2041e89655aSPoul-Henning Kamp 		bidx = puc_port_bar_index(sc, rid);
2059c564b6cSJohn Hay 		if (sc->sc_bar_mappings[bidx].res == NULL)
2069c564b6cSJohn Hay 			continue;
2079c564b6cSJohn Hay 
2089c564b6cSJohn Hay 		switch (sc->sc_desc->ports[i].type) {
2099c564b6cSJohn Hay 		case PUC_PORT_TYPE_COM:
2109c564b6cSJohn Hay 			typestr = "sio";
2119c564b6cSJohn Hay 			break;
2129c564b6cSJohn Hay 		default:
2139c564b6cSJohn Hay 			continue;
2149c564b6cSJohn Hay 		}
2159c564b6cSJohn Hay 		pdev = malloc(sizeof(struct puc_device), M_DEVBUF,
2169c564b6cSJohn Hay 		    M_NOWAIT | M_ZERO);
2179c564b6cSJohn Hay 		if (!pdev)
2189c564b6cSJohn Hay 			continue;
2199c564b6cSJohn Hay 		resource_list_init(&pdev->resources);
2209c564b6cSJohn Hay 
2219c564b6cSJohn Hay 		/* First fake up an IRQ resource. */
2229c564b6cSJohn Hay 		resource_list_add(&pdev->resources, SYS_RES_IRQ, 0,
2239c564b6cSJohn Hay 		    rman_get_start(sc->irqres), rman_get_end(sc->irqres),
2249c564b6cSJohn Hay 		    rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1);
2259c564b6cSJohn Hay 		rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0);
2269c564b6cSJohn Hay 		rle->res = sc->irqres;
2279c564b6cSJohn Hay 
2289c564b6cSJohn Hay 		/* Now fake an IOPORT resource */
2299c564b6cSJohn Hay 		res = sc->sc_bar_mappings[bidx].res;
2309c564b6cSJohn Hay 		resource_list_add(&pdev->resources, SYS_RES_IOPORT, 0,
2319c564b6cSJohn Hay 		    rman_get_start(res) + sc->sc_desc->ports[i].offset,
2321e89655aSPoul-Henning Kamp 		    rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1,
2339c564b6cSJohn Hay 		    8);
2349c564b6cSJohn Hay 		rle = resource_list_find(&pdev->resources, SYS_RES_IOPORT, 0);
2359c564b6cSJohn Hay 
2369c564b6cSJohn Hay 		if (sc->barmuxed == 0) {
2379c564b6cSJohn Hay 			rle->res = sc->sc_bar_mappings[bidx].res;
2389c564b6cSJohn Hay 		} else {
2399c564b6cSJohn Hay 			rle->res = malloc(sizeof(struct resource), M_DEVBUF,
2409c564b6cSJohn Hay 			    M_WAITOK | M_ZERO);
2415aa967d9SYoshihiro Takahashi 			if (rle->res == NULL) {
2425aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
2439c564b6cSJohn Hay 				return (ENOMEM);
2445aa967d9SYoshihiro Takahashi 			}
2459c564b6cSJohn Hay 
2469c564b6cSJohn Hay 			rle->res->r_start = rman_get_start(res) +
2479c564b6cSJohn Hay 			    sc->sc_desc->ports[i].offset;
2489c564b6cSJohn Hay 			rle->res->r_end = rle->res->r_start + 8 - 1;
2499c564b6cSJohn Hay 			rle->res->r_bustag = rman_get_bustag(res);
2509c564b6cSJohn Hay 			bus_space_subregion(rle->res->r_bustag,
2519c564b6cSJohn Hay 			    rman_get_bushandle(res),
2529c564b6cSJohn Hay 			    sc->sc_desc->ports[i].offset, 8,
2539c564b6cSJohn Hay 			    &rle->res->r_bushandle);
2549c564b6cSJohn Hay 		}
2559c564b6cSJohn Hay 
2569c564b6cSJohn Hay 		pdev->serialfreq = sc->sc_desc->ports[i].serialfreq;
2579c564b6cSJohn Hay 
2589c564b6cSJohn Hay 		childunit = puc_find_free_unit(typestr);
2599c564b6cSJohn Hay 		sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit);
2605aa967d9SYoshihiro Takahashi 		if (sc->sc_ports[i].dev == NULL) {
2615aa967d9SYoshihiro Takahashi 			if (sc->barmuxed) {
2625aa967d9SYoshihiro Takahashi 				bus_space_unmap(rman_get_bustag(rle->res),
2635aa967d9SYoshihiro Takahashi 						rman_get_bushandle(rle->res),
2645aa967d9SYoshihiro Takahashi 						8);
2655aa967d9SYoshihiro Takahashi 				free(rle->res, M_DEVBUF);
2665aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
2675aa967d9SYoshihiro Takahashi 			}
2689c564b6cSJohn Hay 			continue;
2695aa967d9SYoshihiro Takahashi 		}
2709c564b6cSJohn Hay 		device_set_ivars(sc->sc_ports[i].dev, pdev);
2719c564b6cSJohn Hay 		device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name);
2729c564b6cSJohn Hay 		if (!bootverbose)
2739c564b6cSJohn Hay 			device_quiet(sc->sc_ports[i].dev);
2749c564b6cSJohn Hay #ifdef PUC_DEBUG
2759c564b6cSJohn Hay 		printf("puc: type %d, bar %x, offset %x\n",
2769c564b6cSJohn Hay 		    sc->sc_desc->ports[i].type,
2779c564b6cSJohn Hay 		    sc->sc_desc->ports[i].bar,
2789c564b6cSJohn Hay 		    sc->sc_desc->ports[i].offset);
27932f606d1SPoul-Henning Kamp 		puc_print_resource_list(&pdev->resources);
2809c564b6cSJohn Hay #endif
2815aa967d9SYoshihiro Takahashi 		if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) {
2825aa967d9SYoshihiro Takahashi 			if (sc->barmuxed) {
2835aa967d9SYoshihiro Takahashi 				bus_space_unmap(rman_get_bustag(rle->res),
2845aa967d9SYoshihiro Takahashi 						rman_get_bushandle(rle->res),
2855aa967d9SYoshihiro Takahashi 						8);
2865aa967d9SYoshihiro Takahashi 				free(rle->res, M_DEVBUF);
2875aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
2885aa967d9SYoshihiro Takahashi 			}
2895aa967d9SYoshihiro Takahashi 		}
2909c564b6cSJohn Hay 	}
2919c564b6cSJohn Hay 
2929c564b6cSJohn Hay #ifdef PUC_DEBUG
2939c564b6cSJohn Hay 	bootverbose = 0;
2949c564b6cSJohn Hay #endif
2959c564b6cSJohn Hay 	return (0);
2969c564b6cSJohn Hay }
2979c564b6cSJohn Hay 
2989c564b6cSJohn Hay /*
2999c564b6cSJohn Hay  * This is just an brute force interrupt handler. It just calls all the
3009c564b6cSJohn Hay  * registered handlers sequencially.
3019c564b6cSJohn Hay  *
3029c564b6cSJohn Hay  * Later on we should maybe have a different handler for boards that can
3039c564b6cSJohn Hay  * tell us which device generated the interrupt.
3049c564b6cSJohn Hay  */
3059c564b6cSJohn Hay static void
3069c564b6cSJohn Hay puc_intr(void *arg)
3079c564b6cSJohn Hay {
3089c564b6cSJohn Hay 	int i;
3099c564b6cSJohn Hay 	struct puc_softc *sc;
3109c564b6cSJohn Hay 
3111e89655aSPoul-Henning Kamp printf("puc_intr\n");
3129c564b6cSJohn Hay 	sc = (struct puc_softc *)arg;
3139c564b6cSJohn Hay 	for (i = 0; i < PUC_MAX_PORTS; i++)
3149c564b6cSJohn Hay 		if (sc->sc_ports[i].ihand != NULL)
3159c564b6cSJohn Hay 			(sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg);
3169c564b6cSJohn Hay }
3179c564b6cSJohn Hay 
31832f606d1SPoul-Henning Kamp const struct puc_device_description *
3199c564b6cSJohn Hay puc_find_description(uint32_t vend, uint32_t prod, uint32_t svend,
3209c564b6cSJohn Hay     uint32_t sprod)
3219c564b6cSJohn Hay {
3229c564b6cSJohn Hay 	int i;
3239c564b6cSJohn Hay 
3249c564b6cSJohn Hay #define checkreg(val, index) \
3259c564b6cSJohn Hay     (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)])
3269c564b6cSJohn Hay 
3279c564b6cSJohn Hay 	for (i = 0; puc_devices[i].name != NULL; i++) {
3289c564b6cSJohn Hay 		if (checkreg(vend, PUC_REG_VEND) &&
3299c564b6cSJohn Hay 		    checkreg(prod, PUC_REG_PROD) &&
3309c564b6cSJohn Hay 		    checkreg(svend, PUC_REG_SVEND) &&
3319c564b6cSJohn Hay 		    checkreg(sprod, PUC_REG_SPROD))
3329c564b6cSJohn Hay 			return (&puc_devices[i]);
3339c564b6cSJohn Hay 	}
3349c564b6cSJohn Hay 
3359c564b6cSJohn Hay #undef checkreg
3369c564b6cSJohn Hay 
3379c564b6cSJohn Hay 	return (NULL);
3389c564b6cSJohn Hay }
3399c564b6cSJohn Hay static int puc_find_free_unit(char *name)
3409c564b6cSJohn Hay {
3419c564b6cSJohn Hay 	devclass_t dc;
3429c564b6cSJohn Hay 	int start;
3439c564b6cSJohn Hay 	int unit;
3449c564b6cSJohn Hay 
3459c564b6cSJohn Hay 	unit = 0;
3469c564b6cSJohn Hay 	start = 0;
3479c564b6cSJohn Hay 	while (resource_int_value(name, unit, "port", &start) == 0 &&
3489c564b6cSJohn Hay 	    start > 0)
3499c564b6cSJohn Hay 		unit++;
3509c564b6cSJohn Hay 	dc = devclass_find(name);
3519c564b6cSJohn Hay 	if (dc == NULL)
3529c564b6cSJohn Hay 		return (-1);
3539c564b6cSJohn Hay 	while (devclass_get_device(dc, unit))
3549c564b6cSJohn Hay 		unit++;
3559c564b6cSJohn Hay #ifdef PUC_DEBUG
3569c564b6cSJohn Hay 	printf("puc: Using %s%d\n", name, unit);
3579c564b6cSJohn Hay #endif
3589c564b6cSJohn Hay 	return (unit);
3599c564b6cSJohn Hay }
3609c564b6cSJohn Hay 
3619c564b6cSJohn Hay #ifdef PUC_DEBUG
3629c564b6cSJohn Hay static void
3639c564b6cSJohn Hay puc_print_resource_list(struct resource_list *rl)
3649c564b6cSJohn Hay {
3651e89655aSPoul-Henning Kamp #if 0
3669c564b6cSJohn Hay 	struct resource_list_entry *rle;
3679c564b6cSJohn Hay 
3689c564b6cSJohn Hay 	printf("print_resource_list: rl %p\n", rl);
3699c564b6cSJohn Hay 	SLIST_FOREACH(rle, rl, link)
3701e89655aSPoul-Henning Kamp 		printf("  type %x, rid %x start %x end %x count %x\n",
3711e89655aSPoul-Henning Kamp 		    rle->type, rle->rid, rle->start, rle->end, rle->count);
3729c564b6cSJohn Hay 	printf("print_resource_list: end.\n");
3731e89655aSPoul-Henning Kamp #endif
3749c564b6cSJohn Hay }
3759c564b6cSJohn Hay #endif
3769c564b6cSJohn Hay 
37732f606d1SPoul-Henning Kamp struct resource *
3789c564b6cSJohn Hay puc_alloc_resource(device_t dev, device_t child, int type, int *rid,
3799c564b6cSJohn Hay     u_long start, u_long end, u_long count, u_int flags)
3809c564b6cSJohn Hay {
3819c564b6cSJohn Hay 	struct puc_device *pdev;
3829c564b6cSJohn Hay 	struct resource *retval;
3839c564b6cSJohn Hay 	struct resource_list *rl;
3849c564b6cSJohn Hay 	struct resource_list_entry *rle;
3859c564b6cSJohn Hay 
3869c564b6cSJohn Hay 	pdev = device_get_ivars(child);
3879c564b6cSJohn Hay 	rl = &pdev->resources;
3889c564b6cSJohn Hay 
3899c564b6cSJohn Hay #ifdef PUC_DEBUG
3909c564b6cSJohn Hay 	printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n",
3919c564b6cSJohn Hay 	    pdev, type, *rid);
3929c564b6cSJohn Hay 	puc_print_resource_list(rl);
3939c564b6cSJohn Hay #endif
3949c564b6cSJohn Hay 	retval = NULL;
3959c564b6cSJohn Hay 	rle = resource_list_find(rl, type, *rid);
3969c564b6cSJohn Hay 	if (rle) {
3979c564b6cSJohn Hay 		start = rle->start;
3989c564b6cSJohn Hay 		end = rle->end;
3999c564b6cSJohn Hay 		count = rle->count;
4009c564b6cSJohn Hay #ifdef PUC_DEBUG
4019c564b6cSJohn Hay 		printf("found rle, %lx, %lx, %lx\n", start, end, count);
4029c564b6cSJohn Hay #endif
4039c564b6cSJohn Hay 		retval = rle->res;
4049c564b6cSJohn Hay 	} else
4059c564b6cSJohn Hay 		printf("oops rle is gone\n");
4069c564b6cSJohn Hay 
4079c564b6cSJohn Hay 	return (retval);
4089c564b6cSJohn Hay }
4099c564b6cSJohn Hay 
41032f606d1SPoul-Henning Kamp int
4119c564b6cSJohn Hay puc_release_resource(device_t dev, device_t child, int type, int rid,
4129c564b6cSJohn Hay     struct resource *res)
4139c564b6cSJohn Hay {
4149c564b6cSJohn Hay 	return (0);
4159c564b6cSJohn Hay }
4169c564b6cSJohn Hay 
41732f606d1SPoul-Henning Kamp int
4189c564b6cSJohn Hay puc_get_resource(device_t dev, device_t child, int type, int rid,
4199c564b6cSJohn Hay     u_long *startp, u_long *countp)
4209c564b6cSJohn Hay {
4219c564b6cSJohn Hay 	struct puc_device *pdev;
4229c564b6cSJohn Hay 	struct resource_list *rl;
4239c564b6cSJohn Hay 	struct resource_list_entry *rle;
4249c564b6cSJohn Hay 
4259c564b6cSJohn Hay 	pdev = device_get_ivars(child);
4269c564b6cSJohn Hay 	rl = &pdev->resources;
4279c564b6cSJohn Hay 
4289c564b6cSJohn Hay #ifdef PUC_DEBUG
4299c564b6cSJohn Hay 	printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev,
4309c564b6cSJohn Hay 	    type, rid);
4319c564b6cSJohn Hay 	puc_print_resource_list(rl);
4329c564b6cSJohn Hay #endif
4339c564b6cSJohn Hay 	rle = resource_list_find(rl, type, rid);
4349c564b6cSJohn Hay 	if (rle) {
4359c564b6cSJohn Hay #ifdef PUC_DEBUG
4369c564b6cSJohn Hay 		printf("found rle %p,", rle);
4379c564b6cSJohn Hay #endif
4389c564b6cSJohn Hay 		if (startp != NULL)
4399c564b6cSJohn Hay 			*startp = rle->start;
4409c564b6cSJohn Hay 		if (countp != NULL)
4419c564b6cSJohn Hay 			*countp = rle->count;
4429c564b6cSJohn Hay #ifdef PUC_DEBUG
4439c564b6cSJohn Hay 		printf(" %lx, %lx\n", rle->start, rle->count);
4449c564b6cSJohn Hay #endif
4459c564b6cSJohn Hay 		return (0);
4469c564b6cSJohn Hay 	} else
4479c564b6cSJohn Hay 		printf("oops rle is gone\n");
4489c564b6cSJohn Hay 	return (ENXIO);
4499c564b6cSJohn Hay }
4509c564b6cSJohn Hay 
45132f606d1SPoul-Henning Kamp int
4529c564b6cSJohn Hay puc_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
4539c564b6cSJohn Hay 	       void (*ihand)(void *), void *arg, void **cookiep)
4549c564b6cSJohn Hay {
4559c564b6cSJohn Hay 	int i;
4569c564b6cSJohn Hay 	struct puc_softc *sc;
4579c564b6cSJohn Hay 
4581e89655aSPoul-Henning Kamp printf("puc_setup_intr()\n");
4599c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
4609c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
4619c564b6cSJohn Hay 		if (sc->sc_ports[i].dev == child) {
4629c564b6cSJohn Hay 			if (sc->sc_ports[i].ihand != 0)
4639c564b6cSJohn Hay 				return (ENXIO);
4649c564b6cSJohn Hay 			sc->sc_ports[i].ihand = ihand;
4659c564b6cSJohn Hay 			sc->sc_ports[i].ihandarg = arg;
4669c564b6cSJohn Hay 			*cookiep = arg;
4679c564b6cSJohn Hay 			return (0);
4689c564b6cSJohn Hay 		}
4699c564b6cSJohn Hay 	}
4709c564b6cSJohn Hay 	return (ENXIO);
4719c564b6cSJohn Hay }
4729c564b6cSJohn Hay 
47332f606d1SPoul-Henning Kamp int
4749c564b6cSJohn Hay puc_teardown_intr(device_t dev, device_t child, struct resource *r,
4759c564b6cSJohn Hay 		  void *cookie)
4769c564b6cSJohn Hay {
4779c564b6cSJohn Hay 	int i;
4789c564b6cSJohn Hay 	struct puc_softc *sc;
4799c564b6cSJohn Hay 
4801e89655aSPoul-Henning Kamp printf("puc_teardown_intr()\n");
4819c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
4829c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
4839c564b6cSJohn Hay 		if (sc->sc_ports[i].dev == child) {
4849c564b6cSJohn Hay 			sc->sc_ports[i].ihand = NULL;
4859c564b6cSJohn Hay 			sc->sc_ports[i].ihandarg = NULL;
4869c564b6cSJohn Hay 			return (0);
4879c564b6cSJohn Hay 		}
4889c564b6cSJohn Hay 	}
4899c564b6cSJohn Hay 	return (ENXIO);
4909c564b6cSJohn Hay }
4919c564b6cSJohn Hay 
49232f606d1SPoul-Henning Kamp int
4939c564b6cSJohn Hay puc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
4949c564b6cSJohn Hay {
4959c564b6cSJohn Hay 	struct puc_device *pdev;
4969c564b6cSJohn Hay 
4979c564b6cSJohn Hay 	pdev = device_get_ivars(child);
4989c564b6cSJohn Hay 	if (pdev == NULL)
4999c564b6cSJohn Hay 		return (ENOENT);
5009c564b6cSJohn Hay 
5019c564b6cSJohn Hay 	switch(index) {
5029c564b6cSJohn Hay 	case PUC_IVAR_FREQ:
5039c564b6cSJohn Hay 		*result = pdev->serialfreq;
5049c564b6cSJohn Hay 		break;
5059c564b6cSJohn Hay 	default:
5069c564b6cSJohn Hay 		return (ENOENT);
5079c564b6cSJohn Hay 	}
5089c564b6cSJohn Hay 	return (0);
5099c564b6cSJohn Hay }
5109c564b6cSJohn Hay 
51132f606d1SPoul-Henning Kamp devclass_t puc_devclass;
5129c564b6cSJohn Hay 
513