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