xref: /freebsd/sys/dev/puc/puc.c (revision 084254f80770c2c3fd71da3a2fe223b8d4b8b102)
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 
133084254f8SMaxim Sobolev static int
134084254f8SMaxim Sobolev puc_probe_ilr(struct puc_softc *sc, struct resource *res)
135084254f8SMaxim Sobolev {
136084254f8SMaxim Sobolev 	u_char t1, t2;
137084254f8SMaxim Sobolev 	int i;
138084254f8SMaxim Sobolev 
139084254f8SMaxim Sobolev 	switch (sc->sc_desc->ilr_type) {
140084254f8SMaxim Sobolev 	case PUC_ILR_TYPE_DIGI:
141084254f8SMaxim Sobolev 		sc->ilr_st = rman_get_bustag(res);
142084254f8SMaxim Sobolev 		sc->ilr_sh = rman_get_bushandle(res);
143084254f8SMaxim Sobolev 		for (i = 0; i < 2; i++) {
144084254f8SMaxim Sobolev 			t1 = bus_space_read_1(sc->ilr_st, sc->ilr_sh,
145084254f8SMaxim Sobolev 			    sc->sc_desc->ilr_offset[i]);
146084254f8SMaxim Sobolev 			t1 = ~t1;
147084254f8SMaxim Sobolev 			bus_space_write_1(sc->ilr_st, sc->ilr_sh,
148084254f8SMaxim Sobolev 			    sc->sc_desc->ilr_offset[i], t1);
149084254f8SMaxim Sobolev 			t2 = bus_space_read_1(sc->ilr_st, sc->ilr_sh,
150084254f8SMaxim Sobolev 			    sc->sc_desc->ilr_offset[i]);
151084254f8SMaxim Sobolev 			if (t2 == t1)
152084254f8SMaxim Sobolev 				return (0);
153084254f8SMaxim Sobolev 		}
154084254f8SMaxim Sobolev 		return (1);
155084254f8SMaxim Sobolev 
156084254f8SMaxim Sobolev 	default:
157084254f8SMaxim Sobolev 		break;
158084254f8SMaxim Sobolev 	}
159084254f8SMaxim Sobolev 	return (0);
160084254f8SMaxim Sobolev }
161084254f8SMaxim Sobolev 
16232f606d1SPoul-Henning Kamp int
16332f606d1SPoul-Henning Kamp puc_attach(device_t dev, const struct puc_device_description *desc)
1649c564b6cSJohn Hay {
1659c564b6cSJohn Hay 	char *typestr;
166da5e9a5bSMarcel Moolenaar 	int bidx, childunit, i, irq_setup, rid, type;
1679c564b6cSJohn Hay 	struct puc_softc *sc;
1689c564b6cSJohn Hay 	struct puc_device *pdev;
1699c564b6cSJohn Hay 	struct resource *res;
1709c564b6cSJohn Hay 	struct resource_list_entry *rle;
1719c564b6cSJohn Hay 
1729c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
1739c564b6cSJohn Hay 	bzero(sc, sizeof(*sc));
17432f606d1SPoul-Henning Kamp 	sc->sc_desc = desc;
1759c564b6cSJohn Hay 	if (sc->sc_desc == NULL)
1769c564b6cSJohn Hay 		return (ENXIO);
1779c564b6cSJohn Hay 
1789c564b6cSJohn Hay #ifdef PUC_DEBUG
1799c564b6cSJohn Hay 	bootverbose = 1;
1809c564b6cSJohn Hay 
1819c564b6cSJohn Hay 	printf("puc: name: %s\n", sc->sc_desc->name);
1829c564b6cSJohn Hay #endif
1839c564b6cSJohn Hay 	rid = 0;
1849c564b6cSJohn Hay 	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
1859c564b6cSJohn Hay 	    RF_ACTIVE | RF_SHAREABLE);
1869c564b6cSJohn Hay 	if (!res)
1879c564b6cSJohn Hay 		return (ENXIO);
1889c564b6cSJohn Hay 
1899c564b6cSJohn Hay 	sc->irqres = res;
1909c564b6cSJohn Hay 	sc->irqrid = rid;
191d3c10e33SPoul-Henning Kamp #ifdef PUC_FASTINTR
192d3c10e33SPoul-Henning Kamp 	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
193d3c10e33SPoul-Henning Kamp 	    INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie);
194d3c10e33SPoul-Henning Kamp 	if (irq_setup == 0)
1951f02c343SPoul-Henning Kamp 		sc->fastintr = INTR_FAST;
196d3c10e33SPoul-Henning Kamp 	else
1979c564b6cSJohn Hay 		irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
1989c564b6cSJohn Hay 		    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
199d3c10e33SPoul-Henning Kamp #else
200d3c10e33SPoul-Henning Kamp 	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
201d3c10e33SPoul-Henning Kamp 	    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
202d3c10e33SPoul-Henning Kamp #endif
2039c564b6cSJohn Hay 	if (irq_setup != 0)
2049c564b6cSJohn Hay 		return (ENXIO);
2059c564b6cSJohn Hay 
2069c564b6cSJohn Hay 	rid = 0;
2079c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
2081e89655aSPoul-Henning Kamp 		if (i > 0 && rid == sc->sc_desc->ports[i].bar)
2099c564b6cSJohn Hay 			sc->barmuxed = 1;
2109c564b6cSJohn Hay 		rid = sc->sc_desc->ports[i].bar;
2111e89655aSPoul-Henning Kamp 		bidx = puc_port_bar_index(sc, rid);
2129c564b6cSJohn Hay 
2139c564b6cSJohn Hay 		if (sc->sc_bar_mappings[bidx].res != NULL)
2149c564b6cSJohn Hay 			continue;
215da5e9a5bSMarcel Moolenaar 
216da5e9a5bSMarcel Moolenaar 		type = (sc->sc_desc->ports[i].flags & PUC_FLAGS_MEMORY)
217da5e9a5bSMarcel Moolenaar 		    ? SYS_RES_MEMORY : SYS_RES_IOPORT;
218da5e9a5bSMarcel Moolenaar 
219da5e9a5bSMarcel Moolenaar 		res = bus_alloc_resource(dev, type, &rid, 0ul, ~0ul, 1,
220da5e9a5bSMarcel Moolenaar 		    RF_ACTIVE);
2219c564b6cSJohn Hay 		if (res == NULL) {
2229c564b6cSJohn Hay 			printf("could not get resource\n");
2239c564b6cSJohn Hay 			continue;
2249c564b6cSJohn Hay 		}
225da5e9a5bSMarcel Moolenaar 		sc->sc_bar_mappings[bidx].type = type;
2269c564b6cSJohn Hay 		sc->sc_bar_mappings[bidx].res = res;
227084254f8SMaxim Sobolev 
228084254f8SMaxim Sobolev 		if (sc->sc_desc->ilr_type != PUC_ILR_TYPE_NONE) {
229084254f8SMaxim Sobolev 			sc->ilr_enabled = puc_probe_ilr(sc, res);
230084254f8SMaxim Sobolev 			if (sc->ilr_enabled)
231084254f8SMaxim Sobolev 				device_printf(dev, "ILR enabled\n");
232084254f8SMaxim Sobolev 			else
233084254f8SMaxim Sobolev 				device_printf(dev, "ILR disabled\n");
234084254f8SMaxim Sobolev 		}
2359c564b6cSJohn Hay #ifdef PUC_DEBUG
236da5e9a5bSMarcel Moolenaar 		printf("%s rid %d bst %x, start %x, end %x\n",
237da5e9a5bSMarcel Moolenaar 		    (type == SYS_RES_MEMORY) ? "memory" : "port", rid,
2389c564b6cSJohn Hay 		    (u_int)rman_get_bustag(res), (u_int)rman_get_start(res),
2399c564b6cSJohn Hay 		    (u_int)rman_get_end(res));
2409c564b6cSJohn Hay #endif
2419c564b6cSJohn Hay 	}
2429c564b6cSJohn Hay 
2431e89655aSPoul-Henning Kamp 	if (desc->init != NULL) {
2441e89655aSPoul-Henning Kamp 		i = desc->init(sc);
2451e89655aSPoul-Henning Kamp 		if (i != 0)
2461e89655aSPoul-Henning Kamp 			return (i);
2471e89655aSPoul-Henning Kamp 	}
2489c564b6cSJohn Hay 
2499c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
2509c564b6cSJohn Hay 		rid = sc->sc_desc->ports[i].bar;
2511e89655aSPoul-Henning Kamp 		bidx = puc_port_bar_index(sc, rid);
2529c564b6cSJohn Hay 		if (sc->sc_bar_mappings[bidx].res == NULL)
2539c564b6cSJohn Hay 			continue;
2549c564b6cSJohn Hay 
2559c564b6cSJohn Hay 		switch (sc->sc_desc->ports[i].type) {
2569c564b6cSJohn Hay 		case PUC_PORT_TYPE_COM:
2579c564b6cSJohn Hay 			typestr = "sio";
2589c564b6cSJohn Hay 			break;
2599c564b6cSJohn Hay 		default:
2609c564b6cSJohn Hay 			continue;
2619c564b6cSJohn Hay 		}
2629c564b6cSJohn Hay 		pdev = malloc(sizeof(struct puc_device), M_DEVBUF,
2639c564b6cSJohn Hay 		    M_NOWAIT | M_ZERO);
2649c564b6cSJohn Hay 		if (!pdev)
2659c564b6cSJohn Hay 			continue;
2669c564b6cSJohn Hay 		resource_list_init(&pdev->resources);
2679c564b6cSJohn Hay 
2689c564b6cSJohn Hay 		/* First fake up an IRQ resource. */
2699c564b6cSJohn Hay 		resource_list_add(&pdev->resources, SYS_RES_IRQ, 0,
2709c564b6cSJohn Hay 		    rman_get_start(sc->irqres), rman_get_end(sc->irqres),
2719c564b6cSJohn Hay 		    rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1);
2729c564b6cSJohn Hay 		rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0);
2739c564b6cSJohn Hay 		rle->res = sc->irqres;
2749c564b6cSJohn Hay 
275da5e9a5bSMarcel Moolenaar 		/* Now fake an IOPORT or MEMORY resource */
2769c564b6cSJohn Hay 		res = sc->sc_bar_mappings[bidx].res;
277da5e9a5bSMarcel Moolenaar 		type = sc->sc_bar_mappings[bidx].type;
278da5e9a5bSMarcel Moolenaar 		resource_list_add(&pdev->resources, type, 0,
2799c564b6cSJohn Hay 		    rman_get_start(res) + sc->sc_desc->ports[i].offset,
2801e89655aSPoul-Henning Kamp 		    rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1,
2819c564b6cSJohn Hay 		    8);
282da5e9a5bSMarcel Moolenaar 		rle = resource_list_find(&pdev->resources, type, 0);
2839c564b6cSJohn Hay 
2849c564b6cSJohn Hay 		if (sc->barmuxed == 0) {
2859c564b6cSJohn Hay 			rle->res = sc->sc_bar_mappings[bidx].res;
2869c564b6cSJohn Hay 		} else {
2879c564b6cSJohn Hay 			rle->res = malloc(sizeof(struct resource), M_DEVBUF,
288a163d034SWarner Losh 			    M_WAITOK | M_ZERO);
2895aa967d9SYoshihiro Takahashi 			if (rle->res == NULL) {
2905aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
2919c564b6cSJohn Hay 				return (ENOMEM);
2925aa967d9SYoshihiro Takahashi 			}
2939c564b6cSJohn Hay 
2949c564b6cSJohn Hay 			rle->res->r_start = rman_get_start(res) +
2959c564b6cSJohn Hay 			    sc->sc_desc->ports[i].offset;
2969c564b6cSJohn Hay 			rle->res->r_end = rle->res->r_start + 8 - 1;
2979c564b6cSJohn Hay 			rle->res->r_bustag = rman_get_bustag(res);
2989c564b6cSJohn Hay 			bus_space_subregion(rle->res->r_bustag,
2999c564b6cSJohn Hay 			    rman_get_bushandle(res),
3009c564b6cSJohn Hay 			    sc->sc_desc->ports[i].offset, 8,
3019c564b6cSJohn Hay 			    &rle->res->r_bushandle);
3029c564b6cSJohn Hay 		}
3039c564b6cSJohn Hay 
3049c564b6cSJohn Hay 		pdev->serialfreq = sc->sc_desc->ports[i].serialfreq;
3059c564b6cSJohn Hay 
3069c564b6cSJohn Hay 		childunit = puc_find_free_unit(typestr);
3079c564b6cSJohn Hay 		sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit);
3085aa967d9SYoshihiro Takahashi 		if (sc->sc_ports[i].dev == NULL) {
3095aa967d9SYoshihiro Takahashi 			if (sc->barmuxed) {
3105aa967d9SYoshihiro Takahashi 				bus_space_unmap(rman_get_bustag(rle->res),
311da5e9a5bSMarcel Moolenaar 				    rman_get_bushandle(rle->res), 8);
3125aa967d9SYoshihiro Takahashi 				free(rle->res, M_DEVBUF);
3135aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
3145aa967d9SYoshihiro Takahashi 			}
3159c564b6cSJohn Hay 			continue;
3165aa967d9SYoshihiro Takahashi 		}
3179c564b6cSJohn Hay 		device_set_ivars(sc->sc_ports[i].dev, pdev);
3189c564b6cSJohn Hay 		device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name);
3199c564b6cSJohn Hay 		if (!bootverbose)
3209c564b6cSJohn Hay 			device_quiet(sc->sc_ports[i].dev);
3219c564b6cSJohn Hay #ifdef PUC_DEBUG
3229c564b6cSJohn Hay 		printf("puc: type %d, bar %x, offset %x\n",
3239c564b6cSJohn Hay 		    sc->sc_desc->ports[i].type,
3249c564b6cSJohn Hay 		    sc->sc_desc->ports[i].bar,
3259c564b6cSJohn Hay 		    sc->sc_desc->ports[i].offset);
32632f606d1SPoul-Henning Kamp 		puc_print_resource_list(&pdev->resources);
3279c564b6cSJohn Hay #endif
32832bc35fdSPoul-Henning Kamp 		device_set_flags(sc->sc_ports[i].dev,
32932bc35fdSPoul-Henning Kamp 		    sc->sc_desc->ports[i].flags);
3305aa967d9SYoshihiro Takahashi 		if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) {
3315aa967d9SYoshihiro Takahashi 			if (sc->barmuxed) {
3325aa967d9SYoshihiro Takahashi 				bus_space_unmap(rman_get_bustag(rle->res),
3335aa967d9SYoshihiro Takahashi 						rman_get_bushandle(rle->res),
3345aa967d9SYoshihiro Takahashi 						8);
3355aa967d9SYoshihiro Takahashi 				free(rle->res, M_DEVBUF);
3365aa967d9SYoshihiro Takahashi 				free(pdev, M_DEVBUF);
3375aa967d9SYoshihiro Takahashi 			}
3385aa967d9SYoshihiro Takahashi 		}
3399c564b6cSJohn Hay 	}
3409c564b6cSJohn Hay 
3419c564b6cSJohn Hay #ifdef PUC_DEBUG
3429c564b6cSJohn Hay 	bootverbose = 0;
3439c564b6cSJohn Hay #endif
3449c564b6cSJohn Hay 	return (0);
3459c564b6cSJohn Hay }
3469c564b6cSJohn Hay 
347084254f8SMaxim Sobolev static u_int32_t
348084254f8SMaxim Sobolev puc_ilr_read(struct puc_softc *sc)
349084254f8SMaxim Sobolev {
350084254f8SMaxim Sobolev 	u_int32_t mask;
351084254f8SMaxim Sobolev 	int i;
352084254f8SMaxim Sobolev 
353084254f8SMaxim Sobolev 	mask = 0;
354084254f8SMaxim Sobolev 	switch (sc->sc_desc->ilr_type) {
355084254f8SMaxim Sobolev 	case PUC_ILR_TYPE_DIGI:
356084254f8SMaxim Sobolev 		for (i = 1; i >= 0; i--) {
357084254f8SMaxim Sobolev 			mask = (mask << 8) | (bus_space_read_1(sc->ilr_st,
358084254f8SMaxim Sobolev 			    sc->ilr_sh, sc->sc_desc->ilr_offset[i]) & 0xff);
359084254f8SMaxim Sobolev 		}
360084254f8SMaxim Sobolev 		break;
361084254f8SMaxim Sobolev 
362084254f8SMaxim Sobolev 	default:
363084254f8SMaxim Sobolev 		mask = 0xffffffff;
364084254f8SMaxim Sobolev 		break;
365084254f8SMaxim Sobolev 	}
366084254f8SMaxim Sobolev 	return (mask);
367084254f8SMaxim Sobolev }
368084254f8SMaxim Sobolev 
3699c564b6cSJohn Hay /*
370084254f8SMaxim Sobolev  * This is an interrupt handler. For boards that can't tell us which
371084254f8SMaxim Sobolev  * device generated the interrupt it just calls all the registered
372084254f8SMaxim Sobolev  * handlers sequencially, but for boards that can tell us which
373084254f8SMaxim Sobolev  * device(s) generated the interrupt it calls only handlers for devices
374084254f8SMaxim Sobolev  * that actually generated the interrupt.
3759c564b6cSJohn Hay  */
3769c564b6cSJohn Hay static void
3779c564b6cSJohn Hay puc_intr(void *arg)
3789c564b6cSJohn Hay {
3799c564b6cSJohn Hay 	int i;
380084254f8SMaxim Sobolev 	u_int32_t ilr_mask;
3819c564b6cSJohn Hay 	struct puc_softc *sc;
3829c564b6cSJohn Hay 
3839c564b6cSJohn Hay 	sc = (struct puc_softc *)arg;
384084254f8SMaxim Sobolev 	ilr_mask = sc->ilr_enabled ? puc_ilr_read(sc) : 0xffffffff;
3859c564b6cSJohn Hay 	for (i = 0; i < PUC_MAX_PORTS; i++)
386084254f8SMaxim Sobolev 		if (sc->sc_ports[i].ihand != NULL &&
387084254f8SMaxim Sobolev 		    ((ilr_mask >> i) & 0x00000001))
3889c564b6cSJohn Hay 			(sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg);
3899c564b6cSJohn Hay }
3909c564b6cSJohn Hay 
39132f606d1SPoul-Henning Kamp const struct puc_device_description *
3929c564b6cSJohn Hay puc_find_description(uint32_t vend, uint32_t prod, uint32_t svend,
3939c564b6cSJohn Hay     uint32_t sprod)
3949c564b6cSJohn Hay {
3959c564b6cSJohn Hay 	int i;
3969c564b6cSJohn Hay 
3979c564b6cSJohn Hay #define checkreg(val, index) \
3989c564b6cSJohn Hay     (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)])
3999c564b6cSJohn Hay 
4009c564b6cSJohn Hay 	for (i = 0; puc_devices[i].name != NULL; i++) {
4019c564b6cSJohn Hay 		if (checkreg(vend, PUC_REG_VEND) &&
4029c564b6cSJohn Hay 		    checkreg(prod, PUC_REG_PROD) &&
4039c564b6cSJohn Hay 		    checkreg(svend, PUC_REG_SVEND) &&
4049c564b6cSJohn Hay 		    checkreg(sprod, PUC_REG_SPROD))
4059c564b6cSJohn Hay 			return (&puc_devices[i]);
4069c564b6cSJohn Hay 	}
4079c564b6cSJohn Hay 
4089c564b6cSJohn Hay #undef checkreg
4099c564b6cSJohn Hay 
4109c564b6cSJohn Hay 	return (NULL);
4119c564b6cSJohn Hay }
412ed4208e9SPoul-Henning Kamp 
413ed4208e9SPoul-Henning Kamp static int
414ed4208e9SPoul-Henning Kamp puc_find_free_unit(char *name)
4159c564b6cSJohn Hay {
4169c564b6cSJohn Hay 	devclass_t dc;
4179c564b6cSJohn Hay 	int start;
4189c564b6cSJohn Hay 	int unit;
4199c564b6cSJohn Hay 
4209c564b6cSJohn Hay 	unit = 0;
4219c564b6cSJohn Hay 	start = 0;
4229c564b6cSJohn Hay 	while (resource_int_value(name, unit, "port", &start) == 0 &&
4239c564b6cSJohn Hay 	    start > 0)
4249c564b6cSJohn Hay 		unit++;
4259c564b6cSJohn Hay 	dc = devclass_find(name);
4269c564b6cSJohn Hay 	if (dc == NULL)
4279c564b6cSJohn Hay 		return (-1);
4289c564b6cSJohn Hay 	while (devclass_get_device(dc, unit))
4299c564b6cSJohn Hay 		unit++;
4309c564b6cSJohn Hay #ifdef PUC_DEBUG
4319c564b6cSJohn Hay 	printf("puc: Using %s%d\n", name, unit);
4329c564b6cSJohn Hay #endif
4339c564b6cSJohn Hay 	return (unit);
4349c564b6cSJohn Hay }
4359c564b6cSJohn Hay 
4369c564b6cSJohn Hay #ifdef PUC_DEBUG
4379c564b6cSJohn Hay static void
4389c564b6cSJohn Hay puc_print_resource_list(struct resource_list *rl)
4399c564b6cSJohn Hay {
4401e89655aSPoul-Henning Kamp #if 0
4419c564b6cSJohn Hay 	struct resource_list_entry *rle;
4429c564b6cSJohn Hay 
4439c564b6cSJohn Hay 	printf("print_resource_list: rl %p\n", rl);
4449c564b6cSJohn Hay 	SLIST_FOREACH(rle, rl, link)
4451e89655aSPoul-Henning Kamp 		printf("  type %x, rid %x start %x end %x count %x\n",
4461e89655aSPoul-Henning Kamp 		    rle->type, rle->rid, rle->start, rle->end, rle->count);
4479c564b6cSJohn Hay 	printf("print_resource_list: end.\n");
4481e89655aSPoul-Henning Kamp #endif
4499c564b6cSJohn Hay }
4509c564b6cSJohn Hay #endif
4519c564b6cSJohn Hay 
45232f606d1SPoul-Henning Kamp struct resource *
4539c564b6cSJohn Hay puc_alloc_resource(device_t dev, device_t child, int type, int *rid,
4549c564b6cSJohn Hay     u_long start, u_long end, u_long count, u_int flags)
4559c564b6cSJohn Hay {
4569c564b6cSJohn Hay 	struct puc_device *pdev;
4579c564b6cSJohn Hay 	struct resource *retval;
4589c564b6cSJohn Hay 	struct resource_list *rl;
4599c564b6cSJohn Hay 	struct resource_list_entry *rle;
4609c564b6cSJohn Hay 
4619c564b6cSJohn Hay 	pdev = device_get_ivars(child);
4629c564b6cSJohn Hay 	rl = &pdev->resources;
4639c564b6cSJohn Hay 
4649c564b6cSJohn Hay #ifdef PUC_DEBUG
4659c564b6cSJohn Hay 	printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n",
4669c564b6cSJohn Hay 	    pdev, type, *rid);
4679c564b6cSJohn Hay 	puc_print_resource_list(rl);
4689c564b6cSJohn Hay #endif
4699c564b6cSJohn Hay 	retval = NULL;
4709c564b6cSJohn Hay 	rle = resource_list_find(rl, type, *rid);
4719c564b6cSJohn Hay 	if (rle) {
4729c564b6cSJohn Hay 		start = rle->start;
4739c564b6cSJohn Hay 		end = rle->end;
4749c564b6cSJohn Hay 		count = rle->count;
4759c564b6cSJohn Hay #ifdef PUC_DEBUG
4769c564b6cSJohn Hay 		printf("found rle, %lx, %lx, %lx\n", start, end, count);
4779c564b6cSJohn Hay #endif
4789c564b6cSJohn Hay 		retval = rle->res;
4799c564b6cSJohn Hay 	} else
4809c564b6cSJohn Hay 		printf("oops rle is gone\n");
4819c564b6cSJohn Hay 
4829c564b6cSJohn Hay 	return (retval);
4839c564b6cSJohn Hay }
4849c564b6cSJohn Hay 
48532f606d1SPoul-Henning Kamp int
4869c564b6cSJohn Hay puc_release_resource(device_t dev, device_t child, int type, int rid,
4879c564b6cSJohn Hay     struct resource *res)
4889c564b6cSJohn Hay {
4899c564b6cSJohn Hay 	return (0);
4909c564b6cSJohn Hay }
4919c564b6cSJohn Hay 
49232f606d1SPoul-Henning Kamp int
4939c564b6cSJohn Hay puc_get_resource(device_t dev, device_t child, int type, int rid,
4949c564b6cSJohn Hay     u_long *startp, u_long *countp)
4959c564b6cSJohn Hay {
4969c564b6cSJohn Hay 	struct puc_device *pdev;
4979c564b6cSJohn Hay 	struct resource_list *rl;
4989c564b6cSJohn Hay 	struct resource_list_entry *rle;
4999c564b6cSJohn Hay 
5009c564b6cSJohn Hay 	pdev = device_get_ivars(child);
5019c564b6cSJohn Hay 	rl = &pdev->resources;
5029c564b6cSJohn Hay 
5039c564b6cSJohn Hay #ifdef PUC_DEBUG
5049c564b6cSJohn Hay 	printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev,
5059c564b6cSJohn Hay 	    type, rid);
5069c564b6cSJohn Hay 	puc_print_resource_list(rl);
5079c564b6cSJohn Hay #endif
5089c564b6cSJohn Hay 	rle = resource_list_find(rl, type, rid);
5099c564b6cSJohn Hay 	if (rle) {
5109c564b6cSJohn Hay #ifdef PUC_DEBUG
5119c564b6cSJohn Hay 		printf("found rle %p,", rle);
5129c564b6cSJohn Hay #endif
5139c564b6cSJohn Hay 		if (startp != NULL)
5149c564b6cSJohn Hay 			*startp = rle->start;
5159c564b6cSJohn Hay 		if (countp != NULL)
5169c564b6cSJohn Hay 			*countp = rle->count;
5179c564b6cSJohn Hay #ifdef PUC_DEBUG
5189c564b6cSJohn Hay 		printf(" %lx, %lx\n", rle->start, rle->count);
5199c564b6cSJohn Hay #endif
5209c564b6cSJohn Hay 		return (0);
5219c564b6cSJohn Hay 	} else
5229c564b6cSJohn Hay 		printf("oops rle is gone\n");
5239c564b6cSJohn Hay 	return (ENXIO);
5249c564b6cSJohn Hay }
5259c564b6cSJohn Hay 
52632f606d1SPoul-Henning Kamp int
5279c564b6cSJohn Hay puc_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
5289c564b6cSJohn Hay 	       void (*ihand)(void *), void *arg, void **cookiep)
5299c564b6cSJohn Hay {
5309c564b6cSJohn Hay 	int i;
5319c564b6cSJohn Hay 	struct puc_softc *sc;
5329c564b6cSJohn Hay 
5339c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
5341f02c343SPoul-Henning Kamp 	if ((flags & INTR_FAST) != sc->fastintr)
535d3c10e33SPoul-Henning Kamp 		return (ENXIO);
5369c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
5379c564b6cSJohn Hay 		if (sc->sc_ports[i].dev == child) {
5389c564b6cSJohn Hay 			if (sc->sc_ports[i].ihand != 0)
5399c564b6cSJohn Hay 				return (ENXIO);
5409c564b6cSJohn Hay 			sc->sc_ports[i].ihand = ihand;
5419c564b6cSJohn Hay 			sc->sc_ports[i].ihandarg = arg;
5429c564b6cSJohn Hay 			*cookiep = arg;
5439c564b6cSJohn Hay 			return (0);
5449c564b6cSJohn Hay 		}
5459c564b6cSJohn Hay 	}
5469c564b6cSJohn Hay 	return (ENXIO);
5479c564b6cSJohn Hay }
5489c564b6cSJohn Hay 
54932f606d1SPoul-Henning Kamp int
5509c564b6cSJohn Hay puc_teardown_intr(device_t dev, device_t child, struct resource *r,
5519c564b6cSJohn Hay 		  void *cookie)
5529c564b6cSJohn Hay {
5539c564b6cSJohn Hay 	int i;
5549c564b6cSJohn Hay 	struct puc_softc *sc;
5559c564b6cSJohn Hay 
5569c564b6cSJohn Hay 	sc = (struct puc_softc *)device_get_softc(dev);
5579c564b6cSJohn Hay 	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
5589c564b6cSJohn Hay 		if (sc->sc_ports[i].dev == child) {
5599c564b6cSJohn Hay 			sc->sc_ports[i].ihand = NULL;
5609c564b6cSJohn Hay 			sc->sc_ports[i].ihandarg = NULL;
5619c564b6cSJohn Hay 			return (0);
5629c564b6cSJohn Hay 		}
5639c564b6cSJohn Hay 	}
5649c564b6cSJohn Hay 	return (ENXIO);
5659c564b6cSJohn Hay }
5669c564b6cSJohn Hay 
56732f606d1SPoul-Henning Kamp int
5689c564b6cSJohn Hay puc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
5699c564b6cSJohn Hay {
5709c564b6cSJohn Hay 	struct puc_device *pdev;
5719c564b6cSJohn Hay 
5729c564b6cSJohn Hay 	pdev = device_get_ivars(child);
5739c564b6cSJohn Hay 	if (pdev == NULL)
5749c564b6cSJohn Hay 		return (ENOENT);
5759c564b6cSJohn Hay 
5769c564b6cSJohn Hay 	switch(index) {
5779c564b6cSJohn Hay 	case PUC_IVAR_FREQ:
5789c564b6cSJohn Hay 		*result = pdev->serialfreq;
5799c564b6cSJohn Hay 		break;
5809c564b6cSJohn Hay 	default:
5819c564b6cSJohn Hay 		return (ENOENT);
5829c564b6cSJohn Hay 	}
5839c564b6cSJohn Hay 	return (0);
5849c564b6cSJohn Hay }
585