xref: /freebsd/sys/dev/puc/puc.c (revision d3c10e33e62906d1a792cfade4d63dd66a466b10)
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 
84237d2ddaSJuli Mallett #include "opt_puc.h"
85237d2ddaSJuli Mallett 
869c564b6cSJohn Hay #include <sys/param.h>
879c564b6cSJohn Hay #include <sys/systm.h>
889c564b6cSJohn Hay #include <sys/kernel.h>
899c564b6cSJohn Hay #include <sys/bus.h>
909c564b6cSJohn Hay #include <sys/conf.h>
919c564b6cSJohn Hay #include <sys/malloc.h>
929c564b6cSJohn Hay 
939c564b6cSJohn Hay #include <machine/bus.h>
949c564b6cSJohn Hay #include <machine/resource.h>
959c564b6cSJohn Hay #include <sys/rman.h>
969c564b6cSJohn Hay 
979c564b6cSJohn Hay #include <dev/pci/pcireg.h>
989c564b6cSJohn Hay #include <dev/pci/pcivar.h>
9932f606d1SPoul-Henning Kamp 
10032f606d1SPoul-Henning Kamp #define PUC_ENTRAILS	1
1019c564b6cSJohn Hay #include <dev/puc/pucvar.h>
1029c564b6cSJohn Hay 
1039c564b6cSJohn Hay struct puc_device {
1049c564b6cSJohn Hay 	struct resource_list resources;
1059c564b6cSJohn Hay 	u_int serialfreq;
1069c564b6cSJohn Hay };
1079c564b6cSJohn Hay 
1089c564b6cSJohn Hay static void puc_intr(void *arg);
1099c564b6cSJohn Hay 
1109c564b6cSJohn Hay static int puc_find_free_unit(char *);
1119c564b6cSJohn Hay #ifdef PUC_DEBUG
1129c564b6cSJohn Hay static void puc_print_resource_list(struct resource_list *);
1139c564b6cSJohn Hay #endif
1149c564b6cSJohn Hay 
115c9168019SPoul-Henning Kamp devclass_t puc_devclass;
116c9168019SPoul-Henning Kamp 
1171e89655aSPoul-Henning Kamp static int
1181e89655aSPoul-Henning Kamp puc_port_bar_index(struct puc_softc *sc, int bar)
1191e89655aSPoul-Henning Kamp {
1201e89655aSPoul-Henning Kamp 	int i;
1211e89655aSPoul-Henning Kamp 
1221e89655aSPoul-Henning Kamp 	for (i = 0; i < PUC_MAX_BAR; i += 1) {
1231e89655aSPoul-Henning Kamp 		if (!sc->sc_bar_mappings[i].used)
1241e89655aSPoul-Henning Kamp 			break;
1251e89655aSPoul-Henning Kamp 		if (sc->sc_bar_mappings[i].bar == bar)
1261e89655aSPoul-Henning Kamp 			return (i);
1271e89655aSPoul-Henning Kamp 	}
1281e89655aSPoul-Henning Kamp 	sc->sc_bar_mappings[i].bar = bar;
1291e89655aSPoul-Henning Kamp 	sc->sc_bar_mappings[i].used = 1;
1301e89655aSPoul-Henning Kamp 	return (i);
1311e89655aSPoul-Henning Kamp }
1321e89655aSPoul-Henning Kamp 
13332f606d1SPoul-Henning Kamp int
13432f606d1SPoul-Henning Kamp puc_attach(device_t dev, const struct puc_device_description *desc)
1359c564b6cSJohn Hay {
1369c564b6cSJohn Hay 	char *typestr;
1379c564b6cSJohn Hay 	int bidx, childunit, i, irq_setup, rid;
1389c564b6cSJohn Hay 	struct puc_softc *sc;
1399c564b6cSJohn Hay 	struct puc_device *pdev;
1409c564b6cSJohn Hay 	struct resource *res;
1419c564b6cSJohn Hay 	struct resource_list_entry *rle;
1429c564b6cSJohn Hay 
1439c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
1449c564b6cSJohn Hay 	bzero(sc, sizeof(*sc));
14532f606d1SPoul-Henning Kamp 	sc->sc_desc = desc;
1469c564b6cSJohn Hay 	if (sc->sc_desc == NULL)
1479c564b6cSJohn Hay 		return (ENXIO);
1489c564b6cSJohn Hay 
1499c564b6cSJohn Hay #ifdef PUC_DEBUG
1509c564b6cSJohn Hay 	bootverbose = 1;
1519c564b6cSJohn Hay 
1529c564b6cSJohn Hay 	printf("puc: name: %s\n", sc->sc_desc->name);
1539c564b6cSJohn Hay #endif
1549c564b6cSJohn Hay 	rid = 0;
1559c564b6cSJohn Hay 	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
1569c564b6cSJohn Hay 	    RF_ACTIVE | RF_SHAREABLE);
1579c564b6cSJohn Hay 	if (!res)
1589c564b6cSJohn Hay 		return (ENXIO);
1599c564b6cSJohn Hay 
1609c564b6cSJohn Hay 	sc->irqres = res;
1619c564b6cSJohn Hay 	sc->irqrid = rid;
162d3c10e33SPoul-Henning Kamp #ifdef PUC_FASTINTR
163d3c10e33SPoul-Henning Kamp 	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
164d3c10e33SPoul-Henning Kamp 	    INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie);
165d3c10e33SPoul-Henning Kamp 	if (irq_setup == 0)
166d3c10e33SPoul-Henning Kamp 		sc->fastintr = 1;
167d3c10e33SPoul-Henning Kamp 	else
1689c564b6cSJohn Hay 		irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
1699c564b6cSJohn Hay 		    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
170d3c10e33SPoul-Henning Kamp #else
171d3c10e33SPoul-Henning Kamp 	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
172d3c10e33SPoul-Henning Kamp 	    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
173d3c10e33SPoul-Henning Kamp #endif
1749c564b6cSJohn Hay 	if (irq_setup != 0)
1759c564b6cSJohn Hay 		return (ENXIO);
1769c564b6cSJohn Hay 
1779c564b6cSJohn Hay 	rid = 0;
1789c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
1791e89655aSPoul-Henning Kamp 		if (i > 0 && rid == sc->sc_desc->ports[i].bar)
1809c564b6cSJohn Hay 			sc->barmuxed = 1;
1819c564b6cSJohn Hay 		rid = sc->sc_desc->ports[i].bar;
1821e89655aSPoul-Henning Kamp 		bidx = puc_port_bar_index(sc, rid);
1839c564b6cSJohn Hay 
1849c564b6cSJohn Hay 		if (sc->sc_bar_mappings[bidx].res != NULL)
1859c564b6cSJohn Hay 			continue;
1869c564b6cSJohn Hay 		res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
1879c564b6cSJohn Hay 		    0ul, ~0ul, 1, RF_ACTIVE);
1889c564b6cSJohn Hay 		if (res == NULL) {
1899c564b6cSJohn Hay 			printf("could not get resource\n");
1909c564b6cSJohn Hay 			continue;
1919c564b6cSJohn Hay 		}
1929c564b6cSJohn Hay 		sc->sc_bar_mappings[bidx].res = res;
1939c564b6cSJohn Hay #ifdef PUC_DEBUG
1941e89655aSPoul-Henning Kamp 		printf("port rid %d bst %x, start %x, end %x\n", rid,
1959c564b6cSJohn Hay 		    (u_int)rman_get_bustag(res), (u_int)rman_get_start(res),
1969c564b6cSJohn Hay 		    (u_int)rman_get_end(res));
1979c564b6cSJohn Hay #endif
1989c564b6cSJohn Hay 	}
1999c564b6cSJohn Hay 
2001e89655aSPoul-Henning Kamp 	if (desc->init != NULL) {
2011e89655aSPoul-Henning Kamp 		i = desc->init(sc);
2021e89655aSPoul-Henning Kamp 		if (i != 0)
2031e89655aSPoul-Henning Kamp 			return (i);
2041e89655aSPoul-Henning Kamp 	}
2059c564b6cSJohn Hay 
2069c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
2079c564b6cSJohn Hay 		rid = sc->sc_desc->ports[i].bar;
2081e89655aSPoul-Henning Kamp 		bidx = puc_port_bar_index(sc, rid);
2099c564b6cSJohn Hay 		if (sc->sc_bar_mappings[bidx].res == NULL)
2109c564b6cSJohn Hay 			continue;
2119c564b6cSJohn Hay 
2129c564b6cSJohn Hay 		switch (sc->sc_desc->ports[i].type) {
2139c564b6cSJohn Hay 		case PUC_PORT_TYPE_COM:
2149c564b6cSJohn Hay 			typestr = "sio";
2159c564b6cSJohn Hay 			break;
2169c564b6cSJohn Hay 		default:
2179c564b6cSJohn Hay 			continue;
2189c564b6cSJohn Hay 		}
2199c564b6cSJohn Hay 		pdev = malloc(sizeof(struct puc_device), M_DEVBUF,
2209c564b6cSJohn Hay 		    M_NOWAIT | M_ZERO);
2219c564b6cSJohn Hay 		if (!pdev)
2229c564b6cSJohn Hay 			continue;
2239c564b6cSJohn Hay 		resource_list_init(&pdev->resources);
2249c564b6cSJohn Hay 
2259c564b6cSJohn Hay 		/* First fake up an IRQ resource. */
2269c564b6cSJohn Hay 		resource_list_add(&pdev->resources, SYS_RES_IRQ, 0,
2279c564b6cSJohn Hay 		    rman_get_start(sc->irqres), rman_get_end(sc->irqres),
2289c564b6cSJohn Hay 		    rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1);
2299c564b6cSJohn Hay 		rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0);
2309c564b6cSJohn Hay 		rle->res = sc->irqres;
2319c564b6cSJohn Hay 
2329c564b6cSJohn Hay 		/* Now fake an IOPORT resource */
2339c564b6cSJohn Hay 		res = sc->sc_bar_mappings[bidx].res;
2349c564b6cSJohn Hay 		resource_list_add(&pdev->resources, SYS_RES_IOPORT, 0,
2359c564b6cSJohn Hay 		    rman_get_start(res) + sc->sc_desc->ports[i].offset,
2361e89655aSPoul-Henning Kamp 		    rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1,
2379c564b6cSJohn Hay 		    8);
2389c564b6cSJohn Hay 		rle = resource_list_find(&pdev->resources, SYS_RES_IOPORT, 0);
2399c564b6cSJohn Hay 
2409c564b6cSJohn Hay 		if (sc->barmuxed == 0) {
2419c564b6cSJohn Hay 			rle->res = sc->sc_bar_mappings[bidx].res;
2429c564b6cSJohn Hay 		} else {
2439c564b6cSJohn Hay 			rle->res = malloc(sizeof(struct resource), M_DEVBUF,
2449c564b6cSJohn Hay 			    M_WAITOK | M_ZERO);
2455aa967d9SYoshihiro Takahashi 			if (rle->res == NULL) {
2465aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
2479c564b6cSJohn Hay 				return (ENOMEM);
2485aa967d9SYoshihiro Takahashi 			}
2499c564b6cSJohn Hay 
2509c564b6cSJohn Hay 			rle->res->r_start = rman_get_start(res) +
2519c564b6cSJohn Hay 			    sc->sc_desc->ports[i].offset;
2529c564b6cSJohn Hay 			rle->res->r_end = rle->res->r_start + 8 - 1;
2539c564b6cSJohn Hay 			rle->res->r_bustag = rman_get_bustag(res);
2549c564b6cSJohn Hay 			bus_space_subregion(rle->res->r_bustag,
2559c564b6cSJohn Hay 			    rman_get_bushandle(res),
2569c564b6cSJohn Hay 			    sc->sc_desc->ports[i].offset, 8,
2579c564b6cSJohn Hay 			    &rle->res->r_bushandle);
2589c564b6cSJohn Hay 		}
2599c564b6cSJohn Hay 
2609c564b6cSJohn Hay 		pdev->serialfreq = sc->sc_desc->ports[i].serialfreq;
2619c564b6cSJohn Hay 
2629c564b6cSJohn Hay 		childunit = puc_find_free_unit(typestr);
2639c564b6cSJohn Hay 		sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit);
2645aa967d9SYoshihiro Takahashi 		if (sc->sc_ports[i].dev == NULL) {
2655aa967d9SYoshihiro Takahashi 			if (sc->barmuxed) {
2665aa967d9SYoshihiro Takahashi 				bus_space_unmap(rman_get_bustag(rle->res),
2675aa967d9SYoshihiro Takahashi 						rman_get_bushandle(rle->res),
2685aa967d9SYoshihiro Takahashi 						8);
2695aa967d9SYoshihiro Takahashi 				free(rle->res, M_DEVBUF);
2705aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
2715aa967d9SYoshihiro Takahashi 			}
2729c564b6cSJohn Hay 			continue;
2735aa967d9SYoshihiro Takahashi 		}
2749c564b6cSJohn Hay 		device_set_ivars(sc->sc_ports[i].dev, pdev);
2759c564b6cSJohn Hay 		device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name);
2769c564b6cSJohn Hay 		if (!bootverbose)
2779c564b6cSJohn Hay 			device_quiet(sc->sc_ports[i].dev);
2789c564b6cSJohn Hay #ifdef PUC_DEBUG
2799c564b6cSJohn Hay 		printf("puc: type %d, bar %x, offset %x\n",
2809c564b6cSJohn Hay 		    sc->sc_desc->ports[i].type,
2819c564b6cSJohn Hay 		    sc->sc_desc->ports[i].bar,
2829c564b6cSJohn Hay 		    sc->sc_desc->ports[i].offset);
28332f606d1SPoul-Henning Kamp 		puc_print_resource_list(&pdev->resources);
2849c564b6cSJohn Hay #endif
2855aa967d9SYoshihiro Takahashi 		if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) {
2865aa967d9SYoshihiro Takahashi 			if (sc->barmuxed) {
2875aa967d9SYoshihiro Takahashi 				bus_space_unmap(rman_get_bustag(rle->res),
2885aa967d9SYoshihiro Takahashi 						rman_get_bushandle(rle->res),
2895aa967d9SYoshihiro Takahashi 						8);
2905aa967d9SYoshihiro Takahashi 				free(rle->res, M_DEVBUF);
2915aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
2925aa967d9SYoshihiro Takahashi 			}
2935aa967d9SYoshihiro Takahashi 		}
2949c564b6cSJohn Hay 	}
2959c564b6cSJohn Hay 
2969c564b6cSJohn Hay #ifdef PUC_DEBUG
2979c564b6cSJohn Hay 	bootverbose = 0;
2989c564b6cSJohn Hay #endif
2999c564b6cSJohn Hay 	return (0);
3009c564b6cSJohn Hay }
3019c564b6cSJohn Hay 
3029c564b6cSJohn Hay /*
3039c564b6cSJohn Hay  * This is just an brute force interrupt handler. It just calls all the
3049c564b6cSJohn Hay  * registered handlers sequencially.
3059c564b6cSJohn Hay  *
3069c564b6cSJohn Hay  * Later on we should maybe have a different handler for boards that can
3079c564b6cSJohn Hay  * tell us which device generated the interrupt.
3089c564b6cSJohn Hay  */
3099c564b6cSJohn Hay static void
3109c564b6cSJohn Hay puc_intr(void *arg)
3119c564b6cSJohn Hay {
3129c564b6cSJohn Hay 	int i;
3139c564b6cSJohn Hay 	struct puc_softc *sc;
3149c564b6cSJohn Hay 
3159c564b6cSJohn Hay 	sc = (struct puc_softc *)arg;
3169c564b6cSJohn Hay 	for (i = 0; i < PUC_MAX_PORTS; i++)
3179c564b6cSJohn Hay 		if (sc->sc_ports[i].ihand != NULL)
3189c564b6cSJohn Hay 			(sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg);
3199c564b6cSJohn Hay }
3209c564b6cSJohn Hay 
32132f606d1SPoul-Henning Kamp const struct puc_device_description *
3229c564b6cSJohn Hay puc_find_description(uint32_t vend, uint32_t prod, uint32_t svend,
3239c564b6cSJohn Hay     uint32_t sprod)
3249c564b6cSJohn Hay {
3259c564b6cSJohn Hay 	int i;
3269c564b6cSJohn Hay 
3279c564b6cSJohn Hay #define checkreg(val, index) \
3289c564b6cSJohn Hay     (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)])
3299c564b6cSJohn Hay 
3309c564b6cSJohn Hay 	for (i = 0; puc_devices[i].name != NULL; i++) {
3319c564b6cSJohn Hay 		if (checkreg(vend, PUC_REG_VEND) &&
3329c564b6cSJohn Hay 		    checkreg(prod, PUC_REG_PROD) &&
3339c564b6cSJohn Hay 		    checkreg(svend, PUC_REG_SVEND) &&
3349c564b6cSJohn Hay 		    checkreg(sprod, PUC_REG_SPROD))
3359c564b6cSJohn Hay 			return (&puc_devices[i]);
3369c564b6cSJohn Hay 	}
3379c564b6cSJohn Hay 
3389c564b6cSJohn Hay #undef checkreg
3399c564b6cSJohn Hay 
3409c564b6cSJohn Hay 	return (NULL);
3419c564b6cSJohn Hay }
342ed4208e9SPoul-Henning Kamp 
343ed4208e9SPoul-Henning Kamp static int
344ed4208e9SPoul-Henning Kamp puc_find_free_unit(char *name)
3459c564b6cSJohn Hay {
3469c564b6cSJohn Hay 	devclass_t dc;
3479c564b6cSJohn Hay 	int start;
3489c564b6cSJohn Hay 	int unit;
3499c564b6cSJohn Hay 
3509c564b6cSJohn Hay 	unit = 0;
3519c564b6cSJohn Hay 	start = 0;
3529c564b6cSJohn Hay 	while (resource_int_value(name, unit, "port", &start) == 0 &&
3539c564b6cSJohn Hay 	    start > 0)
3549c564b6cSJohn Hay 		unit++;
3559c564b6cSJohn Hay 	dc = devclass_find(name);
3569c564b6cSJohn Hay 	if (dc == NULL)
3579c564b6cSJohn Hay 		return (-1);
3589c564b6cSJohn Hay 	while (devclass_get_device(dc, unit))
3599c564b6cSJohn Hay 		unit++;
3609c564b6cSJohn Hay #ifdef PUC_DEBUG
3619c564b6cSJohn Hay 	printf("puc: Using %s%d\n", name, unit);
3629c564b6cSJohn Hay #endif
3639c564b6cSJohn Hay 	return (unit);
3649c564b6cSJohn Hay }
3659c564b6cSJohn Hay 
3669c564b6cSJohn Hay #ifdef PUC_DEBUG
3679c564b6cSJohn Hay static void
3689c564b6cSJohn Hay puc_print_resource_list(struct resource_list *rl)
3699c564b6cSJohn Hay {
3701e89655aSPoul-Henning Kamp #if 0
3719c564b6cSJohn Hay 	struct resource_list_entry *rle;
3729c564b6cSJohn Hay 
3739c564b6cSJohn Hay 	printf("print_resource_list: rl %p\n", rl);
3749c564b6cSJohn Hay 	SLIST_FOREACH(rle, rl, link)
3751e89655aSPoul-Henning Kamp 		printf("  type %x, rid %x start %x end %x count %x\n",
3761e89655aSPoul-Henning Kamp 		    rle->type, rle->rid, rle->start, rle->end, rle->count);
3779c564b6cSJohn Hay 	printf("print_resource_list: end.\n");
3781e89655aSPoul-Henning Kamp #endif
3799c564b6cSJohn Hay }
3809c564b6cSJohn Hay #endif
3819c564b6cSJohn Hay 
38232f606d1SPoul-Henning Kamp struct resource *
3839c564b6cSJohn Hay puc_alloc_resource(device_t dev, device_t child, int type, int *rid,
3849c564b6cSJohn Hay     u_long start, u_long end, u_long count, u_int flags)
3859c564b6cSJohn Hay {
3869c564b6cSJohn Hay 	struct puc_device *pdev;
3879c564b6cSJohn Hay 	struct resource *retval;
3889c564b6cSJohn Hay 	struct resource_list *rl;
3899c564b6cSJohn Hay 	struct resource_list_entry *rle;
3909c564b6cSJohn Hay 
3919c564b6cSJohn Hay 	pdev = device_get_ivars(child);
3929c564b6cSJohn Hay 	rl = &pdev->resources;
3939c564b6cSJohn Hay 
3949c564b6cSJohn Hay #ifdef PUC_DEBUG
3959c564b6cSJohn Hay 	printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n",
3969c564b6cSJohn Hay 	    pdev, type, *rid);
3979c564b6cSJohn Hay 	puc_print_resource_list(rl);
3989c564b6cSJohn Hay #endif
3999c564b6cSJohn Hay 	retval = NULL;
4009c564b6cSJohn Hay 	rle = resource_list_find(rl, type, *rid);
4019c564b6cSJohn Hay 	if (rle) {
4029c564b6cSJohn Hay 		start = rle->start;
4039c564b6cSJohn Hay 		end = rle->end;
4049c564b6cSJohn Hay 		count = rle->count;
4059c564b6cSJohn Hay #ifdef PUC_DEBUG
4069c564b6cSJohn Hay 		printf("found rle, %lx, %lx, %lx\n", start, end, count);
4079c564b6cSJohn Hay #endif
4089c564b6cSJohn Hay 		retval = rle->res;
4099c564b6cSJohn Hay 	} else
4109c564b6cSJohn Hay 		printf("oops rle is gone\n");
4119c564b6cSJohn Hay 
4129c564b6cSJohn Hay 	return (retval);
4139c564b6cSJohn Hay }
4149c564b6cSJohn Hay 
41532f606d1SPoul-Henning Kamp int
4169c564b6cSJohn Hay puc_release_resource(device_t dev, device_t child, int type, int rid,
4179c564b6cSJohn Hay     struct resource *res)
4189c564b6cSJohn Hay {
4199c564b6cSJohn Hay 	return (0);
4209c564b6cSJohn Hay }
4219c564b6cSJohn Hay 
42232f606d1SPoul-Henning Kamp int
4239c564b6cSJohn Hay puc_get_resource(device_t dev, device_t child, int type, int rid,
4249c564b6cSJohn Hay     u_long *startp, u_long *countp)
4259c564b6cSJohn Hay {
4269c564b6cSJohn Hay 	struct puc_device *pdev;
4279c564b6cSJohn Hay 	struct resource_list *rl;
4289c564b6cSJohn Hay 	struct resource_list_entry *rle;
4299c564b6cSJohn Hay 
4309c564b6cSJohn Hay 	pdev = device_get_ivars(child);
4319c564b6cSJohn Hay 	rl = &pdev->resources;
4329c564b6cSJohn Hay 
4339c564b6cSJohn Hay #ifdef PUC_DEBUG
4349c564b6cSJohn Hay 	printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev,
4359c564b6cSJohn Hay 	    type, rid);
4369c564b6cSJohn Hay 	puc_print_resource_list(rl);
4379c564b6cSJohn Hay #endif
4389c564b6cSJohn Hay 	rle = resource_list_find(rl, type, rid);
4399c564b6cSJohn Hay 	if (rle) {
4409c564b6cSJohn Hay #ifdef PUC_DEBUG
4419c564b6cSJohn Hay 		printf("found rle %p,", rle);
4429c564b6cSJohn Hay #endif
4439c564b6cSJohn Hay 		if (startp != NULL)
4449c564b6cSJohn Hay 			*startp = rle->start;
4459c564b6cSJohn Hay 		if (countp != NULL)
4469c564b6cSJohn Hay 			*countp = rle->count;
4479c564b6cSJohn Hay #ifdef PUC_DEBUG
4489c564b6cSJohn Hay 		printf(" %lx, %lx\n", rle->start, rle->count);
4499c564b6cSJohn Hay #endif
4509c564b6cSJohn Hay 		return (0);
4519c564b6cSJohn Hay 	} else
4529c564b6cSJohn Hay 		printf("oops rle is gone\n");
4539c564b6cSJohn Hay 	return (ENXIO);
4549c564b6cSJohn Hay }
4559c564b6cSJohn Hay 
45632f606d1SPoul-Henning Kamp int
4579c564b6cSJohn Hay puc_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
4589c564b6cSJohn Hay 	       void (*ihand)(void *), void *arg, void **cookiep)
4599c564b6cSJohn Hay {
4609c564b6cSJohn Hay 	int i;
4619c564b6cSJohn Hay 	struct puc_softc *sc;
4629c564b6cSJohn Hay 
4639c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
464d3c10e33SPoul-Henning Kamp 	if ((flags & INTR_FAST) && !sc->fastintr)
465d3c10e33SPoul-Henning Kamp 		return (ENXIO);
4669c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
4679c564b6cSJohn Hay 		if (sc->sc_ports[i].dev == child) {
4689c564b6cSJohn Hay 			if (sc->sc_ports[i].ihand != 0)
4699c564b6cSJohn Hay 				return (ENXIO);
4709c564b6cSJohn Hay 			sc->sc_ports[i].ihand = ihand;
4719c564b6cSJohn Hay 			sc->sc_ports[i].ihandarg = arg;
4729c564b6cSJohn Hay 			*cookiep = arg;
4739c564b6cSJohn Hay 			return (0);
4749c564b6cSJohn Hay 		}
4759c564b6cSJohn Hay 	}
4769c564b6cSJohn Hay 	return (ENXIO);
4779c564b6cSJohn Hay }
4789c564b6cSJohn Hay 
47932f606d1SPoul-Henning Kamp int
4809c564b6cSJohn Hay puc_teardown_intr(device_t dev, device_t child, struct resource *r,
4819c564b6cSJohn Hay 		  void *cookie)
4829c564b6cSJohn Hay {
4839c564b6cSJohn Hay 	int i;
4849c564b6cSJohn Hay 	struct puc_softc *sc;
4859c564b6cSJohn Hay 
4869c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
4879c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
4889c564b6cSJohn Hay 		if (sc->sc_ports[i].dev == child) {
4899c564b6cSJohn Hay 			sc->sc_ports[i].ihand = NULL;
4909c564b6cSJohn Hay 			sc->sc_ports[i].ihandarg = NULL;
4919c564b6cSJohn Hay 			return (0);
4929c564b6cSJohn Hay 		}
4939c564b6cSJohn Hay 	}
4949c564b6cSJohn Hay 	return (ENXIO);
4959c564b6cSJohn Hay }
4969c564b6cSJohn Hay 
49732f606d1SPoul-Henning Kamp int
4989c564b6cSJohn Hay puc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
4999c564b6cSJohn Hay {
5009c564b6cSJohn Hay 	struct puc_device *pdev;
5019c564b6cSJohn Hay 
5029c564b6cSJohn Hay 	pdev = device_get_ivars(child);
5039c564b6cSJohn Hay 	if (pdev == NULL)
5049c564b6cSJohn Hay 		return (ENOENT);
5059c564b6cSJohn Hay 
5069c564b6cSJohn Hay 	switch(index) {
5079c564b6cSJohn Hay 	case PUC_IVAR_FREQ:
5089c564b6cSJohn Hay 		*result = pdev->serialfreq;
5099c564b6cSJohn Hay 		break;
5109c564b6cSJohn Hay 	default:
5119c564b6cSJohn Hay 		return (ENOENT);
5129c564b6cSJohn Hay 	}
5139c564b6cSJohn Hay 	return (0);
5149c564b6cSJohn Hay }
515